Update Cordio host & controller stack to 21.04

feature-ble-cordio-21.04
Chris Swinchatt 2021-07-19 13:02:47 +01:00 committed by GitHub
parent cf54d36bfb
commit 8afb1c5bac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
287 changed files with 11587 additions and 5155 deletions

View File

@ -24,6 +24,7 @@
#include "ble/common/BLETypes.h"
#include "ble/driver/CordioHCITransportDriver.h"
#include "ble/common/blecommon.h"
#include "hal/ticker_api.h"
// FIXME: make this invisible!
#include "wsf_buf.h"
@ -145,7 +146,14 @@ public:
*
* Any call to write signals to the driver that the host stack is active.
*/
virtual void on_host_stack_inactivity();
virtual void on_host_stack_inactivity();
/**
* React to host stack preparing to enter deep sleep.
*
* \param[in] wakeTimeMs The amount of time in which to wake.
*/
virtual void on_deep_sleep(timestamp_t wakeTimeMs) {}
/* BLE Tester commands */

View File

@ -0,0 +1,131 @@
Change Log
r21.04
Improvements:
FW-3921 Deprecate power management API
FW-3996 Improve interoperability with connection establishment when LL_OP_MODE_FLAG_ENA_FEAT_LLCP_STARTUP is enabled
FW-4045 Relocate CIS Audio codec decode to end of CIS ISO event
FW-4047 CIS Should change RTE parameters if it cannot honor host-requested value
Defects fixed:
FW-3851 HCI_LE_CIS_Established event has MAX_PDUs fields zero on both Master and Slave
FW-3879 Incorrect AuxOffsetPtr value with large skip values
FW-3890 Master may not synchronize with PAST
FW-3981 HCI_LE_Setup_ISO_Data_Path for a BIS may incorrectly return success when clearing
FW-3982 HCI_LE_Read_Remote_Features may return bits not in controller-to-controller mask
FW-3986 HCI_Disconnect for CIS should return HCI_ERR_LOCAL_TERMINATED
FW-3987 CIS ISO test Rx mode incorrectly counts successful packets
FW-3989 Framed CIS test Rx mode will hang when receiving a data packet
FW-3995 HCI_LE_Read_Remote_Features with LL_OP_MODE_FLAG_ENA_FEAT_LLCP_STARTUP enabled may be disallowed
FW-3997 HCI_LE_Set_Address_Resolution_Enable set to FALSE may prevents controller from generating RPA for peer
FW-3998 HCI_LE_Set_Address_Resolution_Enable set to FALSE may incorrectly continue to resolve RPA packets
FW-3999 HCI_LE_ISO_Receive_Test for BIS does not receive when datapath is disabled
FW-4004 HCI_LE_Transmit_Power_Reporting not generated when delta is 0
FW-4005 Flushing of a PDU when a framed assembly has not started will discard the next valid PDU
FW-4020 Allow payload with SYNC_INFO when synchronizing with Periodic Advertiser
FW-4021 Periodic Synchronizer may use incorrect Aux Offset
FW-4028 IAL BIS case times out before able to complete test procedure
FW-4035 LL initialization directives are multiply defined
FW-4039 LL_FEAT_ISO_SYNC feature bit not set
FW-4042 CIS has MIC failure if two data packets are sent in same ISO event
FW-4044 Peripheral CIS is not able to be schedule after a connection update
FW-4046 CIS acknowledgement scheme does not work correctly
FW-4048 Peripheral CIS may not advance payloads even after central acknowledges them
Known limitations:
FW-3789 ISO timestamps and packet counters may not be aligned in certain scenarios
FW-3886 DLE max packet time should cap at 1M PHY when LE Coded PHY is disabled
FW-4063 HCI_LE_Advertising_Set_Terminated may report incorrect Num_Completed_Extended_Advertising_Events with ExtAdv using LE Coded PHY
r21.02
Improvements:
FW-3988 LeSetCigParams defensive coding for zero-division
Known limitations:
FW-3981 HCI_LE_Setup_ISO_Data_Path for a BIS may incorrectly return success when clearing
FW-3982 HCI_LE_Read_Remote_Features may return bits not in controller-to-controller mask
FW-3986 HCI_Disconnect for CIS should return HCI_ERR_LOCAL_TERMINATED
FW-3789 ISO timestamps and packet counters may not be aligned in certain scenarios
FW-3851 HCI_LE_CIS_Established event has MAX_PDUs fields zero on both Master and Slave
FW-3879 Incorrect AuxOffsetPtr value with large skip values
FW-3886 DLE max packet time should cap at 1M PHY when LE Coded PHY is disabled
FW-3890 Master may not synchronize with PAST
FW-3987 CIS ISO test Rx mode incorrectly counts successful packets
FW-3989 Framed CIS test Rx mode will hang when receiving a data packet
FW-3995 HCI_LE_Read_Remote_Features with LL_OP_MODE_FLAG_ENA_FEAT_LLCP_STARTUP enabled may be disallowed
FW-3997 HCI_LE_Set_Address_Resolution_Enable set to FALSE may prevents controller from generating RPA for peer
FW-3998 HCI_LE_Set_Address_Resolution_Enable set to FALSE may incorrectly continue to resolve RPA packets
FW-3999 HCI_LE_ISO_Receive_Test for BIS does not receive when datapath is disabled
FW-4004 HCI_LE_Transmit_Power_Reporting not generated when delta is 0
FW-4005 Flushing of a PDU when a framed assembly has not started will discard the next valid PDU
r20.12
Improvements:
FW-3385 Non-blocking scheme for PAL flash
FW-3728 Packetcraft Audio Cape for PCA10056
FW-3838 Token monitor utility script
FW-3848 CIS and BIS recombination of SDUs
FW-3862 BV32 codec integrated on nRF52840
FW-3864 Write flash between radio events on nRF52840
FW-3865 Nordic secure bootloader updates firmware from internal flash
FW-3876 Tester should have a way to sequentially queue ISO Packets
FW-3899 Controller should queue up disconnect commands for multiple CIS
FW-3905 Change BIS datapath to use generic functions
FW-3907 ITM SWO trace diagnostics
FW-3931 Power control monitor improvements
FW-3943 Sydney erratta: CIS RTE max removed (0x0F -> 0xFF)
FW-3949 LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2 force CIS to use Coded PHY S2 option
Defects fixed:
FW-3263 Scanner may not filter AdvReport events when Filter Policy is 0x02 and RPA is used
FW-3781 Some broadcaster BIS PTO combinations may fail
FW-3821 BIS broadcaster may corrupt transmitted ISO SDUs
FW-3822 HCI_LE_BIG_Create_Sync does not filter on BIS[i]
FW-3831 HCI_GetVersion does not report build number
FW-3837 Incorrect BIS length will prevent adjacent BIS from receive
FW-3839 CIS interleaved uses incorrect channels on subevent 3+
FW-3841 Timer may expire early
FW-3845 CIS and ACL are using wrong channel parameters
FW-3846 BIS encryption may use incorrect packet counter
FW-3849 Command complete for setting CIG params will always return CIG=0
FW-3850 Disconnecting ACL with CIS does not return a terminated event for CIS
FW-3856 BIS should send lost packet SDUs to the host if no PDU is received
FW-3857 BIS Framed PDUs are not sent in consecutive subevents
FW-3858 Unframed BIS may send duplicate Data PDUs when BN > 1
FW-3868 LE_REMOVE_CIG command doesn't have CIG ID field.
FW-3869 Radio scheduler may operate on list out of order
FW-3870 PHY incorrect when using CIS encryption that differs in PHY with ACL
FW-3872 Removing CIS output data path returns command disallowed
FW-3873 Closing and re-opening the same CIS will not properly establish the second CIS
FW-3875 Controller will not send LLCP anymore if receiving UNKNOWN_RSP for a power control LLCP
FW-3877 LhciRegisterSendTrCompleteHandler() callback does not persist after HCI_Reset
FW-3878 Inline decryption does not filter encrypted packets that are NACK'ed
FW-3881 CIS may attempt transmission after a failed receive
FW-3882 CIS may receive on incorrect PHY when encrypted
FW-3883 CIS rx timeout will cause the whole ISO event to be canceled
FW-3884 CIS Slave encryption will not transmit correctly when bn StoM>0 and NSE>1
FW-3894 CIS Slave will not respond to ACL events if CIS is disconnected
FW-3895 CIS will not pass up lost or invalid SDUs to host
FW-3896 MIC failure upon establishing 2 CIS
FW-3906 Radio scheduler may overlap reservations
FW-3908 Periodic Advertising may not send SyncInfo when restarting
FW-3937 CIS MIC error returns two discconnection events
FW-3941 Advertising while scanning may skip first advertising event
FW-3942 CIS may duplicate packets when using codec datapath
Known limitations:
FW-3789 ISO timestamps and packet counters may not be aligned in certain scenarios
FW-3851 HCI_LE_CIS_Established event has MAX_PDUs fields zero on both Master and Slave
FW-3879 Incorrect AuxOffsetPtr value with large skip values
FW-3886 DLE max packet time should cap at 1M PHY when LE Coded PHY is disabled
FW-3890 Master may not synchronize with PAST

View File

@ -350,6 +350,24 @@ void BbBleGetPerScanStats(BbBlePerScanPktStats_t *pStats);
/*************************************************************************************************/
void BbBleGetConnStats(BbBleDataPktStats_t *pStats);
/*************************************************************************************************/
/*!
* \brief Get CIS packet statistics.
*
* \param pStats CIS data statistics.
*/
/*************************************************************************************************/
void BbBleGetCisStats(BbBleDataPktStats_t *pStats);
/*************************************************************************************************/
/*!
* \brief Get BIS packet statistics.
*
* \param pStats BIS data statistics.
*/
/*************************************************************************************************/
void BbBleGetBisStats(BbBleDataPktStats_t *pStats);
/*************************************************************************************************/
/*!
* \brief Get test mode packet statistics.
@ -404,15 +422,6 @@ void BbBleBisMasterInit(void);
/*************************************************************************************************/
void BbBleBisSlaveInit(void);
/*************************************************************************************************/
/*!
* \brief Get CIS packet statistics.
*
* \param pStats CIS data statistics.
*/
/*************************************************************************************************/
void BbBleGetCisStats(BbBleDataPktStats_t *pStats);
/*! \} */ /* BB_API_BLE */
#ifdef __cplusplus

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2016-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -99,6 +99,15 @@ typedef void (*BbBleTxAdvSetup_t)(BbOpDesc_t *pBod, uint32_t advTxTime);
/*! \brief Chain indication PDU transmit setup call signature. */
typedef uint32_t (*BbBleTxAuxSetup_t)(BbOpDesc_t *pBod, bool_t isChainInd);
/*! \brief Aux Rx setup call signature. Returns TRUE if Scan was programmed. */
typedef bool_t (*BbBleRxAuxSetup_t)(BbOpDesc_t *pBod, uint32_t refTime, uint32_t remScanDur);
/*! \brief Aux Tx complete call signature. Returns TRUE if BOD is complete. */
typedef bool_t (*BbBleAuxTxComp_t)(BbOpDesc_t *pBod, uint8_t status);
/*! \brief Aux Rx complete call signature. Returns TRUE if BOD is complete. */
typedef bool_t (*BbBleAuxRxComp_t)(BbOpDesc_t * const pCur, uint8_t status, int8_t rssi, uint32_t crc, uint32_t timestamp, uint8_t rxPhyOptions);
/*! \brief Returns TRUE if an scan request/response required. */
typedef bool_t (*BbBleAdvComp_t)(BbOpDesc_t *pBod, const uint8_t *pBuf);
@ -152,6 +161,13 @@ typedef struct
BbBleAdvComp_t txReqCback; /*!< Scan request completion callback. */
BbBleAdvComp_t rxRspCback; /*!< Scan response completion callback. */
/* Aux Scan BOD link */
BbOpDesc_t *auxScanBod; /*!< Pointer to the Aux Scan BOD */
BbBleRxAuxSetup_t auxScanCheckCback; /*!< Setup an Aux Scan that needs to be programmed ASAP. */
BbBleAuxTxComp_t auxScanTxCompCback; /*!< Aux Scan Tx complete. */
BbBleAuxRxComp_t auxScanRxCompCback; /*!< Aux Scan Rx complete. */
bool_t auxScanOpRunning; /*!< Informs if an Aux Scan operation is running in the context of the Ext Scan BOD. */
uint8_t txReqLen; /*!< Scan request buffer length. */
uint8_t scanChMap; /*!< Scan channel map. */
@ -202,6 +218,7 @@ typedef struct
uint8_t *pTxAuxReqBuf; /*!< Scan request buffer. */
BbBleAdvComp_t rxAuxAdvCback; /*!< Advertising completion callback. */
BbBleAdvPost_t rxAuxAdvPostCback; /*!< Advertising completion post callback. */
BbBleAdvComp_t rxAuxRspCback; /*!< Scan response completion callback. */
BbBleRxChain_t rxAuxChainCback; /*!< Chain completion callback. */
BbBleRxChainPost_t rxAuxChainPostCback;/*!< Chain completion post callback. */
@ -291,13 +308,14 @@ typedef struct
/*! \brief CIS master event operation data (\ref BB_BLE_OP_MST_CIS_EVENT). */
typedef struct
{
BbBleCisCheckContOp_t checkContOpCback; /*!< Check whether to continue current operation callback. */
BbBleExec_t execCback; /*!< Execute callback. */
BbBleExec_t contExecCback; /*!< Continue execute callback. */
BbBleCisPostExec_t postSubEvtCback; /*!< Post subevent callback. */
BbBleCancel_t cancelCback; /*!< Cancel callback. */
BbBleTxDataComp_t txDataCback; /*!< Transmit completion callback. */
BbBleCisRxDataComp_t rxDataCback; /*!< Receive completion callback. */
BbBleCisCheckContOp_t checkContOpCback; /*!< Check whether to continue current operation callback. */
BbBleCisCheckContOp_t checkContOpPostCback; /*!< Check whether to continue current operation callback. */
BbBleExec_t execCback; /*!< Execute callback. */
BbBleExec_t contExecCback; /*!< Continue execute callback. */
BbBleCisPostExec_t postSubEvtCback; /*!< Post subevent callback. */
BbBleCancel_t cancelCback; /*!< Cancel callback. */
BbBleTxDataComp_t txDataCback; /*!< Transmit completion callback. */
BbBleCisRxDataComp_t rxDataCback; /*!< Receive completion callback. */
/* Return parameters. */
int8_t rssi; /*!< RSSI of the last received packet. */
uint8_t rxPhyOptions; /*!< Rx PHY options. */
@ -306,13 +324,14 @@ typedef struct
/*! \brief CIS slave event operation data (\ref BB_BLE_OP_SLV_CIS_EVENT). */
typedef struct
{
BbBleCisCheckContOp_t checkContOpCback; /*!< Check whether to continue current operation callback. */
BbBleExec_t execCback; /*!< Execute callback. */
BbBleExec_t contExecCback; /*!< Continue execute callback. */
BbBleCisPostExec_t postSubEvtCback; /*!< Post subevent callback. */
BbBleCancel_t cancelCback; /*!< Cancel callback. */
BbBleTxDataComp_t txDataCback; /*!< Transmit completion callback. */
BbBleRxDataComp_t rxDataCback; /*!< Receive completion callback. */
BbBleCisCheckContOp_t checkContOpCback; /*!< Check whether to continue current operation callback. */
BbBleCisCheckContOp_t checkContOpPostCback; /*!< Check whether to continue current operation callback. */
BbBleExec_t execCback; /*!< Execute callback. */
BbBleExec_t contExecCback; /*!< Continue execute callback. */
BbBleCisPostExec_t postSubEvtCback; /*!< Post subevent callback. */
BbBleCancel_t cancelCback; /*!< Cancel callback. */
BbBleTxDataComp_t txDataCback; /*!< Transmit completion callback. */
BbBleRxDataComp_t rxDataCback; /*!< Receive completion callback. */
/* Return parameters. */
bool_t isFirstTs; /*!< True for the first timestamp. */
@ -490,6 +509,49 @@ void BbBleBisRxData(uint8_t *pBuf, uint16_t len, uint32_t nextPduTime, PalBbBleC
/*************************************************************************************************/
void BbBleBisRxDataReAcq(uint32_t syncTime, PalBbBleChan_t *pChan);
/*************************************************************************************************/
/*!
* \brief Execute auxiliary scanning master BOD.
*
* \param pBod Pointer to the BOD to execute.
* \param pBle BLE operation parameters.
*/
/*************************************************************************************************/
void BbMstExecuteLinkedAuxScanOp(BbOpDesc_t *pBod, BbBleData_t *pBle);
/*************************************************************************************************/
/*!
* \brief Tx completion for auxiliary scanning master operation.
*
* \param status Completion status.
* \param pBod Pointer to the BOD
*
* Setup for next action in the operation or complete the operation.
*
* \return TRUE if BOD is complete, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t BbMstAuxScanTxCompHandler(BbOpDesc_t * const pBod, uint8_t status);
/*************************************************************************************************/
/*!
* \brief Rx completion for auxiliary scanning master operation.
*
* \param pCur Pointer to the BOD
* \param status Reception status.
* \param rssi RSSI value.
* \param crc CRC value.
* \param timestamp Start of packet timestamp in microseconds.
* \param rxPhyOptions Rx PHY options.
*
* Setup for next action in the operation or complete the operation.
*
* \return TRUE if BOD is complete, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t BbMstAuxScanRxCompHandler(BbOpDesc_t * const pCur, uint8_t status, int8_t rssi, uint32_t crc,
uint32_t timestamp, uint8_t rxPhyOptions);
/*! \} */ /* BB_API_BLE */
#ifdef __cplusplus

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2016-2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -44,6 +44,10 @@ extern "C" {
/*! \brief Set a flag. */
#define BB_BLE_PDU_FILT_SET_FLAG(pFilt, flag) (pFilt)->flags |= BB_BLE_PDU_FILT_FLAG_##flag;
/*! \brief Clear a flag. */
#define BB_BLE_PDU_FILT_CLR_FLAG(pFilt, flag) (pFilt)->flags &= ~(BB_BLE_PDU_FILT_FLAG_##flag);
/*! \brief PDU filtering flags. */
enum
{

View File

@ -76,6 +76,7 @@ void LhciBisSlaveInit(void);
void LhciBisMasterInit(void);
void LhciIsoInit(void);
void LhciPowerControlInit(void);
void LhciEnhConnUpdateInit(void);
void LhciVsExtInit(lhciCmdHandler_t decodeCmd);
void LhciHandlerInit(wsfHandlerId_t handlerId);
void LhciHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,7 +36,7 @@ extern "C" {
#endif
/*! \brief Version number. */
#define LL_VER_NUM 1366
#define LL_VER_NUM 21015
/**************************************************************************************************
Data Types
@ -164,6 +164,11 @@ typedef struct
bool_t phyCodedSup; /*!< Coded PHY supported. */
bool_t stableModIdxTxSup; /*!< Tx stable modulation index supported. */
bool_t stableModIdxRxSup; /*!< Rx stable modulation index supported. */
/* Power control */
int8_t pcHighThreshold; /*!< High RSSI threshold for power monitoring. */
int8_t pcLowThreshold; /*!< Low RSSI threshold for power monitoring. */
/* Channel classification reporting. */
uint8_t chClassIntSpacing; /*!< Interval spacing of channel classification reporting. */
} LlRtCfg_t;
/*! \} */ /* LL_API_INIT */
@ -253,15 +258,23 @@ typedef struct
#define LL_FEAT_CIS_MASTER_ROLE (UINT64_C(1) << 28) /*!< Connected Isochronous Stream Master Role supported. */
#define LL_FEAT_CIS_SLAVE_ROLE (UINT64_C(1) << 29) /*!< Connected Isochronous Stream Slave Role supported. */
#define LL_FEAT_ISO_BROADCASTER (UINT64_C(1) << 30) /*!< Isochronous Broadcaster Role supported. */
#define LL_FEAT_ISO_SYNC (UINT64_C(1) << 31) /*!< Isochronous Synchronizer Role supported. */
#define LL_FEAT_ISO_SYNC (UINT64_C(1) << 31) /*!< Isochronous Synchronized Receiver Role supported. */
#define LL_FEAT_ISO_HOST_SUPPORT (UINT64_C(1) << 32) /*!< Host support for ISO Channels. */
#define LL_FEAT_POWER_CONTROL_REQUEST (UINT64_C(1) << 33) /*!< Power control requests supported. */
#define LL_FEAT_POWER_CHANGE_IND (UINT64_C(1) << 34) /*!< Power control power change indication supported. */
#define LL_FEAT_PATH_LOSS_MONITOR (UINT64_C(1) << 35) /*!< Path loss monitoring supported. */
/* --- Core Spec Sydney --- */
#define LL_FEAT_PER_ADV_ADI_SUP (UINT64_C(1) << 36) /*!< Periodic advertising ADI field supported. */
#define LL_FEAT_CONN_SUBRATE (UINT64_C(1) << 37) /*!< Connection subrating supported. */
#define LL_FEAT_CONN_SUBRATE_HOST_SUPPORT (UINT64_C(1) << 38) /*!< Host support for connection subrating. */
#define LL_FEAT_CHANNEL_CLASSIFICATION (UINT64_C(1) << 39) /*!< Channel classification supported. */
/* Bits 56 - 62 are RFU for testing. */
#define LL_HOST_CONTROLLED_FEAT LL_FEAT_ISO_HOST_SUPPORT /*!< Feature bits controlled by the host. */
/*! \brief Feature bits controlled by the host. */
#define LL_HOST_CONTROLLED_FEAT (LL_FEAT_ISO_HOST_SUPPORT | LL_FEAT_CONN_SUBRATE_HOST_SUPPORT)
#define LL_FEAT_ALL_MASK (UINT64_C(0x0000000FFF01FFFF)) /*!< All feature mask, need to be updated when new features are added. */
/*! \brief All feature mask. */
#define LL_FEAT_ALL_MASK (UINT64_C(0x000000FFFFFFFFFF))
/*! \brief This parameter identifies the device role. */
typedef enum
@ -289,14 +302,19 @@ enum
LL_OP_MODE_FLAG_ENA_MST_CIS_NULL_PDU = (1 << 12), /*!< Enable CIS master sends additional NULL PDU for acknowledge scheme. */
LL_OP_MODE_FLAG_ENA_SLV_AUX_IND_ADVA = (1 << 13), /*!< AdvA will be included in AUX_ADV_IND instead of ADV_EXT_IND. */
LL_OP_MODE_FLAG_ENA_ADV_CHAN_RAND = (1 << 14), /*!< Enable advertising channel randomization. */
LL_OP_MODE_DISABLE_POWER_MONITOR = (1 << 15), /*!< Disable power monitoring. */
LL_OP_MODE_FLAG_DIS_POWER_MONITOR = (1 << 15), /*!< Disable power monitoring. */
LL_OP_MODE_FLAG_ENA_BIS_RECV_DUP = (1 << 16), /*!< Enable BIS receive duplicates. */
LL_OP_MODE_FLAG_ENA_ISO_LOST_NOTIFY = (1 << 17), /*!< Enable HCI ISO lost SDU notification. */
LL_OP_MODE_FLAG_ENA_CH_RPT_LLCP_AFTER_FEAT = (1 << 18), /*!< Perform channel report LLCP after feature exchange. */
LL_OP_MODE_FLAG_IGNORE_CRC_ERR_TS = (1 << 19), /*!< Ignore timestamp of Rx packet with CRC error. */
LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2 = (1 << 20), /*!< Force CIS to use Coded PHY with S2 option. */
/* diagnostics only */
LL_OP_MODE_FLAG_ENA_ADV_DLY = (1 << 16), /*!< Enable advertising delay. */
LL_OP_MODE_FLAG_ENA_SCAN_BACKOFF = (1 << 17), /*!< Enable scan backoff. */
LL_OP_MODE_FLAG_ENA_WW = (1 << 18), /*!< Enable window widening. */
LL_OP_MODE_FLAG_ENA_SLV_LATENCY = (1 << 19), /*!< Enable slave latency. */
LL_OP_MODE_FLAG_ENA_LLCP_TIMER = (1 << 20), /*!< Enable LLCP timer. */
LL_OP_MODE_FLAG_IGNORE_CRC_ERR_TS = (1 << 21) /*!< Ignore timestamp of RX packet with CRC error. */
LL_OP_MODE_FLAG_ENA_ADV_DLY = (1 << 24), /*!< Enable advertising delay. */
LL_OP_MODE_FLAG_ENA_SCAN_BACKOFF = (1 << 25), /*!< Enable scan backoff. */
LL_OP_MODE_FLAG_ENA_WW = (1 << 26), /*!< Enable window widening. */
LL_OP_MODE_FLAG_ENA_SLV_LATENCY = (1 << 27), /*!< Enable slave latency. */
LL_OP_MODE_FLAG_ENA_LLCP_TIMER = (1 << 28), /*!< Enable LLCP timer. */
LL_OP_MODE_FLAG_ENA_SUBRATE_CE = (1 << 29) /*!< Enable subrating connection events. */
};
/*! \} */ /* LL_API_DEVICE */
@ -485,7 +503,14 @@ enum
};
/*! \brief Periodic advertising create sync options valid bits. */
#define LL_PER_ADV_CREATE_SYNC_OPTIONS_BITS 0x03
#define LL_PER_ADV_CREATE_SYNC_OPTIONS_BITS 0x07
/*! \brief Periodic advertising enable bits. */
enum
{
LL_PER_ADV_ENABLE_ADV_ENABLE_BIT = (1 << 0), /*!< Enable bit for periodic advertising enable command. */
LL_PER_ADV_ENABLE_ADI_ENABLE_BIT = (1 << 1) /*!< Enable bit for periodic advertising ADI inclusion. */
};
/*! \brief Periodic advertising create sync command. */
typedef struct
@ -732,8 +757,8 @@ typedef enum
/*! \brief ISO data path. */
typedef enum
{
LL_ISO_DATA_PATH_HCI = 0x00,
LL_ISO_DATA_PATH_VS = 0x01, /*!< Vendor Specific. */
LL_ISO_DATA_PATH_HCI = 0x00, /*!< HCI data path. */
LL_ISO_DATA_PATH_VS = 0x01, /*!< Vendor Specific data path. */
LL_ISO_DATA_PATH_TOTAL, /*!< Total number of data path methods. */
@ -747,6 +772,15 @@ enum
LL_ISO_DATA_PATH_OUTPUT_BIT = (1 << 1) /*!< Data path output bit. */
};
/*! \brief LE setup ISO Data Path command. */
typedef struct
{
LlIsoDataPathDir_t dpDir:8; /*!< Data path direction. */
uint8_t dpId; /*!< Data path ID. */
uint8_t vsCfgLen; /*!< Length of \a pVsCfg. */
const uint8_t *pVsCfg; /*!< VS configuration buffer. */
} LlIsoConfigDataPath_t;
/*! \brief LE setup ISO Data Path command. */
typedef struct
{
@ -756,18 +790,19 @@ typedef struct
uint8_t codecFormat; /*!< Codec Format. */
uint16_t codecCompId; /*!< Codec Company ID. */
uint16_t codecId; /*!< Codec ID. */
uint32_t ctrDly; /*!< Codec ID. */
uint32_t ctrDly; /*!< Controller delay. */
uint8_t codecConfigLen; /*!< Codec configuration length. */
uint8_t *pCodecConfig; /*!< Codec configuration. */
const uint8_t *pCodecConfig; /*!< Codec configuration. */
} LlIsoSetupDataPath_t;
/*! \brief BIG Create BIG message. */
/*! \brief BIG Create BIG command. */
typedef struct
{
uint8_t bigHandle; /*!< Used to identify the BIG. */
uint8_t advHandle; /*!< Used to identify the periodic advertising train. */
uint8_t numBis; /*!< Total number of BISes in the BIG. */
uint32_t sduInterUsec; /*!< Interval, in microseconds, of BIG SDUs. */
uint8_t bcstCode[LL_BC_LEN];/*!< Session key used to encrypt and decrypt BIS payloads. */
uint16_t maxSdu; /*!< Maximum size of an SDU. */
uint16_t mtlMs; /*!< Maximum time in milliseconds. */
uint8_t rtn; /*!< Retransmitted number. */
@ -775,16 +810,16 @@ typedef struct
uint8_t packing; /*!< Sequential or Interleaved packing. */
LlFraming_t framing:8; /*!< Unframed or Framed. */
uint8_t encrypt; /*!< Unencrypted or Encrypted. */
uint8_t bcstCode[LL_BC_LEN];/*!< Session key used to encrypt and decrypt BIS payloads. */
} LlCreateBig_t;
/*! \brief BIG Create BIG Test message. */
/*! \brief BIG Create BIG Test command. */
typedef struct
{
uint8_t bigHandle; /*!< Used to identify the BIG. */
uint8_t advHandle; /*!< Used to identify the periodic advertising train. */
uint8_t numBis; /*!< Total number of BISes in the BIG. */
uint32_t sduInterUsec; /*!< Interval in microseconds of BIG SDUs. */
uint8_t bcstCode[LL_BC_LEN];/*!< Code used to derive the session key. */
uint16_t isoInter; /*!< Duration of an isochronous interval for BIG PDUs in 1.25ms unit. */
uint8_t nse; /*!< Total number of subevents in each interval of each BIS in the BIG. */
uint16_t maxSdu; /*!< Maximum size of a SDU. */
@ -796,10 +831,9 @@ typedef struct
uint8_t irc; /*!< Number of times the scheduled payload(s) are transmitted in a given event. */
uint8_t pto; /*!< Offset used for pre-transmissions. */
uint8_t encrypt; /*!< Unencrypted or Encrypted. */
uint8_t bcstCode[LL_BC_LEN];/*!< Code used to derive the session key. */
} LlCreateBigTest_t;
/*! \brief BIG Create Sync message. */
/*! \brief BIG Create Sync command. */
typedef struct
{
uint8_t bigHandle; /*!< Used to identify the BIG. */
@ -814,6 +848,21 @@ typedef struct
/*! \} */ /* LL_API_ISO */
/*! \addtogroup LL_API_ECU
* \{ */
/*! \brief Subrate parameter. */
typedef struct
{
uint16_t srMin; /*!< Subrate minimum value. */
uint16_t srMax; /*!< Subrate maximum value. */
uint16_t maxLatency; /*!< Maximum latency. */
uint16_t contNum; /*!< Continuation number. */
uint16_t svt; /*!< Supervision timeout in 10ms units. */
} LlSubrateParam_t;
/*! \} */ /* LL_API_ECU */
/*! \addtogroup LL_API_ENCRYPT
* \{ */
@ -903,7 +952,6 @@ typedef struct
uint32_t duplicatePkt; /*!< Retransmitted CIS data PDUs. */
} LlIsoLinkQual_t;
/*! \} */ /* LL_API_TEST */
/*! \addtogroup LL_API_EVENT
@ -966,7 +1014,9 @@ enum
LL_TX_POWER_REPORTING_IND, /*!< LL txPower change report received. */
LL_PATH_LOSS_REPORTING_IND, /*!< Path loss reporting event. */
LL_ISO_EVT_CMPL_IND, /*!< ISO Event complete event. */
LL_BIG_INFO_ADV_REPORT_IND /*!< BIG Info advertising report event. */
LL_BIG_INFO_ADV_REPORT_IND, /*!< BIG Info advertising report event. */
/* --- Core Spec Sydney --- */
LL_SUBRATE_CHANGE_IND /*!< Enhanced connection update complete. */
};
/*! \brief Advertising report indication */
@ -1069,6 +1119,7 @@ typedef struct
uint8_t status; /*!< Status. */
uint16_t handle; /*!< Connection handle. */
bool_t enabled; /*!< Encryption enabled. */
uint8_t encKeySize; /*!< Encryption key size. */
} LlEncChangeInd_t;
/*! \brief Key refresh indication */
@ -1456,7 +1507,19 @@ typedef struct
uint16_t connHandle; /*!< Connection handle. */
uint8_t curPathLoss; /*!< Current path loss. */
uint8_t zoneEntered; /*!< Zone entered. */
} LlPathLossThresholdEvt_t;
} LlPathLossThresholdInd_t;
/*! \brief Subrate change event. */
typedef struct
{
wsfMsgHdr_t hdr; /*!< Event header. */
uint8_t status; /*!< Status. */
uint16_t handle; /*!< Connection handle. */
uint16_t srFactor; /*!< Subrate factor. */
uint16_t perLatency; /*!< Peripheral latency. */
uint16_t contNum; /*!< Continuation number. */
uint16_t svt; /*!< Supervision timeout in 10ms units. */
} LlSubrateChangeInd_t;
/*! \brief Union of all event types */
typedef union
@ -1507,9 +1570,11 @@ typedef union
LlBigSyncLostInd_t bigSyncLostInd; /*!< LE BIG sync lost. */
LlPeerScaCnf_t peerScaCnf; /*!< LE request peer SCA complete. */
LlPowerReportInd_t powerRptInd; /*!< LE transmit power reporting indication. */
LlIsoEventCmplInd_t isoEvtCmplInd; /*!< VS ISO Event complete. */
LlIsoEventCmplInd_t isoEvtCmplInd; /*!< ISO Event complete. */
LlBigInfoAdvRptInd_t bigInfoInd; /*!< LE Big Info indication. */
LlPathLossThresholdEvt_t pathLossEvt; /*!< LE Path loss threshold reporting event. */
LlPathLossThresholdInd_t pathLossInd; /*!< LE Path loss threshold reporting indication. */
/* --- Core Spec Sydney --- */
LlSubrateChangeInd_t subrateChangeInd; /*!< Subrate change event. */
} LlEvt_t;
/*! \brief Event callback */
@ -3841,27 +3906,31 @@ void LlGetPerScanContextSize(uint8_t *pMaxPerScan, uint16_t *pPerScanCtxSize);
/*************************************************************************************************/
/*!
* \brief Get CIG context size.
* \brief Get CIS context size.
*
* \param pMaxCig Buffer to return the maximum number of CIG.
* \param pCigCtxSize Buffer to return the size in bytes of the CIG context.
*
* Return the connection context sizes.
*/
/*************************************************************************************************/
void LlGetCigContextSize(uint8_t *pMaxCig, uint16_t *pCigCtxSize);
/*************************************************************************************************/
/*!
* \brief Get CIS context size.
*
* \param pMaxCis Buffer to return the maximum number of CIS.
* \param pCisCtxSize Buffer to return the size in bytes of the CIS context.
*
* Return the connection context sizes.
*/
/*************************************************************************************************/
void LlGetCisContextSize(uint8_t *pMaxCis, uint16_t *pCisCtxSize);
void LlGetCisContextSize(uint8_t *pMaxCig, uint16_t *pCigCtxSize, uint8_t *pMaxCis, uint16_t *pCisCtxSize);
/*************************************************************************************************/
/*!
* \brief Get BIS context size.
*
* \param pMaxBig Buffer to return the maximum number of BIG.
* \param pBigCtxSize Buffer to return the size in bytes of the BIG context.
* \param pMaxBis Buffer to return the maximum number of BIS.
* \param pBisCtxSize Buffer to return the size in bytes of the BIS context.
*
* Return the connection context sizes.
*/
/*************************************************************************************************/
void LlGetBisContextSize(uint8_t *pMaxBig, uint16_t *pBigCtxSize, uint8_t *pMaxBis, uint16_t *pBisCtxSize);
/*************************************************************************************************/
/*!
@ -3874,9 +3943,67 @@ uint16_t LlStatsGetHandlerWatermarkUsec(void);
/*! \} */ /* LL_API_DIAG */
/*! \addtogroup LL_API_CIS
/*! \addtogroup LL_API_ISO
* \{ */
/*************************************************************************************************/
/*!
* \brief Used by a broadcaster host to command is used to create one or more BISes of a BIG
* in the controller.
*
* \param pCreateBig Create BIG parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlCreateBig(LlCreateBig_t *pCreateBig);
/*************************************************************************************************/
/*!
* \brief Used by a broadcaster host to command is used to create one or more BISes of a BIG
* in the ISO test mode.
*
* \param pCreateBigTest Create BIG Test parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlCreateBigTest(LlCreateBigTest_t *pCreateBigTest);
/*************************************************************************************************/
/*!
* \brief Used to terminate the transmission of all BISes of a BIG, or to cancel the process
* of creating a BIG using the HCI_LE_Create_BIG command from the Isochronous Broadcaster.
*
* \param bigHandle Used to identify the BIG.
* \param reason Termination reason.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlTerminateBig(uint8_t bigHandle, uint8_t reason);
/*************************************************************************************************/
/*!
* \brief Used to synchronize and receive PDUs from one or more BISes within a BIG.
*
* \param pCreateSync BIG Create Sync parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlBigCreateSync(LlBigCreateSync_t *pCreateSync);
/*************************************************************************************************/
/*!
* \brief Used to stop synchronization with the BIG or to cancel the process of synchronizing
* to BISes invoked by the HCI_LE_BIG_Create_Sync command
*
* \param bigHandle Used to identify the BIG.
*/
/*************************************************************************************************/
void LlBigTerminateSync(uint8_t bigHandle);
/*************************************************************************************************/
/*!
* \brief Used by a master host to set the parameters of all connected isochronous streams
@ -3951,64 +4078,6 @@ uint8_t LlAcceptCisReq(uint16_t cisHandle);
/*************************************************************************************************/
uint8_t LlRejectCisReq(uint16_t cisHandle, uint8_t reason);
/*************************************************************************************************/
/*!
* \brief Used by a broadcaster host to command is used to create one or more BISes of a BIG
* in the controller.
*
* \param pCreateBig Create BIG parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlCreateBig(LlCreateBig_t *pCreateBig);
/*************************************************************************************************/
/*!
* \brief Used by a broadcaster host to command is used to create one or more BISes of a BIG
* in the ISO test mode.
*
* \param pCreateBigTest Create BIG Test parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlCreateBigTest(LlCreateBigTest_t *pCreateBigTest);
/*************************************************************************************************/
/*!
* \brief Used to terminate the transmission of all BISes of a BIG, or to cancel the process
* of creating a BIG using the HCI_LE_Create_BIG command from the Isochronous Broadcaster.
*
* \param bigHandle Used to identify the BIG.
* \param reason Termination reason.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlTerminateBig(uint8_t bigHandle, uint8_t reason);
/*************************************************************************************************/
/*!
* \brief Used to synchronize and receive PDUs from one or more BISes within a BIG.
*
* \param pCreateSync BIG Create Sync parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlBigCreateSync(LlBigCreateSync_t *pCreateSync);
/*************************************************************************************************/
/*!
* \brief Used to stop synchronization with the BIG or to cancel the process of synchronizing
* to BISes invoked by the HCI_LE_BIG_Create_Sync command
*
* \param bigHandle Used to identify the BIG.
*/
/*************************************************************************************************/
void LlBigTerminateSync(uint8_t bigHandle);
/*************************************************************************************************/
/*!
* \brief Read the Time_Stamp and Time_Offset of a transmitted ISO_SDU identified by the
@ -4024,6 +4093,18 @@ void LlBigTerminateSync(uint8_t bigHandle);
/*************************************************************************************************/
uint8_t LlReadIsoTxSync(uint16_t handle, uint16_t *pPktSn, uint32_t *pTs, uint32_t *pTimeOffs);
/*************************************************************************************************/
/*!
* \brief Used to request the Controller to configure the data transport path in a given
* direction between the Controller and the Host.
*
* \param pConfigDataPath Parameters for configure data path.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LlConfigureDataPath(LlIsoConfigDataPath_t *pConfigDataPath);
/*************************************************************************************************/
/*!
* \brief Used to identify and enable the isochronous data path between the host and the
@ -4182,7 +4263,49 @@ uint8_t *LlRecvIsoData(void);
/*************************************************************************************************/
void LlRecvIsoDataComplete(uint8_t numBufs);
/*! \} */ /* LL_API_CIS */
/*! \} */ /* LL_API_ISO */
/*! \addtogroup LL_API_ECU
* \{ */
/*************************************************************************************************/
/*!
* \brief Initialize LL subsystem for enhanced connection update.
*
* This function initializes the LL subsystem for use with enhanced connection updates.
*/
/*************************************************************************************************/
void LlEnhConnUpdateInit(void);
/*************************************************************************************************/
/*!
* \brief Set the initial values for subrating requests.
*
* \param pSubrate Subrate parameter.
*
* \return Status error code.
*
* Set the initial values for the acceptable parameters for subrating requests for all future ACL
* connections where the Controller is the Central. This command does not affect any existing
* connection.
*/
/*************************************************************************************************/
uint8_t LlSetDefaultSubrate(LlSubrateParam_t *pSubrate);
/*************************************************************************************************/
/*!
* \brief Request subrate change.
*
* \param handle Connection handle.
* \param pSubrate Subrate parameter.
*
* Used by a Central or a Peripheral to request a change to the subrating factor and/or other
* parameters applied to an existing connection using the Connection Subrate Update procedure.
*/
/*************************************************************************************************/
void LlSubrateReq(uint16_t handle, LlSubrateParam_t *pSubrate);
/*! \} */ /* LL_API_ECU */
#ifdef __cplusplus
};

View File

@ -62,7 +62,7 @@ extern "C" {
#ifndef BT_VER
/*! \brief Initialize default BT version. */
#define BT_VER LL_VER_BT_CORE_SPEC_5_1
#define BT_VER LL_VER_BT_CORE_SPEC_5_0
#endif
/**************************************************************************************************

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -56,7 +56,7 @@ extern "C" {
enum
{
SCH_RM_PREF_PERFORMANCE, /*!< Performance is preferred, search from minimum interval. */
SCH_RM_PREF_CAPACITY /*!< Capacity is preferred, search from maximum interval. */
SCH_RM_PREF_CAPACITY /*!< Capacity is preferred, search from maximum interval. */
};
/**************************************************************************************************

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2018 ARM Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -159,6 +159,8 @@ typedef struct BbOpDesc_tag
PalBbProt_t protId:8; /*!< Protocol type. */
bool_t recoverable; /*!< Indicates if the BOD can recover if the dueUsec time is in the past. */
BbBodCback_t endCback; /*!< End of BOD callback (when BOD ends). */
BbBodCback_t abortCback; /*!< Abort BOD callback (when BOD is removed before beginning). */
@ -375,7 +377,7 @@ uint32_t BbAdjustTime(uint32_t dueUsec);
/*************************************************************************************************/
/*!
* \brief Get Delta between target and reference time. Only valid if target time is in the future.
* \brief Get delta between target and reference time. Only valid if target time is in the future.
*
* \param targetUsec Target time in microseconds.
* \param refUsec Reference time in microseconds.

View File

@ -39,12 +39,6 @@ extern "C" {
#define CHCI_BUF_TAILROOM 4 /*!< Extra byte allocation required for buffer (e.g., for MIC). */
#endif
/*** Scheduler ***/
#ifndef SCH_TIMER_REQUIRED
#define SCH_TIMER_REQUIRED TRUE /*!< If hardware timer is required for radio access scheduler.*/
#endif
#ifdef __cplusplus
};
#endif

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -91,6 +91,18 @@ extern "C" {
#define LL_MAX_BN 8 /*!< Absolute maximum number of bursts. */
#endif
#ifndef LL_PC_TBL_POW
#define LL_PC_TBL_POW 2 /*!< Running average power control array sizes, must be a power of 2. */
#endif
#ifndef LL_PC_SERVICE_MS
#define LL_PC_SERVICE_MS 1000 /*!< Power control service intervals in milliseconds. */
#endif
#ifndef LL_PC_REQ_CHANGE_DBM
#define LL_PC_REQ_CHANGE_DBM 5 /*!< Request of increase/decrease in power value in units of dBm. */
#endif
#ifndef LHCI_ENABLE_VS
#define LHCI_ENABLE_VS 1 /*!< Enable vendor specific command processing. */
#endif
@ -108,7 +120,8 @@ extern "C" {
#endif
#ifndef BB_ADV_PLD_MAX_LEN
#define BB_ADV_PLD_MAX_LEN 255 /*!< Maximum advertising channel payload length (valid range 95 to 255). */
#define BB_ADV_PLD_MAX_LEN (BB_DATA_PLD_MAX_LEN + 4)
/*!< Maximum advertising channel payload length (valid range 95 to 255). */
#endif
#ifndef BB_FIXED_DATA_PKT_LEN

View File

@ -68,15 +68,6 @@ void chciTrRecv(uint8_t prot, uint8_t type, uint8_t *pBuf);
/*************************************************************************************************/
void chciTrSendComplete(void);
/*************************************************************************************************/
/*!
* \brief Service the transport device.
*
* \return TRUE if work pending, FALSE if no work is pending.
*/
/*************************************************************************************************/
bool_t ChciTrService(void);
#ifdef __cplusplus
};
#endif

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 ARM Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -49,19 +49,16 @@ void SchInit(void);
void SchHandlerInit(wsfHandlerId_t handlerId);
void SchReset(void);
uint16_t SchStatsGetHandlerWatermarkUsec(void);
uint16_t SchStatsGetDelayLoadWatermarkCount(void);
uint32_t SchStatsGetDelayLoadTotalCount(void);
/* Control */
void SchHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
void SchLoadHandler(void);
/* List maintenance */
void SchInsertNextAvailable(BbOpDesc_t *pBod);
bool_t SchInsertAtDueTime(BbOpDesc_t *pBod, BbConflictAct_t conflictCback);
bool_t SchInsertEarlyAsPossible(BbOpDesc_t *pBod, uint32_t min, uint32_t max);
bool_t SchInsertLateAsPossible(BbOpDesc_t *pBod, uint32_t min, uint32_t max);
bool_t SchRemove(BbOpDesc_t *pBod);
void SchRemove(BbOpDesc_t *pBod);
void SchReload(BbOpDesc_t *pBod);
bool_t SchIsBodCancellable(BbOpDesc_t *pBod);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -53,7 +53,7 @@ extern const BbRtCfg_t *pBbRtCfg;
*
* \return Scan duration in microseconds.
*
* This function is calculates the duration of the scan examining:
* This function calculates the duration of the scan examining:
* - total elapsed scan time
* - neighboring BOD
* - maximum scan period
@ -98,7 +98,6 @@ static uint32_t bbBleCalcScanDurationUsec(BbOpDesc_t *pBod, BbBleMstAdvEvent_t *
if (pBod->pNext)
{
uint32_t timeToNextOpUsec = BbGetTargetTimeDelta(pBod->pNext->dueUsec, refTime);
/* Limit scanning to the edge of neighboring BOD. */
@ -151,6 +150,13 @@ static bool_t bbContScanOp(BbOpDesc_t *pBod, BbBleMstAdvEvent_t *pScan)
return TRUE;
}
/* Check if an Aux Scan needs to be started ASAP because of a short auxOffset. */
if (pScan->auxScanCheckCback && pScan->auxScanCheckCback(pBod, curTime, scanDurUsec))
{
pBod->prot.pBle->op.mstAdv.auxScanOpRunning = TRUE;
return FALSE;
}
bbBleCb.bbParam.dueUsec = BbAdjustTime(bbBleCb.lastScanStartUsec + BbGetSchSetupDelayUs());
bbBleCb.bbParam.rxTimeoutUsec = scanDurUsec;
PalBbBleSetDataParams(&bbBleCb.bbParam);
@ -191,6 +197,18 @@ static void bbMstScanTxCompCback(uint8_t status)
bool_t bodComplete = FALSE;
bool_t bodCont = FALSE;
if (pScan->auxScanTxCompCback && (pScan->auxScanOpRunning == TRUE))
{
/* This is a linked operation. Call the Aux Scan callback. */
if (pScan->auxScanTxCompCback(pScan->auxScanBod, status) == TRUE)
{
/* BOD complete. Clear the linked BOD. */
pScan->auxScanBod = NULL;
pScan->auxScanOpRunning = FALSE;
}
return;
}
#if (BB_SNIFFER_ENABLED == TRUE)
/* Save evtState to be used later in packet forwarding. */
uint8_t evtState = bbBleCb.evtState;
@ -318,6 +336,19 @@ static void bbMstScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint
bool_t bodComplete = FALSE;
bool_t bodCont = FALSE;
if (pScan->auxScanRxCompCback && pScan->auxScanOpRunning == TRUE)
{
/* This is a linked operation. Call the Aux Scan callback. */
if (pScan->auxScanRxCompCback(pScan->auxScanBod, status, rssi, crc, timestamp, rxPhyOptions) == TRUE)
{
/* BOD complete. Clear the linked BOD. */
pScan->auxScanBod = NULL;
pScan->auxScanOpRunning = FALSE;
}
return;
}
#if (BB_SNIFFER_ENABLED == TRUE)
/* Save evtState to be used later in packet forwarding. */
uint8_t evtState = bbBleCb.evtState;
@ -521,6 +552,16 @@ static void bbMstScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint
static void bbMstExecuteScanOp(BbOpDesc_t *pBod, BbBleData_t *pBle)
{
BbBleMstAdvEvent_t * const pScan = &pBod->prot.pBle->op.mstAdv;
uint32_t curTime = PalBbGetCurrentTime();
/* Check if dueUsec time is in the past. */
if (BbGetTargetTimeDelta(pBod->dueUsec, curTime) == 0)
{
/* Update dueUsec time and start Scan for the remaining duration. */
bbBleCb.lastScanStartUsec = pBod->dueUsec;
pBod->dueUsec = curTime + BbGetSchSetupDelayUs();
pScan->elapsedUsec = BbGetTargetTimeDelta(curTime, bbBleCb.lastScanStartUsec);
}
if (pScan->preExecCback)
{

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -52,15 +52,16 @@ static uint8_t bbPerScanBuf[LL_EXT_ADVB_MAX_LEN];
* \brief Tx completion for auxiliary scanning master operation.
*
* \param status Completion status.
* \param pBod Pointer to the BOD
*
* Setup for next action in the operation or complete the operation.
*
* \return TRUE if BOD is complete, FALSE otherwise.
*/
/*************************************************************************************************/
static void bbMstAuxScanTxCompCback(uint8_t status)
bool_t BbMstAuxScanTxCompHandler(BbOpDesc_t *pBod, uint8_t status)
{
BB_ISR_START();
WSF_ASSERT(BbGetCurrentBod());
WSF_ASSERT(pBod);
bool_t bodComplete = FALSE;
@ -72,7 +73,6 @@ static void bbMstAuxScanTxCompCback(uint8_t status)
{
pPkt = bbSnifferCtx.snifferGetPktFn();
}
BbOpDesc_t * const pCur = BbGetCurrentBod();
#endif
switch (bbBleCb.evtState++)
@ -128,10 +128,30 @@ static void bbMstAuxScanTxCompCback(uint8_t status)
pPkt->pktType.meta.status = status;
pPkt->pktType.meta.state = evtState;
bbBleSnifferMstAuxScanPktHandler(pCur, pPkt);
bbBleSnifferMstAuxScanPktHandler(pBod, pPkt);
}
#else
(void)pBod;
#endif
return bodComplete;
}
/*************************************************************************************************/
/*!
* \brief Tx completion for auxiliary scanning master operation.
*
* \param status Completion status.
*
* Setup for next action in the operation or complete the operation.
*/
/*************************************************************************************************/
static void bbMstAuxScanTxCompCback(uint8_t status)
{
BB_ISR_START();
(void)BbMstAuxScanTxCompHandler(BbGetCurrentBod(), status);
BB_ISR_MARK(bbAuxScanStats.txIsrUsec);
}
@ -139,6 +159,7 @@ static void bbMstAuxScanTxCompCback(uint8_t status)
/*!
* \brief Rx completion for auxiliary scanning master operation.
*
* \param pCur Pointer to the BOD
* \param status Reception status.
* \param rssi RSSI value.
* \param crc CRC value.
@ -146,15 +167,14 @@ static void bbMstAuxScanTxCompCback(uint8_t status)
* \param rxPhyOptions Rx PHY options.
*
* Setup for next action in the operation or complete the operation.
*
* \return TRUE if BOD is complete, FALSE otherwise.
*/
/*************************************************************************************************/
static void bbMstAuxScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint32_t timestamp, uint8_t rxPhyOptions)
bool_t BbMstAuxScanRxCompHandler(BbOpDesc_t * const pCur, uint8_t status, int8_t rssi, uint32_t crc, uint32_t timestamp, uint8_t rxPhyOptions)
{
BB_ISR_START();
WSF_ASSERT(pCur);
WSF_ASSERT(BbGetCurrentBod());
BbOpDesc_t * const pCur = BbGetCurrentBod();
BbBleData_t * const pBle = pCur->prot.pBle;
BbBleMstAuxAdvEvent_t * const pAuxScan = &pBle->op.mstAuxAdv;
@ -195,54 +215,65 @@ static void bbMstAuxScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, u
#endif
uint32_t auxOffsetUsec;
if (pAuxScan->rxAuxAdvCback(pCur, bbAuxAdvBuf))
bool_t txScanReq = pAuxScan->rxAuxAdvCback(pCur, bbAuxAdvBuf);
if ((txScanReq) && (pAuxScan->pTxAuxReqBuf))
{
if (pAuxScan->pTxAuxReqBuf)
{
/* Tx response PDU. */
/* Tx response PDU. */
bbBleCb.evtState = BB_EVT_STATE_TX_SCAN_OR_CONN_INIT;
bbBleCb.evtState = BB_EVT_STATE_TX_SCAN_OR_CONN_INIT;
BB_ISR_MARK(bbAuxScanStats.txSetupUsec);
BB_ISR_MARK(bbAuxScanStats.txSetupUsec);
PalBbBleTxBufDesc_t desc = {.pBuf = pAuxScan->pTxAuxReqBuf, .len = pAuxScan->txAuxReqLen};
PalBbBleTxBufDesc_t desc = {.pBuf = pAuxScan->pTxAuxReqBuf, .len = pAuxScan->txAuxReqLen};
bbBleSetTifs();
PalBbBleTxTifsData(&desc, 1);
}
}
else if ((pAuxScan->rxAuxChainCback) &&
((auxOffsetUsec = pAuxScan->rxAuxChainCback(pCur, bbAuxAdvBuf)) > 0))
{
/* Rx chain indication PDU. */
bbBleCb.evtState = BB_EVT_STATE_RX_CHAIN_IND;
/* Cancel Tifs operation is needed for passive scan and non connectable/scannable adv with chain. */
PalBbBleCancelTifs();
PalBbBleSetChannelParam(&pBle->chan);
bbBleCb.bbParam.dueUsec = BbAdjustTime(timestamp + auxOffsetUsec);
PalBbBleSetDataParams(&bbBleCb.bbParam);
BB_ISR_MARK(bbAuxScanStats.rxSetupUsec);
bbBleClrIfs(); /* CHAIN_IND does not use TIFS. */
PalBbBleRxData(bbAuxAdvBuf, sizeof(bbAuxAdvBuf));
WSF_ASSERT(pAuxScan->rxAuxChainPostCback);
if (pAuxScan->rxAuxChainPostCback(pCur, bbAuxAdvBuf) == FALSE)
{
bodCont = TRUE;
}
bbBleSetTifs();
PalBbBleTxTifsData(&desc, 1);
}
else
{
if (pAuxScan->rxAuxChainPostCback)
PalBbBleCancelTifs();
}
if (pAuxScan->rxAuxAdvPostCback)
{
pAuxScan->rxAuxAdvPostCback(pCur, bbAuxAdvBuf);
}
if (!txScanReq)
{
if ((pAuxScan->rxAuxChainCback) &&
((auxOffsetUsec = pAuxScan->rxAuxChainCback(pCur, bbAuxAdvBuf)) > 0))
{
pAuxScan->rxAuxChainPostCback(pCur, bbAuxAdvBuf);
/* Rx chain indication PDU. */
bbBleCb.evtState = BB_EVT_STATE_RX_CHAIN_IND;
/* Cancel Tifs operation is needed for passive scan and non connectable/scannable adv with chain. */
PalBbBleCancelTifs();
PalBbBleSetChannelParam(&pBle->chan);
bbBleCb.bbParam.dueUsec = BbAdjustTime(timestamp + auxOffsetUsec);
PalBbBleSetDataParams(&bbBleCb.bbParam);
BB_ISR_MARK(bbAuxScanStats.rxSetupUsec);
bbBleClrIfs(); /* CHAIN_IND does not use TIFS. */
PalBbBleRxData(bbAuxAdvBuf, sizeof(bbAuxAdvBuf));
WSF_ASSERT(pAuxScan->rxAuxChainPostCback);
if (pAuxScan->rxAuxChainPostCback(pCur, bbAuxAdvBuf) == FALSE)
{
bodCont = TRUE;
}
}
else
{
if (pAuxScan->rxAuxChainPostCback)
{
pAuxScan->rxAuxChainPostCback(pCur, bbAuxAdvBuf);
}
bodCont = TRUE;
}
bodCont = TRUE;
}
break;
}
@ -494,8 +525,29 @@ static void bbMstAuxScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, u
}
#endif
BB_ISR_MARK(bbAuxScanStats.rxIsrUsec);
return bodComplete;
}
/*************************************************************************************************/
/*!
* \brief Rx completion for auxiliary scanning master operation.
*
* \param status Reception status.
* \param rssi RSSI value.
* \param crc CRC value.
* \param timestamp Start of packet timestamp in microseconds.
* \param rxPhyOptions Rx PHY options.
*
* Setup for next action in the operation or complete the operation.
*/
/*************************************************************************************************/
static void bbMstAuxScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint32_t timestamp, uint8_t rxPhyOptions)
{
BB_ISR_START();
(void)BbMstAuxScanRxCompHandler(BbGetCurrentBod(), status, rssi, crc, timestamp, rxPhyOptions);
BB_ISR_MARK(bbAuxScanStats.rxIsrUsec);
}
/*************************************************************************************************/
@ -856,3 +908,34 @@ void BbBleGetPerScanStats(BbBlePerScanPktStats_t *pStats)
*pStats = bbPerScanStats;
}
/*************************************************************************************************/
/*!
* \brief Execute auxiliary scanning master BOD.
*
* \param pBod Pointer to the BOD to execute.
* \param pBle BLE operation parameters.
*/
/*************************************************************************************************/
void BbMstExecuteLinkedAuxScanOp(BbOpDesc_t *pBod, BbBleData_t *pBle)
{
BbBleMstAuxAdvEvent_t * const pAuxScan = &pBod->prot.pBle->op.mstAuxAdv;
PalBbBleSetChannelParam(&pBle->chan);
bbBleCb.bbParam.rxTimeoutUsec = pAuxScan->rxSyncDelayUsec;
bbBleCb.bbParam.dueUsec = BbAdjustTime(pBod->dueUsec);
pBod->dueUsec = bbBleCb.bbParam.dueUsec;
PalBbBleSetDataParams(&bbBleCb.bbParam);
bbBleCb.evtState = 0;
if (pAuxScan->pTxAuxReqBuf)
{
bbBleSetTifs(); /* active scan or initiating */
}
else
{
bbBleClrIfs(); /* passive scan */
}
PalBbBleRxData(bbAuxAdvBuf, sizeof(bbAuxAdvBuf));
}

View File

@ -119,7 +119,7 @@ static bool_t bbSetupAdvOp(BbOpDesc_t *pBod, BbBleSlvAdvEvent_t *pAdv, uint8_t s
{
/* Schedule with absolute frame gap. */
uint32_t advGap = SchBleCalcAdvPktDurationUsec(pBle->chan.txPhy, pBle->chan.initTxPhyOptions, pAdv->txAdvLen) +
BbGetSchSetupDelayUs();
BbGetSchSetupDelayUs();
uint32_t auxOffsUsec = SchBleGetAlignedAuxOffsUsec(advGap);
bbBleCb.bbParam.dueUsec = BbAdjustTime(bbBleCb.bbParam.dueUsec + auxOffsUsec);
}

View File

@ -193,7 +193,6 @@ Cleanup:
BbTerminateBod();
}
#if (BB_SNIFFER_ENABLED == TRUE)
if (pPkt)
{

View File

@ -137,7 +137,14 @@ void BbBleBisSlaveInit(void)
/*************************************************************************************************/
void BbBleBisTxData(PalBbBleTxBufDesc_t descs[], uint8_t cnt, uint32_t nextPduTime, PalBbBleChan_t *pNextChan)
{
bbBleSetAbsIfs(nextPduTime, pNextChan);
if (pNextChan)
{
bbBleSetAbsIfs(nextPduTime, pNextChan);
}
else
{
bbBleClrIfs();
}
if (bbBleCb.evtState == 0)
{
@ -149,3 +156,13 @@ void BbBleBisTxData(PalBbBleTxBufDesc_t descs[], uint8_t cnt, uint32_t nextPduTi
PalBbBleTxTifsData(descs, cnt);
}
}
/*************************************************************************************************/
/*!
* \brief Get BIS packet statistics.
*/
/*************************************************************************************************/
void BbBleGetBisStats(BbBleDataPktStats_t *pStats)
{
*pStats = bbBisStats;
}

View File

@ -80,10 +80,10 @@ void BbBleCisTxData(PalBbBleTxBufDesc_t descs[], uint8_t cnt)
/*************************************************************************************************/
void BbBleCisRxData(uint8_t *pBuf, uint16_t len)
{
WSF_ASSERT(!bbBleCb.pRxCisDataBuf);
WSF_ASSERT(!bbBleCb.pRxDataBuf);
bbBleCb.pRxCisDataBuf = pBuf;
bbBleCb.rxCisDataLen = len;
bbBleCb.pRxDataBuf = pBuf;
bbBleCb.rxDataLen = len;
if ((BbGetCurrentBod()->prot.pBle->chan.opType == BB_BLE_OP_SLV_CIS_EVENT) &&
(bbBleCb.evtState == 0))
@ -95,7 +95,7 @@ void BbBleCisRxData(uint8_t *pBuf, uint16_t len)
/*************************************************************************************************/
/*!
* \brief Get connection packet statistics.
* \brief Get CIS packet statistics.
*/
/*************************************************************************************************/
void BbBleGetCisStats(BbBleDataPktStats_t *pStats)

View File

@ -71,6 +71,11 @@ static bool_t bbMstCisCheckContOp(BbOpDesc_t *pCur, BbBleMstCisEvent_t *pCis, bo
return TRUE;
}
/* Cancel TIFS timer. */
PalBbBleCancelTifs();
(void)pCis->checkContOpPostCback(pCur, pNewCisCtx);
/* Updated channel parameter. */
BbBleData_t *pBle = pCur->prot.pBle;
PalBbBleSetChannelParam(&pBle->chan);
@ -121,13 +126,13 @@ static void bbMstCisTxCompCback(uint8_t status)
pCis->txDataCback(pCur, status);
if (bbBleCb.pRxCisDataBuf &&
if (bbBleCb.pRxDataBuf &&
(status == BB_STATUS_SUCCESS))
{
BB_ISR_MARK(bbCisStats.rxSetupUsec);
bbBleSetTifs(); /* TODO set only if Tx may follow in CE */
PalBbBleRxTifsData(bbBleCb.pRxCisDataBuf, bbBleCb.rxDataLen);
PalBbBleRxTifsData(bbBleCb.pRxDataBuf, bbBleCb.rxDataLen);
}
else
{
@ -140,10 +145,10 @@ static void bbMstCisTxCompCback(uint8_t status)
case BB_STATUS_FAILED:
default:
/* Free Rx data buffer before BOD end. */
if (bbBleCb.pRxCisDataBuf != NULL) /* buffer should always exist, but still check */
if (bbBleCb.pRxDataBuf != NULL) /* buffer should always exist, but still check */
{
uint8_t *pBuf = bbBleCb.pRxCisDataBuf;
bbBleCb.pRxCisDataBuf = NULL;
uint8_t *pBuf = bbBleCb.pRxDataBuf;
bbBleCb.pRxDataBuf = NULL;
pCis->rxDataCback(pCur, pBuf, BB_STATUS_CANCELED);
}
break;
@ -199,9 +204,9 @@ static void bbMstCisRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint3
pCis->rssi = rssi;
pCis->rxPhyOptions = rxPhyOptions;
WSF_ASSERT(bbBleCb.pRxCisDataBuf);
uint8_t *pBuf = bbBleCb.pRxCisDataBuf;
bbBleCb.pRxCisDataBuf = NULL;
WSF_ASSERT(bbBleCb.pRxDataBuf);
uint8_t *pBuf = bbBleCb.pRxDataBuf;
bbBleCb.pRxDataBuf = NULL;
pCis->rxDataCback(pCur, pBuf, status);
@ -210,7 +215,7 @@ static void bbMstCisRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint3
if (BbGetBodTerminateFlag() || bodComplete)
{
WSF_ASSERT(!bbBleCb.pRxCisDataBuf);
WSF_ASSERT(!bbBleCb.pRxDataBuf);
/* Cancel TIFS timer if active. */
switch (status)
@ -280,6 +285,7 @@ static void bbMstExecuteCisOp(BbOpDesc_t *pBod, BbBleData_t *pBle)
WSF_ASSERT(pBle->op.mstCis.rxDataCback);
WSF_ASSERT(pBle->op.mstCis.execCback);
WSF_ASSERT(pBle->op.mstCis.checkContOpCback);
WSF_ASSERT(pBle->op.mstCis.checkContOpPostCback);
#if(LL_ENABLE_TESTER)
pBle->chan.txPower += pBle->chan.txPwrOffset;
@ -317,10 +323,10 @@ static void bbMstCancelCisOp(BbOpDesc_t *pBod, BbBleData_t *pBle)
PalBbBleCancelData();
if (bbBleCb.pRxCisDataBuf)
if (bbBleCb.pRxDataBuf)
{
uint8_t *pBuf = bbBleCb.pRxCisDataBuf;
bbBleCb.pRxCisDataBuf = NULL;
uint8_t *pBuf = bbBleCb.pRxDataBuf;
bbBleCb.pRxDataBuf = NULL;
/* Buffer free expected to be called during this routine. */
pBle->op.mstCis.rxDataCback(pBod, pBuf, BB_STATUS_CANCELED);

View File

@ -83,6 +83,11 @@ static bool_t bbSlvCisCheckNextOp(BbOpDesc_t *pCur, BbBleSlvCisEvent_t *pCis, bo
return TRUE;
}
/* Cancel TIFS timer. */
PalBbBleCancelTifs();
(void)pCis->checkContOpPostCback(pCur, pNewCisCtx);
/* Update channel parameter. */
BbBleData_t *pBle = pCur->prot.pBle;
PalBbBleSetChannelParam(&pBle->chan);
@ -148,10 +153,10 @@ static void bbSlvCisTxCompCback(uint8_t status)
{
if (bodComplete)
{
if (bbBleCb.pRxCisDataBuf != NULL)
if (bbBleCb.pRxDataBuf != NULL)
{
uint8_t *pBuf = bbBleCb.pRxCisDataBuf;
bbBleCb.pRxCisDataBuf = NULL;
uint8_t *pBuf = bbBleCb.pRxDataBuf;
bbBleCb.pRxDataBuf = NULL;
pCis->rxDataCback(pCur, pBuf, BB_STATUS_CANCELED);
}
@ -168,10 +173,10 @@ static void bbSlvCisTxCompCback(uint8_t status)
}
else
{
if (bbBleCb.pRxCisDataBuf != NULL)
if (bbBleCb.pRxDataBuf != NULL)
{
uint8_t *pBuf = bbBleCb.pRxCisDataBuf;
bbBleCb.pRxCisDataBuf = NULL;
uint8_t *pBuf = bbBleCb.pRxDataBuf;
bbBleCb.pRxDataBuf = NULL;
pCis->rxDataCback(pCur, pBuf, BB_STATUS_CANCELED);
}
@ -231,7 +236,7 @@ static void bbSlvCisRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint3
if (pCis->isFirstTs == TRUE)
{
/* Update startTs for the successful rx, otherwise use the due time. */
/* Update startTs for the successful Rx, otherwise use the due time. */
if (status == BB_STATUS_SUCCESS)
{
pCis->startTsUsec = timestamp;
@ -245,30 +250,49 @@ static void bbSlvCisRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, uint3
}
else
{
/* Update rxTs for the successful rx, otherwise use the due time. */
/* Update rxTs for the successful Rx, otherwise use the due time. */
if (status == BB_STATUS_SUCCESS)
{
pCis->rxTsUsec = timestamp;
}
}
WSF_ASSERT(bbBleCb.pRxCisDataBuf);
WSF_ASSERT(bbBleCb.pRxDataBuf);
uint8_t *pBuf = bbBleCb.pRxCisDataBuf;
bbBleCb.pRxCisDataBuf = NULL;
uint8_t *pBuf = bbBleCb.pRxDataBuf;
bbBleCb.pRxDataBuf = NULL;
/* Set Tx buffer or BOD cancel expected to be called during this routine. */
pCis->rxDataCback(pCur, pBuf, status);
if ((status != BB_STATUS_RX_TIMEOUT) && /* BB_STATUS_RX_TIMEOUT will setup Tx which will be failed and terminate BOD. */
BbGetBodTerminateFlag())
bool_t bodComplete = FALSE;
bool_t newCisCtx = FALSE;
switch (status)
{
WSF_ASSERT(!bbBleCb.pRxCisDataBuf);
case BB_STATUS_RX_TIMEOUT:
case BB_STATUS_FAILED:
bodComplete = bbSlvCisCheckNextOp(pCur, pCis, &newCisCtx);
/* Skip the post subevent callback if switching to the new CIS context. */
if (newCisCtx == FALSE)
{
bbSlvCisPostSubEvt(pCur, pCis, status);
}
break;
default:
break;
}
if (BbGetBodTerminateFlag() || bodComplete)
{
WSF_ASSERT(!bbBleCb.pRxDataBuf);
/* Cancel TIFS timer if active. */
switch (status)
{
case BB_STATUS_SUCCESS:
case BB_STATUS_CRC_FAILED:
PalBbBleCancelTifs();
break;
default:
@ -320,6 +344,7 @@ static void bbSlvExecuteCisOp(BbOpDesc_t *pBod, BbBleData_t *pBle)
WSF_ASSERT(pCis->rxDataCback);
WSF_ASSERT(pCis->execCback);
WSF_ASSERT(pCis->checkContOpCback);
WSF_ASSERT(pCis->checkContOpPostCback);
pCis->isFirstTs = TRUE;
pCis->rxTsUsec = pBod->dueUsec;
@ -357,10 +382,10 @@ static void bbSlvCancelCisOp(BbOpDesc_t *pBod, BbBleData_t *pBle)
PalBbBleCancelData();
if (bbBleCb.pRxCisDataBuf)
if (bbBleCb.pRxDataBuf)
{
uint8_t *pBuf = bbBleCb.pRxCisDataBuf;
bbBleCb.pRxCisDataBuf = NULL;
uint8_t *pBuf = bbBleCb.pRxDataBuf;
bbBleCb.pRxDataBuf = NULL;
/* Buffer free expected to be called during this routine. */
pBle->op.slvCis.rxDataCback(pBod, pBuf, BB_STATUS_CANCELED);

View File

@ -94,10 +94,6 @@ typedef struct
uint16_t rxDataLen; /*!< Receive data buffer length. */
uint8_t *pRxDataBuf; /*!< Current Rx data buffer. */
/* TODO combine with above? */
uint16_t rxCisDataLen; /*!< Receive CIS data buffer length. */
uint8_t *pRxCisDataBuf; /*!< Current Rx CIS data buffer. */
} bbBleCtrlBlk_t;
/**************************************************************************************************

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -99,6 +99,13 @@ enum
LCTR_SCAN_PHY_ALL = 0xFF /*!< All PHY scanners. */
};
/*! \brief Periodic scan receive enable bits. */
enum
{
LCTR_PER_RECV_ENABLE_REPORT_BIT_POS = 0, /*!< Enable periodic scan reports. */
LCTR_PER_RECV_ENABLE_FILTERING_BIT_POS = 1 /*!< Enable filtering by ADI of periodic advertising trains. */
};
/**************************************************************************************************
Data Types
**************************************************************************************************/
@ -142,6 +149,7 @@ typedef struct
uint64_t advAddr; /*!< Advertiser Address. */
uint16_t skip; /*!< Skip. */
uint16_t syncTimeOut; /*!< Synchronization Timeout. */
uint8_t dupFilterEnable; /*!< Duplicate filtering enable. */
} lctrPerCreateSyncMsg_t;
/*! \brief Periodic transfer sync message. */
@ -204,7 +212,7 @@ uint64_t LctrGetPerScanChanMap(uint16_t handle);
bool_t lctrMstPerIsSyncHandleValid(uint16_t syncHandle);
void LctrPastInit(void);
uint8_t LctrPeriodicAdvSyncTransfer(uint16_t connHandle, uint16_t serviceData, uint16_t syncHandle);
void LctrMstPerSetRcvEnable(uint16_t syncHandle, bool_t enable);
void LctrMstPerSetRcvEnable(uint16_t syncHandle, uint8_t enable);
#ifdef __cplusplus
};

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -88,7 +88,7 @@ enum
LCTR_CONN_MSG_API_CIS_REQ_ACCEPT, /*!< Peer CIS request accept API event. */
LCTR_CONN_MSG_API_CIS_REQ_REJECT, /*!< Peer CIS request accept API event. */
LCTR_CONN_MSG_API_PWR_CTRL_REQ, /*!< Peer power control request API event. */
LCTR_CONN_MSG_API_SUBRATE_REQ, /*!< Subrate request API event. */
/* Internal events */
_LCTR_CONN_INT_EVENTS = 40,
LCTR_CONN_DATA_PENDING, /*!< New data pending. */
@ -100,9 +100,12 @@ enum
LCTR_CONN_LLCP_VERSION_EXCH, /*!< LL initiated remote version exchange. */
LCTR_CONN_LLCP_FEATURE_EXCH, /*!< LL initiated remote feature exchange. */
LCTR_CONN_LLCP_LENGTH_EXCH, /*!< LL initiated data length exchange. */
LCTR_CONN_LLCP_PWR_CTRL_REQ, /*!< LL initiated power control request. */
LCTR_CONN_LLCP_PWR_CTRL_SERVICE, /*!< Service power control monitor. */
LCTR_CONN_LLCP_TERM, /*!< LL initiated termination. */
LCTR_CONN_LLCP_CHANNEL_STATUS, /*!< LL initiated channel status. */
LCTR_CONN_LLCP_CHANNEL_REPORTING, /*!< LL initiated channel reporting. */
LCTR_CONN_LLCP_PROC_CMPL, /*!< LLCP procedure completed. */
LCTR_CONN_LLCP_PROC_ABORTED, /*!< LLCP procedure aborted. */
LCTR_CONN_LLCP_START_PENDING, /*!< Start pending LLCP procedure. */
LCTR_CONN_LLCP_SKIP_CONN_PARAM, /*!< Skip connection parameter exchange. */
LCTR_CONN_LLCP_REJECT_CONN_UPD, /*!< Reject a connection update. */
@ -240,6 +243,34 @@ typedef struct
uint8_t phy; /*!< PHY requested. */
} lctrMsgPwrCtrlReq_t;
/*! \brief Internal subrate request message. */
typedef struct
{
lctrMsgHdr_t hdr; /*!< Message Header. */
uint16_t srMin; /*!< Subrate minimum value. */
uint16_t srMax; /*!< Subrate maximum value. */
uint16_t maxLatency; /*!< Maximum latency. */
uint16_t contNum; /*!< Continuation number. */
uint16_t svt; /*!< Supervision timeout in 10ms units. */
} lctrMsgSubrateReq_t;
/*! \brief Channel reporting indication message. */
typedef struct
{
lctrMsgHdr_t hdr; /*!< Message Header. */
uint8_t enable; /*!< Enable. */
uint8_t minSpacing; /*!< Minimum status report spacing. */
uint8_t maxDelay; /*!< Maximum status report delay. */
} lctrMsgChRptInd_t;
/*! \brief Channel status indication message. */
typedef struct
{
lctrMsgHdr_t hdr; /*!< Message Header. */
uint8_t chanStatus[LL_MAX_NUM_CHAN_DATA];
/*!< Status of used channels. */
} lctrMsgChStatusInd_t;
/*! \brief Link layer controller message data. */
typedef union
{
@ -258,6 +289,9 @@ typedef union
lctrPerAdvSyncTrsf_t perAdvSyncTrsf; /*!< Periodic advertising sync transfer data. */
lctrScaReq_t scaReq; /*!< Sleep clock accuracy request. */
lctrMsgPwrCtrlReq_t pwrCtrlReq; /*!< Power control request. */
lctrMsgSubrateReq_t subrateReq; /*!< Subrate request. */
lctrMsgChRptInd_t chanRptInd; /*!< Channel report indication. */
lctrMsgChStatusInd_t chanStatusInd; /*!< Channel status indication. */
/* CIS */
lctrCreateCis_t createCis; /*!< Create CIS message data. */
@ -314,6 +348,8 @@ void LctrVsConnInit(const LctrVsHandlers_t *pHdlrs);
uint8_t LctrValidateConnSpec(const LlConnSpec_t *pConnSpec);
uint8_t LctrValidateModifyScaParam(uint8_t action);
bool_t LctrIsProcActPended(uint16_t handle, uint8_t event);
bool_t LctrIsFeatExchHostInit(uint16_t handle);
void LctrSetHostNotifyFeatExch(uint16_t handle);
/* Status */
bool_t LctrIsConnHandleEnabled(uint16_t handle);
@ -326,6 +362,7 @@ uint64_t LctrGetChannelMap(uint16_t handle);
uint64_t LctrGetUsedFeatures(uint16_t handle);
uint8_t LctrGetTxPhy(uint16_t handle);
uint8_t LctrGetRxPhy(uint16_t handle);
bool_t LctrCisTerminationInProgress(uint16_t handle);
void LctrGetPeerMinUsedChan(uint16_t handle, uint8_t *pPeerMinUsedChan);
bool_t LctrIsWaitingForReply(uint16_t handle, uint8_t reply);
bool_t LctrIsCisEnabled(uint16_t handle);
@ -341,7 +378,6 @@ bool_t LctrSetEncMode(uint16_t handle, const LlEncMode_t *pMode);
void LctrSetConnOpFlags(uint16_t handle, uint32_t flags, bool_t enable);
uint8_t lctrSetPowerMonitorEnable(uint16_t handle, bool_t enable);
/* Data path */
void LctrTxAcl(uint8_t *pAclBuf);
uint8_t *LctrRxAcl(void);

View File

@ -45,6 +45,7 @@ void LctrTxIso(uint8_t *pIsoBuf);
uint8_t *LctrRxIso(void);
void LctrRxIsoComplete(uint8_t numBufs);
uint8_t LctrReadIsoTxSync(uint16_t handle, uint16_t *pPktSn, uint32_t *pTs, uint32_t *pTimeOffs);
uint8_t LctrConfigureDataPath(LlIsoConfigDataPath_t *pConfigDataPath);
uint8_t LctrSetupIsoDataPath(LlIsoSetupDataPath_t *pSetupDataPath);
uint8_t LctrRemoveIsoDataPath(uint16_t handle, uint8_t dpDir);
uint8_t LctrIsoTxTest(uint16_t handle, uint8_t pldType);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -53,14 +53,22 @@ typedef struct
uint32_t dataPendMsk; /*!< Bitmask of connection handles with new pending data. */
/* PHY */
uint8_t allPhys; /*!< Default all PHYs. */
uint8_t txPhys; /*!< Default transmitter PHYs. */
uint8_t rxPhys; /*!< Default receiver PHYs. */
/* PAST */
uint8_t syncMode; /*!< Default sync transfer mode. */
uint16_t syncSkip; /*!< Default sync skip for periodic adv sync transfer. */
uint16_t syncTimeout; /*!< Default sync timeout for periodic adv sync transfer. */
/* Enhanced Connection Update */
uint16_t defSrMin; /*!< Default subrate minimum value. */
uint16_t defSrMax; /*!< Default subrate maximum value. */
uint16_t defMaxLatency; /*!< Default maximum latency. */
uint16_t defContNum; /*!< Default continuation number. */
uint16_t defSvt; /*!< Default supervision timeout. */
} lmgrConnCtrlBlk_t;
/**************************************************************************************************

View File

@ -154,7 +154,6 @@ void LlInitLlInit(void)
#if (BT_VER >= LL_VER_BT_CORE_SPEC_5_2)
LlCisMasterInit();
LlBisMasterInit();
LlPowerControlInit();
#endif
#else
#ifdef INIT_OBSERVER
@ -171,7 +170,6 @@ void LlInitLlInit(void)
#if (BT_VER >= LL_VER_BT_CORE_SPEC_5_2)
LlCisSlaveInit();
LlBisSlaveInit();
LlPowerControlInit();
#endif
#else
#ifdef INIT_BROADCASTER
@ -187,6 +185,12 @@ void LlInitLlInit(void)
#if (BT_VER >= LL_VER_BT_CORE_SPEC_5_1)
LlPastInit();
#endif
#if (BT_VER >= LL_VER_BT_CORE_SPEC_5_2)
LlPowerControlInit();
#endif
#if (BT_VER >= LL_VER_BT_CORE_SPEC_SYDNEY)
LlEnhConnUpdateInit();
#endif
#endif
#endif
@ -263,10 +267,13 @@ uint32_t LlInitSetLlRtCfg(const LlRtCfg_t *pLlRtCfg, uint8_t *pFreeMem, uint32_t
LlInitRunTimeCfg(pLlRtCfg);
#if defined (INIT_PERIPHERAL) || defined (INIT_CENTRAL)
memUsed = LlInitConnMem(pFreeMem, freeMemAvail);
pFreeMem += memUsed;
freeMemAvail -= memUsed;
totalMemUsed += memUsed;
if (pLlRtCfg->maxConn)
{
memUsed = LlInitConnMem(pFreeMem, freeMemAvail);
pFreeMem += memUsed;
freeMemAvail -= memUsed;
totalMemUsed += memUsed;
}
#endif
#if (BT_VER >= LL_VER_BT_CORE_SPEC_5_0)

View File

@ -4,7 +4,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -118,6 +118,9 @@ void LlInitLhciInit(void)
#if (BT_VER >= LL_VER_BT_CORE_SPEC_5_1)
LhciPastInit();
#endif
#if (BT_VER >= LL_VER_BT_CORE_SPEC_SYDNEY)
LhciEnhConnUpdateInit();
#endif
#endif
#endif
#endif
@ -141,6 +144,7 @@ void LlInitLhciInit(void)
#endif
LhciIsoInit();
LhciPowerControlInit();
#endif
}
@ -164,5 +168,12 @@ uint32_t LlInitControllerInit(LlInitRtCfg_t *pCfg)
LlInitLhciHandler();
LhciInitFinalize();
#if (CHCI_TR_COMP_ENA)
{
extern void LhciTrEventComplete(void);
LhciRegisterSendTrCompleteHandler(LhciTrEventComplete);
}
#endif
return totalMemUsed;
}

View File

@ -64,6 +64,7 @@ static uint8_t lctrPerScanSetup(lctrPerCreateSyncCtrlBlk_t *pPerCreateSync, lctr
pPerScanCtx->syncTimeOutMs = LCTR_PER_SYNC_TIMEOUT_TO_MS(pMsg->syncTimeOut);
pPerScanCtx->createDispId = createDispId;
pPerScanCtx->repDisabled = pMsg->repDisabled;
pPerScanCtx->dupFilterEnable = pMsg->dupFilterEnable;
return LL_SUCCESS;
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -106,7 +106,6 @@ void lctrExtAdvActStart(lctrAdvSet_t *pAdvSet)
pAdvSet->pExtAdvAuxPtr = NULL;
pAdvSet->connIndRcvd = FALSE;
pAdvSet->shutdown = FALSE;
pAdvSet->bodTermCnt = 0;
uint8_t status;
if ((status = lctrSlvExtAdvBuildOp(pAdvSet, pLctrSlvExtAdvMsg->enable.durMs)) != LL_SUCCESS)
@ -150,7 +149,6 @@ void lctrExtAdvActSelfStart(lctrAdvSet_t *pAdvSet)
pAdvSet->pExtAdvAuxPtr = NULL;
pAdvSet->connIndRcvd = FALSE;
pAdvSet->shutdown = FALSE;
pAdvSet->bodTermCnt = 0;
uint8_t status;
if ((status = lctrSlvExtAdvBuildOp(pAdvSet, pLctrSlvExtAdvMsg->enable.durMs)) != LL_SUCCESS)
@ -217,9 +215,10 @@ void lctrExtAdvActShutdown(lctrAdvSet_t *pAdvSet)
/*************************************************************************************************/
void lctrExtAdvActResetShutdown(lctrAdvSet_t *pAdvSet)
{
/* LCTR_MSG_RESET is broadcasted by hciReset and the processing order between ext ADV SM and periodic ADV SM is not guaranteed. */
/* If ext ADV SM runs first, it will purge all info and periodic ADV SM may not run as intended. */
/* So, reset cleanup of periodic advertising has to be done from extended ADV SM. */
/* LCTR_MSG_RESET is broadcasted by hciReset and the processing order between ext ADV SM and
* periodic ADV SM is not guaranteed. If ext ADV SM runs first, it will purge all info and periodic
* ADV SM may not run as intended. So, reset cleanup of periodic advertising has to be done from
* extended ADV SM. */
if (pAdvSet->perParam.perState == LCTR_PER_ADV_STATE_ENABLED)
{
lctrPeriodicAdvActShutdown(pAdvSet);
@ -424,9 +423,10 @@ void lctrExtAdvActAdvTerm(lctrAdvSet_t *pAdvSet)
/*************************************************************************************************/
void lctrExtAdvActReset(lctrAdvSet_t *pAdvSet)
{
/* LCTR_MSG_RESET is broadcasted by hciReset and the processing order between ext ADV SM and periodic ADV SM is not guaranteed. */
/* If ext ADV SM runs first, it will purge all info and periodic ADV SM may not run as intended. */
/* So, reset cleanup of periodic advertising has to be done from extended ADV SM. */
/* LCTR_MSG_RESET is broadcasted by hciReset and the processing order between ext ADV SM and
* periodic ADV SM is not guaranteed. If ext ADV SM runs first, it will purge all info and periodic
* ADV SM may not run as intended. So, reset cleanup of periodic advertising has to be done from
* extended ADV SM. */
if (pAdvSet->perParam.perState == LCTR_PER_ADV_STATE_ENABLED)
{
lctrPeriodicAdvActShutdown(pAdvSet);
@ -468,6 +468,9 @@ void lctrExtAdvActDurationExpired(lctrAdvSet_t *pAdvSet)
/* Signal shutdown, event completion occurs in lctrExtAdvActSelfTerm(). */
pAdvSet->shutdown = TRUE;
SchRemove(&pAdvSet->advBod);
SchRemove(&pAdvSet->auxAdvBod);
}
/*************************************************************************************************/
@ -541,6 +544,11 @@ void lctrPeriodicAdvActStart(lctrAdvSet_t *pAdvSet)
pAdvSet->didPerUpdate = TRUE;
}
if (pAdvSet->perParam.enableAdi)
{
pAdvSet->perParam.advDID = lctrCalcDID(pAdvSet->advData.pBuf, pAdvSet->advData.len);
}
LmgrSendPeriodicAdvEnableCnf(pAdvSet->handle, LL_SUCCESS);
LmgrIncResetRefCount();
}

View File

@ -51,11 +51,13 @@ static void lctrNotifyHostBigCreateSyncComplete(lctrBigCtx_t *pBigCtx, LlStatus_
evt.irc = pBigCtx->irc;
evt.maxPdu = pBigCtx->maxPdu;
evt.isoInterval = LL_MATH_DIV_1250(pBigCtx->isoInterUsec);
evt.numBis = pBigCtx->numBis;
for (unsigned int i = 0; i < evt.numBis; i++)
for (unsigned int i = 0; i < LL_MAX_BIS; i++)
{
evt.bisHandle[i] = pBigCtx->pBisCtx[i]->handle;
if (pBigCtx->pBisCtx[i])
{
evt.bisHandle[evt.numBis++] = pBigCtx->pBisCtx[i]->handle;
}
}
}
@ -152,12 +154,42 @@ void lctrMstBigActBigSync(lctrBigCtx_t *pBigCtx)
for (unsigned int i = 0; i < pBigInfo->numBis; i++)
{
lctrBisCtx_t *pBisCtx;
unsigned int j;
/* Availability is verified on BIG Create Sync command. */
pBisCtx = lctrAllocBisCtx(pBigCtx);
WSF_ASSERT(pBisCtx);
for (j = 0; j < pBigCtx->roleData.mst.numBisIdx; j++)
{
/* Check host BIS filter. */
if (pBigCtx->roleData.mst.bisIdx[j] == (i + 1))
{
/* Availability is verified on BIG Create Sync command. */
pBisCtx = lctrAllocBisCtx(pBigCtx);
WSF_ASSERT(pBisCtx);
lctrSetupBisContext(pBisCtx, pBigInfo->seedAccAddr, pBigInfo->baseCrcInit, pBigInfo->chanMap, pBigInfo->phy);
lctrSetupBisContext(pBisCtx, pBigInfo->seedAccAddr, pBigInfo->baseCrcInit, pBigInfo->chanMap, pBigInfo->phy);
if (pBigCtx->roleData.mst.pFirstBisCtx == NULL)
{
/* Optimize ISR by reducing lookup on every event; store first BIS. */
pBigCtx->roleData.mst.pFirstBisCtx = pBisCtx;
pBigCtx->roleData.mst.firstBisOffsUsec = pBigCtx->bisSpaceUsec * i;
pBigCtx->roleData.mst.firstBisEvtIdx = i;
}
else if (pBigCtx->roleData.mst.pSecondBisCtx == NULL)
{
/* Optimize ISR by reducing lookup on every event; store second BIS; NULL if none. */
pBigCtx->roleData.mst.pSecondBisCtx = pBisCtx;
}
break;
}
}
if (j == pBigCtx->roleData.mst.numBisIdx)
{
/* Disable BIS subevent. */
pBigCtx->pBisCtx[pBigCtx->numBis++] = NULL;
}
}
lctrMstBigBuildOp(pBigCtx, &pLctrMstBigMsg->bigInfo.data);
@ -176,13 +208,9 @@ void lctrMstBigActBigSync(lctrBigCtx_t *pBigCtx)
/*************************************************************************************************/
void lctrMstBigActTerm(lctrBigCtx_t *pBigCtx)
{
BbStop(BB_PROT_BLE);
/* Shutdown completes with events generated in BOD end callback. */
lctrFreeBigCtx(pBigCtx);
LmgrDecResetRefCount();
lctrNotifyHostSyncLost(pBigCtx->handle, pBigCtx->bcp.term.reason);
pBigCtx->roleData.mst.syncLostReason = pBigCtx->bcp.term.reason;
}
/*************************************************************************************************/
@ -194,12 +222,7 @@ void lctrMstBigActTerm(lctrBigCtx_t *pBigCtx)
/*************************************************************************************************/
void lctrMstBigActShutdown(lctrBigCtx_t *pBigCtx)
{
/* By removing BOD from scheduler, BOD end callback will be called. */
/* Shutdown completes with events generated in BOD end callback. */
if (!SchRemove(&pBigCtx->bod))
{
lctrMstBigSendMsg(pBigCtx, LCTR_MST_BIG_INT_TERMINATED_SYNC);
}
/* Shutdown completes with events generated in BOD end callback. */
if (pBigCtx->state == LCTR_MST_BIG_STATE_SYNCING)
{
@ -216,12 +239,7 @@ void lctrMstBigActShutdown(lctrBigCtx_t *pBigCtx)
/*************************************************************************************************/
void lctrMstBigActSyncLost(lctrBigCtx_t *pBigCtx)
{
/* By removing BOD from scheduler, BOD end callback will be called. */
/* Shutdown completes with events generated in BOD end callback. */
if (!SchRemove(&pBigCtx->bod))
{
lctrMstBigSendMsg(pBigCtx, LCTR_MST_BIG_INT_TERMINATED_SYNC);
}
/* Shutdown completes with events generated in BOD end callback. */
pBigCtx->roleData.mst.syncLostReason = LL_ERROR_CODE_CONN_TIMEOUT;
}
@ -235,12 +253,7 @@ void lctrMstBigActSyncLost(lctrBigCtx_t *pBigCtx)
/*************************************************************************************************/
void lctrMstBigActMicFailed(lctrBigCtx_t *pBigCtx)
{
/* By removing BOD from scheduler, BOD end callback will be called. */
/* Shutdown completes with events generated in BOD end callback. */
if (!SchRemove(&pBigCtx->bod))
{
lctrMstBigSendMsg(pBigCtx, LCTR_MST_BIG_INT_TERMINATED_SYNC);
}
/* Shutdown completes with events generated in BOD end callback. */
pBigCtx->roleData.mst.syncLostReason = LL_ERROR_CODE_CONN_TERM_MIC_FAILURE;
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,6 +36,46 @@
Local Functions
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Send next CIS disconnect LLCP to be processed, if needed.
*
* \param ACL Handle that can continue CIS termination procedures.
*/
/*************************************************************************************************/
static void lctrCheckPendingCisTermination(uint16_t aclHandle)
{
for (unsigned int i = 0; i < pLctrRtCfg->maxCis; i++)
{
lctrCisCtx_t *pCisCtx = &pLctrCisTbl[i];
lctrCisDisc_t *pMsg;
if ((pCisCtx->aclHandle == aclHandle) &&
!pCisCtx->isClosing && pCisCtx->termPend)
{
if ((pMsg = (lctrCisDisc_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = pCisCtx->aclHandle;
pMsg->hdr.dispId = LCTR_DISP_CONN;
pMsg->hdr.event = LCTR_CONN_MSG_API_DISCONNECT;
pMsg->cisHandle = pCisCtx->cisHandle;
pMsg->reason = pCisCtx->reason;
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
pCisCtx->termPend = FALSE;
}
else
{
LL_TRACE_WARN1("lctrCisActDisc: CIS OOM while terminating handle %d", pCisCtx->cisHandle);
}
return;
}
}
}
/*************************************************************************************************/
/*!
* \brief Send CIS termination indication PDU.
@ -94,16 +134,16 @@ void lctrNotifyHostCisTerm(lctrCisCtx_t *pCisCtx)
{
LlDisconnectInd_t evt =
{
.hdr =
{
.param = pCisCtx->cisHandle,
.event = LL_DISCONNECT_IND,
.status = LL_SUCCESS
},
.hdr =
{
.param = pCisCtx->cisHandle,
.event = LL_DISCONNECT_IND,
.status = LL_SUCCESS
},
.status = LL_SUCCESS,
.handle = pCisCtx->cisHandle,
.reason = pCisCtx->reason
.status = LL_SUCCESS,
.handle = pCisCtx->cisHandle,
.reason = pCisCtx->reason
};
LL_TRACE_INFO2("### LlEvent ### LL_DISCONNECT_IND, handle=%u, status=LL_SUCCESS, reason=%u", pCisCtx->cisHandle, pCisCtx->reason);
@ -126,9 +166,9 @@ void lctrNotifyHostCisEst(lctrCisCtx_t *pCisCtx, uint8_t status, uint32_t cigSyn
{
.hdr =
{
.param = pCisCtx->cisHandle,
.event = LL_CIS_EST_IND,
.status = status
.param = pCisCtx->cisHandle,
.event = LL_CIS_EST_IND,
.status = status
}
};
@ -146,6 +186,9 @@ void lctrNotifyHostCisEst(lctrCisCtx_t *pCisCtx, uint8_t status, uint32_t cigSyn
evt.ftMToS = pCisCtx->ftMToS;
evt.ftSToM = pCisCtx->ftSToM;
evt.isoInterval = pCisCtx->isoInterval;
evt.maxPduMToS = (pCisCtx->role == LL_ROLE_MASTER) ? pCisCtx->localDataPdu.maxTxLen : pCisCtx->localDataPdu.maxRxLen;
evt.maxPduSToM = (pCisCtx->role == LL_ROLE_SLAVE) ? pCisCtx->localDataPdu.maxTxLen : pCisCtx->localDataPdu.maxRxLen;
LL_TRACE_INFO2("### LlEvent ### LL_CIS_EST_IND, cisHandle=%u, status=%u", pCisCtx->cisHandle, status);
@ -311,18 +354,13 @@ void lctrCisActCisEst(lctrCisCtx_t *pCisCtx)
BbBleData_t *pBle = &pConnCtx->bleData;
pCigCtx->numCisEsted++;
LL_TRACE_INFO1("lctrCisActCisEst, pCigCtx->numCisEsted=%u", pCigCtx->numCisEsted);
/* Initialize txPower. */
uint8_t txPhy = (pCisCtx->role == LL_ROLE_MASTER) ? pCisCtx->phyMToS : pCisCtx->phySToM;
uint8_t option = pBle->chan.initTxPhyOptions;
int8_t txPwr = LCTR_GET_TXPOWER(pConnCtx, txPhy, option);
LL_TRACE_INFO1("lctrCisActCisEst phy = %d", txPhy);
if ((txPwr == LL_PWR_CTRL_TXPOWER_UNMANAGED) && (pConnCtx->peerReqRecvd))
{
LL_TRACE_INFO0(" txPower previously unmanaged. Initalized txPower.");
LCTR_SET_TXPOWER(pConnCtx, txPhy, pLctrRtCfg->defTxPwrLvl);
if (txPhy == LL_PHY_LE_CODED)
@ -330,7 +368,7 @@ void lctrCisActCisEst(lctrCisCtx_t *pCisCtx)
LCTR_SET_TXPOWER(pConnCtx, LL_PC_PHY_CODED_S2, pLctrRtCfg->defTxPwrLvl);
}
/* pCisCtx->bleData.chan.txPower = LCTR_GET_TXPOWER(pConnCtx, txPhy, option); //Handled in the init */
/* pCisCtx->bleData.chan.txPower = LCTR_GET_TXPOWER(pConnCtx, txPhy, option); */ /* Handled during initialization. */
if (pConnCtx->usedFeatSet & LL_FEAT_POWER_CHANGE_IND)
{
pCisCtx->powerIndReq = TRUE;
@ -338,10 +376,10 @@ void lctrCisActCisEst(lctrCisCtx_t *pCisCtx)
}
else
{
LL_TRACE_INFO1(" txPower = %d", txPwr);
pCisCtx->bleData.chan.txPower = txPwr;
}
LL_TRACE_INFO2("lctrCisActCisEst, numCisEsted=%u txPower=%u", pCigCtx->numCisEsted, txPwr);
}
/*************************************************************************************************/
@ -378,16 +416,30 @@ void lctrCisActDisc(lctrCisCtx_t *pCisCtx)
{
lctrCisDisc_t *pMsg;
if ((pMsg = (lctrCisDisc_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
if (!LctrCisTerminationInProgress(pCisCtx->aclHandle))
{
pMsg->hdr.handle = pCisCtx->aclHandle;
pMsg->hdr.dispId = LCTR_DISP_CONN;
pMsg->hdr.event = LCTR_CONN_MSG_API_DISCONNECT;
if ((pMsg = (lctrCisDisc_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = pCisCtx->aclHandle;
pMsg->hdr.dispId = LCTR_DISP_CONN;
pMsg->hdr.event = LCTR_CONN_MSG_API_DISCONNECT;
pMsg->cisHandle = pCisCtx->cisHandle;
pMsg->reason = pCisCtx->reason;
pMsg->cisHandle = pCisCtx->cisHandle;
pMsg->reason = pCisCtx->reason;
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
pCisCtx->termPend = FALSE;
}
else
{
LL_TRACE_WARN1("lctrCisActDisc: CIS OOM while terminating handle %d", pCisCtx->cisHandle);
}
}
else
{
LL_TRACE_INFO1("lctrCisActDisc: CIS Termination pending, CIS Termination queued for handle %d", pCisCtx->cisHandle);
pCisCtx->termPend = TRUE;
}
}
@ -400,19 +452,11 @@ void lctrCisActDisc(lctrCisCtx_t *pCisCtx)
/*************************************************************************************************/
void lctrCisActClosed(lctrCisCtx_t *pCisCtx)
{
/* Stop output data path. */
switch (pCisCtx->dataPathOutCtx.id)
{
case LL_ISO_DATA_PATH_VS:
WSF_ASSERT(lctrCodecHdlr.stop);
lctrCodecHdlr.stop(pCisCtx->cisHandle);
break;
case LL_ISO_DATA_PATH_DISABLED:
case LL_ISO_DATA_PATH_HCI:
default:
/* No action required. */
break;
}
uint16_t aclHandle = pCisCtx->aclHandle;
/* Must do one at a time in case one datapath is not used. */
LctrRemoveIsoDataPath(pCisCtx->cisHandle, LL_ISO_DATA_PATH_INPUT_BIT);
LctrRemoveIsoDataPath(pCisCtx->cisHandle, LL_ISO_DATA_PATH_OUTPUT_BIT);
LL_TRACE_INFO1("lctrCisActClosed, pCisCtx->cisHandle=%u", pCisCtx->cisHandle);
@ -433,6 +477,8 @@ void lctrCisActClosed(lctrCisCtx_t *pCisCtx)
pCisCtx->isClosing = FALSE;
lctrCleanupCtx(pCisCtx);
}
lctrCheckPendingCisTermination(aclHandle);
}
/*************************************************************************************************/
@ -449,12 +495,11 @@ void lctrCisActFail(lctrCisCtx_t *pCisCtx)
LL_TRACE_INFO2("lctrCisActFail, pCisCtx->cisHandle=%u pCisCtx->state=%u", pCisCtx->cisHandle, pCisCtx->state);
/* Supervision timeout case */
/* Supervision timeout or MIC timeout case */
if (pCisCtx->state == LCTR_CIS_STATE_EST)
{
pCisCtx->isClosing = TRUE; /* Close the context in the CIG BOD end callback. */
SchRemove(&pCigCtx->cigBod);
lctrNotifyHostCisTerm(pCisCtx);
}
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -50,8 +50,9 @@ static void lctrCalCeRefFirstCis(lctrConnCtx_t *pCtx, lctrCisCtx_t *pCisCtx)
uint32_t refTime;
pCisCtx->ceRef = pCtx->eventCounter +
LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency; /* ensure slave will listen to this packet */
((LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency) * /* ensure slave will listen to this packet */
pCtx->ecu.srFactor); /* include subrating factor */
pCisCtx->cisCeRef = 0;
refTime = pConnBod->dueUsec + (pCisCtx->ceRef - pCtx->eventCounter) * LCTR_CONN_IND_US(pCtx->connInterval);
@ -94,8 +95,9 @@ static void lctrCalCeRefNotFirstCis(lctrConnCtx_t *pCtx, lctrCisCtx_t *pCisCtx)
uint32_t offsetUsec = 0;
pCisCtx->ceRef = pCtx->eventCounter +
LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency; /* ensure slave will listen to this packet */
((LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency) * /* ensure slave will listen to this packet */
pCtx->ecu.srFactor); /* include subrating factor */
aclRefTime = pConnBod->dueUsec + (pCisCtx->ceRef - pCtx->eventCounter) * LCTR_CONN_IND_US(pCtx->connInterval);
@ -301,7 +303,7 @@ void lctrMstCisLlcpActHostCisReq(lctrConnCtx_t *pCtx, lctrCisCtx_t *pCisCtx)
/* Check whether the parameter for the BOD is valid or not. */
if (pCigCtx->isValid == FALSE)
{
LL_TRACE_WARN0("Fail to create CIS due to invalid parameters");
LL_TRACE_WARN0("lctrMstCisLlcpActHostCisReq: Fail to create CIS due to invalid parameters");
lctrCisStoreLocalLowResourceTerminateReason(pCisCtx);
result = FALSE;
}
@ -313,9 +315,11 @@ void lctrMstCisLlcpActHostCisReq(lctrConnCtx_t *pCtx, lctrCisCtx_t *pCisCtx)
SCH_RM_PREF_PERFORMANCE,
LCTR_ISO_INT_TO_US(pCigCtx->isoInterval),
LCTR_ISO_INT_TO_US(pCigCtx->isoInterval),
pCigCtx->cigSyncDelayUsec, NULL, lctrGetCigRefTime))
pCigCtx->cigSyncDelayUsec,
NULL,
lctrGetCigRefTime))
{
LL_TRACE_WARN0("Fail to create CIS due to scheduling limitation");
LL_TRACE_WARN0("lctrMstCisLlcpActHostCisReq: Fail to create CIS due to scheduling limitation");
lctrCisStoreLocalLowResourceTerminateReason(pCisCtx);
result = FALSE;
}
@ -418,7 +422,7 @@ void lctrMstCisLlcpActPeerCisRsp(lctrConnCtx_t *pCtx, lctrCisCtx_t *pCisCtx)
if (pCigCtx->isBodBuilt == FALSE)
{
WSF_ASSERT(pCisCtx->cisCeRef == 0)
WSF_ASSERT(pCisCtx->cisCeRef == 0);
lctrMstCisBuildCigOp(pCigCtx);
}

View File

@ -168,12 +168,12 @@ static void lctrNotifyHostCisReq(lctrCisCtx_t *pCisCtx)
{
LlCisReqInd_t evt =
{
.hdr =
{
.param = pCisCtx->cisHandle,
.event = LL_CIS_REQ_IND,
.status = LL_SUCCESS
}
.hdr =
{
.param = pCisCtx->cisHandle,
.event = LL_CIS_REQ_IND,
.status = LL_SUCCESS
}
};
evt.aclHandle = pCisCtx->aclHandle;
@ -181,7 +181,7 @@ static void lctrNotifyHostCisReq(lctrCisCtx_t *pCisCtx)
evt.cigId = pCisCtx->cigId;
evt.cisId = pCisCtx->cisId;
LL_TRACE_INFO1("### LlEvent ### LL_CIS_REQ_IND, cisHandle=%u", pCisCtx->cisHandle);
LL_TRACE_INFO3("### LlEvent ### LL_CIS_REQ_IND, cisHandle=%u cigId=%u cisId=%u", pCisCtx->cisHandle, pCisCtx->cigId, pCisCtx->cisId);
bool_t evtSent = LmgrSendEvent((LlEvt_t *)&evt);
@ -363,7 +363,7 @@ void lctrSlvCisLlcpActPeerCisInd(lctrConnCtx_t *pCtx, lctrCisCtx_t *pCisCtx)
{
/* If the anchor point of the stream is before end of the first stream, it is interleaved packing scheme. */
if (BbGetTargetTimeDelta(cigRefTime + pHeadCisCtx->subIntervUsec,
pCisCtx->data.slv.anchorOffsetUsec + pCtx->data.slv.anchorPointUsec + LCTR_CONN_IND_US(pCtx->connInterval)) > 0)
pCisCtx->data.slv.anchorOffsetUsec + pCtx->data.slv.anchorPointUsec + LCTR_CONN_IND_US(pCtx->connInterval)) > 0)
{
pCigCtx->packing = LL_PACKING_INTERLEAVED;
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -42,7 +42,7 @@
Macros
**************************************************************************************************/
/*! \brief Valid feature bits applicable between controllers */
/*! \brief Valid feature bits applicable between controllers. */
#define LCTR_FEAT_PEER_MASK (LL_FEAT_ENCRYPTION | \
LL_FEAT_CONN_PARAM_REQ_PROC | \
LL_FEAT_EXT_REJECT_IND | \
@ -68,12 +68,15 @@
LL_FEAT_ISO_HOST_SUPPORT | \
LL_FEAT_POWER_CONTROL_REQUEST | \
LL_FEAT_POWER_CHANGE_IND | \
LL_FEAT_PATH_LOSS_MONITOR)
LL_FEAT_PATH_LOSS_MONITOR | \
LL_FEAT_CONN_SUBRATE | \
LL_FEAT_CONN_SUBRATE_HOST_SUPPORT | \
LL_FEAT_CHANNEL_CLASSIFICATION)
/*! \brief Used feature bitmask. */
#define LCTR_USED_FEAT_SET_MASK 0x000000FFFF
/*! \brief Features bits mask over the air */
/*! \brief Features bits mask over the air. */
#define LCTR_OTA_FEAT_MASK (~LL_FEAT_REMOTE_PUB_KEY_VALIDATION & LCTR_FEAT_PEER_MASK)
/*************************************************************************************************/
@ -99,7 +102,6 @@ static bool_t lctrValidateConnParam(const lctrConnParam_t *pConnParam)
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Compute the sleep clock accuracy index in connection context.
@ -126,6 +128,39 @@ static uint8_t lctrComputeConnSca(lctrConnCtx_t *pCtx)
return (uint8_t) (sca + pCtx->scaMod);
}
/*************************************************************************************************/
/*!
* \brief Queue channel reporting indication to be sent out.
*
* \param pCtx Connection context.
* \param enable Enable/disable.
*/
/*************************************************************************************************/
static void lctrQueueChannelReportingInd(lctrConnCtx_t *pCtx, bool_t enable)
{
lctrMsgChRptInd_t *pMsg;
if ((pMsg = (lctrMsgChRptInd_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = LCTR_GET_CONN_HANDLE(pCtx);
pMsg->hdr.dispId = LCTR_DISP_CONN;
pMsg->hdr.event = LCTR_CONN_LLCP_CHANNEL_REPORTING;
/* Use default if the run-time configuration is not within spec range. */
uint8_t spacing = pLctrRtCfg->chClassIntSpacing;
if ((spacing > LL_CH_RPT_SPACING_MAX) ||
(spacing < LL_CH_RPT_SPACING_MIN))
{
spacing = LL_CH_RPT_SPACING_DEFAULT;
}
pMsg->enable = enable;
pMsg->maxDelay = spacing;
pMsg->minSpacing = spacing;
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \brief Notify host of connect indication.
@ -306,8 +341,9 @@ void lctrSendChanMapUpdateInd(lctrConnCtx_t *pCtx)
#endif
{
pCtx->chanMapUpd.instant = pCtx->eventCounter +
LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency; /* ensure slave will listen to this packet */
((LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency) * /* ensure slave will listen to this packet */
pCtx->ecu.srFactor); /* include subrating factor */
}
/*** Assemble control PDU. ***/
@ -407,6 +443,9 @@ void lctrSendFeatureRsp(lctrConnCtx_t *pCtx)
/*************************************************************************************************/
void lctrStoreUsedFeatures(lctrConnCtx_t *pCtx)
{
pCtx->peerFeatures = lctrDataPdu.pld.featReqRsp.featSet & LCTR_FEAT_PEER_MASK;
/* TODO: make usedFeatSet calculated when needed based on peerFeatures. Use function LctrGetUsedFeatures. */
pCtx->usedFeatSet = lmgrCb.features & lctrDataPdu.pld.featReqRsp.featSet & LCTR_FEAT_PEER_MASK;
pCtx->featExchFlag = TRUE;
@ -415,6 +454,27 @@ void lctrStoreUsedFeatures(lctrConnCtx_t *pCtx)
(lctrDataPdu.pld.featReqRsp.featSet & LL_FEAT_STABLE_MOD_IDX_TRANSMITTER) ? TRUE : FALSE;
pCtx->bleData.chan.peerRxStableModIdx =
(lctrDataPdu.pld.featReqRsp.featSet & LL_FEAT_STABLE_MOD_IDX_RECEIVER) ? TRUE : FALSE;
/* If channel classification is supported and enabled, turn on channel classification. */
if ((pCtx->role == LL_ROLE_MASTER) && (!pCtx->chanStatRptEnable) &&
(pCtx->usedFeatSet & LL_FEAT_CHANNEL_CLASSIFICATION) &&
(lctrGetConnOpFlag(pCtx, LL_OP_MODE_FLAG_ENA_CH_RPT_LLCP_AFTER_FEAT)))
{
lctrQueueChannelReportingInd(pCtx, TRUE);
}
/* Start timer for power monitor if the feature is supported. */
if ((pCtx->usedFeatSet & LL_FEAT_POWER_CONTROL_REQUEST) &&
(pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->powerMonitorScheme == LCTR_PC_MONITOR_AUTO) &&
!lmgrGetOpFlag(LL_OP_MODE_FLAG_DIS_POWER_MONITOR))
{
WsfTimerStartMs(&pCtx->tmrPowerCtrl, LL_PC_SERVICE_MS);
}
else
{
WsfTimerStop(&pCtx->tmrPowerCtrl);
}
}
/*************************************************************************************************/
@ -937,7 +997,6 @@ static void lctrSendDataLengthPdu(lctrConnCtx_t *pCtx, uint8_t opcode)
{
uint8_t *pBuf = pPdu;
/*** Assemble control PDU. ***/
UINT8_TO_BSTREAM (pBuf, opcode);
@ -945,7 +1004,7 @@ static void lctrSendDataLengthPdu(lctrConnCtx_t *pCtx, uint8_t opcode)
uint16_t maxRxTime = pCtx->localDataPdu.maxRxTime;
uint16_t maxTxTime = pCtx->localDataPdu.maxTxTime;
/* If LL_FEAT_LE_CODED_PHY is not supported, maxRxTime and maxTxTime can not be more than 2128.*/
/* If LL_FEAT_LE_CODED_PHY is not supported, maxRxTime and maxTxTime can not be more than 2120 (2128 if CTEs are supported).*/
if (!pCtx->featExchFlag ||
!(pCtx->usedFeatSet & LL_FEAT_LE_CODED_PHY))
{
@ -1023,7 +1082,7 @@ void lctrStoreRemoteDataLength(lctrConnCtx_t *pCtx)
uint16_t maxRxTime = pCtx->localDataPdu.maxRxTime;
uint16_t maxTxTime = pCtx->localDataPdu.maxTxTime;
/* If LL_FEAT_LE_CODED_PHY is not supported, maxRxTime and maxTxTime can not be more than 2128. */
/* If LL_FEAT_LE_CODED_PHY is not supported, maxRxTime and maxTxTime can not be more than 2120 (2128 if CTEs are supported). */
if (!pCtx->featExchFlag ||
!(pCtx->usedFeatSet & LL_FEAT_LE_CODED_PHY))
{
@ -1185,6 +1244,209 @@ static void lctrSendPeerScaReqPdu(lctrConnCtx_t *pCtx, uint8_t opcode)
}
}
/*************************************************************************************************/
/*!
* \brief Send channel reporting indication PDU.
*
* \param pCtx Connection context.
* \param opcode PDU opcode.
*/
/*************************************************************************************************/
static void lctrSendChannelReportingIndPdu(lctrConnCtx_t *pCtx)
{
uint8_t *pPdu;
if ((pPdu = lctrTxCtrlPduAlloc(LL_CH_REPORTING_LEN)) != NULL)
{
uint8_t *pBuf = pPdu;
/*** Assemble control PDU. ***/
UINT8_TO_BSTREAM (pBuf, LL_PDU_CH_REPORTING_IND);
UINT8_TO_BSTREAM (pBuf, pLctrConnMsg->chanRptInd.enable);
UINT8_TO_BSTREAM (pBuf, pLctrConnMsg->chanRptInd.minSpacing);
UINT8_TO_BSTREAM (pBuf, pLctrConnMsg->chanRptInd.maxDelay);
/*** Queue for transmit. ***/
lctrTxCtrlPduQueue(pCtx, pPdu);
}
}
/*************************************************************************************************/
/*!
* \brief Send channel status indication PDU.
*
* \param pCtx Connection context.
* \param opcode PDU opcode.
*/
/*************************************************************************************************/
static void lctrSendChannelStatusIndPdu(lctrConnCtx_t *pCtx)
{
static uint8_t CHAN_STATUS_BIT_LENGTH = 2;
uint8_t *pPdu;
if ((pPdu = lctrTxCtrlPduAlloc(LL_CH_STATUS_LEN)) != NULL)
{
uint8_t *pBuf = pPdu;
uint8_t i, packedChanByte;
uint8_t curCh = 0;
/*** Assemble control PDU. ***/
UINT8_TO_BSTREAM (pBuf, LL_PDU_CH_STATUS_IND);
/* Pack all but final byte */
for (i = 0; i < (LL_CH_STATUS_LEN - 2); i++)
{
packedChanByte =
(pLctrConnMsg->chanStatusInd.chanStatus[curCh]) |
(pLctrConnMsg->chanStatusInd.chanStatus[curCh + 1] << (CHAN_STATUS_BIT_LENGTH * 1)) |
(pLctrConnMsg->chanStatusInd.chanStatus[curCh + 2] << (CHAN_STATUS_BIT_LENGTH * 2)) |
(pLctrConnMsg->chanStatusInd.chanStatus[curCh + 3] << (CHAN_STATUS_BIT_LENGTH * 3));
UINT8_TO_BSTREAM (pBuf, packedChanByte);
curCh += 4;
}
/* Pack final byte here (outside loop because it is not fully packed). */
packedChanByte = pLctrConnMsg->chanStatusInd.chanStatus[curCh];
UINT8_TO_BSTREAM (pBuf, packedChanByte);
/*** Queue for transmit. ***/
lctrTxCtrlPduQueue(pCtx, pPdu);
}
}
/*************************************************************************************************/
/*!
* \brief Send channel status indication.
*
* \param pCtx Connection context.
*/
/*************************************************************************************************/
void lctrSendChannelStatusInd(lctrConnCtx_t *pCtx)
{
lctrSendChannelStatusIndPdu(pCtx);
/* The procedure completes after sending out the indication. */
pCtx->llcpNotifyMask &= ~(1 << LCTR_PROC_CMN_CH_STATUS_REPORT);
lctrSendConnMsg(pCtx, LCTR_CONN_LLCP_PROC_CMPL);
}
/*************************************************************************************************/
/*!
* \brief Store received channel status indication.
*
* \param pCtx Connection context.
*/
/*************************************************************************************************/
void lctrStoreChannelStatusInd(lctrConnCtx_t *pCtx)
{
if (pCtx->role != LL_ROLE_MASTER)
{
LL_TRACE_WARN1("Received CHANNEL_STATUS_IND on peripheral connection handle=%u", LCTR_GET_CONN_HANDLE(pCtx));
/* The procedure completes after receiving the indication. */
lctrSendConnMsg(pCtx, LCTR_CONN_LLCP_PROC_CMPL);
return;
}
uint32_t receivedTime = PalBbGetCurrentTime();
if (BbGetTargetTimeDelta(receivedTime, pCtx->data.mst.recvdChanStatTs) >= pCtx->data.mst.chanStatMinIntUs)
{
uint8_t i;
for (i = 0; i < LL_CH_STATUS_LEN - 2; i ++)
{
pCtx->data.mst.peerChannelStatus[i * 4] = lctrDataPdu.pld.chanStatusInd.chanStatusMap[i] & (0x03 << 0);
pCtx->data.mst.peerChannelStatus[(i * 4) + 1] = lctrDataPdu.pld.chanStatusInd.chanStatusMap[i] & (0x03 << 2);
pCtx->data.mst.peerChannelStatus[(i * 4) + 2] = lctrDataPdu.pld.chanStatusInd.chanStatusMap[i] & (0x03 << 4);
pCtx->data.mst.peerChannelStatus[(i * 4) + 3] = lctrDataPdu.pld.chanStatusInd.chanStatusMap[i] & (0x03 << 6);
}
/* Final byte has less than 4 channels. */
pCtx->data.mst.peerChannelStatus[i * 4] = lctrDataPdu.pld.chanStatusInd.chanStatusMap[i] & (0x03 << 0);
}
else
{
LL_TRACE_WARN1("Received channel status from peripheral too early. Handle=%u", LCTR_GET_CONN_HANDLE(pCtx));
}
/* The procedure completes after receiving the indication. */
lctrSendConnMsg(pCtx, LCTR_CONN_LLCP_PROC_CMPL);
}
/*************************************************************************************************/
/*!
* \brief Send channel reporting indication.
*
* \param pCtx Connection context.
*/
/*************************************************************************************************/
void lctrSendChannelReportingInd(lctrConnCtx_t *pCtx)
{
if (pCtx->role != LL_ROLE_MASTER)
{
LL_TRACE_WARN0("lctrSendChannelReportingInd: Shall not be called as a peripheral.");
pCtx->llcpNotifyMask &= ~(1 << LCTR_PROC_CMN_CH_CLASS_REPORTING);
lctrSendConnMsg(pCtx, LCTR_CONN_LLCP_PROC_CMPL);
return;
}
lctrSendChannelReportingIndPdu(pCtx);
pCtx->chanStatRptEnable = pLctrConnMsg->chanRptInd.enable;
pCtx->data.mst.chanStatMinIntUs = LCTR_CH_RPT_IND_US(pLctrConnMsg->chanRptInd.minSpacing);
/* Minus minimum spacing to allow a controller to send LL_CHANNEL_STATUS_IND right away if desired. */
pCtx->data.mst.recvdChanStatTs = PalBbGetCurrentTime() - pCtx->data.mst.chanStatMinIntUs;
/* The procedure completes after sending out the indication. */
pCtx->llcpNotifyMask &= ~(1 << LCTR_PROC_CMN_CH_CLASS_REPORTING);
lctrSendConnMsg(pCtx, LCTR_CONN_LLCP_PROC_CMPL);
}
/*************************************************************************************************/
/*!
* \brief Store received channel reporting indication.
*
* \param pCtx Connection context.
*/
/*************************************************************************************************/
void lctrStoreChannelReportingInd(lctrConnCtx_t *pCtx)
{
if (pCtx->role != LL_ROLE_SLAVE)
{
LL_TRACE_WARN1("lctrStoreChannelReportingInd: Received LL_CH_RPT_IND as a central. Handle=%d", LCTR_GET_CONN_HANDLE(pCtx));
pCtx->llcpNotifyMask &= ~(1 << LCTR_PROC_CMN_CH_CLASS_REPORTING);
lctrSendConnMsg(pCtx, LCTR_CONN_LLCP_PROC_CMPL);
return;
}
if ((lctrDataPdu.pld.chanRptInd.enable > TRUE) ||
(lctrDataPdu.pld.chanRptInd.minSpacing < LL_CH_RPT_SPACING_MIN) ||
(lctrDataPdu.pld.chanRptInd.maxDelay < LL_CH_RPT_SPACING_MIN) ||
(lctrDataPdu.pld.chanRptInd.minSpacing > LL_CH_RPT_SPACING_MAX) ||
(lctrDataPdu.pld.chanRptInd.maxDelay > LL_CH_RPT_SPACING_MAX) ||
(lctrDataPdu.pld.chanRptInd.maxDelay < lctrDataPdu.pld.chanRptInd.minSpacing))
{
lctrSendRejectInd(pCtx, LL_ERROR_CODE_INVALID_LMP_PARAMS, TRUE);
}
else
{
pCtx->chanStatRptEnable = lctrDataPdu.pld.chanRptInd.enable;
pCtx->data.slv.chanStatMinIntUs = LCTR_CH_RPT_IND_US(lctrDataPdu.pld.chanRptInd.minSpacing);
pCtx->data.slv.chanStatMaxDelay = LCTR_CH_RPT_IND_US(lctrDataPdu.pld.chanRptInd.maxDelay);
if (pCtx->chanStatRptEnable)
{
pCtx->data.slv.queuedChanStatusTs = PalBbGetCurrentTime();
}
pCtx->data.slv.lastStatusSentTs = PalBbGetCurrentTime();
}
/* The procedure completes after receiving the indication. */
lctrSendConnMsg(pCtx, LCTR_CONN_LLCP_PROC_CMPL);
}
/*************************************************************************************************/
/*!
* \brief Update action for sca processing.

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -179,13 +179,16 @@ void lctrCalcSessionKey(lctrConnCtx_t *pCtx)
/* Use AES to transform LTK to session key using session key diversifier as seed. */
PalCryptoAesEcb(pCtx->ltk, pEnc->sk, pCtx->skd);
WSF_ASSERT(lctrInitCipherBlkHdlr);
memcpy(pEnc->iv, pCtx->iv, sizeof(pEnc->iv));
pEnc->dir = (pCtx->role == LL_ROLE_MASTER) ? 1 : 0; /* master = 1; slave = 0 */
pEnc->type = PAL_BB_TYPE_ACL;
pCtx->txPktCounter = 0;
pCtx->rxPktCounter = 0;
lctrInitCipherBlkHdlr(pEnc, LCTR_GET_CONN_HANDLE(pCtx), pEnc->dir);
if (lctrInitCipherBlkHdlr)
{
lctrInitCipherBlkHdlr(pEnc, LCTR_GET_CONN_HANDLE(pCtx), pEnc->dir);
}
}
/*************************************************************************************************/

View File

@ -4,7 +4,7 @@
*
* \brief Link layer controller connection power control state machine action routines.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -37,6 +37,27 @@
#include <string.h>
#include "lctr_int_pc.h"
/**************************************************************************************************
Constants
**************************************************************************************************/
#ifndef PC_ENABLE_DEBUG
/*! \brief Enable power control debug statements. */
#define PC_ENABLE_DEBUG FALSE
#endif
#if PC_ENABLE_DEBUG
#define LCTR_PC_DBG_TRACE_INFO0(m) LL_TRACE_INFO0(m)
#define LCTR_PC_DBG_TRACE_INFO1(m, v1) LL_TRACE_INFO1(m, v1)
#define LCTR_PC_DBG_TRACE_INFO2(m, v1, v2) LL_TRACE_INFO2(m, v1, v2)
#define LCTR_PC_DBG_TRACE_INFO3(m, v1, v2, v3) LL_TRACE_INFO3(m, v1, v2, v3)
#else
#define LCTR_PC_DBG_TRACE_INFO0(m)
#define LCTR_PC_DBG_TRACE_INFO1(m, v1)
#define LCTR_PC_DBG_TRACE_INFO2(m, v1, v2)
#define LCTR_PC_DBG_TRACE_INFO3(m, v1, v2, v3)
#endif
/*************************************************************************************************/
/*!
* \brief Return the power control index of a phy bit.
@ -83,7 +104,7 @@ int8_t lctrAttemptTxPowerChange(lctrConnCtx_t *pCtx, uint8_t phy, int8_t delta)
int8_t reqTxPower, curTxPower, newTxPower;
if (LCTR_GET_TXPOWER(pCtx, phy, option) == LL_PWR_CTRL_TXPOWER_UNAVAILABLE)
{
/* The current controller does not support this phy. */
/* The current controller does not support this PHY. */
return 0;
}
else if (LCTR_GET_TXPOWER(pCtx, phy, option) == LL_PWR_CTRL_TXPOWER_UNMANAGED)
@ -107,7 +128,7 @@ int8_t lctrAttemptTxPowerChange(lctrConnCtx_t *pCtx, uint8_t phy, int8_t delta)
newTxPower = PalRadioIncreasePower(reqTxPower, delta);
/* Update txPower. */
LL_TRACE_INFO3("lctrAttemptTxPowerChange: Power change -> handle=%d phy=%d txPow=%d", LCTR_GET_CONN_HANDLE(pCtx), phy + (option == BB_PHY_OPTIONS_BLE_S2) ? 1 : 0, newTxPower);
LCTR_PC_DBG_TRACE_INFO3("lctrAttemptTxPowerChange: Power change -> handle=%d phy=%d txPow=%d", LCTR_GET_CONN_HANDLE(pCtx), phy + (option == BB_PHY_OPTIONS_BLE_S2) ? 1 : 0, newTxPower);
LCTR_SET_TXPOWER(pCtx, phy + (((phy == LL_PHY_LE_CODED) && (option == BB_PHY_OPTIONS_BLE_S2)) ? 1 : 0), newTxPower);
/* Update current txPower if necessary. */
@ -204,7 +225,7 @@ void lctrStorePowerControlAction(lctrConnCtx_t *pCtx)
pCtx->delta = pLctrConnMsg->pwrCtrlReq.delta;
pCtx->reqPhy = pLctrConnMsg->pwrCtrlReq.phy;
LL_TRACE_INFO2("lctrStorePowerControlAction, PHY=%u delta=%u", pCtx->reqPhy, pCtx->delta);
LCTR_PC_DBG_TRACE_INFO2("lctrStorePowerControlAction, phy=%u delta=%u", pCtx->reqPhy, pCtx->delta);
/* If the power wasn't managed before, start managing it now. */
if (LCTR_GET_TXPOWER(pCtx, pCtx->reqPhy, BB_PHY_OPTIONS_BLE_S2) == LL_PWR_CTRL_TXPOWER_UNMANAGED)
@ -268,7 +289,7 @@ void lctrStorePeerPowerControlReq(lctrConnCtx_t *pCtx)
(pCtx->bleData.chan.rxPhy == phyIdx) &&
(pCtx->peerTxPower != pld.txPower))
{
lctrNotifyPowerReportInd(pCtx, LL_POWER_REPORT_REASON_REMOTE, phyIdx, pld.txPower,
lctrNotifyPowerReportInd(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_REMOTE, phyIdx, pld.txPower,
lctrGetPowerLimits(pld.txPower),
pld.txPower - pCtx->peerTxPower);
}
@ -281,11 +302,11 @@ void lctrStorePeerPowerControlReq(lctrConnCtx_t *pCtx)
if ((pCtx->peerTxPower == LL_PWR_CTRL_TXPOWER_UNAVAILABLE) ||
(pCtx->peerTxPower == LL_PWR_CTRL_TXPOWER_UNMANAGED))
{
LL_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower unmanaged or unavailable. Phy=%d", pld.phy);
LCTR_PC_DBG_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower unmanaged or unavailable, phy=%d", pld.phy);
}
else
{
LL_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower=%d", pCtx->peerTxPower);
LCTR_PC_DBG_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower=%d", pCtx->peerTxPower);
}
}
@ -315,7 +336,7 @@ void lctrStorePeerPowerControlReq(lctrConnCtx_t *pCtx)
}
int8_t newTxPower = LCTR_GET_TXPOWER(pCtx, phy, option);
lctrNotifyPowerReportInd(pCtx, LL_POWER_REPORT_REASON_LOCAL, phyIdx, newTxPower,
lctrNotifyPowerReportInd(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_LOCAL, phyIdx, newTxPower,
lctrGetPowerLimits(newTxPower),
pCtx->delta);
}
@ -338,7 +359,7 @@ void lctrSendPeerPowerControlRsp(lctrConnCtx_t *pCtx)
}
else
{
LL_TRACE_WARN0("lctrSendPeerPowerControlRsp: Peer sent invalid parameters for power control request.");
LL_TRACE_WARN0("lctrSendPeerPowerControlRsp: peer sent invalid parameters for power control request");
lctrSendRejectInd(pCtx, pCtx->reqErrCode, TRUE);
pCtx->reqErrCode = LL_SUCCESS;
}
@ -359,7 +380,7 @@ void lctrStorePeerPowerControlRsp(lctrConnCtx_t *pCtx)
if ((pCtx->powerRptRemote) &&
(pCtx->peerTxPower != pld.txPower))
{
lctrNotifyPowerReportInd(pCtx, LL_POWER_REPORT_REASON_REMOTE, pCtx->reqPhy, pld.txPower,
lctrNotifyPowerReportInd(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_REMOTE, pCtx->reqPhy, pld.txPower,
pld.limits,
pld.txPower - pCtx->peerTxPower);
}
@ -374,18 +395,18 @@ void lctrStorePeerPowerControlRsp(lctrConnCtx_t *pCtx)
if ((pCtx->peerTxPower == LL_PWR_CTRL_TXPOWER_UNAVAILABLE) ||
(pCtx->peerTxPower == LL_PWR_CTRL_TXPOWER_UNMANAGED))
{
LL_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower unmanaged or unavailable. Phy=%d", pCtx->reqPhy);
LCTR_PC_DBG_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower unmanaged or unavailable, phy=%d", pCtx->reqPhy);
}
else
{
LL_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower=%d", pCtx->peerTxPower);
LCTR_PC_DBG_TRACE_INFO1("lctrStorePeerPowerControlReq: txPower=%d", pCtx->peerTxPower);
if (pCtx->controllerInitRead)
{
pCtx->controllerInitRead = FALSE;
}
if (pCtx->monitoringState == LCTR_PC_MONITOR_PATH_LOSS)
if (pCtx->powerMonitorScheme == LCTR_PC_MONITOR_PATH_LOSS)
{
if (pCtx->pclMonitorParam.pathLoss.initialPathLossRead)
{
@ -400,7 +421,7 @@ void lctrStorePeerPowerControlRsp(lctrConnCtx_t *pCtx)
/* Store delta for reporting. */
pCtx->delta = pld.delta;
LL_TRACE_INFO3("lctrStorePeerPowerControlRsp: peerTxPower=%d, peerPwrLimits=%d, peerApr=%d", pld.txPower, pld.limits, pld.apr);
LCTR_PC_DBG_TRACE_INFO3("lctrStorePeerPowerControlRsp: peerTxPower=%d, peerPwrLimits=%d, peerApr=%d", pld.txPower, pld.limits, pld.apr);
}
/*************************************************************************************************/
@ -408,6 +429,7 @@ void lctrStorePeerPowerControlRsp(lctrConnCtx_t *pCtx)
* \brief Notify host of power report indication.
*
* \param pCtx Connection context.
* \param status Status code.
* \param reason Reason this indication was sent.
* \param phy PHY.
* \param txPower Current txPower.
@ -415,7 +437,7 @@ void lctrStorePeerPowerControlRsp(lctrConnCtx_t *pCtx)
* \param delta Delta from last txPower.
*/
/*************************************************************************************************/
void lctrNotifyPowerReportInd(lctrConnCtx_t *pCtx, uint8_t reason, uint8_t phy, int8_t txPower, uint8_t limits, int8_t delta)
void lctrNotifyPowerReportInd(lctrConnCtx_t *pCtx, uint8_t status, uint8_t reason, uint8_t phy, int8_t txPower, uint8_t limits, int8_t delta)
{
const uint16_t handle = LCTR_GET_CONN_HANDLE(pCtx);
@ -425,7 +447,7 @@ void lctrNotifyPowerReportInd(lctrConnCtx_t *pCtx, uint8_t reason, uint8_t phy,
{
.param = handle,
.event = LL_TX_POWER_REPORTING_IND,
.status = LL_SUCCESS
.status = status
},
.status = LL_SUCCESS,
@ -437,7 +459,15 @@ void lctrNotifyPowerReportInd(lctrConnCtx_t *pCtx, uint8_t reason, uint8_t phy,
.delta = delta
};
LL_TRACE_INFO2("### LlEvent ### lctrNotifyPowerReportInd , handle=%u, reason=%d, status=LL_SUCCESS", handle, reason);
if (status == LL_SUCCESS)
{
LL_TRACE_INFO2("### LlEvent ### lctrNotifyPowerReportInd, handle=%u, reason=%d, status=LL_SUCCESS", handle, reason);
}
else
{
LL_TRACE_INFO1("### LlEvent ### lctrNotifyPowerReportInd, Power procedure rejected, status=%d", status);
}
LmgrSendEvent((LlEvt_t *)&evt);
}
@ -463,7 +493,7 @@ static void lctrSendPowerChangePdu(lctrConnCtx_t *pCtx, uint8_t opcode, uint8_t
uint8_t *pPdu;
if ((pPdu = lctrTxCtrlPduAlloc(LL_PWR_CHNG_IND_LEN)) != NULL)
if ((pPdu = lctrTxCtrlPduAlloc(LL_PWR_CHANGE_IND_LEN)) != NULL)
{
bool_t seperateIndNeeded = FALSE;
uint8_t *pBuf = pPdu;
@ -521,7 +551,7 @@ static void lctrSendPowerChangePdu(lctrConnCtx_t *pCtx, uint8_t opcode, uint8_t
/*************************************************************************************************/
void lctrSendPowerChangeInd(lctrConnCtx_t *pCtx, uint8_t phy, int8_t delta, int8_t txPower, bool_t phyChange)
{
lctrSendPowerChangePdu(pCtx, LL_PDU_PWR_CHNG_IND, phy, delta, txPower, phyChange);
lctrSendPowerChangePdu(pCtx, LL_PDU_PWR_CHANGE_IND, phy, delta, txPower, phyChange);
}
/*************************************************************************************************/
@ -534,16 +564,15 @@ void lctrSendPowerChangeInd(lctrConnCtx_t *pCtx, uint8_t phy, int8_t delta, int8
void lctrStorePeerPowerInd(lctrConnCtx_t *pCtx)
{
lctrPwrChngInd_t * pPdu = &lctrDataPdu.pld.pwrChngInd;
LL_TRACE_INFO3("lctrStorePeerPowerInd: Phy=%d Delta=%d txPower=%d", pPdu->phy, pPdu->delta, pPdu->txPower);
LCTR_PC_DBG_TRACE_INFO3("lctrStorePeerPowerInd: phy=%d delta=%d txPower=%d", pPdu->phy, pPdu->delta, pPdu->txPower);
if (pPdu->phy & (1 << (pCtx->bleData.chan.rxPhy - 1)))
{
if ((pCtx->peerTxPower != pPdu->txPower) &&
(pCtx->powerRptRemote))
if (pCtx->powerRptRemote)
{
lctrNotifyPowerReportInd(pCtx, LL_POWER_REPORT_REASON_REMOTE, pCtx->bleData.chan.rxPhy, pPdu->txPower,
pPdu->limits,
pPdu->txPower - pCtx->peerTxPower);
lctrNotifyPowerReportInd(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_REMOTE,
pCtx->bleData.chan.rxPhy, pPdu->txPower, pPdu->limits,
pPdu->txPower - pCtx->peerTxPower);
}
if (pPdu->phy == pCtx->bleData.chan.rxPhy)
@ -553,11 +582,11 @@ void lctrStorePeerPowerInd(lctrConnCtx_t *pCtx)
if ((pCtx->peerTxPower == LL_PWR_CTRL_TXPOWER_UNAVAILABLE) ||
(pCtx->peerTxPower == LL_PWR_CTRL_TXPOWER_UNMANAGED))
{
LL_TRACE_INFO1("lctrStorePeerPowerInd: txPower unmanaged or unavailable. Phy=%d", pPdu->phy);
LCTR_PC_DBG_TRACE_INFO1("lctrStorePeerPowerInd: txPower unmanaged or unavailable, phy=%d", pPdu->phy);
}
else
{
LL_TRACE_INFO1("lctrStorePeerPowerInd: txPower=%d", pCtx->peerTxPower);
LCTR_PC_DBG_TRACE_INFO1("lctrStorePeerPowerInd: txPower=%d", pCtx->peerTxPower);
}
}
}
@ -578,62 +607,53 @@ void lctrSendPeerPowerRsp(lctrConnCtx_t *pCtx)
/*************************************************************************************************/
/*!
* \brief Power monitoring action function
* \brief Service connection power monitor.
*
* \param pCtx Connection context.
*/
/*************************************************************************************************/
void lctrAutoPowerMonitorAct(lctrConnCtx_t *pCtx)
void lctrConnServicePowerMonitor(lctrConnCtx_t *pCtx)
{
if (!(pCtx->usedFeatSet & LL_FEAT_POWER_CONTROL_REQUEST))
if (!(pCtx->usedFeatSet & LL_FEAT_POWER_CONTROL_REQUEST) ||
lmgrGetOpFlag(LL_OP_MODE_FLAG_DIS_POWER_MONITOR))
{
pCtx->monitoringState = LCTR_PC_MONITOR_DISABLED;
return;
}
if (lmgrCb.opModeFlags & LL_OP_MODE_DISABLE_POWER_MONITOR)
{
return;
}
int8_t sendReqDelta = 0;
if ((pCtx->rssi < pCtx->pclMonitorParam.autoMonitor.lowThreshold) ||
(pCtx->lastRxStatus != BB_STATUS_SUCCESS))
{
pCtx->pclMonitorParam.autoMonitor.curTimeSpent++;
/* Restore the sign after finding the absolute value average RSSI. */
lctrRssiAddAveragePoint(&pCtx->pclMonitorParam.autoMonitor.rssiRunAvg,
-((int8_t) (pCtx->pclMonitorParam.autoMonitor.accumulatedRssi / pCtx->pclMonitorParam.autoMonitor.totalAccumulatedRssi)));
pCtx->pclMonitorParam.autoMonitor.accumulatedRssi = 0;
pCtx->pclMonitorParam.autoMonitor.totalAccumulatedRssi = 0;
if (pCtx->pclMonitorParam.autoMonitor.curTimeSpent >= pCtx->pclMonitorParam.autoMonitor.minTimeSpent)
{
if (!(pCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MAX_BIT))
{
LL_TRACE_INFO1("RSSI too low, requesting increase in power. phy=%u", pCtx->bleData.chan.rxPhy);
sendReqDelta = pCtx->pclMonitorParam.autoMonitor.requestVal;
}
pCtx->pclMonitorParam.autoMonitor.curTimeSpent = 0;
}
}
else if (pCtx->rssi > pCtx->pclMonitorParam.autoMonitor.highThreshold)
if (pCtx->pclMonitorParam.autoMonitor.rssiRunAvg.avgCount >= LL_PC_TBL_LEN)
{
pCtx->pclMonitorParam.autoMonitor.curTimeSpent++;
int8_t averageRunning = lctrRssiGetAverage(&pCtx->pclMonitorParam.autoMonitor.rssiRunAvg);
if (pCtx->pclMonitorParam.autoMonitor.curTimeSpent >= pCtx->pclMonitorParam.autoMonitor.minTimeSpent)
if ((averageRunning > pCtx->pclMonitorParam.autoMonitor.highThreshold) &&
(!(pCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MIN_BIT)))
{
if (!(pCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MIN_BIT))
{
LL_TRACE_INFO1("RSSI too high, requesting decrease in power. phy=%u", pCtx->bleData.chan.rxPhy);
sendReqDelta = -(pCtx->pclMonitorParam.autoMonitor.requestVal);
}
pCtx->pclMonitorParam.autoMonitor.curTimeSpent = 0;
sendReqDelta = -(pCtx->pclMonitorParam.autoMonitor.requestVal);
}
else if ((averageRunning < pCtx->pclMonitorParam.autoMonitor.lowThreshold) &&
!(pCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MAX_BIT))
{
sendReqDelta = pCtx->pclMonitorParam.autoMonitor.requestVal;
}
}
else
{
pCtx->pclMonitorParam.autoMonitor.curTimeSpent = 0;
}
if (sendReqDelta != 0)
{
if ((pCtx->llcpActiveProc == LCTR_PROC_PWR_CTRL) ||
(pCtx->llcpPendMask & (1 << LCTR_PROC_PWR_CTRL)))
{
LL_TRACE_WARN0("Power control LLCP already pending -- try increasing service interval");
return;
}
uint8_t reqPhy = pCtx->bleData.chan.rxPhy + (((pCtx->bleData.chan.rxPhy == BB_PHY_BLE_CODED) && (pCtx->bleData.chan.initTxPhyOptions == BB_PHY_OPTIONS_BLE_S2)) ? 1 : 0);
lctrMsgPwrCtrlReq_t *pMsg;
@ -646,5 +666,7 @@ void lctrAutoPowerMonitorAct(lctrConnCtx_t *pCtx)
pMsg->phy = reqPhy;
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
}
pCtx->pclMonitorParam.autoMonitor.rssiRunAvg.avgCount = 0;
}
}

View File

@ -186,8 +186,9 @@ void lctrSendPhyUpdateIndPdu(lctrConnCtx_t *pCtx, uint8_t txPhys, uint8_t rxPhys
else
#endif
{
ceOffset = LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency; /* ensure slave will listen this packet */
ceOffset = ((LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency) * /* ensure slave will listen to this packet */
pCtx->ecu.srFactor); /* include subrating factor */
}
if (txPhys || rxPhys)

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -117,6 +117,15 @@ extern "C" {
/*! \brief Change supervision timeout value to us. */
#define LCTR_SUP_TIMEOUT_VAL_TO_US(x) (x * 10000)
/*! \brief Array size of running average arrays, derived from LL_PC_TBL_LEN. */
#define LL_PC_TBL_LEN (1 << LL_PC_TBL_POW)
/*! \brief Calculate microsecond format from channel reporting parameter (200 millisecond ticks). */
#define LCTR_CH_RPT_IND_US(x) ((((uint64_t) x) * 200) * 1000)
/*! \brief Calculate microsecond format from channel reporting parameter (200 millisecond ticks). */
#define LCTR_CH_RPT_IND_US(x) ((((uint64_t) x) * 200) * 1000)
/**************************************************************************************************
Data Types
**************************************************************************************************/
@ -136,6 +145,15 @@ typedef void (*LctrRmCback_t)(uint32_t rsvnOffs[], uint32_t refTime);
/*! \brief Channel class update handler call signature. */
typedef uint8_t (*lctrChClassHdlr_t)(uint64_t chanMap);
/*! \brief RSSI running average data type. */
typedef struct
{
int8_t averageRssi[LL_PC_TBL_LEN];
/*!< Running average RSSI. */
uint8_t rssiIdx; /*!< Running average RSSI index. */
uint8_t avgCount; /*!< Count of average entries since last reset. */
} lctrRssiRunAvg_t;
/**************************************************************************************************
Globals
**************************************************************************************************/
@ -164,6 +182,10 @@ uint16_t lctrCalcTotalAccuracy(uint8_t mstScaIdx);
uint32_t lctrComputeCrcInit(void);
uint32_t lctrCalcWindowWideningUsec(uint32_t unsyncTimeUsec, uint32_t caPpm);
/* RSSI Averaging. */
int8_t lctrRssiGetAverage(lctrRssiRunAvg_t *pAvg);
void lctrRssiAddAveragePoint(lctrRssiRunAvg_t *pAvg, int8_t value);
/* Host events */
void lctrNotifyHostHwErrInd(uint8_t code);
void lctrNotifyHostConnectInd(uint16_t handle, uint8_t role, lctrConnInd_t *pConnInd,

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -191,6 +191,7 @@ typedef struct
BbBleData_t scanBleData; /*!< BLE BB operation data. */
BbOpDesc_t auxScanBod; /*!< Auxiliary scan BOD. */
BbBleData_t auxBleData; /*!< Auxiliary BLE BB operation data. */
bool_t scheduleAuxAsap; /*!< Signal BB to program Aux Scan. */
} lctrExtScanCtx_t;
/*! \brief Extended scanning control block. */
@ -234,6 +235,7 @@ typedef struct
bool_t cancelByHost; /*!< Cancel command was issued from host. */
bool_t firstPerAdvRcv; /*!< True if first periodic advertising packet is received. */
bool_t repDisabled; /*!< Reporting disabled. */
bool_t dupFilterEnable; /*!< Filtering by ADI field enabled. */
bool_t bodAborted; /*!< Tue if periodic scan BOD was aborted. */
uint8_t createDispId; /*!< Dispatcher id to tell if periodic sync was created or transferred. */
lctrTermHdlr_t termCback; /*!< Termination callback. */
@ -257,13 +259,14 @@ typedef struct
uint32_t lastAnchorPointUsec;/*!< Last anchor point in microseconds. */
uint16_t lastActiveEvent; /*!< Last active event counter. */
uint16_t initEventCounter; /*!< Initial event counter received from sync_info. */
uint16_t lastDid; /*!< Last ADI received, if applicable. */
/* ACAD */
lctrAcadParam_t acadParams[LCTR_ACAD_NUM_ID]; /*!< ACAD control block array. */
/* Local periodic scanning parameters */
uint16_t skip; /*!< Skip. */
uint16_t syncTimeOutMs; /*!< Synchronization Timeout in Milliseconds. */
uint32_t syncTimeOutMs; /*!< Synchronization Timeout in Milliseconds. */
/* Filtering parameters */
bbBlePerPduFiltParams_t filtParam; /*!< Periodic scan filter parameters. */
@ -356,12 +359,14 @@ void lctrMstPerScanTransferOpCommit(uint16_t connHandle);
bool_t lctrMstDiscoverRxExtAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf);
void lctrMstDiscoverRxExtAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf);
bool_t lctrMstDiscoverRxAuxAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf);
void lctrMstDiscoverRxAuxAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf);
bool_t lctrMstDiscoverRxAuxScanRspHandler(BbOpDesc_t *pOp, const uint8_t *pRspBuf);
uint32_t lctrMstDiscoverRxAuxChainHandler(BbOpDesc_t *pOp, const uint8_t *pChainBuf);
bool_t lctrMstDiscoverRxAuxChainPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pChainBuf);
bool_t lctrMstDiscoverRxLegacyAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf);
bool_t lctrMstDiscoverTxLegacyScanReqHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf);
bool_t lctrMstDiscoverRxLegacyScanRspHandler(BbOpDesc_t *pOp, const uint8_t *pRspBuf);
bool_t lctrMstLinkAuxOffsetScanSetup(BbOpDesc_t *pBod, uint32_t refTime, uint32_t remScanDur);
/* ISR: Discovery BOD handlers */
void lctrMstExtDiscoverEndOp(BbOpDesc_t *pOp);
void lctrMstExtDiscoverAbortOp(BbOpDesc_t *pOp);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2017 ARM Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -50,7 +50,6 @@ enum
};
/*! \brief Common extended advertising PDU types. */
enum
{
LCTR_PDU_ADV_EXT_IND,

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -43,7 +43,7 @@ extern "C" {
**************************************************************************************************/
/*! \brief Maximum value of the AuxPtr offset field. */
#define LCTR_AUX_PTR_MAX_OFFSET 0x3FFF
#define LCTR_AUX_PTR_MAX_OFFSET 0x1FFF
/*! \brief Number of shifted bytes for Used PHY field from the AUX Offset. */
#define LCTR_AUX_OFFS_USED_PHY_SHIFT 13
@ -138,6 +138,9 @@ typedef struct
bool_t shutdown; /*!< Client initiated shutdown flag. */
uint32_t perAdvInterUsec; /*!< Periodic advertising interval in microseconds. */
bool_t enableAdi; /*!< Enable ADI field in Periodic Advertising. */
uint16_t advDID; /*!< Advertising Data ID. */
uint32_t advInterMinUsec; /*!< Periodic Advertising Interval Minimum in microseconds. */
uint32_t advInterMaxUsec; /*!< Periodic Advertising Interval Maximum in BB ticks. */
uint16_t advEventProp; /*!< Periodic Advertising Event Properties. */
@ -238,7 +241,6 @@ typedef struct
/* BB/ISR context */
bool_t shutdown; /*!< Client initiated shutdown flag. */
uint8_t bodTermCnt; /*!< Number of BOD terminated. */
BbOpDesc_t advBod; /*!< Advertising BOD. */
BbBleData_t bleData; /*!< BLE data. */
BbOpDesc_t auxAdvBod; /*!< Auxiliary advertising BOD. */

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -66,22 +66,23 @@ typedef struct
struct
{
/* Data */
wsfQueue_t txDataQ; /*!< Transmit ISO queue. */
uint8_t numTxSduComp; /*!< Number of Tx completed SDUs. */
lctrIsoalTxCtx_t isoalTxCtx; /*!< ISOAL transmit context. */
} slv; /*!< BIS slave specific data. */
wsfQueue_t txDataQ; /*!< Transmit ISO queue. */
uint8_t numTxSduComp; /*!< Number of Tx completed SDUs. */
lctrIsoalTxCtx_t isoalTxCtx; /*!< ISOAL transmit context. */
lctrInDataPathCtx_t dataPathInCtx; /*!< Datapath input context. */
} slv; /*!< BIS slave specific data. */
struct
{
/* Data */
wsfQueue_t rxDataQ; /*!< Receive ISO Data PDU pending queue. */
wsfQueue_t rxIsoSduQ; /*!< Receive ISO SDU PDU pending queue. */
lctrIsoalRxCtx_t isoalRxCtx; /*!< ISOAL Receive context. */
wsfQueue_t rxDataQ; /*!< Receive ISO Data PDU pending queue. */
lctrIsoalRxCtx_t isoalRxCtx; /*!< ISOAL receive context. */
lctrOutDataPathCtx_t dataPathOutCtx; /*!< Output data path context. */
/* ISO test */
LlIsoTestCtrs_t stats; /*!< Rx statistics. */
} mst; /*!< BIS master specific data. */
} roleData; /*!< Role specific data. */
LlIsoTestCtrs_t stats; /*!< Rx statistics. */
} mst; /*!< BIS master specific data. */
} roleData; /*!< Role specific data. */
/* ISO test */
struct
@ -93,22 +94,21 @@ typedef struct
{
struct
{
uint32_t payloadCtr; /*!< Payload counter for framed transmissions. */
} framed; /*!< Framed context. */
uint32_t payloadCtr; /*!< Payload counter for framed transmissions. */
} framed;
struct
{
uint8_t payloadOffset; /*!< Payload offset for unframed transmissions. */
} unframed; /*!< Unframed context. */
} util; /*!< Role-based utility variables. */
LlIsoPldType_t pldType:8; /*!< Test payload type. */
} test; /*!< ISO Test data. */
uint8_t burstIdx; /*!< BN Index for unframed transmissions. */
} unframed;
} util;
LlIsoPldType_t pldType:8; /*!< Test payload type. */
} test;
/* BB */
lmgrChanParam_t chSelInfo; /*!< Channel selection state. */
PalBbBleChan_t chan; /*!< Channelization parameters. */
/* Data */
LlIsoDataPath_t path:8; /*!< Input audio data path. */
LlIsoLlid_t lastLlid:8; /*!< Last LLID. */
} lctrBisCtx_t;
@ -164,19 +164,26 @@ typedef struct lctrBigCtx_tag
uint8_t bisIdx[LL_MAX_BIS]; /*!< List of indices of BISes. */
/* Sync timeout */
uint32_t bigSyncTimeoutMs; /*!< Synchronization timeout in microseconds. */
wsfTimer_t bigSyncTmr; /*!< Synchronization timeout timer. */
/* Event state */
uint16_t totalAcc; /*!< Total clock accuracy. */
uint16_t extraWwUsec; /*!< Extra window widening time in microseconds. */
uint32_t rxSyncTime; /*!< Last received BIG anchor point. */
uint32_t anchorPoint; /*!< BIG anchor point. */
uint32_t bigSyncTimeoutMs; /*!< Synchronization timeout in microseconds. */
/* Encryption */
uint8_t bcstCode[LL_BC_LEN]; /*!< Broadcast Code. */
} mst; /*!< BIG master specific data. */
} roleData; /*!< Role-specific data. */
uint8_t bcstCode[LL_BC_LEN]; /*!< Broadcast Code. Array address should be word-aligned. */
/* Event state */
uint16_t totalAcc; /*!< Total clock accuracy. */
uint16_t initWwUsec; /*!< Initial synchronization window widening time in microseconds. */
uint32_t rxSyncTime; /*!< Last received BIG anchor point. */
uint32_t anchorPoint; /*!< BIG anchor point. */
lctrBisCtx_t *pFirstBisCtx; /*!< First BIS context (ISR optimization to reduce lookups). */
lctrBisCtx_t *pSecondBisCtx; /*!< Second BIS context (ISR optimization to reduce lookups). */
uint32_t firstBisOffsUsec; /*!< First BIS offset from the anchor point in microseconds. */
uint8_t firstBisEvtIdx; /*!< First BIS index. */
/* Reception status. */
bool_t lastPduMissed; /*!< Rx failure on last PDU. */
} mst; /*!< BIG master specific data. */
} roleData; /*!< Role-specific data. */
/* Control */
struct
@ -210,9 +217,6 @@ typedef struct lctrBigCtx_tag
bool_t encrypt; /*!< Encryption enable for BIS. */
uint8_t giv[LL_GIV_LEN]; /*!< GIV. */
uint8_t gskd[LL_GSKD_LEN]; /*!< GSKD. */
/* Reception status. */
bool_t lastPduMissed; /*!< Rx failure on last PDU. */
} lctrBigCtx_t;
/*! \brief ISR subevent context. */
@ -245,7 +249,6 @@ bool_t lctrIsBigSynchronizing(void);
/* BIS Context */
lctrBisCtx_t *lctrAllocBisCtx(lctrBigCtx_t *pBigCtx);
void lctrCleanupBisCtx(lctrBisCtx_t *pBisCtx);
void lctrFreeBisCtx(lctrBisCtx_t *pBisCtx);
lctrBisCtx_t *lctrFindBisByHandle(uint16_t bisHandle);
uint8_t lctrGetNumAvailBisCtx(void);
@ -266,11 +269,11 @@ void lctrBigTxCtrlQueuePopCleanup(lctrBigCtx_t *pBigCtx);
/* BIS Rx Data Path */
uint8_t *lctrBisRxIsoSduDeq(lctrBisCtx_t *pBisCtx);
void lctrBisRxIsoSduEnq(lctrBisCtx_t *pBisCtx, uint8_t *pBuf);
uint8_t *lctrBisRxIsoDataPduAlloc(void);
void lctrBisRxIsoDataPduFree(uint8_t *pPdu);
void lctrBisEnqueueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t *pRxBuf, uint64_t evtCtr);
uint8_t *lctrBisDequeueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t *pEvtCtrLsb);
void lctrBisEnqueueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t *pRxBuf, uint8_t burstIdx);
uint8_t *lctrBisDequeueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t burstIdx);
uint8_t *lctrBisDequeueRxDataPduTop(lctrBisCtx_t *pBisCtx);
/* ISO Test mode */
uint8_t lctrBisTxTest(lctrBisCtx_t *pBisCtx, uint8_t pldType);
@ -281,9 +284,8 @@ uint8_t LctrBisReadTestCounters(lctrBisCtx_t *pBisCtx, LlIsoTestCtrs_t *pStats);
void lctrBisDefaults(void);
void lctrNotifyIsoTxComplete(lctrBigCtx_t *pBigCtx);
void lctrBisCalcGroupSessionKey(const uint8_t *pGSKD, const uint8_t *pBC, uint8_t *pGSK);
uint8_t lctrBisSetDataPath(lctrBisCtx_t *pBisCtx, LlIsoDataPathDir_t dpDir, LlIsoDataPath_t dpId);
bool_t lctrSlvBisCalcNextIdxSequential(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts);
bool_t lctrSlvBisCalcNextIdxInterleaved(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts);
bool_t lctrBisCalcNextIdxSequential(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts);
bool_t lctrBisCalcNextIdxInterleaved(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts);
#ifdef __cplusplus
};

View File

@ -4,7 +4,7 @@
*
* \brief Internal link layer controller isochronous master interface file.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -90,6 +90,7 @@ void lctrMstSetupBigChannel(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo);
/* ISR: BOD handlers */
void lctrMstBisRxCompletion(BbOpDesc_t *pBod, uint8_t *pBuf, uint8_t status);
void lctrMstBigBeginOp(BbOpDesc_t *pOp);
void lctrMstBigAbortOp(BbOpDesc_t *pOp);
void lctrMstBigEndOp(BbOpDesc_t *pOp);
#ifdef __cplusplus

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -160,6 +160,8 @@ typedef struct
uint32_t cigSyncDelayUsec; /*!< CIG synchronous delay in microsecond. */
bool_t cisDone; /*!< CIS transfer is done, no more subevent for the CIS. Used for interleaved CIS only. */
bool_t isClosing; /*!< TRUE if the context is closing. */
bool_t termPend; /*!< The CIS has pended a termination. */
bool_t hostInitTerm; /*!< The host has initiated the termination. */
uint8_t subEvtCounter; /*!< Sub event counter. */
bool_t isTxDone; /*!< TRUE if all the Tx are done, start sending NULL packet. */
@ -172,9 +174,10 @@ typedef struct
uint64_t rxPktCounter; /*!< Receive packet counter. */
/* Buffers */
uint8_t dataHdrBuf[LL_DATA_HDR_LEN]; /*!< Data header buffer */
uint8_t dataBuf[10]; /*!< Data header buffer */
uint8_t dataHdrBuf[LL_DATA_HDR_LEN]; /*!< Data header buffer. */
uint8_t dataBuf[10]; /*!< Data header buffer. */
uint16_t dataCounter; /*!< Data counter. */
uint8_t dataSn; /*!< Data sequence number. */
/* LLCP */
bool_t isCisReqPend; /*!< True if CIS_REQ is sent and response is not received yet. */
@ -196,6 +199,7 @@ typedef struct
uint32_t firstRxStartTsUsec; /*!< Timestamp of the first received frame regardless of CRC error in microseconds. */
uint8_t consCrcFailed; /*!< Number of consecutive CRC failures. */
uint8_t rxStatus; /*!< Rx status. */
bool_t lastTxNull; /*!< Last packet sent was a null. */
} slv; /*!< Slave connection specific data. */
struct
@ -220,7 +224,6 @@ typedef struct
uint8_t numTxComp; /*!< Number of completed Tx buffers. */
uint32_t delayUsec; /*!< Time between the start of subevent to the start of next subevent in microsecond.
Same as subEvtInter for sequential scheme, different for interleaved scheme. */
uint8_t *pRxBuf; /*!< Pointer to the RX buffer later to be cleaned. */
bool_t validRx; /*!< TRUE if the RX buffer is valid and shall be processed. */
bool_t txPduIsAcked; /*!< TRUE if the TX PDU is acked. */
bool_t txBufPendAck; /*!< A transmit buffer is pending acknowledgement. */
@ -410,6 +413,7 @@ bool_t lctrCisIsListEmpty(lctrCisList_t *pList);
uint8_t lctrCisGetListCount(lctrCisList_t *pList);
lctrCisCtx_t * lctrCisGetHeadCis(lctrCisList_t *pList);
bool_t lctrCisIsHeadCis(lctrCisList_t *pList, lctrCisCtx_t *pCisCtx);
bool_t lctrCisIsTailCis(lctrCisList_t *pList, lctrCisCtx_t *pCisCtx);
lctrCisCtx_t * lctrCisGetNextCis(lctrCisList_t *pList, lctrCisCtx_t *pCurCis);
lctrCisCtx_t * lctrCisGetPreCis(lctrCisList_t *pList, lctrCisCtx_t *pCurCis);
bool_t lctrCisAreCisCtxDone(lctrCisList_t *pList);
@ -466,7 +470,7 @@ void lctrCisTxQueuePopCleanup(lctrCisCtx_t *pCisCtx);
uint8_t lctrCisTxQueueClear(lctrCisCtx_t *pCisCtx);
/* CIS Rx data path */
uint8_t *lctrCisRxPduAlloc(uint16_t maxRxLen);
uint8_t *lctrCisRxPduAlloc();
void lctrCisRxPduFree(uint8_t *pBuf);
void lctrCisRxEnq(uint8_t *pBuf, uint16_t eventCounter, uint16_t cisHandle);
uint8_t *lctrCisRxDeq(uint16_t *pConnHandle);
@ -487,7 +491,8 @@ void lctrCisTxPduAck(lctrCisCtx_t *pCisCtx);
void lctrCisProcessTxAckCleanup(lctrCisCtx_t *pCisCtx);
void lctrCisRxPostProcessing(lctrCisCtx_t *pCisCtx, uint8_t *pRxBuf);
void lctrCisTxTestPayloadHandler(lctrCisCtx_t * pCisCtx);
void lctrCisPowerMonitorCheckRssi(int8_t rssi, uint8_t status, uint8_t phy, lctrConnCtx_t *pConnCtx);
void lctrCisCheckUnframedFlush(lctrCisCtx_t *pCisCtx);
void lctrCisServicePowerMonitor(lctrConnCtx_t *pConnCtx);
/* Scheduler */
BbOpDesc_t *lctrCisResolveConflict(BbOpDesc_t *pNewOp, BbOpDesc_t *pExistOp);
@ -506,7 +511,7 @@ static inline void lctrCisIncPacketCounterTx(lctrCisCtx_t *pCisCtx)
/* Set the new packet counter for inline encryption. */
if (lctrSetEncryptPktCountHdlr)
{
lctrSetEncryptPktCountHdlr(&pCisCtx->bleData.chan.enc, pCisCtx->txPktCounter);
lctrSetEncryptPktCountHdlr(pCisCtx->txPktCounter);
}
}
@ -520,11 +525,47 @@ static inline void lctrCisIncPacketCounterTx(lctrCisCtx_t *pCisCtx)
static inline void lctrCisIncPacketCounterRx(lctrCisCtx_t *pCisCtx)
{
pCisCtx->rxPktCounter++;
}
/* Set the new packet counter for inline encryption. */
/*************************************************************************************************/
/*!
* \brief Set the CIS Tx packet counter value in the BB.
*
* \param pCisCtx Connection context.
*/
/*************************************************************************************************/
static inline void lctrSetBbCisPacketCounterTx(lctrCisCtx_t *pCisCtx)
{
if (lctrSetEncryptPktCountHdlr)
{
PalCryptoEnc_t * const pEnc = &pCisCtx->bleData.chan.enc;
if (!pEnc->enaEncrypt)
{
return;
}
lctrSetEncryptPktCountHdlr(pCisCtx->txPktCounter);
}
}
/*************************************************************************************************/
/*!
* \brief Set the CIS Rx packet counter value in the BB.
*
* \param pCisCtx Connection context.
*/
/*************************************************************************************************/
static inline void lctrSetBbCisPacketCounterRx(lctrCisCtx_t *pCisCtx)
{
if (lctrSetDecryptPktCountHdlr)
{
/* lctrSetDecryptPktCountHdlr(&pCisCtx->bleData.chan.enc, pCisCtx->rxPktCounter); */ /* Not necessary. */
PalCryptoEnc_t * const pEnc = &pCisCtx->bleData.chan.enc;
if (!pEnc->enaDecrypt)
{
return;
}
lctrSetDecryptPktCountHdlr(pCisCtx->rxPktCounter);
}
}

View File

@ -88,6 +88,7 @@ void lctrMstCisCigRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
/* ISR: BOD handlers */
uint32_t lctrMstCisCheckContOp(BbOpDesc_t *pOp, bool_t *pNewCisCtx);
uint32_t lctrMstCisCheckContOpPostCback(BbOpDesc_t *pOp, bool_t *pNewCisCtx);
void lctrMstCisCigBeginOp(BbOpDesc_t *pOp);
void lctrMstCisCigContOp(BbOpDesc_t *pOp);
void lctrMstCisCigPostSubEvt(BbOpDesc_t *pOp, uint8_t status);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -83,6 +83,7 @@ void lctrSlvCisCigBeginOp(BbOpDesc_t *pOp);
void lctrSlvCisCigContOp(BbOpDesc_t *pOp);
void lctrSlvCisCigPostSubEvt(BbOpDesc_t *pOp, uint8_t status);
uint32_t lctrSlvCisCheckContOp(BbOpDesc_t *pOp, bool_t *pNewCisCtx);
uint32_t lctrSlvCisCheckContOpPostCback(BbOpDesc_t *pOp, bool_t *pNewCisCtx);
void lctrSlvCisCigEndOp(BbOpDesc_t *pOp);
void lctrSlvCisCigCleanupOp(BbOpDesc_t *pOp);
void lctrSlvCisCigAbortOp(BbOpDesc_t *pOp);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -67,25 +67,13 @@ extern "C" {
/*! \brief Resolve connection context from the handle. */
#define LCTR_GET_CONN_CTX(h) &(pLctrConnTbl[h])
/*! \brief Resolve txPower from phy index. */
/*! \brief Resolve txPower from PHY index. */
#define LCTR_GET_TXPOWER(pCtx, phy, option) \
(pCtx->phyTxPower[phy - (((phy == LL_PHY_LE_CODED) && (option == BB_PHY_OPTIONS_BLE_S2)) ? 0 : 1)])
/*! \brief Set the txpower of a specified PHY. */
#define LCTR_SET_TXPOWER(pCtx, phy, pow) (pCtx->phyTxPower[phy - 1] = pow)
/*! \brief Low threshold for power monitoring. */
#define LCTR_RSSI_LOW_THRESHOLD -65
/*! \brief High threshold for power monitoring. */
#define LCTR_RSSI_HIGH_THRESHOLD -30
/*! \brief Minimum time spent until request. */
#define LCTR_PC_MIN_TIME 15
/*! \brief Default request of increase/decrease in value. */
#define LCTR_PC_REQUEST_VAL 5
/*! \brief Special reset terminate reason. */
#define LCTR_RESET_TERM_REASON 0xFF
@ -147,6 +135,8 @@ enum
LCTR_PROC_CMN_SET_MIN_USED_CHAN, /*!< Set minimum number of used channels procedure. */
LCTR_PROC_CMN_PER_ADV_SYNC_TRSF, /*!< Periodic advertising sync transfer procedure. */
LCTR_PROC_CMN_REQ_PEER_SCA, /*!< Request peer SCA procedure. */
LCTR_PROC_CMN_CH_CLASS_REPORTING, /*!< Channel classification reporting procedure. */
LCTR_PROC_CMN_CH_STATUS_REPORT, /*!< Channel status reporting procedure. */
LCTR_PROC_CMN_TOTAL, /*!< Total number of common procedures. */
/* Custom SM LLCP procedures. */
@ -162,6 +152,7 @@ enum
LCTR_PROC_CIS_TERM_PEER, /*!< Peer-initiated CIS termination procedure. */
LCTR_PROC_PWR_IND, /*!< Power indication prodecure. */
LCTR_PROC_PWR_CTRL, /*!< Power control procedure. */
LCTR_PROC_SUBRATE, /*!< Subrate procedure. */
LCTR_PROC_INVALID = 0xFF /*!< Invalid ID. */
@ -225,11 +216,19 @@ typedef struct
bool_t rxFromMaster; /*!< At least one successful packet received from master. */
uint32_t firstRxStartTsUsec; /*!< Timestamp of the first received frame regardless of CRC error in microseconds. */
uint32_t lastStatusSentTs; /*!< Timestamp of last channel status update. */
uint32_t chanStatMinIntUs; /*!< Minimum interval in us between channel status updates. */
uint32_t chanStatMaxDelay; /*!< Max delay before a change of channel status is allowed to be sent. */
uint32_t queuedChanStatusTs; /*!< Timestamp of last channel status that is queued to be sent out. */
} slv; /*!< Slave connection specific data. */
struct
{
bool_t sendConnUpdInd; /*!< Send LL_CONNECTION_UPDATE_IND flag. */
uint8_t peerChannelStatus[LL_MAX_NUM_CHAN_DATA];
/*!< Current channel status map of peer. */
uint32_t recvdChanStatTs; /*!< Timestamp of last received channel status from peer. */
uint32_t chanStatMinIntUs; /*!< Minimum interval in us between channel status updates. */
} mst; /*!< Master connection specific data. */
} data; /*!< Role specific data. */
@ -264,6 +263,7 @@ typedef struct
wsfQueue_t rxDataQ; /*!< Receive data pending queue. */
uint8_t numTxComp; /*!< Number of completed Tx buffers. */
uint8_t numRxPend; /*!< Number of Rx pending buffers. */
uint8_t numTxPendCtrlPdu; /*!< Number of pending Control PDUs. */
bool_t emptyPduPend; /*!< Empty PDU ACK pending. */
bool_t emptyPduFirstAtt; /*!< Empty PDU first attempt. */
bool_t forceStartPdu; /*!< Next data will be forced to be a start PDU */
@ -302,6 +302,7 @@ typedef struct
bool_t remoteVerValid; /*!< Peer version data valid. */
lctrVerInd_t remoteVer; /*!< Peer version data. */
bool_t featExchFlag; /*!< Flag for completed feature exchange. */
uint64_t peerFeatures; /*!< Peer reported features. */
uint64_t usedFeatSet; /*!< Used feature set. */
uint8_t peerSca; /*!< Peer SCA. */
@ -310,6 +311,9 @@ typedef struct
uint8_t peerApr[LL_PC_PHY_TOTAL];
/*!< Acceptable reduction of power as calculated by the peer. */
/* Channel reporting parameters. */
bool_t chanStatRptEnable; /*!< Enable status of channel status reporting. */
/* Data length */
lctrDataLen_t localDataPdu; /*!< Local Data PDU parameters. */
lctrDataLen_t effDataPdu; /*!< Effective Data PDU parameters. */
@ -332,7 +336,7 @@ typedef struct
uint16_t perServiceData; /*!< ID for periodic sync indication. */
uint16_t perSyncHandle; /*!< Periodic sync handle. */
/* PAST(Periodic advertising sync transfer) parameters. */
/* PAST parameters. */
uint8_t syncMode; /*!< Sync transfer mode. */
uint16_t syncSkip; /*!< Sync skip for periodic adv sync transfer. */
uint16_t syncTimeout; /*!< Sync timeout for periodic adv sync transfer. */
@ -342,6 +346,7 @@ typedef struct
uint8_t encState; /*!< Current encryption state. */
uint8_t pingState; /*!< Current ping state. */
uint8_t connUpdState; /*!< Connection update state. */
uint8_t ecuState; /*!< Enhanced connection update state. */
uint8_t phyUpdState; /*!< PHY update state. */
uint8_t cmnState; /*!< Common LLCP state. */
bool_t peerReplyWaiting; /*!< Peer waiting for reply. */
@ -369,6 +374,7 @@ typedef struct
uint8_t reqErrCode; /*!< LLCP error code. */
/* Power Control */
wsfTimer_t tmrPowerCtrl; /*!< Power control monitor timer. */
int8_t delta; /*!< Power control delta storage. */
bool_t peerReqRecvd; /*!< Peer request received. */
uint8_t reqPhy; /*!< PHY of most recent power control request. */
@ -381,10 +387,11 @@ typedef struct
{
struct
{
int8_t highThreshold; /*!< High extreme RSSI threshold. */
int8_t lowThreshold; /*!< Low extreme RSSI threshold. */
uint8_t minTimeSpent; /*!< Minimum time spent in an extreme RSSI zone to trigger a request. */
uint8_t curTimeSpent; /*!< Current time spent in an extreme RSSI zone. */
int8_t highThreshold; /*!< High RSSI threshold. */
int8_t lowThreshold; /*!< Low RSSI threshold. */
uint8_t totalAccumulatedRssi; /*!< Total accumulated RSSI samples in current sample slot. */
uint32_t accumulatedRssi; /*!< Absolute value of accumulated RSSI in current RSSI sample slot (RSSI can never be positive). */
lctrRssiRunAvg_t rssiRunAvg; /*!< RSSI running average. */
uint8_t requestVal; /*!< Value of increase/decrease in power to request. */
} autoMonitor; /*!< Autonomous RSSI monitoring specific data. */
@ -403,10 +410,43 @@ typedef struct
} pclMonitorParam; /*!< Power control monitoring data. */
/* CIS */
uint16_t llcpCisHandle; /*!< CIS handle for the LLCP procedure. */
lctrCheckTermFn_t checkCisTerm; /*!< Pointer to the check CIS termination function. */
lctrCheckCisEstAclFn_t checkCisEstAcl; /*!< Pointer to the check if CIS is established function. */
uint8_t cisRssiExtremeTimeSpent; /*!< CIS's current time spent in an extreme zone. */
uint16_t llcpCisHandle; /*!< CIS handle for the LLCP procedure. */
lctrCheckTermFn_t checkCisTerm; /*!< Pointer to the check CIS termination function. */
lctrCheckCisEstAclFn_t checkCisEstAcl; /*!< Pointer to the check if CIS is established function. */
uint8_t cisRssiExtremeTimeSpent; /*!< CIS's current time spent in an extreme zone. */
uint8_t cisTotalAccumulatedRssi; /*!< Total accumulated RSSI samples in current sample slot. */
uint32_t cisAccumulatedRssi; /*!< Absolute value of accumulated RSSI in current RSSI sample slot (RSSI can never be positive). */
lctrRssiRunAvg_t cisRunAvg; /*!< Running average of RSSI for CIS connection for power control. */
/* Enhanced Connection Update */
struct
{
/* Default values. */
uint16_t defSrMin; /*!< Subrate minimum value. */
uint16_t defSrMax; /*!< Subrate maximum value. */
uint16_t defMaxLatency; /*!< Maximum latency. */
uint16_t defContNum; /*!< Continuation number. */
uint16_t defSvt; /*!< Supervision timeout. */
/* Active values. */
uint16_t srFactor; /*!< Active subrate factor. */
uint16_t srBaseEvent; /*!< Subrate base event. */
uint16_t contNum; /*!< Continuation number. */
uint16_t svt; /*!< Supervision timeout. */
uint16_t contNumCtr; /*!< Number of continuation number in subrate events. */
struct
{
uint16_t srFactor; /*!< Active subrate factor. */
uint16_t srBaseEvent; /*!< Subrate base event. */
uint16_t contNum; /*!< Continuation number. */
uint16_t contNumCtr; /*!< Number of continuation number in subrate events. */
uint16_t maxLatency; /*!< Maximum latency. */
uint16_t svt; /*!< Supervision timeout. */
} pending;
bool_t isSubrateTransMode; /*!< True if central in subrate transition mode. */
} ecu; /*!< Enhanced connection update parameters. */
} lctrConnCtx_t;
/*! \brief Call signature of a cipher block handler. */
@ -419,7 +459,7 @@ typedef bool_t (*lctrPktEncHdlr_t)(PalCryptoEnc_t *pEnc, uint8_t *pHdr, uint8_t
typedef bool_t (*lctrPktDecHdlr_t)(PalCryptoEnc_t *pEnc, uint8_t *pBuf);
/*! \brief Call signature of a set packet count handler. */
typedef void (*lctrPktCntHdlr_t)(PalCryptoEnc_t *pEnc, uint64_t pktCnt);
typedef void (*lctrPktCntHdlr_t)(uint64_t pktCnt);
/*! \brief Call signature of a LLCP state machine handler. */
typedef bool_t (*LctrLlcpHdlr_t)(lctrConnCtx_t *pCtx, uint8_t event);
@ -440,21 +480,31 @@ typedef void (*lctrPcMonAct_t)(lctrConnCtx_t *pCtx);
typedef void (*lctrPcPowInd_t)(lctrConnCtx_t *pCtx, uint8_t phy, int8_t delta, int8_t txPower, bool_t phyChange);
/*! \brief Call signature of power report notification handler. */
typedef void (*lctrPcNotifyPwr_t)(lctrConnCtx_t *pCtx, uint8_t reason, uint8_t phy, int8_t txPower, uint8_t limits, int8_t delta);
typedef void (*lctrPcNotifyPwr_t)(lctrConnCtx_t *pCtx, uint8_t status, uint8_t reason, uint8_t phy, int8_t txPower, uint8_t limits, int8_t delta);
/*! \brief Call signature of CIS pend disconnect function. */
typedef bool_t (*lctrPendCisDisc_t)(lctrConnCtx_t *pCtx);
/*! \brief Call signature of CIS power monitoring function. */
typedef void (*lctrCisServicePowerMonitor_t)(lctrConnCtx_t *pCtx);
/*! \brief Call signature of calculate number of subrated connection events. */
typedef uint16_t (*lctrCalcSubrateConnEvents_t)(lctrConnCtx_t *pCtx, uint16_t numDataPdu);
/*! \brief Call signature of check LLCP override. */
typedef bool_t (*lctrCheckLlcpOverride_t)(lctrConnCtx_t *pCtx);
/*! \brief LLCP state machine handlers. */
enum
{
LCTR_LLCP_SM_ENCRYPT, /*!< Encryption LLCP state machine. */
LCTR_LLCP_SM_PING, /*!< Ping state machine. */
LCTR_LLCP_SM_ENH_CONN_UPD, /*!< Enhanced connection update state machine. */
LCTR_LLCP_SM_CONN_UPD, /*!< Connection update state machine. */
LCTR_LLCP_SM_PHY_UPD, /*!< PHY update state machine. */
LCTR_LLCP_SM_CIS_EST, /*!< CIS establishment state machine. */
LCTR_LLCP_SM_CIS_TERM, /*!< CIS termination state machine. */
LCTR_LLCP_SM_PC, /*!< Power control state machine. */
LCTR_LLCP_SM_PC, /*!< Power control state machine. */
LCTR_LLCP_SM_CMN, /*!< Common LLCP state machine. */
LCTR_LLCP_SM_TOTAL /*!< Total number of LLCP state machine. */
};
@ -480,9 +530,12 @@ extern lctrLlcpEh_t lctrSendPerSyncFromBcstFn;
extern lctrLlcpEh_t lctrStorePeriodicSyncTrsfFn;
extern lctrLlcpEh_t lctrSendPeriodicSyncIndFn;
extern lctrLlcpEh_t lctrReceivePeriodicSyncIndFn;
extern lctrPcMonAct_t lctrPcActTbl[LCTR_PC_MONITOR_SCHEME_TOTAL];
extern lctrPcMonAct_t lctrPathLossMonitorActFn;
extern lctrPcPowInd_t lctrSendPowerChangeIndCback;
extern lctrPcNotifyPwr_t lctrNotifyPowerReportIndCback;
extern lctrCisServicePowerMonitor_t lctrCisServicePowerMonitorFn;
extern lctrCalcSubrateConnEvents_t lctrCalcSubrateConnEventsFn;
extern lctrCheckLlcpOverride_t lctrSlvCheckEncOverridePhyUpdateFn;
/**************************************************************************************************
Function Declarations
@ -573,6 +626,12 @@ void lctrSendPeerScaRsp(lctrConnCtx_t *pCtx);
void lctrStorePeerSca(lctrConnCtx_t *pCtx);
void lctrNotifyHostPeerScaCnf(lctrConnCtx_t *pCtx);
/* Channel status reporting actions. */
void lctrSendChannelStatusInd(lctrConnCtx_t *pCtx);
void lctrStoreChannelStatusInd(lctrConnCtx_t *pCtx);
void lctrSendChannelReportingInd(lctrConnCtx_t *pCtx);
void lctrStoreChannelReportingInd(lctrConnCtx_t *pCtx);
/* Unknown/Unsupported */
void lctrSendUnknownRsp(lctrConnCtx_t *pCtx);
void lctrSendRejectInd(lctrConnCtx_t *pCtx, uint8_t reason, bool_t forceRejectExtInd);
@ -637,6 +696,9 @@ uint8_t lctrGetPowerLimits(int8_t txPower);
/* Reservation */
uint32_t lctrGetConnRefTime(uint8_t connHandle, uint32_t *pDurUsec);
/* Channel map updating. */
uint8_t lctrConnChClassUpdate(uint64_t chanMap);
/*************************************************************************************************/
/*!
* \brief Set flags for link termination.
@ -749,11 +811,11 @@ static inline void lctrIncPacketCounterTx(lctrConnCtx_t *pCtx)
/*************************************************************************************************/
static inline void lctrIncPacketCounterRx(lctrConnCtx_t *pCtx)
{
if (lctrSetEncryptPktCountHdlr)
if (lctrSetDecryptPktCountHdlr)
{
PalCryptoEnc_t * const pEnc = &pCtx->bleData.chan.enc;
if ((pEnc->enaEncrypt) &&
if ((pEnc->enaDecrypt) &&
(pEnc->nonceMode == PAL_BB_NONCE_MODE_PKT_CNTR))
{
pCtx->rxPktCounter++;
@ -782,10 +844,10 @@ static inline void lctrSetBbPacketCounterTx(lctrConnCtx_t *pCtx)
switch (pEnc->nonceMode)
{
case PAL_BB_NONCE_MODE_PKT_CNTR:
lctrSetEncryptPktCountHdlr(pEnc, pCtx->txPktCounter);
lctrSetEncryptPktCountHdlr(pCtx->txPktCounter);
break;
case PAL_BB_NONCE_MODE_EXT16_CNTR:
lctrSetEncryptPktCountHdlr(pEnc, pCtx->eventCounter);
lctrSetEncryptPktCountHdlr(pCtx->eventCounter);
break;
default:
break;
@ -814,10 +876,10 @@ static inline void lctrSetBbPacketCounterRx(lctrConnCtx_t *pCtx)
switch (pEnc->nonceMode)
{
case PAL_BB_NONCE_MODE_PKT_CNTR:
lctrSetDecryptPktCountHdlr(pEnc, pCtx->rxPktCounter);
lctrSetDecryptPktCountHdlr(pCtx->rxPktCounter);
break;
case PAL_BB_NONCE_MODE_EXT16_CNTR:
lctrSetDecryptPktCountHdlr(pEnc, pCtx->eventCounter);
lctrSetDecryptPktCountHdlr(pCtx->eventCounter);
break;
default:
break;
@ -870,11 +932,11 @@ static inline void lctrStoreConnTimeoutTerminateReason(lctrConnCtx_t *pCtx)
/*************************************************************************************************/
static inline void lctrDataTxIncAvailBuf(void)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrConnCb.availTxBuf++;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/
@ -884,11 +946,11 @@ static inline void lctrDataTxIncAvailBuf(void)
/*************************************************************************************************/
static inline void lctrDataTxDecAvailBuf(void)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrConnCb.availTxBuf--;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/
@ -900,11 +962,11 @@ static inline void lctrDataTxDecAvailBuf(void)
/*************************************************************************************************/
static inline void lctrDataRxIncAvailBuf(uint8_t numBufs)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrConnCb.availRxBuf += numBufs;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/

View File

@ -82,23 +82,23 @@ typedef struct
} lctrIsoTxBufDesc_t;
/*! \brief Start stream call signature. */
typedef bool_t (*lctrCodecStartStream)(uint16_t id, PalCodecSreamParam_t *pParam);
typedef bool_t (*lctrCodecStartStream)(uint16_t id, PalCodecStreamParam_t *pParam);
/*! \brief Stop stream call signature. */
typedef void (*lctrCodecStopStream)(uint16_t id);
typedef void (*lctrCodecStopStream)(uint16_t id, PalCodecDir_t dir);
/*! \brief Stream in data call signature. */
typedef uint16_t (*lctrCodecStreamIn)(uint16_t id, uint8_t *pBuf, uint16_t len, uint32_t *pPktCtr);
/*! \brief Stream in data request call signature. */
typedef void (*lctrCodecStreamInReq)(uint16_t id, uint8_t *pData, uint16_t len);
/*! \brief Stream out data call signature. */
typedef void (*lctrCodecStreamOut)(uint16_t id, const uint8_t *pBuf, uint16_t len, uint32_t pktCtr);
typedef void (*lctrCodecStreamOut)(uint16_t id, const uint8_t *pBuf, uint16_t len, uint32_t sduRef);
/*! \brief Codec event handlers. */
typedef struct
{
lctrCodecStartStream start; /*!< Start stream. */
lctrCodecStopStream stop; /*!< Stop stream. */
lctrCodecStreamIn in; /*!< Stream data input. */
lctrCodecStreamInReq inReq; /*!< Stream data input request. */
lctrCodecStreamOut out; /*!< Stream data output. */
} lctrCodecHandlers_t;
@ -134,7 +134,7 @@ typedef struct
{
wsfQueue_t pendSduQ; /*!< Pending PDU fragments. */
uint16_t curLen; /*!< Current length of SDU being received. */
uint8_t ps; /*!< Packet status. */
lctrPktStatus_t ps:8; /*!< Packet status. */
} unframed; /*!< Unframed specific data. */
} data; /*!< Framing-specific data. */
} lctrIsoalRxCtx_t;
@ -142,30 +142,55 @@ typedef struct
/*! \brief Input datapath context. */
typedef struct
{
LlIsoDataPath_t id; /*!< Input data path ID. */
} lctrInDataPathCtx_t; /*!< Input datapath configuration. */
LlIsoDataPath_t id:8; /*!< Input data path ID. */
union
{
struct
{
uint16_t streamId; /*!< Stream ID. */
} codec; /*!< Codec-specific configuration. */
} cfg; /*!< Data path specific configuration. */
} lctrInDataPathCtx_t; /*!< Input data path configuration. */
/*! \brief Output datapath context. */
typedef struct
{
LlIsoDataPath_t id; /*!< Output data path ID. */
LlIsoDataPath_t id:8; /*!< Output data path ID. */
union
{
struct
{
wsfQueue_t rxDataQ; /*!< Receive data pending queue. */
uint8_t numRxPend; /*!< Number of messages pending in the RX queue. */
uint8_t numRxPend; /*!< Number of messages pending in the Rx queue. */
} hci; /*!< HCI data path configuration. */
} cfg; /*!< Datapath-specific configuration parameters. */
} lctrOutDataPathCtx_t; /*!< Output datapath configuration. */
/*! \brief Datapath context. */
struct
{
wsfQueue_t rxDataQ; /*!< Receive data pending queue. */
uint8_t numRxPend; /*!< Number of messages pending in the Rx queue. */
uint16_t streamId; /*!< Stream ID. */
} codec; /*!< Codec-specific configuration. */
} cfg; /*!< Data path specific configuration parameters. */
} lctrOutDataPathCtx_t; /*!< Output data path configuration. */
/*! \brief Data path context. */
typedef union
{
lctrInDataPathCtx_t in; /*!< Input context. */
lctrOutDataPathCtx_t out; /*!< Output context. */
} lctrDataPathCtx_t; /*!< Datapath context collection. */
} lctrDataPathCtx_t; /*!< Data path context collection. */
/*! \brief Data path setup parameters. */
typedef struct
{
uint16_t handle; /*!< ISO Handle. */
uint32_t isoInt; /*!< ISO interval. */
uint32_t pktCtr; /*!< Current packet counter. */
uint8_t dpDir; /*!< Data path direction. */
lctrDataPathCtx_t *pDataPathCtx; /*!< Data path context. */
} lctrDpParams_t;
/**************************************************************************************************
Function Declarations
@ -179,15 +204,17 @@ void lctrNotifyHostIsoEventComplete(uint8_t handle, uint32_t evtCtr);
/* ISO data path */
lctrIsoTxBufDesc_t *lctrAllocIsoTxBufDesc(void);
void lctrFreeIsoTxBufDesc(lctrIsoTxBufDesc_t *pDesc);
uint8_t lctrSetupIsoDataPath( LlIsoSetupDataPath_t *pSetupDataPath, lctrDataPathCtx_t *pDataPathCtx);
void lctrIsoSendCodecSdu(uint16_t id);
bool_t lctrIsoRxConnEnq(lctrOutDataPathCtx_t *pOutDataPathCtx, uint16_t handle, uint8_t *pBuf);
void lctrIsoOutDataPathClear(lctrOutDataPathCtx_t *pOutCtx);
uint8_t lctrIsoSetupDataPath(lctrDpParams_t *pDpParam, LlIsoSetupDataPath_t *pSetupDataPath);
void lctrIsoSendCodecSdu(uint16_t id, uint32_t pktCtr, uint32_t ts, uint8_t *pData, uint16_t actLen);
bool_t lctrIsoRxConnEnq(lctrOutDataPathCtx_t *pOutDataPathCtx, uint16_t handle, uint32_t pktCtr, uint8_t *pBuf);
void lctrIsoInDataPathClear(lctrDpParams_t *pDpParam);
void lctrIsoOutDataPathClear(lctrDpParams_t *pDpParam);
void lctrIsoalRxDataPathClear(lctrIsoalRxCtx_t *pRxCtx, uint8_t framing);
void lctrIsoOutDataPathSetup(lctrOutDataPathCtx_t *pOutCtx);
uint8_t lctrIsoInDataPathSetup(lctrDpParams_t *pDpParam, LlIsoSetupDataPath_t *pSetupDataPath);
uint8_t lctrIsoOutDataPathSetup(lctrDpParams_t *pDpParam, LlIsoSetupDataPath_t *pSetupDataPath);
uint8_t *lctrIsoRxConnDeq(lctrOutDataPathCtx_t *pOutCtx);
bool_t lctrIsoUnframedRxSduPendQueue(lctrIsoalRxCtx_t *pRxCtx, uint8_t *pSdu, uint16_t handle,
uint16_t dataLen, uint8_t llid);
uint8_t *lctrRxSduAlloc(void);
bool_t lctrRecombineRxUnframedSdu(lctrIsoalRxCtx_t *pRxCtx, uint8_t *pSduFrag);
/* ISO Test mode. */
uint8_t *lctrGenerateIsoTestData(uint16_t handle, LlIsoPldType_t pldType, uint16_t maxSdu, uint32_t pktCtr);
@ -205,11 +232,11 @@ uint8_t *lctrTxIsoDataPduAlloc(void);
/*************************************************************************************************/
static inline void lctrIsoSduTxIncAvailBuf(void)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrIsoCb.availTxBuf++;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/
@ -219,11 +246,11 @@ static inline void lctrIsoSduTxIncAvailBuf(void)
/*************************************************************************************************/
static inline void lctrIsoSduTxDecAvailBuf(void)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrIsoCb.availTxBuf--;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/
@ -235,11 +262,11 @@ static inline void lctrIsoSduTxDecAvailBuf(void)
/*************************************************************************************************/
static inline void lctrIsoDataRxIncAvailBuf(uint8_t numBufs)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrIsoCb.availRxBuf += numBufs;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/
@ -249,11 +276,11 @@ static inline void lctrIsoDataRxIncAvailBuf(uint8_t numBufs)
/*************************************************************************************************/
static inline void lctrIsoDataRxDecAvailBuf(void)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrIsoCb.availRxBuf--;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
#ifdef __cplusplus

View File

@ -4,7 +4,7 @@
*
* \brief Internal link layer controller power control interface file.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,25 +24,17 @@
#define LCTR_INT_PC_H
#include "lctr_api.h"
#include "lctr_int_conn.h"
#include "lctr_int_conn_slave.h"
#include "lctr_int_conn_master.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
External Constants
**************************************************************************************************/
/*! \brief Master LLCP state machine table. */
extern LctrLlcpHdlr_t lctrMstLlcpSmTbl[LCTR_LLCP_SM_TOTAL];
/*! \brief Slave LLCP state machine table. */
extern LctrLlcpHdlr_t lctrSlvLlcpSmTbl[LCTR_LLCP_SM_TOTAL];
/*************************************************************************************************
* Function Declarations
*************************************************************************************************/
uint8_t lctrCalcPathLossZone(lctrConnCtx_t *pCtx);
void lctrNotifyHostPathLossRpt(lctrConnCtx_t *pCtx);
void lctrPathLossMonitorAct(lctrConnCtx_t *pCtx);
@ -59,10 +51,10 @@ void lctrSendPeerPowerControlRsp(lctrConnCtx_t *pCtx);
void lctrStorePeerPowerControlRsp(lctrConnCtx_t *pCtx);
/* Power monitoring actions. */
void lctrAutoPowerMonitorAct(lctrConnCtx_t *pCtx);
void lctrConnServicePowerMonitor(lctrConnCtx_t *pCtx);
/* Power reporting actions. */
void lctrNotifyPowerReportInd(lctrConnCtx_t *pCtx, uint8_t reason, uint8_t phy, int8_t txPower, uint8_t limits, int8_t delta);
void lctrNotifyPowerReportInd(lctrConnCtx_t *pCtx, uint8_t status, uint8_t reason, uint8_t phy, int8_t txPower, uint8_t limits, int8_t delta);
int8_t lctrAttemptTxPowerChange(lctrConnCtx_t *pCtx, uint8_t phy, int8_t delta);
void lctrSendPowerChangeInd(lctrConnCtx_t *pCtx, uint8_t phy, int8_t delta, int8_t txPower, bool_t phyChange);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2016-2017 ARM Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -50,6 +50,8 @@ void lctrSendPhyUpdateIndPdu(lctrConnCtx_t *pCtx, uint8_t txPhys, uint8_t rxPhys
void lctrNotifyHostPhyUpdateInd(lctrConnCtx_t *pCtx, uint8_t status);
bool_t lctrSlvCheckEncOverridePhyUpdate(lctrConnCtx_t *pCtx);
#ifdef __cplusplus
};
#endif

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,6 +27,7 @@
#include "lctr_api_bis_master.h"
#include "sch_api.h"
#include "sch_api_ble.h"
#include "bb_ble_api_op.h"
#include "bb_ble_api_reslist.h"
#include "bb_ble_api_whitelist.h"
#include "bb_ble_api_periodiclist.h"
@ -879,6 +880,40 @@ bool_t lctrMstDiscoverRxExtAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf
return txScanReq;
}
/*************************************************************************************************/
/*!
* \brief Check if an Aux Scan should be programmed ASAP because of a too small auxOffset.
*
* \param pBod Originating operation.
* \param refTime Refference time in microseconds
* \param remScanDur Remaining scan duration in microseconds
*
* \return TRUE if Aux Scan was programmed, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t lctrMstLinkAuxOffsetScanSetup(BbOpDesc_t *pBod, uint32_t refTime, uint32_t remScanDur)
{
bool_t result = FALSE;
lctrExtScanCtx_t * const pExtScanCtx = pBod->pCtx;
BbOpDesc_t * const pAuxBod = &pExtScanCtx->auxScanBod;
if (pExtScanCtx->scheduleAuxAsap == TRUE)
{
pExtScanCtx->scheduleAuxAsap = FALSE;
/* Check if Aux Scan can be programmed in the remaining Ext Scan duration. */
if (BbGetTargetTimeDelta(pAuxBod->dueUsec + pAuxBod->minDurUsec, refTime) < remScanDur)
{
/* The Aux Scan will run in the context of the Ext Scan BOD. */
pBod->prot.pBle->op.mstAdv.auxScanBod = pAuxBod;
BbMstExecuteLinkedAuxScanOp(pAuxBod, &pExtScanCtx->auxBleData);
result = TRUE;
}
}
return result;
}
/*************************************************************************************************/
/*!
* \brief Extended scan discover state advertising packet receive (primary channel)
@ -947,12 +982,6 @@ void lctrMstDiscoverRxExtAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t
else
{
/* Delay Non-connectable and non-scannable with auxiliary packet PDU filtering in the AUX_ADV_IND.*/
lctrMstExtScanIsr.advAReceived = FALSE;
lctrMstExtScanIsr.tgtAReceived = FALSE;
lctrMstExtScanIsr.advA = 0;
lctrMstExtScanIsr.tgtA = 0;
lctrMstExtScanIsr.advARand = 0;
lctrMstExtScanIsr.tgtARand = 0;
/* Retrieve advA and tgtA if present. */
if (extAdvHdrFlags & LL_EXT_HDR_ADV_ADDR_BIT)
@ -961,12 +990,25 @@ void lctrMstDiscoverRxExtAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t
lctrMstExtScanIsr.advA = pExtScanCtx->extAdvHdr.advAddr;
lctrMstExtScanIsr.advARand = advHdr.txAddrRnd;
}
else
{
lctrMstExtScanIsr.advAReceived = FALSE;
lctrMstExtScanIsr.advA = 0;
lctrMstExtScanIsr.advARand = 0;
}
if (extAdvHdrFlags & LL_EXT_HDR_TGT_ADDR_BIT)
{
lctrMstExtScanIsr.tgtAReceived = TRUE;
lctrMstExtScanIsr.tgtA = pExtScanCtx->extAdvHdr.tgtAddr;
lctrMstExtScanIsr.tgtARand = advHdr.rxAddrRnd;
}
else
{
lctrMstExtScanIsr.tgtAReceived = FALSE;
lctrMstExtScanIsr.tgtA = 0;
lctrMstExtScanIsr.tgtARand = 0;
}
}
}
/* else case, delay connectable and scannable PDU filtering in the AUX_ADV_IND. */
@ -1201,98 +1243,7 @@ bool_t lctrMstDiscoverRxAuxAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf
/* Continue processing for sync establishment filter even when scan filtering failed. */
}
/*** Periodic advertising event filtering. ***/
bool_t advAMatch = FALSE;
uint64_t peerIdAddr = 0;
uint8_t peerIdAddrType = 0;
BbBlePduFiltResultsGetPeerIdAddr(&pAuxScan->filtResults, &peerIdAddr, &peerIdAddrType);
if ((lctrPerCreateSync.state == LCTR_CREATE_SYNC_STATE_DISCOVER) &&
(lctrMstPerScanIsr.filtResult == FALSE))
{
if ((lctrPerCreateSync.filtParam.advSID != pExtScanCtx->extAdvHdr.sid) ||
(lctrPerCreateSync.filtParam.advAddrType != (peerIdAddrType & LL_ADDR_RANDOM_BIT)) ||
(lctrPerCreateSync.filtParam.advAddr != peerIdAddr))
{
/* Address type, address or SID does not match. */
lctrMstPerScanIsr.filtResult = TRUE;
}
}
if ((lctrPerCreateSync.state == LCTR_CREATE_SYNC_STATE_DISCOVER) &&
(lctrMstPerScanIsr.filtResult == TRUE) &&
(lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_ADI_BIT) &&
((lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_ADV_ADDR_BIT) ||
(lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_SYNC_INFO_BIT)))
{
if (lctrPerCreateSync.filtParam.filterPolicy == LL_PER_SCAN_FILTER_PL_BIT)
{
if ((BbBlePeriodicListCheckAddr((peerIdAddrType & LL_ADDR_RANDOM_BIT), peerIdAddr,
pExtScanCtx->extAdvHdr.sid)) == FALSE)
{
/* Not in the periodic list. */
break;
}
else
{
lctrMstPerScanIsr.filtResult = FALSE;
advAMatch = TRUE;
}
}
else
{
if ((lctrPerCreateSync.filtParam.advSID != pExtScanCtx->extAdvHdr.sid) ||
(lctrPerCreateSync.filtParam.advAddrType != (peerIdAddrType & LL_ADDR_RANDOM_BIT)) ||
(lctrPerCreateSync.filtParam.advAddr != peerIdAddr))
{
/* Address type, address or SID does not match. */
break;
}
else
{
lctrMstPerScanIsr.filtResult = FALSE;
advAMatch = TRUE;
}
}
}
if (pExtScanCtx->extAdvHdr.extHdrFlags & LL_EXT_HDR_SYNC_INFO_BIT)
{
lctrUnpackSyncInfo(&pExtScanCtx->secSyncInfo, pExtScanCtx->extAdvHdr.pSyncInfo);
}
if ((lctrPerCreateSync.state == LCTR_CREATE_SYNC_STATE_DISCOVER) &&
(lctrMstPerScanIsr.filtResult == FALSE) &&
(pExtScanCtx->extAdvHdr.extHdrFlags & LL_EXT_HDR_SYNC_INFO_BIT) &&
lctrPerCreateSync.createSyncPending == FALSE)
{
lctrPerScanCtx_t *pPerScanCtx = lctrPerCreateSync.pPerScanCtx;
/*** Save peer periodic advertising parameters. ***/
pPerScanCtx->eventCounter = pExtScanCtx->secSyncInfo.eventCounter;
pPerScanCtx->initEventCounter = pExtScanCtx->secSyncInfo.eventCounter;
pPerScanCtx->perInterUsec = LCTR_PER_INTER_TO_US(pExtScanCtx->secSyncInfo.syncInter);
pPerScanCtx->sca = pExtScanCtx->secSyncInfo.sca;
pPerScanCtx->rxPhys = lctrConvertAuxPtrPhyToBbPhy(pExtScanCtx->priChAuxPtr.auxPhy);
pPerScanCtx->skipInterUsec = pPerScanCtx->perInterUsec * pPerScanCtx->skip;
if (advAMatch == TRUE)
{
/* AdvA is received in the aux_adv_ind and pass the filtering, save info in the context. */
pPerScanCtx->advAddr = peerIdAddr;
pPerScanCtx->advAddrType = peerIdAddrType;
pPerScanCtx->advSID = pExtScanCtx->extAdvHdr.sid;
/* Address to be used for sync transfer. */
pPerScanCtx->trsfAdvAddr = pExtScanCtx->extAdvHdr.advAddr;
pPerScanCtx->trsfAddrType = lctrMstExtScanIsr.advHdr.txAddrRnd;
}
uint32_t endTs = pAuxScan->auxStartTsUsec +
SchBleCalcAdvPktDurationUsec(pBle->chan.rxPhy, pAuxScan->auxRxPhyOptions, pAuxScan->txAuxReqLen);
lctrMstPerScanOpCommit(pExtScanCtx, &pExtScanCtx->priChAuxPtr, &pExtScanCtx->secSyncInfo, pAuxScan->auxStartTsUsec, endTs);
lctrMstPerScanIsr.syncWithSlave = FALSE;
}
/*** Periodic advertising event filtering done in post process. ***/
break;
}
@ -1398,6 +1349,131 @@ bool_t lctrMstDiscoverRxAuxAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf
return txScanReq;
}
/*************************************************************************************************/
/*!
* \brief Auxiliary scan discover state advertising packet receive
* post process handler.
*
* \param pOp Originating operation.
* \param pAdvBuf Received advertising buffer.
*
*/
/*************************************************************************************************/
void lctrMstDiscoverRxAuxAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf)
{
WSF_ASSERT(pOp->protId == BB_PROT_BLE);
WSF_ASSERT(pOp->prot.pBle->chan.opType == BB_BLE_OP_MST_AUX_ADV_EVENT);
BbBleData_t * const pBle = pOp->prot.pBle;
BbBleMstAuxAdvEvent_t * const pAuxScan = &pBle->op.mstAuxAdv;
lctrExtScanCtx_t * pExtScanCtx = pOp->pCtx;
/*** Periodic advertising event filtering. ***/
switch (lctrMstExtScanIsr.advHdr.pduType)
{
case LL_PDU_AUX_ADV_IND:
{
bool_t advAMatch = FALSE;
uint64_t peerIdAddr = 0;
uint8_t peerIdAddrType = 0;
BbBlePduFiltResultsGetPeerIdAddr(&pAuxScan->filtResults, &peerIdAddr, &peerIdAddrType);
if ((lctrPerCreateSync.state == LCTR_CREATE_SYNC_STATE_DISCOVER) &&
(lctrMstPerScanIsr.filtResult == FALSE))
{
if ((lctrPerCreateSync.filtParam.advSID != pExtScanCtx->extAdvHdr.sid) ||
(lctrPerCreateSync.filtParam.advAddrType != (peerIdAddrType & LL_ADDR_RANDOM_BIT)) ||
(lctrPerCreateSync.filtParam.advAddr != peerIdAddr))
{
/* Address type, address or SID does not match. */
lctrMstPerScanIsr.filtResult = TRUE;
}
}
if ((lctrPerCreateSync.state == LCTR_CREATE_SYNC_STATE_DISCOVER) &&
(lctrMstPerScanIsr.filtResult == TRUE) &&
(lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_ADI_BIT) &&
((lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_ADV_ADDR_BIT) ||
(lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_SYNC_INFO_BIT)))
{
if (lctrPerCreateSync.filtParam.filterPolicy == LL_PER_SCAN_FILTER_PL_BIT)
{
if ((BbBlePeriodicListCheckAddr((peerIdAddrType & LL_ADDR_RANDOM_BIT), peerIdAddr,
pExtScanCtx->extAdvHdr.sid)) == FALSE)
{
/* Not in the periodic list. */
break;
}
else
{
lctrMstPerScanIsr.filtResult = FALSE;
advAMatch = TRUE;
}
}
else
{
if ((lctrPerCreateSync.filtParam.advSID != pExtScanCtx->extAdvHdr.sid) ||
(lctrPerCreateSync.filtParam.advAddrType != (peerIdAddrType & LL_ADDR_RANDOM_BIT)) ||
(lctrPerCreateSync.filtParam.advAddr != peerIdAddr))
{
/* Address type, address or SID does not match. */
break;
}
else
{
lctrMstPerScanIsr.filtResult = FALSE;
advAMatch = TRUE;
}
}
}
if (pExtScanCtx->extAdvHdr.extHdrFlags & LL_EXT_HDR_SYNC_INFO_BIT)
{
lctrUnpackSyncInfo(&pExtScanCtx->secSyncInfo, pExtScanCtx->extAdvHdr.pSyncInfo);
}
if ((lctrPerCreateSync.state == LCTR_CREATE_SYNC_STATE_DISCOVER) &&
(lctrMstPerScanIsr.filtResult == FALSE) &&
(pExtScanCtx->extAdvHdr.extHdrFlags & LL_EXT_HDR_SYNC_INFO_BIT) &&
lctrPerCreateSync.createSyncPending == FALSE)
{
lctrPerScanCtx_t *pPerScanCtx = lctrPerCreateSync.pPerScanCtx;
/* Save peer periodic advertising parameters. */
pPerScanCtx->eventCounter = pExtScanCtx->secSyncInfo.eventCounter;
pPerScanCtx->initEventCounter = pExtScanCtx->secSyncInfo.eventCounter;
pPerScanCtx->perInterUsec = LCTR_PER_INTER_TO_US(pExtScanCtx->secSyncInfo.syncInter);
pPerScanCtx->sca = pExtScanCtx->secSyncInfo.sca;
pPerScanCtx->rxPhys = lctrConvertAuxPtrPhyToBbPhy(pExtScanCtx->priChAuxPtr.auxPhy);
pPerScanCtx->skipInterUsec = pPerScanCtx->perInterUsec * pPerScanCtx->skip;
if (advAMatch == TRUE)
{
/* AdvA is received in the aux_adv_ind and pass the filtering, save info in the context. */
pPerScanCtx->advAddr = peerIdAddr;
pPerScanCtx->advAddrType = peerIdAddrType;
pPerScanCtx->advSID = pExtScanCtx->extAdvHdr.sid;
/* Address to be used for sync transfer. */
pPerScanCtx->trsfAdvAddr = pExtScanCtx->extAdvHdr.advAddr;
pPerScanCtx->trsfAddrType = lctrMstExtScanIsr.advHdr.txAddrRnd;
}
uint32_t endTs = pAuxScan->auxStartTsUsec +
SchBleCalcAdvPktDurationUsec(pBle->chan.rxPhy, pAuxScan->auxRxPhyOptions, pAuxScan->txAuxReqLen);
lctrMstPerScanOpCommit(pExtScanCtx, &pExtScanCtx->priChAuxPtr, &pExtScanCtx->secSyncInfo, pAuxScan->auxStartTsUsec, endTs);
lctrMstPerScanIsr.syncWithSlave = FALSE;
}
break;
}
default:
LL_TRACE_WARN1("Received advertising PDU with invalid PDU type=%u", lctrMstExtScanIsr.advHdr.pduType);
lctrMstExtScanIsr.filtResult = TRUE;
}
}
/*************************************************************************************************/
/*!
* \brief Master auxiliary scan response receive completion handler.
@ -1969,6 +2045,10 @@ void lctrMstExtDiscoverEndOp(BbOpDesc_t *pOp)
return;
}
/* Clear Aux Scan BOD link. */
pExtScanCtx->scanBleData.op.mstAdv.auxScanOpRunning = FALSE;
pExtScanCtx->scanBleData.op.mstAdv.auxScanBod = NULL;
WSF_ASSERT(pOp->protId == BB_PROT_BLE);
WSF_ASSERT(pOp->prot.pBle->chan.opType == BB_BLE_OP_MST_ADV_EVENT);
@ -2102,7 +2182,7 @@ void lctrMstPerScanEndOp(BbOpDesc_t *pOp)
skip = 1;
}
uint16_t numUnsyncIntervals = pPerScanCtx->eventCounter - pPerScanCtx->lastActiveEvent;
uint16_t numUnsyncIntervals = pPerScanCtx->eventCounter - pPerScanCtx->lastActiveEvent;
while (TRUE)
{
@ -2156,6 +2236,8 @@ void lctrMstPerScanAbortOp(BbOpDesc_t *pOp)
{
lctrPerScanCtx_t * const pPerScanCtx = pOp->pCtx;
LL_TRACE_WARN2("!!! Periodic Scan BOD aborted, syncHandle=%u, eventCounter=%u", LCTR_GET_PER_SCAN_HANDLE(pPerScanCtx), pPerScanCtx->eventCounter);
pPerScanCtx->bodAborted = TRUE;
lctrMstPerScanEndOp(pOp);
}
@ -2179,6 +2261,23 @@ uint32_t lctrMstPerScanRxPerAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBu
BbBleData_t * const pBle = pOp->prot.pBle;
lctrPerScanCtx_t * const pPerScanCtx = pOp->pCtx;
switch (status)
{
case BB_STATUS_SUCCESS:
break;
case BB_STATUS_CRC_FAILED:
LL_TRACE_WARN3("lctrMstPerScanRxPerAdvPktHandler: BB failed with status=CRC_FAILED, syncHandle=%u, bleChan=%u, eventCounter=%u", LCTR_GET_PER_SCAN_HANDLE(pPerScanCtx), pBle->chan.chanIdx, pPerScanCtx->eventCounter);
break;
case BB_STATUS_RX_TIMEOUT:
LL_TRACE_WARN3("lctrMstPerScanRxPerAdvPktHandler: BB failed with status=RX_TIMEOUT, syncHandle=%u, bleChan=%u, eventCounter=%u", LCTR_GET_PER_SCAN_HANDLE(pPerScanCtx), pBle->chan.chanIdx, pPerScanCtx->eventCounter);
break;
case BB_STATUS_FAILED:
LL_TRACE_WARN3("lctrMstPerScanRxPerAdvPktHandler: BB failed with status=FAILED, syncHandle=%u, bleChan=%u, eventCounter=%u", LCTR_GET_PER_SCAN_HANDLE(pPerScanCtx), pBle->chan.chanIdx, pPerScanCtx->eventCounter);
break;
default:
break;
}
/* BB_STATUS_RX_TIMEOUT or BB_STATUS_CRC_FAILED with pAdvBuf NULL. */
if (pAdvBuf == NULL)
{
@ -2216,7 +2315,7 @@ uint32_t lctrMstPerScanRxPerAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBu
lctrMstPerScanIsr.syncWithSlave = TRUE;
}
/*** ACAD processing. ***/
/*** ACAD processing ***/
lctrMstAcadHandler(pPerScanCtx);
@ -2242,7 +2341,20 @@ uint32_t lctrMstPerScanRxPerAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBu
}
}
/*** Periodic Advertising Data processing. ***/
/*** ADI Filtering. ***/
if (pPerScanCtx->dupFilterEnable && (lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_ADI_BIT))
{
/* Duplicate data; do not listen further. */
if (pPerScanCtx->extAdvHdr.did == pPerScanCtx->lastDid)
{
return 0;
}
/* pPerScanCtx->lastDid = pPerScanCtx->extAdvHdr.did; */ /* Done in lctrMstPerScanRxPerAdvPktPostHandler() */
}
/*** Periodic Advertising Data processing ***/
uint32_t auxOffsetUsec = 0;
if (lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_AUX_PTR_BIT)
@ -2278,6 +2390,20 @@ bool_t lctrMstPerScanRxPerAdvPktPostHandler(BbOpDesc_t *pOp, const uint8_t *pAdv
if (pPerScanCtx->state == LCTR_PER_SCAN_STATE_SYNC_ESTD)
{
WsfTimerStartMs(&pPerScanCtx->tmrSupTimeout, pPerScanCtx->syncTimeOutMs);
if (pPerScanCtx->dupFilterEnable)
{
if (lctrMstExtScanIsr.extAdvHdrFlags & LL_EXT_HDR_ADI_BIT)
{
/* Received this data before, do not listen further. */
if (pPerScanCtx->extAdvHdr.did == pPerScanCtx->lastDid)
{
return FALSE;
}
pPerScanCtx->lastDid = pPerScanCtx->extAdvHdr.did;
}
}
}
/* BB_STATUS_RX_TIMEOUT or BB_STATUS_CRC_FAILED with pAdvBuf NULL. */

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -476,7 +476,6 @@ bool_t lctrSlvRxAuxConnReqHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf)
pAdvSet->rspPduHdr.txAddrRnd = (hdr >> LCTR_ADV_HDR_TX_ADD_SHIFT) & 0x0001;
pAdvSet->rspPduHdr.rxAddrRnd = (hdr >> LCTR_ADV_HDR_RX_ADD_SHIFT) & 0x0001;
}
#endif
@ -696,19 +695,16 @@ void lctrSlvExtAdvEndOp(BbOpDesc_t *pOp)
/* Disable (do not reschedule) advertising PDU. */
pAdvSet->shutdown = TRUE;
if (pAdvSet->auxBodUsed &&
(pAdvSet->bodTermCnt++ == 0))
if (pAdvSet->auxBodUsed)
{
pAdvSet->auxBodUsed = FALSE;
/* Ensure all BODs are de-scheduled. */
bool_t result = SchRemove(&pAdvSet->auxAdvBod);
SchRemove(&pAdvSet->auxAdvBod);
}
/* Last BOD to terminate; send terminate event. */
lctrSendAdvSetMsg(pAdvSet, LCTR_EXT_ADV_MSG_TERMINATE);
(void)result;
}
else
{
/* Last BOD to terminate; send terminate event. */
lctrSendAdvSetMsg(pAdvSet, LCTR_EXT_ADV_MSG_TERMINATE);
}
return;
} while (FALSE);
@ -728,18 +724,23 @@ void lctrSlvExtAdvEndOp(BbOpDesc_t *pOp)
if ((pAdvSet->param.advEventProp & LL_ADV_EVT_PROP_LEGACY_ADV_BIT) == 0)
{
/* Update superior PDU including AdvA and TgtA. */
pAdv->txAdvLen = lctrPackAdvExtIndPdu(pAdvSet, pAdvSet->advHdrBuf, FALSE);
bool_t modified = pAdvSet->advData.alt.ext.modified;
if (pAdvSet->advData.alt.ext.modified &&
!pAdvSet->auxBodUsed)
/* Update ADV set before building the PDU. */
if (pAdvSet->advData.alt.ext.modified)
{
pAdvSet->advData.alt.ext.modified = FALSE;
memcpy(pAdvSet->advData.pBuf, pAdvSet->advData.alt.ext.buf, pAdvSet->advData.alt.ext.len);
pAdvSet->advData.len = pAdvSet->advData.alt.ext.len;
pAdvSet->param.advDID = pAdvSet->advData.alt.ext.did;
pAdvSet->advData.fragPref = pAdvSet->advData.alt.ext.fragPref;
}
/* Update superior PDU including AdvA and TgtA. */
pAdv->txAdvLen = lctrPackAdvExtIndPdu(pAdvSet, pAdvSet->advHdrBuf, FALSE);
if (modified && !pAdvSet->auxBodUsed)
{
/* Advertising offloading to auxiliary channel. */
if (pAdvSet->pExtAdvAuxPtr)
{
@ -912,11 +913,6 @@ void lctrSlvExtAdvEndOp(BbOpDesc_t *pOp)
uint32_t totalDuration = pOp->minDurUsec;
uint32_t prefIntervalUsec;
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_ADV_DLY))
{
pOp->dueUsec += BB_BLE_TO_US(lctrCalcAdvDelay());
}
if (pAdvSet->auxBodUsed)
{
totalDuration += pAdvSet->auxAdvBod.minDurUsec;
@ -928,10 +924,16 @@ void lctrSlvExtAdvEndOp(BbOpDesc_t *pOp)
if (pAdvSet->advBodAbort)
{
pAdvSet->advBodAbort = FALSE;
(void)SchInsertEarlyAsPossible(pOp, 0, LCTR_SCH_MAX_SPAN);
SchInsertNextAvailable(pOp);
}
else
{
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_ADV_DLY))
{
pOp->dueUsec += BB_BLE_TO_US(lctrCalcAdvDelay());
}
/* Scheduling must succeed with LCTR_SCH_MAX_SPAN. */
(void)SchInsertEarlyAsPossible(pOp, prefIntervalUsec, LCTR_SCH_MAX_SPAN);
}
}
@ -986,18 +988,12 @@ void lctrSlvAuxAdvEndOp(BbOpDesc_t *pOp)
pAdvSet->shutdown = TRUE;
pAdvSet->auxBodUsed = FALSE;
if (pAdvSet->bodTermCnt++ == 0)
{
/* Ensure all BODs are de-scheduled. */
bool_t result = SchRemove(&pAdvSet->advBod);
/* Ensure all BODs are de-scheduled. */
SchRemove(&pAdvSet->advBod);
/* Last BOD to terminate; send terminate event. */
lctrSendAdvSetMsg(pAdvSet, LCTR_EXT_ADV_MSG_TERMINATE);
(void)result; /* It is possible to fail to remove BOD when BOD is not in the list(scheduling conflict) or there is not enough time to remove the BOD. */
}
else
{
/* Last BOD to terminate; send terminate event. */
lctrSendAdvSetMsg(pAdvSet, LCTR_EXT_ADV_MSG_TERMINATE);
}
return;
} while (FALSE);
@ -1107,6 +1103,7 @@ void lctrSlvPeriodicAdvEndOp(BbOpDesc_t *pOp)
pAdvSet->perAdvData.alt.ext.modified = FALSE;
memcpy(pAdvSet->perAdvData.pBuf, pAdvSet->perAdvData.alt.ext.buf, pAdvSet->perAdvData.alt.ext.len);
pAdvSet->perAdvData.len = pAdvSet->perAdvData.alt.ext.len;
pAdvSet->perParam.advDID = pAdvSet->perAdvData.alt.ext.did;
}
/*** Update operation ***/

View File

@ -120,12 +120,6 @@ static void lctrMstBigControlEncrypt(lctrBigCtx_t *pBigCtx)
uint64_t pktCtr = pBigCtx->eventCounter * pBigCtx->bn;
pBigCtx->ctrChan.enc.pTxPktCounter = &pktCtr;
/* Set the new packet counter for inline encryption. */
if (lctrSetEncryptPktCountHdlr)
{
lctrSetEncryptPktCountHdlr(&pBigCtx->ctrChan.enc, pktCtr);
}
if (pBigCtx->encrypt && lctrPktEncryptHdlr)
{
uint16_t len = lctrSlvBisIsr.pCtrlBuf[LCTR_ISO_DATA_PDU_LEN_OFFSET];
@ -174,6 +168,13 @@ static void lctrSlvBisTxControl(lctrBigCtx_t *pBigCtx)
LCTR_BIS_WR_CSSN(desc.pBuf[LCTR_ISO_DATA_PDU_FC_OFFSET], pBigCtx->bcp.cssn);
LCTR_BIS_CLR_CSTF(desc.pBuf[LCTR_ISO_DATA_PDU_FC_OFFSET]);
/* Set the control packet counter for inline encryption. */
if (pBigCtx->encrypt && lctrSetEncryptPktCountHdlr)
{
uint64_t pktCtr = pBigCtx->eventCounter * pBigCtx->bn;
lctrSetEncryptPktCountHdlr(pktCtr);
}
BbBleBisTxData(&desc, 1, 0, NULL);
}
@ -242,6 +243,13 @@ static void lctrSlvBisTxData(lctrBigCtx_t *pBigCtx)
}
#endif
/* set the inline encryption packet counter to the current bisPayloadCounter */
if (pBigCtx->encrypt && lctrSetEncryptPktCountHdlr)
{
uint64_t pktCtr = (pBigCtx->eventCounter * pBigCtx->bn) + lctrSlvBisIsr.se.burstIdx;
lctrSetEncryptPktCountHdlr(pktCtr);
}
BbBleBisTxData(pTxDesc, descCnt,
pBigCtx->bod.dueUsec + lctrSlvBisIsr.nextSeOffs,
lctrSlvBisIsr.pNextChan);
@ -480,7 +488,7 @@ void lctrSlvBisTxCompletionSequential(BbOpDesc_t *pOp, uint8_t status)
size_t numSePkts = (pBigCtx->bn * pBigCtx->irc) + lctrSlvBisIsr.se.ptIdx;
if (!lctrSlvBisCalcNextIdxSequential(pBigCtx, &lctrSlvBisIsr.se, numSePkts))
if (!lctrBisCalcNextIdxSequential(pBigCtx, &lctrSlvBisIsr.se, numSePkts))
{
if (lctrSlvBisIsr.pCtrlBuf)
{
@ -495,13 +503,20 @@ void lctrSlvBisTxCompletionSequential(BbOpDesc_t *pOp, uint8_t status)
/* Compute next channel. */
lctrSeCtx_t nextSe = lctrSlvBisIsr.se;
if (lctrSlvBisCalcNextIdxSequential(pBigCtx, &nextSe, numSePkts))
if (lctrBisCalcNextIdxSequential(pBigCtx, &nextSe, numSePkts))
{
lctrSlvBisIsr.pNextChan = &pBigCtx->pBisCtx[nextSe.bisEvtIdx]->chan;
}
else
{
lctrSlvBisIsr.pNextChan = &pBigCtx->ctrChan;
if (lctrSlvBisIsr.pCtrlBuf == NULL)
{
lctrSlvBisIsr.pNextChan = NULL;
}
else
{
lctrSlvBisIsr.pNextChan = &pBigCtx->ctrChan;
}
}
/* Compute next packet time. */
@ -542,7 +557,7 @@ void lctrSlvBisTxCompletionInterleaved(BbOpDesc_t *pOp, uint8_t status)
/* BIS loop. */
if (!lctrSlvBisCalcNextIdxInterleaved(pBigCtx, &lctrSlvBisIsr.se, numSePkts))
if (!lctrBisCalcNextIdxInterleaved(pBigCtx, &lctrSlvBisIsr.se, numSePkts))
{
if (lctrSlvBisIsr.pCtrlBuf)
{
@ -558,13 +573,20 @@ void lctrSlvBisTxCompletionInterleaved(BbOpDesc_t *pOp, uint8_t status)
/* Compute next channel. */
lctrSeCtx_t nextSe = lctrSlvBisIsr.se;
if (lctrSlvBisCalcNextIdxInterleaved(pBigCtx, &nextSe, numSePkts))
if (lctrBisCalcNextIdxInterleaved(pBigCtx, &nextSe, numSePkts))
{
lctrSlvBisIsr.pNextChan = &pBigCtx->pBisCtx[nextSe.bisEvtIdx]->chan;
}
else
{
lctrSlvBisIsr.pNextChan = &pBigCtx->ctrChan;
if (lctrSlvBisIsr.pCtrlBuf == NULL)
{
lctrSlvBisIsr.pNextChan = NULL;
}
else
{
lctrSlvBisIsr.pNextChan = &pBigCtx->ctrChan;
}
}
/* Compute next packet time. */
@ -724,10 +746,29 @@ void lctrSlvBigEndOp(BbOpDesc_t *pOp)
LL_TRACE_WARN2("!!! BIG schedule conflict handle=%u, ec[15:0]=%u", pBigCtx->handle, pBigCtx->eventCounter);
}
/* SDU generator. */
/* SDU input. */
lctrSlvBisTxTestPayloadHandler(pBigCtx);
for (unsigned int i = 0; i < pBigCtx->numBis; i++)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[i];
if (pBisCtx->roleData.slv.dataPathInCtx.id == LL_ISO_DATA_PATH_VS)
{
uint8_t *pSduBuf;
if ((pSduBuf = WsfMsgAlloc(pLctrRtCfg->maxIsoSduLen + HCI_ISO_DL_MAX_LEN)) != NULL)
{
WSF_ASSERT(lctrCodecHdlr.inReq);
lctrCodecHdlr.inReq(pBisCtx->handle, pSduBuf + HCI_ISO_HDR_LEN + HCI_ISO_DL_MAX_LEN, pBigCtx->maxSdu);
}
else
{
LL_TRACE_WARN1("!!! Out of memory; dropping input SDU, handle=%u", pBisCtx->handle);
}
}
}
/* Update BIG Info. */
lctrAdvSet_t * const pAdvSet = pBigCtx->roleData.slv.pAdvSet;
@ -740,9 +781,13 @@ void lctrSlvBigEndOp(BbOpDesc_t *pOp)
/* SDU queue maintenance. */
if (pBigCtx->framing == LL_ISO_PDU_TYPE_FRAMED)
switch (pBigCtx->framing)
{
lctrSlvCheckPendingSdu(pBigCtx);
case LL_ISO_PDU_TYPE_FRAMED:
lctrSlvCheckPendingSdu(pBigCtx);
break;
default:
break;
}
/* Notifications. */
@ -765,7 +810,10 @@ void lctrSlvBigAbortOp(BbOpDesc_t *pOp)
WSF_ASSERT(pOp->protId == BB_PROT_BLE);
WSF_ASSERT(pOp->prot.pBle->chan.opType == BB_BLE_OP_SLV_BIS_EVENT);
LL_TRACE_WARN1("BIG BOD aborted, eventCounter=%u", ((lctrBigCtx_t *)pOp->pCtx)->eventCounter);
LL_TRACE_WARN1("!!! BIG Broadcaster BOD aborted, eventCounter=%u", ((lctrBigCtx_t *)pOp->pCtx)->eventCounter);
/* Clear state since abort is called without lctrMstBigBeginOp() initializing state. */
memset(&lctrSlvBisIsr, 0, sizeof(lctrSlvBisIsr));
lctrSlvBigEndOp(pOp);
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 ARM Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -120,9 +120,9 @@ bool_t lctrCisProcessRxAck(lctrCisCtx_t *pCisCtx)
{
bool_t result = FALSE;
/* Nulls must not be ACKed. */
if (pCisCtx->rxHdr.np == 1)
{
/* NULL PDU doesn't need to be acked or processed.*/
return result;
}
@ -141,7 +141,10 @@ bool_t lctrCisProcessRxAck(lctrCisCtx_t *pCisCtx)
if ((pCisCtx->rxHdr.len) ||
((pCisCtx->rxHdr.len == 0) && (pCisCtx->rxHdr.llid == LL_LLID_ISO_UNF_END_PDU)))
{
/* lctrCisIncPacketCounterRx(pCisCtx) */ /* done after decryption in lctrCisRxPendingHandler */
if (lctrSetDecryptPktCountHdlr)
{
lctrCisIncPacketCounterRx(pCisCtx);
}
result = TRUE;
}
else /* Empty PDU. */
@ -152,7 +155,10 @@ bool_t lctrCisProcessRxAck(lctrCisCtx_t *pCisCtx)
/* length of 0 and LLID of LL_LLID_EMPTY_PDU implies padding/empty PDU. */
pCisCtx->txHdr.nesn++;
pCisCtx->rxFtParamList.pHead->ftParam.pduRcved = TRUE;
if (pCisCtx->rxFtParamList.pHead != NULL)
{
pCisCtx->rxFtParamList.pHead->ftParam.pduRcved = TRUE;
}
return result;
}
@ -191,10 +197,9 @@ void lctrCisTxPduAck(lctrCisCtx_t *pCisCtx)
/*************************************************************************************************/
bool_t lctrCisProcessTxAck(lctrCisCtx_t *pCisCtx)
{
if (((pCisCtx->rxHdr.nesn ^ pCisCtx->txHdr.sn) & 1) == 1) /* bits are different */
if (((pCisCtx->rxHdr.nesn ^ pCisCtx->dataSn) & 1) == 1) /* bits are different */
{
pCisCtx->txHdr.sn++;
pCisCtx->dataSn++;
if (pCisCtx->txBufPendAck)
{
@ -205,11 +210,13 @@ bool_t lctrCisProcessTxAck(lctrCisCtx_t *pCisCtx)
else
{
/*** Peer ACK'ed an Empty PDU ***/
pCisCtx->txDataCounter++;
}
pCisCtx->txFtParamList.pHead->ftParam.pduAcked = TRUE;
if (pCisCtx->txFtParamList.pHead != NULL)
{
pCisCtx->txFtParamList.pHead->ftParam.pduAcked = TRUE;
}
return TRUE;
}
@ -276,6 +283,7 @@ uint16_t lctrCisSetupForTx(lctrCigCtx_t *pCigCtx, uint8_t rxStatus, bool_t reqTx
pCisCtx->txHdr.np = 0;
pCisCtx->txHdr.len = 0;
pCisCtx->txHdr.llid = LL_LLID_ISO_UNF_END_PDU;
pCisCtx->txHdr.sn = pCisCtx->dataSn;
if ((rxStatus != BB_STATUS_SUCCESS) ||
reqTx)
@ -312,6 +320,7 @@ uint16_t lctrCisSetupForTx(lctrCigCtx_t *pCigCtx, uint8_t rxStatus, bool_t reqTx
bbDesc[0].pBuf[0] ^= llTesterCb.pktLlId & 0x03;
#endif
lctrSetBbCisPacketCounterTx(pCisCtx);
BbBleCisTxData(&bbDesc[0], bbDescCnt);
numTxBytes = LL_DATA_HDR_LEN + bbDesc[0].pBuf[LCTR_ISO_DATA_PDU_LEN_OFFSET];
@ -325,7 +334,10 @@ uint16_t lctrCisSetupForTx(lctrCigCtx_t *pCigCtx, uint8_t rxStatus, bool_t reqTx
/*** Send Empty PDU ***/
lctrCisBuildEmptyPdu(pCisCtx);
pFtParam->pduType[pFtParam->pduCounter] = LCTR_CIS_PDU_EMPTY;
if (pFtParam != NULL)
{
pFtParam->pduType[pFtParam->pduCounter] = LCTR_CIS_PDU_EMPTY;
}
PalBbBleTxBufDesc_t desc = {.pBuf = lctrCisIsr.emptyPdu, .len = sizeof(lctrCisIsr.emptyPdu)};
BbBleCisTxData(&desc, 1);
@ -347,12 +359,12 @@ uint16_t lctrCisSetupForTx(lctrCigCtx_t *pCigCtx, uint8_t rxStatus, bool_t reqTx
/*************************************************************************************************/
void lctrCisRxPostProcessing(lctrCisCtx_t *pCisCtx, uint8_t *pRxBuf)
{
if (pCisCtx->validRx) /* Another buffer ready to replace the received one. */
{
lctrCisRxEnq(pRxBuf, pCisCtx->cisEvtCounter, pCisCtx->cisHandle);
}
else
if (!pCisCtx->validRx && (pRxBuf != NULL)) /* Another buffer ready to replace the received one. */
{
lctrCisRxPduFree(pRxBuf);
pRxBuf = NULL;
}
/* Notify the task */
lctrCisRxEnq(pRxBuf, pCisCtx->cisEvtCounter, pCisCtx->cisHandle);
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -70,16 +70,28 @@ static void lctrMstCisInitIsr(lctrCisCtx_t *pCisCtx)
pCisCtx->txDataCounter = 0;
pCisCtx->rxDataCounter = 0;
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter = 0;
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter = 0;
if (pCisCtx->txFtParamList.pHead->ftParam.bn == 0)
/* List may be empty if BN_S_To_M is 0 */
if (pCisCtx->rxFtParamList.pHead != NULL)
{
pCisCtx->isTxDone = TRUE;
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter = 0;
}
/* List may be empty if BN_M_To_S is 0 */
if (pCisCtx->txFtParamList.pHead != NULL)
{
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter = 0;
if (pCisCtx->txFtParamList.pHead->ftParam.bn == 0)
{
pCisCtx->isTxDone = TRUE;
}
else
{
pCisCtx->isTxDone = FALSE;
}
}
else
{
pCisCtx->isTxDone = FALSE;
pCisCtx->isTxDone = TRUE;
}
/*** Setup for transmit ***/
@ -115,7 +127,7 @@ static void lctrMstCisSetupRx(lctrCigCtx_t *pCigCtx, lctrCisCtx_t *pCisCtx)
/*** Setup for receive ***/
if ((pBuf = lctrCisRxPduAlloc(pCisCtx->localDataPdu.maxRxLen)) != NULL)
if ((pBuf = lctrCisRxPduAlloc()) != NULL)
{
#if (LL_ENABLE_TESTER)
/* Invalidate access address if trigger is set. */
@ -136,12 +148,13 @@ static void lctrMstCisSetupRx(lctrCigCtx_t *pCigCtx, lctrCisCtx_t *pCisCtx)
}
#endif
lctrSetBbCisPacketCounterRx(pCisCtx);
BbBleCisRxData(pBuf, LCTR_CIS_DATA_PDU_LEN(pCisCtx->localDataPdu.maxRxLen));
/* Rx may fail; no more important statements in this code path */
}
else
{
LL_TRACE_ERR1("!!! OOM while initializing receive buffer at start of CE, cisHandle=%u", pCisCtx->cisHandle);
LL_TRACE_ERR2("!!! OOM while initializing receive buffer at start of CE, cisHandle=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->cisEvtCounter);
BbSetBodTerminateFlag();
}
}
@ -196,7 +209,7 @@ static void lctrCisCheckTxFtAfterRx(lctrCisCtx_t *pCisCtx)
if (pFtParam->subEvtCounter == pFtParam->lastSubEvtFt[pFtParam->pduCounter])
{
/* PDU needs to be flushed. */
pCisCtx->txHdr.sn++;
pCisCtx->dataSn++;
pFtParam->isPduDone[pFtParam->pduCounter] = TRUE; /* The PDU is done. */
if (pFtParam->pduType[pFtParam->pduCounter] == LCTR_CIS_PDU_NON_EMPTY)
@ -205,12 +218,17 @@ static void lctrCisCheckTxFtAfterRx(lctrCisCtx_t *pCisCtx)
lctrCisTxPduAck(pCisCtx);
pCisCtx->pduFlushed = TRUE; /* Set the flag, lctrCisProcessTxAckCleanup will be called to do the cleanup later in the lctrMstCisCigPostSubEvt. */
}
pFtParam->pduCounter++;
lctrCisIncPacketCounterTx(pCisCtx);
pCisCtx->isoLinkQualStats.txUnAckPkt++;
pFtParam->pduCounter++;
}
else /* Implies that a retransmit will happen. */
{
pCisCtx->isoLinkQualStats.retransmitPkt++;
}
}
else /* Implies that a retransmit will happen. */
else
{
pCisCtx->isoLinkQualStats.retransmitPkt++;
}
@ -253,12 +271,6 @@ static void lctrCisCheckRxFtAfterRx(lctrCisCtx_t *pCisCtx)
return;
}
if (pCisCtx->rxHdr.np)
{
/* NULL PDU doesn't need to be acked or flushed. */
return;
}
lctrFtParam_t *pFtParam = &pCisCtx->rxFtParamList.pHead->ftParam;
if (pFtParam->pduRcved)
@ -282,6 +294,11 @@ static void lctrCisCheckRxFtAfterRx(lctrCisCtx_t *pCisCtx)
pCisCtx->isoalRxCtx.pduFlushed = TRUE;
pCisCtx->isoalRxCtx.packetSequence++;
pCisCtx->numRxMissed++;
if (pCisCtx->framing == LL_ISO_PDU_TYPE_UNFRAMED)
{
/* Indicate SDU has missing data. */
pCisCtx->isoalRxCtx.data.unframed.ps = LCTR_PS_INVALID;
}
}
}
}
@ -317,12 +334,6 @@ static void lctrCisCheckTxFtAfterBod(lctrCisCtx_t *pCisCtx)
return;
}
if (pCisCtx->txHdr.np)
{
/* NULL PDU doesn't need to be acked or flushed. */
return;
}
lctrFtParamNode_t *pNode = pCisCtx->txFtParamList.pHead;
/* Increment interval counter for all the node in the list. */
@ -340,7 +351,7 @@ static void lctrCisCheckTxFtAfterBod(lctrCisCtx_t *pCisCtx)
pFtParam->intervalCounter == pFtParam->intervalTotal) /* Check if the PDU needs to be flush in this interval. */
{
pFtParam->isPduDone[i] = TRUE;
pCisCtx->txHdr.sn++;
pCisCtx->dataSn++;
if (pFtParam->pduType[i] == LCTR_CIS_PDU_NON_EMPTY)
{
@ -349,6 +360,8 @@ static void lctrCisCheckTxFtAfterBod(lctrCisCtx_t *pCisCtx)
lctrCisTxQueuePopCleanup(pCisCtx);
}
pFtParam->pduCounter++;
lctrCisIncPacketCounterTx(pCisCtx);
}
}
@ -403,7 +416,9 @@ static void lctrCisCheckRxFtAfterBod(lctrCisCtx_t *pCisCtx)
{
pFtParam->isPduDone[i] = TRUE;
pCisCtx->txHdr.nesn++;
lctrCisIncPacketCounterRx(pCisCtx);
pFtParam->pduCounter++;
pCisCtx->isoalRxCtx.pduFlushed = TRUE;
}
}
@ -453,6 +468,98 @@ static void lctrCisCheckFtAfterBod(lctrCisCtx_t *pCisCtx)
External Functions
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Check whether continue the current operation.
*
* \param pOp Operation.
* \param pNewCisCtx A new CIS operation.
*
* \return zero
*/
/*************************************************************************************************/
uint32_t lctrMstCisCheckContOpPostCback(BbOpDesc_t *pOp, bool_t *pNewCisCtx)
{
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
lctrCisCtx_t *pCisCtx = pCigCtx->pCisCtx;
BbBleData_t *pBle = &pCisCtx->bleData;
if (*pNewCisCtx == FALSE)
{
return 0;
}
if (pCigCtx->packing == LL_PACKING_INTERLEAVED)
{
if ((pCisCtx = lctrCisGetNextCis(&pCigCtx->list, pCisCtx)) == NULL)
{
/* End of the list, loop back to the head of the CIS. */
pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
pCigCtx->isLoopBack = TRUE;
pBle = &pCisCtx->bleData;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
/* For interleaved CIS there is always a switch to a new CisCtx, so nextSubEvtChanIdx is not updated in bbMstCisRxCompCback()*/
if (pCisCtx->subEvtCounter <= pCisCtx->nse)
{
lctrMstCisCigPostSubEvt(pOp, BB_STATUS_SUCCESS);
}
}
else
{
/* TODO need to check whether this pCisCtx->rxHdr.cie || pCisCtx->txHdr.cie and no sending more PDU for this CIS. */
/* Get the next CIS in the list. */
if (pCigCtx->isLoopBack == FALSE)
{
lctrFtParam_t txFtParam, rxFtParam;
if (pCisCtx->bnMToS)
{
lctrCisInitFtParam(&txFtParam, pCisCtx->bnMToS, pCisCtx->ftMToS, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->txFtParamList, &txFtParam); /* Assume there is memory. */
}
if (pCisCtx->bnSToM)
{
lctrCisInitFtParam(&rxFtParam, pCisCtx->bnSToM, pCisCtx->ftSToM, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->rxFtParamList, &rxFtParam); /* Assume there is memory. */
}
lctrMstCisInitIsr(pCisCtx);
}
pBle = &pCisCtx->bleData;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
if (pCigCtx->isLoopBack == FALSE)
{
pBle->chan.chanIdx = pCigCtx->pCisCtx->chIdx; /* Set the next channel to the first channel in the next CIS. */
}
else
{
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
/* For interleaved CIS there is always a switch to a new CisCtx, so nextSubEvtChanIdx is not updated in bbMstCisRxCompCback()*/
if (pCisCtx->subEvtCounter <= pCisCtx->nse)
{
lctrMstCisCigPostSubEvt(pOp, BB_STATUS_SUCCESS);
}
}
}
}
return 0;
}
/*************************************************************************************************/
/*!
* \brief Check whether continue the current operation.
@ -622,18 +729,8 @@ SwitchInt:
goto Done;
}
/* End of the list, loop back to the head of the CIS. */
pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
pCigCtx->isLoopBack = TRUE;
pBle = &pCisCtx->bleData;
*pNewCisCtx = TRUE;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
/* Processing will continue in the lctrMstCisCheckContOpPostCback() */
return delayUsec; /* Return the offset from the old CIS */
}
@ -684,43 +781,8 @@ SwitchInt:
return (subIntervUsec - addDelayUsec);
}
/* TODO need to check whether this pCisCtx->rxHdr.cie || pCisCtx->txHdr.cie and no sending more PDU for this CIS. */
/* Get the next CIS in the list. */
if (pCigCtx->isLoopBack == FALSE)
{
lctrFtParam_t txFtParam, rxFtParam;
if (pCisCtx->bnMToS)
{
lctrCisInitFtParam(&txFtParam, pCisCtx->bnMToS, pCisCtx->ftMToS, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->txFtParamList, &txFtParam); /* Assume there is memory. */
}
if (pCisCtx->bnSToM)
{
lctrCisInitFtParam(&rxFtParam, pCisCtx->bnSToM, pCisCtx->ftSToM, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->rxFtParamList, &rxFtParam); /* Assume there is memory. */
}
lctrMstCisInitIsr(pCisCtx);
}
pBle = &pCisCtx->bleData;
*pNewCisCtx = TRUE;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
if (pCigCtx->isLoopBack == FALSE)
{
pBle->chan.chanIdx = pCigCtx->pCisCtx->chIdx; /* Set the next channel to the first channel in the next CIS. */
}
else
{
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
}
/* Processing will continue in the lctrMstCisCheckContOpPostCback() */
return delayUsec; /* Return the offset from the old CIS */
}
@ -850,6 +912,14 @@ void lctrMstCisCigEndOp(BbOpDesc_t *pOp)
while (pCisCtx)
{
/* Check for unframed flushed PDUs. */
if ((pCisCtx->framing == LL_ISO_PDU_TYPE_UNFRAMED) &&
(pCisCtx->isoalRxCtx.pduFlushed == TRUE))
{
pCisCtx->isoalRxCtx.pduFlushed = FALSE;
lctrCisCheckUnframedFlush(pCisCtx);
}
pConnCtx = LCTR_GET_CONN_CTX(pCisCtx->aclHandle);
/* LL_CIS_TERMINATION case */
@ -857,10 +927,20 @@ void lctrMstCisCigEndOp(BbOpDesc_t *pOp)
(pConnCtx->enabled == FALSE) ||
(lctrResetEnabled == TRUE))
{
/* This variable set to TRUE means it is a CIS disconnect that requires an event generation. */
if (pCisCtx->isClosing == TRUE)
/* Notify host when terminate happens unless reseted. */
if (lctrResetEnabled == FALSE)
{
/* This was a host-initiated termination of the CIS. */
if (pConnCtx->enabled == FALSE)
{
pCisCtx->reason = HCI_ERR_REMOTE_TERMINATED;
}
/* If host initiates the termination, the reason code shall be HCI_ERR_LOCAL_TERMINATED in the disconnect complete event. */
else if (pCisCtx->hostInitTerm)
{
pCisCtx->reason = HCI_ERR_LOCAL_TERMINATED;
pCisCtx->hostInitTerm = FALSE;
}
lctrNotifyHostCisTerm(pCisCtx);
}
@ -993,6 +1073,21 @@ void lctrMstCisCigEndOp(BbOpDesc_t *pOp)
}
}
if (pCisCtx->sduSizeMToS &&
(pCisCtx->dataPathInCtx.id == LL_ISO_DATA_PATH_VS))
{
uint8_t *pSduBuf;
if ((pSduBuf = lctrTxIsoDataPduAlloc()) != NULL)
{
WSF_ASSERT(lctrCodecHdlr.inReq);
lctrCodecHdlr.inReq(pCisCtx->cisHandle, pSduBuf + HCI_ISO_HDR_LEN + HCI_ISO_DL_MAX_LEN, pCisCtx->sduSizeMToS);
}
else
{
LL_TRACE_WARN1("!!! Out of memory; dropping input SDU, handle=%u", pCisCtx->cisHandle);
}
}
/* Assemble framed data. */
if ((pCisCtx->framing == LL_ISO_PDU_TYPE_FRAMED) &&
pCisCtx->isoalTxCtx.pendQueueSize)
@ -1028,7 +1123,7 @@ void lctrMstCisCigEndOp(BbOpDesc_t *pOp)
}
pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
LL_TRACE_WARN1("!!! CIS master schedule conflict eventCounter=%u", pCisCtx->cisEvtCounter);
LL_TRACE_WARN2("!!! CIS master schedule conflict handle=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->cisEvtCounter);
}
if (lmgrCb.sendIsoCmplEvt)
@ -1048,6 +1143,8 @@ void lctrMstCisCigAbortOp(BbOpDesc_t *pOp)
{
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
LL_TRACE_WARN1("!!! CIG Master BOD aborted, cigHandle=%u", pCigCtx->cigHandle);
/* Need to setup Tx/Rx flush timeout parameter first since some field will be used in the lctrSlvCisInitIsr. */
if (pCigCtx->numCisEsted > 0)
@ -1093,7 +1190,10 @@ void lctrMstCisCigTxCompletion(BbOpDesc_t *pOp, uint8_t status)
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
lctrCisCtx_t *pCisCtx = pCigCtx->pCisCtx;
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter++;
if (pCisCtx->txFtParamList.pHead != NULL)
{
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter++;
}
}
/*************************************************************************************************/
@ -1110,21 +1210,29 @@ void lctrMstCisCigRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
lctrCisCtx_t *pCisCtx = pCigCtx->pCisCtx;
lctrConnCtx_t *pConnCtx = LCTR_GET_CONN_CTX(pCisCtx->aclHandle);
BbBleData_t * const pBle = &pCisCtx->bleData;
pCisCtx->txFtParamList.pHead->ftParam.pduAcked = FALSE;
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter++;
pCisCtx->rxFtParamList.pHead->ftParam.pduRcved = FALSE;
if (pCisCtx->txFtParamList.pHead != NULL)
{
pCisCtx->txFtParamList.pHead->ftParam.pduAcked = FALSE;
}
if (pCisCtx->rxFtParamList.pHead != NULL)
{
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter++;
pCisCtx->rxFtParamList.pHead->ftParam.pduRcved = FALSE;
}
pCisCtx->validRx = FALSE;
pCisCtx->txPduIsAcked = FALSE;
pCisCtx->pduFlushed = FALSE;
pCisCtx->isoalRxCtx.pduFlushed = FALSE;
if (status == BB_STATUS_CRC_FAILED)
{
pCisCtx->isoLinkQualStats.crcErrPkt++;
}
/*** Cancellation processing ***/
/*** Cancelled processing ***/
if (status == BB_STATUS_CANCELED)
{
@ -1134,22 +1242,58 @@ void lctrMstCisCigRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
/*** Receive packet pre-processing ***/
if (status == BB_STATUS_SUCCESS)
/* Add RSSI to average if monitoring power. */
if ((pConnCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pConnCtx->powerMonitorScheme == LCTR_PC_MONITOR_AUTO))
{
int8_t rssi = (status == LL_SUCCESS) ? pOp->prot.pBle->op.mstCis.rssi : 0x80;
/* Calculations handled on timer expiration for tmrPowerCtrl. */
/* Use a positive value to hold accumulated RSSI, as RSSI will never be positive. */
pConnCtx->cisAccumulatedRssi += (uint32_t) -rssi;
pConnCtx->cisTotalAccumulatedRssi++;
}
switch (status)
{
case BB_STATUS_SUCCESS:
pCisCtx->firstFromPeer = TRUE;
pCisCtx->data.mst.rxFromSlave = TRUE;
}
else if (status == BB_STATUS_CRC_FAILED ||
status == BB_STATUS_RX_TIMEOUT ||
status == BB_STATUS_FAILED)
{
LL_TRACE_WARN2("lctrMstCisCigRxCompletion: BB failed with status=%u, handle=%u", status, pCisCtx->cisHandle);
LL_TRACE_WARN2("lctrMstCisCigRxCompletion: BB failed with cisEvtCounter=%d, bleChan=%u", pCisCtx->cisEvtCounter, pCisCtx->bleData.chan.chanIdx);
break;
case BB_STATUS_CRC_FAILED:
LL_TRACE_WARN3("lctrMstCisCigRxCompletion: BB failed with status=CRC_FAILED, handle=%u, bleChan=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->bleData.chan.chanIdx, pCisCtx->cisEvtCounter);
goto PostProcessing;
case BB_STATUS_RX_TIMEOUT:
LL_TRACE_WARN3("lctrMstCisCigRxCompletion: BB failed with status=RX_TIMEOUT, handle=%u, bleChan=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->bleData.chan.chanIdx, pCisCtx->cisEvtCounter);
pCisCtx->validRx = FALSE;
pCisCtx->txPduIsAcked = FALSE;
goto PostProcessing;
case BB_STATUS_FAILED:
LL_TRACE_WARN3("lctrMstCisCigRxCompletion: BB failed with status=FAILED, handle=%u, bleChan=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->bleData.chan.chanIdx, pCisCtx->cisEvtCounter);
pCisCtx->validRx = FALSE;
pCisCtx->txPduIsAcked = FALSE;
goto PostProcessing;
default:
break;
}
lctrCisUnpackDataPduHdr(&pCisCtx->rxHdr, pRxBuf);
/* Check for MIC failure and if this is not a re-transmission */
if ((status == BB_STATUS_MIC_FAILED) &&
((pCisCtx->rxHdr.sn ^ pCisCtx->txHdr.nesn) & 1) == 0)
{
LL_TRACE_WARN3("lctrMstCisCigRxCompletion: BB failed with MIC_FAILED, handle=%u, rxPacketNum=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->rxPktCounter, pCisCtx->cisEvtCounter);
lctrSendCisMsg(pCisCtx, LCTR_CIS_MSG_CIS_TERM_MIC_FAILED);
lctrCisRxPduFree(pRxBuf);
BbSetBodTerminateFlag();
goto Done;
}
#if (LL_ENABLE_TESTER)
if ((llTesterCb.cisAckMode != LL_TESTER_ACK_MODE_NORMAL) ||
(llTesterCb.cisFwdPkt == TRUE))
@ -1172,34 +1316,22 @@ void lctrMstCisCigRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
/*** Packet post-processing ***/
PostProcessing:
/* Save the Rx buffer and process in the lctrMstCisCigPostSubEvt. */
pCisCtx->pRxBuf = pRxBuf;
/* Check rssi value if power monitoring. */
if (pConnCtx->monitoringState == LCTR_PC_MONITOR_ENABLED)
{
lctrCisPowerMonitorCheckRssi(pOp->prot.pBle->op.mstCis.rssi,
status,
pCisCtx->phySToM +
(((pCisCtx->phySToM == LL_PHY_LE_CODED) &&
(pBle->chan.initTxPhyOptions == LL_PHY_OPTIONS_S2_PREFERRED)) ? 1 : 0),
pConnCtx);
}
lctrCisCheckFtAfterRx(pCisCtx);
/* Tx post-processing. */
lctrCisProcessTxAckCleanup(pCisCtx);
/* Rx post-processing. */
lctrCisRxPostProcessing(pCisCtx, pRxBuf);
return;
/*** ISR complete ***/
Done:
lctrCisCheckFtAfterRx(pCisCtx);
if (status == BB_STATUS_SUCCESS ||
status == BB_STATUS_RX_TIMEOUT ||
status == BB_STATUS_CRC_FAILED ||
status == BB_STATUS_FAILED)
{
lctrCisProcessTxAckCleanup(pCisCtx);
lctrCisRxPostProcessing(pCisCtx, pCisCtx->pRxBuf);
}
return;
lctrCisProcessTxAckCleanup(pCisCtx);
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -72,16 +72,29 @@ static void lctrSlvCisInitIsr(lctrCisCtx_t *pCisCtx)
pCisCtx->txDataCounter = 0;
pCisCtx->rxDataCounter = 0;
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter = 0;
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter = 0;
if (pCisCtx->txFtParamList.pHead->ftParam.bn == 0)
/* List may be empty if BN M_S is 0 */
if (pCisCtx->rxFtParamList.pHead != NULL)
{
pCisCtx->isTxDone = TRUE;
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter = 0;
}
/* List may be empty if BN S_M is 0 */
if (pCisCtx->txFtParamList.pHead != NULL)
{
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter = 0;
if (pCisCtx->txFtParamList.pHead->ftParam.bn == 0)
{
pCisCtx->isTxDone = TRUE;
}
else
{
pCisCtx->isTxDone = FALSE;
}
}
else
{
pCisCtx->isTxDone = FALSE;
pCisCtx->isTxDone = TRUE;
}
/*** Setup for transmit ***/
@ -116,7 +129,7 @@ static void lctrSlvCisCigExecOp(lctrCisCtx_t *pCisCtx)
/*** Setup receiver ***/
if ((pBuf = lctrCisRxPduAlloc(pCisCtx->localDataPdu.maxRxLen)) != NULL)
if ((pBuf = lctrCisRxPduAlloc()) != NULL)
{
#if (LL_ENABLE_TESTER)
if (llTesterCb.isoAccAddrSeTrigMask &&
@ -136,6 +149,7 @@ static void lctrSlvCisCigExecOp(lctrCisCtx_t *pCisCtx)
}
#endif
lctrSetBbCisPacketCounterRx(pCisCtx);
BbBleCisRxData(pBuf, LCTR_CIS_DATA_PDU_LEN(pCisCtx->localDataPdu.maxRxLen));
/* Rx may fail; no more important statements in this code path */
}
@ -161,7 +175,7 @@ static void lctrCisCheckTxFtAfterRx(lctrCisCtx_t *pCisCtx)
return;
}
if (pCisCtx->txHdr.np)
if (pCisCtx->data.slv.lastTxNull)
{
/* NULL PDU doesn't need to be acked or flushed. */
return;
@ -183,19 +197,23 @@ static void lctrCisCheckTxFtAfterRx(lctrCisCtx_t *pCisCtx)
if (pFtParam->subEvtCounter == pFtParam->lastSubEvtFt[pFtParam->pduCounter])
{
/* PDU needs to be flushed. */
pCisCtx->txHdr.sn++;
pCisCtx->dataSn++;
lctrCisIncPacketCounterTx(pCisCtx);
pFtParam->isPduDone[pFtParam->pduCounter] = TRUE; /* The PDU is done. */
pFtParam->pduCounter++;
pCisCtx->isoLinkQualStats.txUnAckPkt++;
if (pFtParam->pduType[pFtParam->pduCounter] == LCTR_CIS_PDU_NON_EMPTY)
{
/* Need to remove from ack queue if non-empty PDU. */
lctrCisTxPduAck(pCisCtx);
pCisCtx->pduFlushed = TRUE; /* Set the flag, lctrCisProcessTxAckCleanup will be called to do the cleanup later in the lctrMstCisCigPostSubEvt. */
pCisCtx->pduFlushed = TRUE; /* Set the flag, lctrCisProcessTxAckCleanup will be called to do the cleanup later in the lctrSlvCisCigPostSubEvt. */
}
pFtParam->pduCounter++;
pCisCtx->isoLinkQualStats.txUnAckPkt++;
}
else /* Implies that a retransmit will happen. */
{
pCisCtx->isoLinkQualStats.retransmitPkt++;
}
}
else /* Implies that a retransmit will happen. */
@ -241,12 +259,6 @@ static void lctrCisCheckRxFtAfterRx(lctrCisCtx_t *pCisCtx)
return;
}
if (pCisCtx->rxHdr.np)
{
/* NULL PDU doesn't need to be acked or flushed. */
return;
}
lctrFtParam_t *pFtParam = &pCisCtx->rxFtParamList.pHead->ftParam;
if (pFtParam->pduRcved)
@ -270,6 +282,11 @@ static void lctrCisCheckRxFtAfterRx(lctrCisCtx_t *pCisCtx)
pCisCtx->isoalRxCtx.pduFlushed = TRUE;
pCisCtx->isoalRxCtx.packetSequence++;
pCisCtx->numRxMissed++;
if (pCisCtx->framing == LL_ISO_PDU_TYPE_UNFRAMED)
{
/* Indicate SDU has missing data. */
pCisCtx->isoalRxCtx.data.unframed.ps = LCTR_PS_INVALID;
}
}
}
}
@ -305,12 +322,6 @@ static void lctrCisCheckTxFtAfterBod(lctrCisCtx_t *pCisCtx)
return;
}
if (pCisCtx->txHdr.np)
{
/* NULL PDU doesn't need to be acked or flushed. */
return;
}
lctrFtParamNode_t *pNode = pCisCtx->txFtParamList.pHead;
/* Increment interval counter for all the node in the list. */
@ -328,16 +339,17 @@ static void lctrCisCheckTxFtAfterBod(lctrCisCtx_t *pCisCtx)
pFtParam->intervalCounter == pFtParam->intervalTotal) /* Check if the PDU needs to be flush in this interval. */
{
pFtParam->isPduDone[i] = TRUE;
pCisCtx->txHdr.sn++;
pCisCtx->dataSn++;
PalBbBleTxBufDesc_t bbDesc[3];
if (lctrCisTxQueuePeek(pCisCtx, &bbDesc[0]))
if (pFtParam->pduType[i] == LCTR_CIS_PDU_NON_EMPTY)
{
/* Need to remove from ack queue if non-empty PDU. */
lctrCisTxPduAck(pCisCtx);
lctrCisTxQueuePopCleanup(pCisCtx);
}
pFtParam->pduCounter++;
lctrCisIncPacketCounterTx(pCisCtx);
}
}
@ -393,6 +405,7 @@ static void lctrCisCheckRxFtAfterBod(lctrCisCtx_t *pCisCtx)
pCisCtx->txHdr.nesn++;
lctrCisIncPacketCounterRx(pCisCtx);
pFtParam->pduCounter++;
pCisCtx->isoalRxCtx.pduFlushed = TRUE;
}
}
@ -441,6 +454,95 @@ static void lctrCisCheckFtAfterBod(lctrCisCtx_t *pCisCtx)
/**************************************************************************************************
External Functions
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Setup for the next current operation.
*
* \param pOp Begin operation.
* \param pNewCisCtx New CIS context to begin.
*
* \return zero.
*/
/*************************************************************************************************/
uint32_t lctrSlvCisCheckContOpPostCback(BbOpDesc_t *pOp, bool_t *pNewCisCtx)
{
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
lctrCisCtx_t *pCisCtx = pCigCtx->pCisCtx;
BbBleData_t *pBle = &pCisCtx->bleData;
if (*pNewCisCtx == FALSE)
{
return 0;
}
if (pCigCtx->packing == LL_PACKING_INTERLEAVED)
{
if ((pCisCtx = lctrCisGetNextCis(&pCigCtx->list, pCisCtx)) == NULL)
{
/* End of the list, loop back to the head of the CIS. */
pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
pCigCtx->isLoopBack = TRUE;
pBle = &pCisCtx->bleData;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
/* For interleaved CIS there is always a switch to a new CisCtx, so nextSubEvtChanIdx is not updated in bbMstCisRxCompCback()*/
if (pCisCtx->subEvtCounter <= pCisCtx->nse)
{
lctrSlvCisCigPostSubEvt(pOp, BB_STATUS_SUCCESS);
}
}
else
{
if (pCigCtx->isLoopBack == FALSE)
{
lctrFtParam_t txFtParam, rxFtParam;
if (pCisCtx->bnSToM)
{
lctrCisInitFtParam(&txFtParam, pCisCtx->bnSToM, pCisCtx->ftSToM, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->txFtParamList, &txFtParam); /* Assume there is memory. */
}
if (pCisCtx->bnMToS)
{
lctrCisInitFtParam(&rxFtParam, pCisCtx->bnMToS, pCisCtx->ftMToS, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->rxFtParamList, &rxFtParam); /* Assume there is memory. */
}
lctrSlvCisInitIsr(pCisCtx);
}
pBle = &pCisCtx->bleData;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
if (pCigCtx->isLoopBack == FALSE)
{
pBle->chan.chanIdx = pCigCtx->pCisCtx->chIdx; /* Set the next channel to the first channel in the next CIS. */
}
else
{
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
/* For interleaved CIS there is always a switch to a new CisCtx, so nextSubEvtChanIdx is not updated in bbMstCisRxCompCback()*/
if (pCisCtx->subEvtCounter <= pCisCtx->nse)
{
lctrSlvCisCigPostSubEvt(pOp, BB_STATUS_SUCCESS);
}
}
}
}
return 0;
}
/*************************************************************************************************/
/*!
@ -629,18 +731,8 @@ SwitchInt:
goto Done;
}
/* End of the list, loop back to the head of the CIS. */
pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
pCigCtx->isLoopBack = TRUE;
pBle = &pCisCtx->bleData;
*pNewCisCtx = TRUE;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
/* Processing will continue in the lctrSlvCisCheckContOpPostCback() */
/* Only apply WW when rx success. */
if (isSuccess)
@ -715,40 +807,8 @@ SwitchInt:
return (offsetUsec - addDelayUsec);
}
if (pCigCtx->isLoopBack == FALSE)
{
lctrFtParam_t txFtParam, rxFtParam;
if (pCisCtx->bnSToM)
{
lctrCisInitFtParam(&txFtParam, pCisCtx->bnSToM, pCisCtx->ftSToM, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->txFtParamList, &txFtParam); /* Assume there is memory. */
}
if (pCisCtx->bnMToS)
{
lctrCisInitFtParam(&rxFtParam, pCisCtx->bnMToS, pCisCtx->ftMToS, pCisCtx->nse);
(void)lctrCisFtInsertTail(&pCisCtx->rxFtParamList, &rxFtParam); /* Assume there is memory. */
}
lctrSlvCisInitIsr(pCisCtx);
}
pBle = &pCisCtx->bleData;
*pNewCisCtx = TRUE;
/* Point to the next CIS. */
pOp->prot.pBle = pBle;
pCigCtx->pCisCtx = pCisCtx;
memcpy(&pBle->chan, &pCigCtx->pCisCtx->bleData.chan, sizeof(pBle->chan));
if (pCigCtx->isLoopBack == FALSE)
{
pBle->chan.chanIdx = pCigCtx->pCisCtx->chIdx; /* Set the next channel to the first channel in the next CIS. */
}
else
{
pBle->chan.chanIdx = pCisCtx->nextSubEvtChanIdx; /* Next subevent channel index is pre-calculated. */
}
/* Processing will continue in the lctrSlvCisCheckContOpPostCback() */
/* Only apply WW when rx success. */
if (isSuccess)
@ -770,6 +830,7 @@ Done:
pCigCtx->pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
pOp->prot.pBle = &pCigCtx->pCisCtx->bleData;
*pNewCisCtx = TRUE;
lctrCisClearCisDone(&pCigCtx->list);
return 0;
}
@ -805,19 +866,40 @@ void lctrSlvCisCigEndOp(BbOpDesc_t *pOp)
/* Re-sync to master's clock. */
pCigCtx->roleData.slv.anchorPointUsec = pCisCtx->data.slv.firstRxStartTsUsec;
pCigCtx->roleData.slv.lastActiveEvent = pCigCtx->roleData.slv.cigEvtCounter;
/* Reset ISR variables. */
pCisCtx->data.slv.syncWithMaster = FALSE;
}
while (pCisCtx)
{
/* Check for unframed flushed PDUs. */
if ((pCisCtx->framing == LL_ISO_PDU_TYPE_UNFRAMED) &&
(pCisCtx->isoalRxCtx.pduFlushed == TRUE))
{
pCisCtx->isoalRxCtx.pduFlushed = FALSE;
lctrCisCheckUnframedFlush(pCisCtx);
}
/* LL_CIS_TERMINATION case */
if ((pCisCtx->isClosing == TRUE) ||
(pConnCtx->enabled == FALSE) ||
(lctrResetEnabled == TRUE))
{
/* This variable set to TRUE means it is a CIS disconnect that requires an event generation. */
if (pCisCtx->isClosing == TRUE)
/* Notify host when terminate happens unless reset occurred. */
if (lctrResetEnabled == FALSE)
{
/* This was a host-initiated termination of the CIS. */
if (pConnCtx->enabled == FALSE)
{
pCisCtx->reason = pConnCtx->termReason;
}
/* If host initiates the termination, the reason code shall be HCI_ERR_LOCAL_TERMINATED in the disconnect complete event. */
else if (pCisCtx->hostInitTerm)
{
pCisCtx->reason = HCI_ERR_LOCAL_TERMINATED;
pCisCtx->hostInitTerm = FALSE;
}
lctrNotifyHostCisTerm(pCisCtx);
}
@ -934,6 +1016,21 @@ void lctrSlvCisCigEndOp(BbOpDesc_t *pOp)
}
}
if (pCisCtx->sduSizeSToM &&
(pCisCtx->dataPathInCtx.id == LL_ISO_DATA_PATH_VS))
{
uint8_t *pSduBuf;
if ((pSduBuf = WsfMsgAlloc(pLctrRtCfg->maxIsoSduLen + HCI_ISO_DL_MAX_LEN)) != NULL)
{
WSF_ASSERT(lctrCodecHdlr.inReq);
lctrCodecHdlr.inReq(pCisCtx->cisHandle, pSduBuf + HCI_ISO_HDR_LEN + HCI_ISO_DL_MAX_LEN, pCisCtx->sduSizeSToM);
}
else
{
LL_TRACE_WARN1("!!! Out of memory; dropping input SDU, handle=%u", pCisCtx->cisHandle);
}
}
/* Assemble framed data. */
if ((pCisCtx->framing == LL_ISO_PDU_TYPE_FRAMED) &&
pCisCtx->isoalTxCtx.pendQueueSize)
@ -997,8 +1094,11 @@ void lctrSlvCisCigEndOp(BbOpDesc_t *pOp)
/* Advance to next interval. */
pOp->dueUsec = pCigCtx->roleData.slv.anchorPointUsec + unsyncTimeUsec - wwTotalUsec;
pOp->minDurUsec = pCigCtx->cigSyncDelayUsec + wwTotalUsec;
pCigCtx->pCisCtx->bleData.op.slvCis.rxSyncDelayUsec = (wwTotalUsec << 1);
/* Use small minDurUsec to improve scheduling. */
pOp->minDurUsec = pCigCtx->list.pHead->pCisCtx->subIntervUsec + wwTotalUsec;
/* TODO: confirm extra rxTimeout time allocation. */
pCigCtx->pCisCtx->bleData.op.slvCis.rxSyncDelayUsec = (wwTotalUsec << 1) + 10;
if (pCigCtx->headCisRmved == TRUE)
{
@ -1016,7 +1116,6 @@ void lctrSlvCisCigEndOp(BbOpDesc_t *pOp)
LL_TRACE_WARN1("!!! CIG slave schedule conflict eventCounter=%u", pCisCtx->cisEvtCounter);
}
if (lmgrCb.sendIsoCmplEvt)
{
lctrNotifyHostIsoEventComplete(pCigCtx->cigHandle, (uint32_t) pCisCtx->cisEvtCounter);
@ -1034,9 +1133,11 @@ void lctrSlvCisCigAbortOp(BbOpDesc_t *pOp)
{
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
LL_TRACE_WARN1("!!! CIG Slave BOD aborted, cigHandle=%u", pCigCtx->cigHandle);
if (pCigCtx->numCisEsted > 0)
{
lctrCisCtx_t *pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
lctrCisCtx_t *pCisCtx = lctrCisGetHeadCis(&pCigCtx->list);
/* It is possible there is no CIS since it is aborting. */
while (pCisCtx)
@ -1078,7 +1179,10 @@ void lctrSlvCisCigTxCompletion(BbOpDesc_t *pOp, uint8_t status)
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
lctrCisCtx_t *pCisCtx = pCigCtx->pCisCtx;
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter++;
if (pCisCtx->txFtParamList.pHead != NULL)
{
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter++;
}
}
/*************************************************************************************************/
@ -1100,24 +1204,44 @@ void lctrSlvCisCigRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
pCisCtx->data.slv.rxStatus = status;
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter++;
pCisCtx->txFtParamList.pHead->ftParam.pduAcked = FALSE;
pCisCtx->rxFtParamList.pHead->ftParam.pduRcved = FALSE;
if (pCisCtx->rxFtParamList.pHead != NULL)
{
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter++;
pCisCtx->rxFtParamList.pHead->ftParam.pduRcved = FALSE;
}
if (pCisCtx->txFtParamList.pHead != NULL)
{
pCisCtx->txFtParamList.pHead->ftParam.pduAcked = FALSE;
}
pCisCtx->validRx = FALSE;
pCisCtx->txPduIsAcked = FALSE;
pCisCtx->pduFlushed = FALSE;
pCisCtx->isoalRxCtx.pduFlushed = FALSE;
/*** Cancellation processing ***/
/*** Cancelled processing ***/
if (status == BB_STATUS_CANCELED)
{
lctrCisRxPduFree(pRxBuf);
goto Done;
}
/*** CIS event pre-processing ***/
/* Add RSSI to average if monitoring power. */
if ((pConnCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pConnCtx->powerMonitorScheme == LCTR_PC_MONITOR_AUTO))
{
int8_t rssi = (status == LL_SUCCESS) ? pOp->prot.pBle->op.slvCis.rssi : 0x80;
/* Calculations handled on timer expiration for tmrPowerCtrl. */
/* Use a positive value to hold accumulated RSSI, as RSSI will never be positive. */
pConnCtx->cisAccumulatedRssi += (uint32_t) (-(rssi));
pConnCtx->cisTotalAccumulatedRssi++;
}
/* Save time stamp for the first Rx. */
if (pCisCtx->data.slv.firstRxFromMaster == TRUE)
{
@ -1141,25 +1265,45 @@ void lctrSlvCisCigRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
pCisCtx->data.slv.rxFromMaster = TRUE;
pCisCtx->data.slv.consCrcFailed = 0;
break;
case BB_STATUS_CRC_FAILED:
pCisCtx->isoLinkQualStats.crcErrPkt++;
/* Fallthrough */
case BB_STATUS_FAILED:
case BB_STATUS_RX_TIMEOUT:
LL_TRACE_WARN2("lctrSlvCisCigRxCompletion: BB failed with status=%u, handle=%u", status, pCisCtx->cisHandle);
LL_TRACE_WARN2("lctrSlvCisCigRxCompletion: BB failed with cisEvtCounter=%d, bleChan=%u", pCisCtx->cisEvtCounter, pCisCtx->bleData.chan.chanIdx);
case BB_STATUS_CRC_FAILED:
LL_TRACE_WARN3("lctrSlvCisCigRxCompletion: BB failed with status=CRC_FAILED, handle=%u, bleChan=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->bleData.chan.chanIdx, pCisCtx->cisEvtCounter);
pCisCtx->isoLinkQualStats.crcErrPkt++;
pCisCtx->validRx = FALSE;
pCisCtx->txPduIsAcked = FALSE;
goto SetupTx;
case BB_STATUS_RX_TIMEOUT:
LL_TRACE_WARN3("lctrSlvCisCigRxCompletion: BB failed with status=RX_TIMEOUT, handle=%u, bleChan=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->bleData.chan.chanIdx, pCisCtx->cisEvtCounter);
pCisCtx->validRx = FALSE;
pCisCtx->txPduIsAcked = FALSE;
lctrCisRxPduFree(pRxBuf);
goto Done;
case BB_STATUS_FAILED:
LL_TRACE_WARN3("lctrSlvCisCigRxCompletion: BB failed with status=FAILED, handle=%u, bleChan=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->bleData.chan.chanIdx, pCisCtx->cisEvtCounter);
pCisCtx->validRx = FALSE;
pCisCtx->txPduIsAcked = FALSE;
lctrCisRxPduFree(pRxBuf);
goto Done;
default:
break;
}
lctrCisUnpackDataPduHdr(&pCisCtx->rxHdr, pRxBuf);
/* Check for MIC failure and if this is not a re-transmission */
if ((status == BB_STATUS_MIC_FAILED) &&
((pCisCtx->rxHdr.sn ^ pCisCtx->txHdr.nesn) & 1) == 0)
{
LL_TRACE_WARN3("lctrSlvCisCigRxCompletion: BB failed with MIC_FAILED, handle=%u, rxPacketNum=%u, eventCounter=%u", pCisCtx->cisHandle, pCisCtx->rxPktCounter, pCisCtx->cisEvtCounter);
lctrSendCisMsg(pCisCtx, LCTR_CIS_MSG_CIS_TERM_MIC_FAILED);
lctrCisRxPduFree(pRxBuf);
BbSetBodTerminateFlag();
goto Done;
}
#if (LL_ENABLE_TESTER)
if ((llTesterCb.cisAckMode != LL_TESTER_ACK_MODE_NORMAL) ||
(llTesterCb.cisFwdPkt == TRUE))
@ -1187,6 +1331,7 @@ SetupTx:
/* Slave always transmits after receiving. */
lctrCisSetupForTx(pCigCtx, status, TRUE);
pCisCtx->data.slv.lastTxNull = pCisCtx->txHdr.np;
/* Tx post-processing. */
lctrCisProcessTxAckCleanup(pCisCtx);
@ -1194,28 +1339,17 @@ SetupTx:
/* Rx post-processing. */
lctrCisRxPostProcessing(pCisCtx, pRxBuf);
/* Check rssi value if power monitoring. */
if (pConnCtx->monitoringState == LCTR_PC_MONITOR_ENABLED)
{
lctrCisPowerMonitorCheckRssi(pOp->prot.pBle->op.slvCis.rssi,
status,
pCisCtx->phySToM +
(((pCisCtx->phySToM == LL_PHY_LE_CODED) &&
(pBle->chan.initTxPhyOptions == LL_PHY_OPTIONS_S2_PREFERRED)) ? 1 : 0),
pConnCtx);
}
return;
/*** ISR complete ***/
Done:
lctrCisCheckFtAfterRx(pCisCtx);
/* Tx post-processing. */
lctrCisProcessTxAckCleanup(pCisCtx);
pCisCtx->data.slv.lastTxNull = pCisCtx->isTxDone;
return;
lctrCisProcessTxAckCleanup(pCisCtx);
}
/*************************************************************************************************/

View File

@ -164,10 +164,11 @@ uint8_t *lctrProcessRxAck(lctrConnCtx_t *pCtx)
pCtx->txHdr.nesn++;
return NULL;
}
lctrIncPacketCounterRx(pCtx);
}
pCtx->txHdr.nesn++;
lctrIncPacketCounterRx(pCtx);
return pNextRxBuf;
}
@ -211,6 +212,12 @@ bool_t lctrProcessTxAck(lctrConnCtx_t *pCtx)
if (pCtx->txHdr.len) /* last packet from ARQ queue; zero length implies empty PDU */
{
if ((pCtx->txHdr.llid == LL_LLID_CTRL_PDU) &&
(pCtx->numTxPendCtrlPdu > 0))
{
pCtx->numTxPendCtrlPdu--;
}
/*** Peer ACK'ed a Data PDU ***/
lctrTxPduAck(pCtx);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -47,6 +47,8 @@ static struct
{
uint8_t consCrcFailed; /*!< Number of consecutive CRC failures. Used only by active operation. */
bool_t rxFromSlave; /*!< At least one packet received from slave. */
uint16_t numTxData; /*!< Number of Tx data PDU in a single CE. */
uint16_t numRxData; /*!< Number of Rx data PDU in a single CE. */
} lctrMstConnIsr;
/*! \brief Check BB meets data PDU requirements. */
@ -216,10 +218,12 @@ void lctrMstConnBeginOp(BbOpDesc_t *pOp)
pLctrVsHdlrs->ceSetup(LCTR_GET_CONN_HANDLE(pCtx));
}
/*** Initialize connection event resources. ***/
/*** Initialize connection event resources ***/
lctrMstConnIsr.consCrcFailed = 0;
lctrMstConnIsr.rxFromSlave = FALSE;
lctrMstConnIsr.numTxData = 0;
lctrMstConnIsr.numRxData = 0;
/*** Setup for transmit ***/
@ -295,6 +299,14 @@ void lctrMstConnEndOp(BbOpDesc_t *pOp)
lctrStoreConnTimeoutTerminateReason(pCtx);
WsfTimerStartMs(&pCtx->tmrSupTimeout, pCtx->supTimeoutMs);
if (!lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_FEAT_LLCP_STARTUP) &&
(pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->powerMonitorScheme == LCTR_PC_MONITOR_AUTO) &&
!lmgrGetOpFlag(LL_OP_MODE_FLAG_DIS_POWER_MONITOR))
{
WsfTimerStartMs(&pCtx->tmrPowerCtrl, LL_PC_SERVICE_MS);
}
pCtx->connEst = TRUE;
}
else if (lctrMstConnIsr.rxFromSlave)
@ -304,13 +316,34 @@ void lctrMstConnEndOp(BbOpDesc_t *pOp)
}
pCtx->rssi = pConn->rssi;
if ((pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->lastRxStatus == BB_STATUS_SUCCESS))
if ((pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED))
{
if (lctrPcActTbl[pCtx->powerMonitorScheme])
/* If a packet did not receive for whatever reason, add a datapoint with the lowest RSSI. */
if (pCtx->lastRxStatus != BB_STATUS_SUCCESS)
{
lctrPcActTbl[pCtx->powerMonitorScheme](pCtx);
pCtx->rssi = 0x80; /* Most negative 8 bit number. */
}
switch (pCtx->powerMonitorScheme)
{
case LCTR_PC_MONITOR_AUTO:
{
/* Calculations handled on timer expiration for tmrPowerCtrl. */
/* Use a positive value to hold accumulated RSSI, as RSSI will never be positive. */
pCtx->pclMonitorParam.autoMonitor.accumulatedRssi += (uint32_t) (-(pCtx->rssi));
pCtx->pclMonitorParam.autoMonitor.totalAccumulatedRssi++;
break;
}
case LCTR_PC_MONITOR_PATH_LOSS:
{
/* Power control monitoring being enabled implies that this function exists. */
lctrPathLossMonitorActFn(pCtx);
break;
}
default:
/* Should not happen. */
WSF_ASSERT(FALSE);
break;
}
}
@ -327,6 +360,17 @@ void lctrMstConnEndOp(BbOpDesc_t *pOp)
return;
}
/* Enhanced Connection Update. */
uint16_t numIntervals = 0;
if (lctrCalcSubrateConnEventsFn)
{
if ((numIntervals = lctrCalcSubrateConnEventsFn(pCtx, lctrMstConnIsr.numTxData + lctrMstConnIsr.numRxData)) > 0)
{
pCtx->eventCounter += numIntervals;
lctrChSelHdlr[pCtx->usedChSel](pCtx, numIntervals - 1);
}
}
if (pCtx->data.mst.sendConnUpdInd)
{
uint8_t *pPdu;
@ -344,8 +388,9 @@ void lctrMstConnEndOp(BbOpDesc_t *pOp)
else
#endif
{
ceOffset = LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency; /* ensure slave will listen this packet */
ceOffset = ((LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency) * /* ensure slave will listen to this packet */
pCtx->ecu.srFactor); /* include subrating factor */
/* TODO: accommodate pCtx->connParam.offset[]. */
}
@ -382,8 +427,7 @@ void lctrMstConnEndOp(BbOpDesc_t *pOp)
/*** Update for next operation ***/
uint32_t anchorPointUsec = pOp->dueUsec;
uint16_t numIntervals = 0;
uint32_t anchorPointUsec = pOp->dueUsec;
if (pBle->chan.tifsTxPhyOptions != BB_PHY_OPTIONS_DEFAULT)
{
@ -455,7 +499,7 @@ void lctrMstConnAbortOp(BbOpDesc_t *pOp)
{
lctrConnCtx_t * const pCtx = pOp->pCtx;
LL_TRACE_INFO2("!!! Connection Master BOD aborted, handle=%u, eventCounter=%u", LCTR_GET_CONN_HANDLE(pCtx), pCtx->eventCounter);
LL_TRACE_WARN2("!!! Connection Master BOD aborted, handle=%u, eventCounter=%u", LCTR_GET_CONN_HANDLE(pCtx), pCtx->eventCounter);
/* Reset operation to state before BOD began */
if (pCtx->emptyPduPend &&
@ -470,6 +514,9 @@ void lctrMstConnAbortOp(BbOpDesc_t *pOp)
return;
}
lctrMstConnIsr.consCrcFailed = 0;
lctrMstConnIsr.rxFromSlave = FALSE;
lctrMstConnEndOp(pOp);
}
@ -488,6 +535,11 @@ void lctrMstConnTxCompletion(BbOpDesc_t *pOp, uint8_t status)
lctrConnCtx_t * const pCtx = pOp->pCtx;
lctrSetControlPduAck(pCtx);
if (pCtx->txHdr.len)
{
lctrMstConnIsr.numTxData++;
}
}
}
@ -571,6 +623,23 @@ void lctrMstConnRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
lctrUnpackDataPduHdr(&pCtx->rxHdr, pRxBuf);
/* Check for MIC failure and if this is not a re-transmission */
if ((status == BB_STATUS_MIC_FAILED) &&
((pCtx->rxHdr.sn ^ pCtx->txHdr.nesn) & 1) == 0)
{
LL_TRACE_WARN3("lctrMstConnRxCompletion: BB failed with status=MIC_FAILED, eventCounter=%u, bleChan=%u, handle=%u", pCtx->eventCounter, pCtx->bleData.chan.chanIdx, LCTR_GET_CONN_HANDLE(pCtx));
lctrSendConnMsg(pCtx, LCTR_CONN_TERM_MIC_FAILED);
/* Close connection event. */
BbSetBodTerminateFlag();
lctrRxPduFree(pRxBuf);
goto Done;
}
if (pCtx->rxHdr.len)
{
lctrMstConnIsr.numRxData++;
}
#if (LL_ENABLE_TESTER)
if (llTesterCb.ackMode != LL_TESTER_ACK_MODE_NORMAL)
{

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -46,6 +46,13 @@
WSF_CT_ASSERT((BB_FIXED_DATA_PKT_LEN == 0) ||
(BB_FIXED_DATA_PKT_LEN >= LCTR_DATA_PDU_MAX_LEN));
/*! \brief Slave connection ISR control block. */
static struct
{
uint16_t numTxData; /*!< Number of Tx data PDU in a single CE. */
uint16_t numRxData; /*!< Number of Rx data PDU in a single CE. */
} lctrSlvConnIsr;
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
@ -160,7 +167,7 @@ static void lctrSlvConnUpdateOp(lctrConnCtx_t *pCtx, bool_t ignoreOffset)
pCtx->data.slv.txWinSizeUsec = txWinSizeUsec;
/* Add additional time due to Tx window size and WW due to Tx window offset. */
pOp->minDurUsec += txWinSizeUsec + wwTxWinOffsetUsec;
pOp->minDurUsec += wwTxWinOffsetUsec;
/*** BLE general setup ***/
@ -280,6 +287,25 @@ static void lctrSlvInitConnIsr(lctrConnCtx_t *pCtx)
pCtx->data.slv.syncWithMaster = FALSE;
pCtx->data.slv.rxFromMaster = FALSE;
pCtx->data.slv.firstRxStartTsUsec = 0;
lctrSlvConnIsr.numTxData = 0;
lctrSlvConnIsr.numRxData = 0;
}
/*************************************************************************************************/
/*!
* \brief Pack a channel status message.
*
* \param pBuf Packed buffer.
*/
/*************************************************************************************************/
static void lctrPackChannelStatusMsg(uint8_t *pBuf)
{
unsigned int i;
for (i = 0; i < LL_MAX_NUM_CHAN_DATA; i++)
{
UINT8_TO_BSTREAM(pBuf, (((UINT64_C(1) << i) & lmgrCb.chanClass) ? LL_CH_CLASS_UNKNOWN : LL_CH_CLASS_BAD));
}
}
/*************************************************************************************************/
@ -308,7 +334,8 @@ void lctrSlvConnBeginOp(BbOpDesc_t *pOp)
pLctrVsHdlrs->ceSetup(LCTR_GET_CONN_HANDLE(pCtx));
}
/*** Initialize connection event resources. ***/
/*** Initialize connection event resources ***/
lctrSlvInitConnIsr(pCtx);
/*** Setup receiver ***/
@ -364,13 +391,35 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
}
pCtx->rssi = pConn->rssi;
if ((pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->lastRxStatus == BB_STATUS_SUCCESS))
if (pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED)
{
if (lctrPcActTbl[pCtx->powerMonitorScheme])
/* If a packet did not receive for whatever reason, add a datapoint with the lowest RSSI. */
if (pCtx->lastRxStatus != BB_STATUS_SUCCESS)
{
lctrPcActTbl[pCtx->powerMonitorScheme](pCtx);
pCtx->rssi = 0x80; /* Most negative 8 bit number. */
}
switch (pCtx->powerMonitorScheme)
{
case LCTR_PC_MONITOR_AUTO:
{
/* Calculations handled on timer expiration for tmrPowerCtrl. */
/* Use a positive value to hold accumulated RSSI, as RSSI will never be positive. */
pCtx->pclMonitorParam.autoMonitor.accumulatedRssi += (uint32_t) (-(pCtx->rssi));
pCtx->pclMonitorParam.autoMonitor.totalAccumulatedRssi++;
break;
}
case LCTR_PC_MONITOR_PATH_LOSS:
{
/* Power control monitoring being enabled implies that this function exists. */
lctrPathLossMonitorActFn(pCtx);
break;
}
default:
/* Should not happen. */
WSF_ASSERT(FALSE);
break;
}
}
@ -393,6 +442,14 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
lctrStoreConnTimeoutTerminateReason(pCtx);
WsfTimerStartMs(&pCtx->tmrSupTimeout, pCtx->supTimeoutMs);
if (!lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_FEAT_LLCP_STARTUP) &&
(pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->powerMonitorScheme == LCTR_PC_MONITOR_AUTO) &&
!lmgrGetOpFlag(LL_OP_MODE_FLAG_DIS_POWER_MONITOR))
{
WsfTimerStartMs(&pCtx->tmrPowerCtrl, LL_PC_SERVICE_MS);
}
pCtx->connEst = TRUE;
}
else if (pCtx->data.slv.rxFromMaster)
@ -447,8 +504,7 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
}
}
/* Slave received connection update on the instant. */
/* Immediately use that packet as the new anchor point and do not apply txWinOffset and txWinSize. */
/* Check if channel status update is required. */
if ((pCtx->llcpActiveProc == LCTR_PROC_CONN_UPD) && lctrSlvCheckConnUpdInstant(pCtx) &&
(pCtx->eventCounter == pCtx->connUpd.instant))
{
@ -456,32 +512,68 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
LL_TRACE_WARN1("Received connection update at instant, applying immediately at CE=%d", pCtx->eventCounter);
}
/* If the channel map has changed since the last time, */
/* Send master the status indication. */
if (pCtx->chanStatRptEnable && pCtx->data.slv.queuedChanStatusTs &&
(BbGetTargetTimeDelta(pOp->dueUsec, pCtx->data.slv.lastStatusSentTs) > pCtx->data.slv.chanStatMinIntUs))
{
/* Make sure that the report has not passed the max delay parameter. */
if (BbGetTargetTimeDelta(pOp->dueUsec, pCtx->data.slv.queuedChanStatusTs) < pCtx->data.slv.chanStatMaxDelay)
{
pCtx->data.slv.lastStatusSentTs = pOp->dueUsec;
lctrMsgChStatusInd_t *pMsg;
if ((pMsg = (lctrMsgChStatusInd_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = LCTR_GET_CONN_HANDLE(pCtx);
pMsg->hdr.dispId = LCTR_DISP_CONN;
pMsg->hdr.event = LCTR_CONN_LLCP_CHANNEL_STATUS;
lctrPackChannelStatusMsg(pMsg->chanStatus);
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
}
}
/* Reset the timestamp to signal that there is no pending status report. */
pCtx->data.slv.queuedChanStatusTs = 0;
}
/*** Update for next operation ***/
uint16_t numUnsyncIntervals = pCtx->eventCounter - pCtx->data.slv.lastActiveEvent + 1;
uint16_t numSkipCe = 0;
uint16_t numSkipSr = 0;
uint16_t srLatency = pCtx->maxLatency;
/* Enhanced Connection Update. */
if (lctrCalcSubrateConnEventsFn)
{
numSkipSr = lctrCalcSubrateConnEventsFn(pCtx, lctrSlvConnIsr.numTxData + lctrSlvConnIsr.numRxData);
srLatency = (pCtx->maxLatency * pCtx->ecu.srFactor) + numSkipSr;
}
if ((pCtx->data.slv.abortSlvLatency == FALSE) &&
lctrGetConnOpFlag(pCtx, LL_OP_MODE_FLAG_ENA_SLV_LATENCY) &&
(pCtx->maxLatency &&
pCtx->data.slv.initAckRcvd &&
pCtx->data.slv.rxFromMaster &&
(WsfQueueEmpty(&pCtx->txArqQ)) &&
(pCtx->state != LCTR_CONN_STATE_TERMINATING)))
pCtx->maxLatency &&
pCtx->data.slv.initAckRcvd &&
pCtx->data.slv.rxFromMaster &&
WsfQueueEmpty(&pCtx->txArqQ) &&
(pCtx->state != LCTR_CONN_STATE_TERMINATING))
{
if (pCtx->llcpActiveProc == LCTR_PROC_INVALID)
{
numSkipCe = pCtx->maxLatency;
numSkipCe = srLatency;
}
else
{
/* Still apply the slave latency if the instant is not reached for the following LLCPs. */
if ((pCtx->llcpActiveProc == LCTR_PROC_CONN_UPD) && lctrSlvCheckConnUpdInstant(pCtx))
{
if ((uint16_t)(pCtx->connUpd.instant - pCtx->eventCounter) > (pCtx->maxLatency + 1))
if ((uint16_t)(pCtx->connUpd.instant - pCtx->eventCounter) > (srLatency + 1))
{
numSkipCe = pCtx->maxLatency;
numSkipCe = srLatency;
}
else if ((pCtx->connUpd.instant - pCtx->eventCounter) > 1)
{
@ -492,9 +584,9 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
else if ((pCtx->llcpActiveProc == LCTR_PROC_CMN_CH_MAP_UPD) &&
(pCtx->cmnState == LCTR_CMN_STATE_BUSY))
{
if ((uint16_t)(pCtx->chanMapUpd.instant - pCtx->eventCounter) > (pCtx->maxLatency + 1))
if ((uint16_t)(pCtx->chanMapUpd.instant - pCtx->eventCounter) > (srLatency + 1))
{
numSkipCe = pCtx->maxLatency;
numSkipCe = srLatency;
}
else if ((pCtx->chanMapUpd.instant - pCtx->eventCounter) > 1)
{
@ -504,9 +596,9 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
}
else if ((pCtx->llcpActiveProc == LCTR_PROC_PHY_UPD) && (pCtx->isSlvPhyUpdInstant == TRUE))
{
if ((uint16_t)(pCtx->phyUpd.instant - pCtx->eventCounter) > (pCtx->maxLatency + 1))
if ((uint16_t)(pCtx->phyUpd.instant - pCtx->eventCounter) > (srLatency + 1))
{
numSkipCe = pCtx->maxLatency;
numSkipCe = srLatency;
}
else if ((pCtx->phyUpd.instant - pCtx->eventCounter) > 1)
{
@ -516,15 +608,23 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
}
}
}
else
{
/* No slave latency; listen at the next subrated connection events. */
numSkipCe = numSkipSr;
}
if (numSkipCe > 0)
{
if (numSkipCe > numSkipSr)
{
LL_TRACE_INFO2("Applying slave latency, last attended eventCounter=%u, wake up at eventCounter=%u", pCtx->eventCounter, pCtx->eventCounter + numSkipCe + 1);
}
pCtx->eventCounter += numSkipCe;
numUnsyncIntervals += numSkipCe;
lctrChSelHdlr[pCtx->usedChSel](pCtx, numSkipCe - 1);
LL_TRACE_INFO2("Applying slave latency, waking up at eventCounter=%u, numSkipCE=%u", pCtx->eventCounter + 1, numSkipCe);
}
while (TRUE)
@ -551,7 +651,9 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
/* Advance to next interval. */
pOp->dueUsec = pCtx->data.slv.anchorPointUsec + connInterUsec - wwTotalUsec;
pOp->minDurUsec = pCtx->data.slv.txWinSizeUsec + pCtx->effConnDurUsec + wwTotalUsec;
/* Use small minDurUsec to improve scheduling. */
pOp->minDurUsec = pCtx->data.slv.txWinSizeUsec + (2 * LL_MAX_DATA_TIME_MIN) + LL_BLE_TIFS_US + wwTotalUsec;
pConn->rxSyncDelayUsec = pCtx->data.slv.txWinSizeUsec + (wwTotalUsec << 1);
if ((pCtx->llcpActiveProc == LCTR_PROC_CONN_UPD) &&
@ -568,12 +670,12 @@ void lctrSlvConnEndOp(BbOpDesc_t *pOp)
lctrSlvConnUpdateOp(pCtx, FALSE);
}
else if ((pCtx->llcpActiveProc == LCTR_PROC_CMN_CH_MAP_UPD) &&
(pCtx->eventCounter == pCtx->chanMapUpd.instant))
(pCtx->eventCounter == pCtx->chanMapUpd.instant))
{
lctrSlvChanMapUpdateOp(pCtx);
}
else if ((pCtx->llcpActiveProc == LCTR_PROC_PHY_UPD) &&
(pCtx->eventCounter == pCtx->phyUpd.instant))
(pCtx->eventCounter == pCtx->phyUpd.instant))
{
lctrSlvPhyUpdateOp(pCtx);
}
@ -620,6 +722,8 @@ void lctrSlvConnAbortOp(BbOpDesc_t *pOp)
{
lctrConnCtx_t * const pCtx = pOp->pCtx;
LL_TRACE_WARN2("!!! Connection Slave BOD aborted, handle=%u, eventCounter=%u", LCTR_GET_CONN_HANDLE(pCtx), pCtx->eventCounter);
lctrSlvInitConnIsr(pCtx);
lctrSlvConnEndOp(pOp);
}
@ -639,6 +743,11 @@ void lctrSlvConnTxCompletion(BbOpDesc_t *pOp, uint8_t status)
lctrConnCtx_t * const pCtx = pOp->pCtx;
lctrSetControlPduAck(pCtx);
if (pCtx->txHdr.len)
{
lctrSlvConnIsr.numTxData++;
}
}
}
@ -693,12 +802,12 @@ void lctrSlvConnRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
{
if (status == BB_STATUS_RX_TIMEOUT)
{
LL_TRACE_WARN3("lctrSlvConnRxCompletion: BB failed with status=RX_TIMEOUT, handle=%u, bleChan=%u, eventCounter=%u", LCTR_GET_CONN_HANDLE(pCtx), pBle->chan.chanIdx, pCtx->eventCounter);
LL_TRACE_WARN3("lctrSlvConnRxCompletion: BB failed with status=RX_TIMEOUT, eventCounter=%u, bleChan=%u, handle=%u", pCtx->eventCounter, pCtx->bleData.chan.chanIdx, LCTR_GET_CONN_HANDLE(pCtx));
}
if (status == BB_STATUS_FAILED)
{
LL_TRACE_ERR3("lctrSlvConnRxCompletion: BB failed with status=FAILED, handle=%u, bleChan=%u, eventCounter=%u", LCTR_GET_CONN_HANDLE(pCtx), pBle->chan.chanIdx, pCtx->eventCounter);
LL_TRACE_ERR3("lctrSlvConnRxCompletion: BB failed with status=FAILED, eventCounter=%u, bleChan=%u, handle=%u", pCtx->eventCounter, pCtx->bleData.chan.chanIdx, LCTR_GET_CONN_HANDLE(pCtx));
}
BbSetBodTerminateFlag();
@ -741,6 +850,23 @@ void lctrSlvConnRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status)
lctrUnpackDataPduHdr(&pCtx->rxHdr, pRxBuf);
/* Check for MIC failure and if this is not a re-transmission */
if ((status == BB_STATUS_MIC_FAILED) &&
((pCtx->rxHdr.sn ^ pCtx->txHdr.nesn) & 1) == 0)
{
LL_TRACE_WARN3("lctrSlvConnRxCompletion: BB failed with status=MIC_FAILED, eventCounter=%u, bleChan=%u, handle=%u", pCtx->eventCounter, pCtx->bleData.chan.chanIdx, LCTR_GET_CONN_HANDLE(pCtx));
lctrSendConnMsg(pCtx, LCTR_CONN_TERM_MIC_FAILED);
/* Close connection event. */
BbSetBodTerminateFlag();
lctrRxPduFree(pRxBuf);
goto Done;
}
if (pCtx->rxHdr.len)
{
lctrSlvConnIsr.numRxData++;
}
/* Check LLID from master. */
if ((pCtx->isSlvReadySent == FALSE) &&
(pCtx->rxHdr.llid != LL_LLID_CTRL_PDU) &&

View File

@ -414,6 +414,16 @@ void lctrRegisterChClassHandler(lctrChClassHdlr_t cback)
{
/* Ensure registration does not exceed limits. */
WSF_ASSERT(lctrChClassHandlerCnt < LCTR_NUM_CH_CLASS_HANDLERS);
/* If callback is already registered, do nothing. */
for (unsigned int i = 0; i < lctrChClassHandlerCnt; i++)
{
if (lctrChClassHandlerTbl[0] == cback)
{
return;
}
}
lctrChClassHandlerTbl[lctrChClassHandlerCnt++] = cback;
}
@ -451,3 +461,42 @@ uint8_t LctrSetChannelClass(uint64_t chanMap)
return result;
}
/*************************************************************************************************/
/*!
* \brief Get average RSSI of an averaging unit.
*
* \param pAvg Average block
*
* \return Average block average.
*/
/*************************************************************************************************/
int8_t lctrRssiGetAverage(lctrRssiRunAvg_t *pAvg)
{
WSF_ASSERT(pAvg->avgCount >= LL_PC_TBL_LEN);
int32_t total = 0;
for (int i = 0; i < LL_PC_TBL_LEN; i++)
{
total += (int32_t) pAvg->averageRssi[i];
}
return (int8_t) (total >> LL_PC_TBL_POW);
}
/*************************************************************************************************/
/*!
* \brief Add a value to the average block.
*
* \param pAvg Average block
* \param value Value to add
*
* \note oldest value will be overwritten.
*/
/*************************************************************************************************/
void lctrRssiAddAveragePoint(lctrRssiRunAvg_t *pAvg, int8_t value)
{
pAvg->averageRssi[pAvg->rssiIdx] = value;
pAvg->rssiIdx = ((pAvg->rssiIdx + 1) == LL_PC_TBL_LEN) ? 0 : (pAvg->rssiIdx + 1);
pAvg->avgCount++;
}

View File

@ -275,6 +275,7 @@ void lctrMstDiscoverBuildOp(void)
pOp->pCtx = &lctrMstScan;
pOp->endCback = lctrMstDiscoverEndOp;
pOp->abortCback = lctrMstDiscoverEndOp;
pOp->recoverable = TRUE;
/*** BLE General Setup ***/
@ -415,6 +416,9 @@ void lctrMstDiscoverBuildOp(void)
SchInsertNextAvailable(pOp);
lctrMstScan.scanWinStartUsec = pOp->dueUsec;
LL_TRACE_INFO1(" >>> Discover started, dueUsec=%u <<<", pOp->dueUsec);
LL_TRACE_INFO1(" pBod=0x%08x", pOp);
}
@ -740,13 +744,13 @@ void LctrMstScanDefaults(void)
/*************************************************************************************************/
void lctrAdvReportsInc(void)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_ASSERT(lmgrMstScanCb.numAdvReport < pLctrRtCfg->maxAdvReports);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrMstScanCb.numAdvReport++;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/
@ -756,13 +760,13 @@ void lctrAdvReportsInc(void)
/*************************************************************************************************/
void lctrAdvReportsDec(void)
{
WSF_CS_INIT();
WSF_CS_INIT(cs);
WSF_ASSERT(lmgrMstScanCb.numAdvReport > 0);
WSF_CS_ENTER();
WSF_CS_ENTER(cs);
lmgrMstScanCb.numAdvReport--;
WSF_CS_EXIT();
WSF_CS_EXIT(cs);
}
/*************************************************************************************************/

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -437,6 +437,7 @@ uint8_t lctrMstExtDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx)
pOp->endCback = lctrMstExtDiscoverEndOp;
pOp->abortCback = lctrMstExtDiscoverAbortOp;
pOp->pCtx = pExtScanCtx;
pOp->recoverable = TRUE;
/*** BLE General Setup ***/
@ -486,6 +487,9 @@ uint8_t lctrMstExtDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx)
pScan->rxAdvCback = lctrMstDiscoverRxExtAdvPktHandler;
pScan->rxAdvPostCback = lctrMstDiscoverRxExtAdvPktPostProcessHandler;
pScan->auxScanCheckCback = lctrMstLinkAuxOffsetScanSetup;
pScan->auxScanTxCompCback = BbMstAuxScanTxCompHandler;
pScan->auxScanRxCompCback = BbMstAuxScanRxCompHandler;
if ((pScan->pRxAdvBuf = WsfMsgAlloc(LL_ADV_HDR_LEN + LL_EXT_ADV_HDR_MAX_LEN)) == NULL)
{
@ -607,6 +611,10 @@ uint8_t lctrMstExtDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx)
lctrActiveExtScan.scanMask |= (1 << scanPhyIndex);
LL_TRACE_INFO1(" >>> ExtDiscover started, handle=%u <<<", LCTR_GET_EXT_SCAN_HANDLE(pExtScanCtx));
LL_TRACE_INFO1(" dueUsec=%u, 0=deferred", pOp->dueUsec);
LL_TRACE_INFO1(" pBod=0x%08x", pOp);
return LL_SUCCESS;
}
@ -673,6 +681,7 @@ uint8_t lctrMstAuxDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx)
pAuxScan->isInit = FALSE;
pAuxScan->rxAuxAdvCback = lctrMstDiscoverRxAuxAdvPktHandler;
pAuxScan->rxAuxAdvPostCback = lctrMstDiscoverRxAuxAdvPktPostProcessHandler;
/*** BLE Scan Setup: Tx scan request packet ***/
@ -731,7 +740,7 @@ uint8_t lctrMstAuxDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx)
/*** Commit operation ***/
/* pOp->minDurUsec = 0; */ /* Defer assignment until AuxPtr is received. */
/* pOp->minDurUsec = 0; */ /* Defer assignment until AuxPtr is received, lctrMstAuxDiscoverOpCommit(). */
/* pOp->maxDurUsec = 0; */ /* Not used for aux scan. */
pExtScanCtx->selfTerm = FALSE;
@ -740,6 +749,8 @@ uint8_t lctrMstAuxDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx)
/* Defer scheduling until AuxPtr is received. */
LL_TRACE_INFO1(" >>> AuxDiscover ready, pBod=0x%08x <<<", pOp);
return LL_SUCCESS;
}
@ -783,7 +794,12 @@ void lctrMstAuxDiscoverOpCommit(lctrExtScanCtx_t *pExtScanCtx, lctrAuxPtr_t *pAu
pOp->dueUsec = startTs + auxOffsetUsec;
SchBleCalcAdvOpDuration(pOp, 0);
if (SchInsertAtDueTime(pOp, NULL))
if (auxOffsetUsec < BbGetSchSetupDelayUs())
{
/* Signal the lower layer to start Aux Scan ASAP, since the auxOffset is too small to run the scheduler. */
pExtScanCtx->scheduleAuxAsap = TRUE;
}
else if (SchInsertAtDueTime(pOp, NULL))
{
pExtScanCtx->auxOpPending = TRUE;
}
@ -879,7 +895,7 @@ void LctrMstExtScanDefaults(void)
uint16_t LctrInitExtScanMem(uint8_t *pFreeMem, uint32_t freeMemSize)
{
/* Extended Scanning requires receiving at least 251 bytes. */
WSF_ASSERT(pLctrRtCfg->maxExtScanDataLen >= LL_EXT_ADVBU_MAX_LEN);
WSF_ASSERT(pLctrRtCfg->maxExtScanDataLen >= WSF_MIN(LL_EXT_ADVBU_MAX_LEN, BB_ADV_PLD_MAX_LEN));
uint8_t *pAvailMem = pFreeMem;
@ -1307,7 +1323,7 @@ void lctrMstPerScanOpCommit(lctrExtScanCtx_t *pExtScanCtx, lctrAuxPtr_t *pAuxPtr
pOp->dueUsec = startTs + syncOffsetUsec;
/* Ensure minimum packet is scheduled; allow PerAdv to schedule tight operations. */
pPerScanCtx->minDurUsec = pOp->minDurUsec = SchBleCalcAdvPktDurationUsec(pBle->chan.rxPhy, BB_PHY_OPTIONS_DEFAULT, LL_ADVB_MIN_LEN);
pPerScanCtx->minDurUsec = pOp->minDurUsec = SchBleCalcAdvPktDurationUsec(pBle->chan.rxPhy, BB_PHY_OPTIONS_DEFAULT, LL_EXT_ADV_HDR_MIN_LEN);
uint16_t numUnsyncIntervals = 0;
while (TRUE)
@ -1315,7 +1331,6 @@ void lctrMstPerScanOpCommit(lctrExtScanCtx_t *pExtScanCtx, lctrAuxPtr_t *pAuxPtr
if (SchInsertAtDueTime(pOp, lctrPerScanResolveConflict))
{
LL_TRACE_INFO1(" >>> Periodic scan started, handle=%u <<<", LCTR_GET_PER_SCAN_HANDLE(pPerScanCtx));
LL_TRACE_INFO1(" pOp=%08x", pOp);
LL_TRACE_INFO1(" dueUsec=%u", pOp->dueUsec);
LL_TRACE_INFO1(" eventCounter=%u", pPerScanCtx->eventCounter);
LL_TRACE_INFO1(" chanIdx=%u", pBle->chan.chanIdx);
@ -1360,7 +1375,7 @@ void lctrMstPerScanTransferOpCommit(uint16_t connHandle)
uint32_t refTime;
uint16_t peC; /* paEventCounter for the AUX_SYNC_IND PDU that we are attempting to receive. */
uint32_t startTs; /* Anchor point of the connection event. */
uint16_t numInterval;
uint32_t numInterval;
/* Pre-resolve common structures for efficient access. */
lctrPerScanCtx_t *pPerScanCtx = lctrPerTransferSync.pPerScanCtx;
@ -1373,6 +1388,12 @@ void lctrMstPerScanTransferOpCommit(uint16_t connHandle)
pPerScanCtx->repDisabled = TRUE;
}
if (pConnCtx->syncMode == LL_SYNC_TRSF_MODE_DUP_FILTERED)
{
pPerScanCtx->dupFilterEnable = TRUE;
pPerScanCtx->lastDid = LL_DID_NOT_PRESENT;
}
pPerScanCtx->syncTimeOutMs = LCTR_PER_SYNC_TIMEOUT_TO_MS(pConnCtx->syncTimeout);
pPerScanCtx->skip = pConnCtx->syncSkip;
pPerScanCtx->sca = trsfSyncInfo.sca;
@ -1409,16 +1430,16 @@ void lctrMstPerScanTransferOpCommit(uint16_t connHandle)
startTs = lctrConnGetAnchorPoint(pConnCtx, pConnCtx->eventCounter);
peC = trsfSyncInfo.eventCounter;
if (BbGetTargetTimeDelta(refTime, startTs + pConnOp->minDurUsec) > 0)
if ((uint16_t)(lctrPerTransferSync.ceRef - pConnCtx->eventCounter) < (uint16_t)LCTR_MAX_INSTANT) /* ceCounter is in the future. */
{
numInterval = BbGetTargetTimeDelta(refTime, startTs + pConnOp->minDurUsec) / pPerScanCtx->perInterUsec;
numInterval = ((uint16_t)(lctrPerTransferSync.ceRef - pConnCtx->eventCounter) * LCTR_CONN_IND_US(pConnCtx->connInterval) + pConnOp->minDurUsec) / pPerScanCtx->perInterUsec;
refTime -= numInterval * pPerScanCtx->perInterUsec;
peC -= numInterval;
offsetUsec = BbGetTargetTimeDelta(refTime , startTs);
}
else /* refTime is in the past. */
{
numInterval = 1 + BbGetTargetTimeDelta(startTs + pConnOp->minDurUsec, refTime)/ pPerScanCtx->perInterUsec;
numInterval = 1 + ((uint16_t)(pConnCtx->eventCounter - lctrPerTransferSync.ceRef) * LCTR_CONN_IND_US(pConnCtx->connInterval) + pConnOp->minDurUsec) / pPerScanCtx->perInterUsec;
refTime += numInterval * pPerScanCtx->perInterUsec;
peC += numInterval;
offsetUsec = BbGetTargetTimeDelta(refTime , startTs);
@ -1463,7 +1484,6 @@ void lctrMstPerScanTransferOpCommit(uint16_t connHandle)
if (SchInsertAtDueTime(pOp, lctrPerScanResolveConflict))
{
LL_TRACE_INFO1(" >>> Periodic scan from transfer started, handle=%u <<<", LCTR_GET_PER_SCAN_HANDLE(pPerScanCtx));
LL_TRACE_INFO1(" pOp=%08x", pOp);
LL_TRACE_INFO1(" dueUsec=%u", pOp->dueUsec);
LL_TRACE_INFO1(" eventCounter=%u", pPerScanCtx->eventCounter);
LL_TRACE_INFO1(" pBle->chan.chanIdx=%u", pBle->chan.chanIdx);
@ -1568,6 +1588,9 @@ lctrPerScanCtx_t *lctrAllocPerScanCtx(void)
/* Default PHY. */
pCtx->rxPhys = lmgrConnCb.rxPhys;
/* ADI filtering. */
pCtx->lastDid = LL_DID_NOT_PRESENT;
return pCtx;
}
}
@ -1602,8 +1625,6 @@ BbOpDesc_t *lctrPerScanResolveConflict(BbOpDesc_t *pNewOp, BbOpDesc_t *pExistOp)
}
/* Supervision timeout is imminent (2 PI). */
LL_TRACE_WARN2("Exit timeout=%u, interval=%u", pExistCtx->tmrSupTimeout.ticks * WSF_MS_PER_TICK * 1000, (uint32_t)(pExistCtx->perInterUsec << 1));
LL_TRACE_WARN2("New timeout=%u, interval=%u", pNewCtx->tmrSupTimeout.ticks * WSF_MS_PER_TICK * 1000, (uint32_t)(pExistCtx->perInterUsec << 1));
if ((pExistCtx->tmrSupTimeout.ticks * WSF_MS_PER_TICK * 1000) < (uint32_t)(pExistCtx->perInterUsec << 1))
{
LL_TRACE_WARN2("!!! Scheduling conflict, imminent SVT: existing handle=%u prioritized over incoming handle=%u", LCTR_GET_PER_SCAN_HANDLE(pExistCtx), LCTR_GET_PER_SCAN_HANDLE(pNewCtx));
@ -1617,7 +1638,6 @@ BbOpDesc_t *lctrPerScanResolveConflict(BbOpDesc_t *pNewOp, BbOpDesc_t *pExistOp)
}
/* Less frequent perInterval (4x). */
if ((LCTR_PER_INTER_TO_MS(pExistCtx->perInterUsec) >> 2) > LCTR_PER_INTER_TO_MS(pNewCtx->perInterUsec))
{
LL_TRACE_WARN2("!!! Scheduling conflict, PI frequency: existing handle=%u prioritized over incoming handle=%u", LCTR_GET_PER_SCAN_HANDLE(pExistCtx), LCTR_GET_PER_SCAN_HANDLE(pNewCtx));
@ -1698,13 +1718,17 @@ void LctrSendPerSyncTrsfRcvdEvt(uint8_t status, lctrPerScanCtx_t *pPerScanCtx)
* \brief Enable or disable reports for the periodic advertising sync.
*
* \param syncHandle Periodic sync handle.
* \param enable Enable or disable reporting.
* \param enable Enable options.
*/
/*************************************************************************************************/
void LctrMstPerSetRcvEnable(uint16_t syncHandle, bool_t enable)
void LctrMstPerSetRcvEnable(uint16_t syncHandle, uint8_t enable)
{
WSF_ASSERT(syncHandle < LL_MAX_PER_SCAN);
lctrPerScanCtx_t *pPerScanCtx = LCTR_GET_PER_SCAN_CTX(syncHandle);
pPerScanCtx->repDisabled = !enable;
pPerScanCtx->repDisabled = !((bool_t) ((enable >> LCTR_PER_RECV_ENABLE_REPORT_BIT_POS) & 1));
if (!pPerScanCtx->repDisabled)
{
pPerScanCtx->dupFilterEnable = (bool_t) ((enable >> LCTR_PER_RECV_ENABLE_FILTERING_BIT_POS) & 1);
}
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -190,16 +190,18 @@ void lctrChooseAdvA(BbBleData_t * const pBle, lctrAdvbPduHdr_t *pPduHdr,
void lctrChoosePeerAddr(BbBleData_t * const pBle, uint8_t ownAddrType,
uint8_t peerAddrType, uint64_t peerAddr, uint64_t *pPeerRpa)
{
/* Attempt to generate RPA for peer. */
BbBleResListGeneratePeer(peerAddrType, peerAddr, pPeerRpa);
/* Resolve peer RPAs whether or not a RPA was generated for peer, unless address resolution is disabled. */
if (lmgrCb.addrResEna)
{
/* Attempt to generate RPA for peer. */
if (ownAddrType & LL_ADDR_IDENTITY_BIT)
{
BbBleResListGeneratePeer(peerAddrType, peerAddr, pPeerRpa);
}
/* Resolve peer RPAs whether or not a RPA was generated for peer. */
BB_BLE_PDU_FILT_SET_FLAG(&pBle->pduFilt, PEER_ADDR_RES_ENA);
}
else
{
BB_BLE_PDU_FILT_CLR_FLAG(&pBle->pduFilt, PEER_ADDR_RES_ENA);
}
}
/*************************************************************************************************/

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -451,57 +451,23 @@ static uint8_t lctrSetExtAdvDataSm(lctrAdvSet_t *pAdvSet, lctrAdvDataBuf_t *pDat
/*** Complete single fragment buffer (no reassembly required) while advertising is enabled. ***/
if (pAdvSet->state == LCTR_EXT_ADV_STATE_ENABLED)
{
bool_t isCancelled = FALSE;
/* BOD's are already running. Data will be updated in the end callback of the BOD's. */
pDataBuf->alt.ext.len = fragLen;
memcpy(pDataBuf->alt.ext.buf, pFragBuf, fragLen);
pDataBuf->alt.ext.did = lctrCalcDID(pFragBuf, fragLen);
pDataBuf->alt.ext.fragPref = fragPref;
pDataBuf->alt.ext.modified = TRUE;
WSF_CS_ENTER();
/* Renew BOD's to make the data updated immediately if possible. */
if (SchIsBodCancellable(&pAdvSet->advBod) &&
((pAdvSet->auxBodUsed == FALSE) || SchIsBodCancellable(&pAdvSet->auxAdvBod)))
{
/* Temporarily disable abort callbacks. */
pAdvSet->advBod.abortCback = NULL;
pAdvSet->auxAdvBod.abortCback = NULL;
/* Remove BOD's */
SchRemove(&pAdvSet->advBod);
/* Remove BOD's; remove completes in abortCback(). */
if (pAdvSet->auxBodUsed)
{
SchRemove(&pAdvSet->auxAdvBod);
}
isCancelled = TRUE;
}
WSF_CS_EXIT();
if (isCancelled)
{
pAdvSet->advData.len = fragLen;
memcpy(pAdvSet->advData.pBuf, pFragBuf, fragLen);
pAdvSet->param.advDID = lctrCalcDID(pFragBuf, fragLen);
pAdvSet->advData.fragPref = fragPref;
/* Update superior PDU. */
BbBleSlvAdvEvent_t * const pAdv = &pAdvSet->bleData.op.slvAdv;
pAdv->txAdvLen = lctrPackAdvExtIndPdu(pAdvSet, pAdvSet->advHdrBuf, FALSE);
/* Re-insert BOD's */
pAdvSet->advBod.abortCback = lctrSlvExtAdvAbortOp;
(void)SchInsertAtDueTime(&pAdvSet->advBod, NULL);
if (pAdvSet->auxBodUsed)
{
pAdvSet->auxAdvBod.abortCback = lctrSlvAuxAdvEndOp;
(void)SchInsertAtDueTime(&pAdvSet->auxAdvBod, NULL);
}
}
else
{
/* BOD's are already running. Data will be updated in the end callback of the BOD's. */
pDataBuf->alt.ext.len = fragLen;
memcpy(pDataBuf->alt.ext.buf, pFragBuf, fragLen);
pDataBuf->alt.ext.did = lctrCalcDID(pFragBuf, fragLen);
pDataBuf->alt.ext.fragPref = fragPref;
pDataBuf->alt.ext.modified = TRUE;
SchRemove(&pAdvSet->advBod);
}
return LL_SUCCESS;
@ -629,6 +595,7 @@ static uint8_t lctrSetPerAdvDataSm(lctrAdvSet_t *pAdvSet, lctrAdvDataBuf_t *pDat
{
pDataBuf->alt.ext.len = fragLen;
memcpy(pDataBuf->alt.ext.buf, pFragBuf, fragLen);
pDataBuf->alt.ext.did = lctrCalcDID(pFragBuf, fragLen);
pDataBuf->alt.ext.modified = TRUE;
return LL_SUCCESS;
@ -676,16 +643,19 @@ static uint8_t lctrSetPerAdvDataSm(lctrAdvSet_t *pAdvSet, lctrAdvDataBuf_t *pDat
/* Append buffer. */
memcpy(pDataBuf->pBuf + pDataBuf->len, pFragBuf, fragLen);
pDataBuf->len += fragLen;
pAdvSet->perParam.advDID = lctrCalcDID(pFragBuf, fragLen);
pDataBuf->ready = TRUE;
break;
case LL_ADV_DATA_OP_COMP:
/* New buffer (discard old buffer). */
memcpy(pDataBuf->pBuf, pFragBuf, fragLen);
pDataBuf->len = fragLen;
pAdvSet->perParam.advDID = lctrCalcDID(pFragBuf, fragLen);
pDataBuf->ready = TRUE;
break;
case LL_ADV_DATA_OP_UNCHANGED:
/* Same buffer. */
pAdvSet->perParam.advDID = lctrCalcDID(pFragBuf, fragLen);
pDataBuf->ready = TRUE;
break;
default:
@ -931,8 +901,6 @@ uint8_t lctrSlvExtAdvBuildOp(lctrAdvSet_t *pAdvSet, uint32_t maxStartMs)
SchInsertNextAvailable(pOp);
}
LL_TRACE_INFO1("### ExtAdvEvent ### Advertising enabled, dueUsec=%u", pOp->dueUsec);
/* Advertising offloading to auxiliary channel. */
if (pAdvSet->pExtAdvAuxPtr)
{
@ -971,6 +939,13 @@ uint8_t lctrSlvExtAdvBuildOp(lctrAdvSet_t *pAdvSet, uint32_t maxStartMs)
lctrSlvTxSetupExtAdvHandler(pOp, pOp->dueUsec);
}
LL_TRACE_INFO1(" >>> ExtAdv started, handle=%u <<<", pAdvSet->handle);
LL_TRACE_INFO1(" priAdvInterMinUsec=%u", pAdvSet->param.priAdvInterMinUsec);
LL_TRACE_INFO1(" priAdvInterMaxUsec=%u", pAdvSet->param.priAdvInterMaxUsec);
LL_TRACE_INFO1(" dueUsec=%u", pOp->dueUsec);
LL_TRACE_INFO1(" pAdvBod=0x%08x", pOp);
LL_TRACE_INFO1(" pAuxAdvBod=0x%08x", &pAdvSet->auxAdvBod);
return LL_SUCCESS;
}
@ -985,8 +960,8 @@ uint8_t lctrSlvExtAdvBuildOp(lctrAdvSet_t *pAdvSet, uint32_t maxStartMs)
void lctrSlvAuxRescheduleOp(lctrAdvSet_t *pAdvSet, BbOpDesc_t * const pOp)
{
uint32_t auxOffsUsec = pAdvSet->advBod.minDurUsec +
WSF_MAX(BbGetSchSetupDelayUs(), LL_BLE_MAFS_US) +
WSF_MAX(pAdvSet->auxDelayUsec, pLctrRtCfg->auxDelayUsec);
WSF_MAX(BbGetSchSetupDelayUs(), LL_BLE_MAFS_US) +
WSF_MAX(pAdvSet->auxDelayUsec, pLctrRtCfg->auxDelayUsec);
auxOffsUsec = WSF_MIN(auxOffsUsec, LL_AUX_PTR_MAX_USEC);
@ -996,14 +971,14 @@ void lctrSlvAuxRescheduleOp(lctrAdvSet_t *pAdvSet, BbOpDesc_t * const pOp)
/* Update BOD duration because extended header length might have been updated. */
SchBleCalcAdvOpDuration(pOp, (pAdvSet->advData.fragPref == LL_ADV_DATA_FRAG_ALLOW) ? pAdvSet->advDataFragLen : 0);
pOp->dueUsec = pAdvSet->advBod.dueUsec + auxOffsUsec + pLctrRtCfg->auxPtrOffsetUsec;
if (pAdvSet->auxSkipInterUsec == 0)
{
pOp->dueUsec = pAdvSet->advBod.dueUsec;
do
{
/* No delay after primary channel operation. */
if (SchInsertAtDueTime(pOp, NULL))
if (SchInsertEarlyAsPossible(pOp, auxOffsUsec + pLctrRtCfg->auxPtrOffsetUsec, pAdvSet->param.priAdvInterMaxUsec))
{
break;
}
@ -1017,10 +992,13 @@ void lctrSlvAuxRescheduleOp(lctrAdvSet_t *pAdvSet, BbOpDesc_t * const pOp)
}
else
{
/* Using EXT_ADV_IND due time as a reference ensures AuxOffset value does not overflow. */
pOp->dueUsec = pAdvSet->advBod.dueUsec;
do
{
/* Link multiple primary channel operations. */
if (SchInsertLateAsPossible(pOp, 0, pAdvSet->auxSkipInterUsec))
if (SchInsertLateAsPossible(pOp, auxOffsUsec + pLctrRtCfg->auxPtrOffsetUsec, pAdvSet->auxSkipInterUsec))
{
break;
}
@ -1054,13 +1032,13 @@ static void lctrSlvAuxCommitOp(lctrAdvSet_t *pAdvSet, BbOpDesc_t * const pOp)
uint32_t advEvtDurUsec = pAdvSet->advBod.minDurUsec;
uint32_t skipTimeUsec = pAdvSet->param.secAdvMaxSkip * /* number of skip events */
(pAdvSet->param.priAdvInterMinUsec + /* minimum interval */
(pAdvSet->param.priAdvInterMinUsec + /* minimum interval */
((LL_MAX_ADV_DLY_MS >> 1) * 1000)) + /* average advDelay */
(LL_MAX_ADV_DLY_MS * 1000); /* ensure no overlap due to advDelay */
skipTimeUsec = WSF_MIN(skipTimeUsec,
LCTR_AUX_PTR_MAX_OFFSET * 300); /* limit maximum */
skipTimeUsec = WSF_MIN(skipTimeUsec, (LCTR_AUX_PTR_MAX_OFFSET * 300)); /* limit maximum */
pAdvSet->auxSkipInterUsec = WSF_MAX(skipTimeUsec, advEvtDurUsec); /* ensure minimum */
pAdvSet->auxSkipInterUsec = WSF_MAX(skipTimeUsec, advEvtDurUsec); /* ensure minimum */
}
lctrSlvAuxRescheduleOp(pAdvSet, pOp);
@ -2156,13 +2134,23 @@ uint8_t LctrSetPeriodicAdvData(uint8_t handle, uint8_t op, uint8_t len, const ui
return LL_ERROR_CODE_UNKNOWN_ADV_ID;
}
if ((pAdvSet->perParam.advParamReady == FALSE) || /* Adv set is not configured for periodic adv. */
(pAdvSet->perParam.perAdvEnabled == TRUE && op != LL_ADV_DATA_OP_COMP) || /* When periodic adv is enabled, complete data shall be provided. Never gonna happen. */
(len == 0 && op != LL_ADV_DATA_OP_COMP)) /* Existing data shall be deleted and no new data provided. */
if (pAdvSet->perParam.advParamReady == FALSE) /* AdvSet is not configured for Periodic Advertising. */
{
return LL_ERROR_CODE_CMD_DISALLOWED;
}
if ((op != LL_ADV_DATA_OP_COMP) && (op != LL_ADV_DATA_OP_UNCHANGED))
{
if (len == 0)
{
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
if (pAdvSet->perParam.perAdvEnabled)
{
return LL_ERROR_CODE_CMD_DISALLOWED;
}
}
uint32_t worstCaseUsec;
uint16_t mafOffset = WSF_MAX(pAdvSet->auxDelayUsec, pLctrRtCfg->auxDelayUsec);
@ -2213,6 +2201,15 @@ uint8_t LctrSetPeriodicAdvData(uint8_t handle, uint8_t op, uint8_t len, const ui
void LctrSetPeriodicAdvEnable(uint8_t handle, bool_t enable)
{
lctrAdvSet_t *pAdvSet;
bool_t enableAdv = enable & LL_PER_ADV_ENABLE_ADV_ENABLE_BIT;
bool_t enableAdi = (enable & LL_PER_ADV_ENABLE_ADI_ENABLE_BIT) >> 1;
if ((enableAdv == TRUE) && (enableAdi == TRUE) &&
!(lmgrCb.features & LL_FEAT_PER_ADV_ADI_SUP))
{
LmgrSendPeriodicAdvEnableCnf(handle, LL_ERROR_CODE_UNSUPPORTED_FEATURE_PARAM_VALUE);
return;
}
if ((pAdvSet = lctrFindAdvSet(handle)) == NULL)
{
@ -2221,7 +2218,7 @@ void LctrSetPeriodicAdvEnable(uint8_t handle, bool_t enable)
}
if ((pAdvSet->perParam.advParamReady == FALSE) || /* Periodic advertising parameters shall be set. */
((enable == TRUE) && (pAdvSet->perAdvData.ready == FALSE)) || /* Periodic advertising data shall be complete. */
((enableAdv == TRUE) && (pAdvSet->perAdvData.ready == FALSE)) || /* Periodic advertising data shall be complete. */
(pAdvSet->param.advEventProp & (LL_ADV_EVT_PROP_CONN_ADV_BIT | LL_ADV_EVT_PROP_SCAN_ADV_BIT | /* Only non-connectable and non-scannable is allowed. */
LL_ADV_EVT_PROP_HIGH_DUTY_ADV_BIT | LL_ADV_EVT_PROP_OMIT_AA_BIT)))/* No high duty cycle, No anonymous advertising. */
{
@ -2229,13 +2226,15 @@ void LctrSetPeriodicAdvEnable(uint8_t handle, bool_t enable)
return;
}
pAdvSet->perParam.enableAdi = enableAdi;
LctrPerAdvEnableMsg_t *pMsg;
if ((pMsg = WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = handle;
pMsg->hdr.dispId = LCTR_DISP_PER_ADV;
pMsg->hdr.event = enable ? LCTR_PER_ADV_MSG_START : LCTR_PER_ADV_MSG_STOP;
pMsg->hdr.event = enableAdv ? LCTR_PER_ADV_MSG_START : LCTR_PER_ADV_MSG_STOP;
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
}
@ -2596,6 +2595,11 @@ void LctrSlvPeriodicAdvInit(void)
{
lmgrPersistCb.featuresDefault |= LL_FEAT_LE_PER_ADV;
}
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_SYDNEY)
{
lmgrPersistCb.featuresDefault |= LL_FEAT_PER_ADV_ADI_SUP;
}
}
/*************************************************************************************************/
@ -2635,8 +2639,6 @@ static void lctrSlvPeriodicCommitOp(lctrAdvSet_t *pAdvSet, BbOpDesc_t * const pO
/* Advance to next interval. */
pOp->dueUsec = anchorPointUsec + perInterUsec;
}
LL_TRACE_INFO1("### ExtAdvEvent ### Periodic advertising enabled, dueUsec=%u", pOp->dueUsec);
}
/*************************************************************************************************/
@ -2753,6 +2755,11 @@ uint8_t lctrSlvPeriodicAdvBuildOp(lctrAdvSet_t *pAdvSet)
pAdvSet->perParam.perAdvInterUsec = perInterUsec;
lctrSlvPeriodicCommitOp(pAdvSet, pOp);
LL_TRACE_INFO2(" >>> PerAdv started, AdvSet.handle=%u perChHopInc=%u <<<", pAdvSet->handle, pAdvSet->perParam.perChHopInc);
LL_TRACE_INFO1(" perInterUsec=%u", perInterUsec);
LL_TRACE_INFO1(" perAccessAddr=0x%08x", pAdvSet->perParam.perAccessAddr);
LL_TRACE_INFO1(" pPerAdvBod=0x%08x", pOp);
return LL_SUCCESS;
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -133,12 +133,6 @@ static void lctrBisFragmentIsoSdu(lctrBisCtx_t *pBisCtx, lctrIsoHdr_t *pIsoHdr,
uint64_t pktCtr = (pBisCtx->pBigCtx->eventCounter * pBisCtx->pBigCtx->bn) + pDesc->fragCnt;
pBisCtx->chan.enc.pTxPktCounter = &pktCtr;
/* Set the new packet counter for inline encryption. */
if (lctrSetEncryptPktCountHdlr)
{
lctrSetEncryptPktCountHdlr(&pBisCtx->chan.enc, pktCtr);
}
if (lctrPktEncryptHdlr &&
lctrPktEncryptHdlr(&pBisCtx->chan.enc,
pDesc->frag[pDesc->fragCnt].hdr,
@ -221,14 +215,19 @@ void lctrFreeBigCtx(lctrBigCtx_t *pBigCtx)
{
lctrBisCtx_t *pBisCtx = pBigCtx->pBisCtx[i];
if (pBisCtx == NULL)
{
/* Filtered BIS. */
continue;
}
switch (pBigCtx->role)
{
case LL_ROLE_SLAVE:
lctrBisSetDataPath(pBisCtx, LL_ISO_DATA_DIR_INPUT, LL_ISO_DATA_PATH_DISABLED);
lctrNotifyIsoTxComplete(pBigCtx);
LctrRemoveIsoDataPath(pBisCtx->handle, LL_ISO_DATA_PATH_INPUT_BIT);
break;
case LL_ROLE_MASTER:
lctrBisSetDataPath(pBisCtx, LL_ISO_DATA_DIR_OUTPUT, LL_ISO_DATA_PATH_DISABLED);
LctrRemoveIsoDataPath(pBisCtx->handle, LL_ISO_DATA_PATH_OUTPUT_BIT);
break;
default:
break;
@ -269,7 +268,8 @@ uint8_t lctrBigIsPerAdvUsed(uint8_t advHandle)
if ((pBigCtx->enabled) &&
(pBigCtx->role == LL_ROLE_SLAVE) &&
(pBigCtx->roleData.slv.pAdvSet))
(pBigCtx->roleData.slv.pAdvSet) &&
(pBigCtx->roleData.slv.pAdvSet->handle == advHandle))
{
return TRUE;
}
@ -372,7 +372,14 @@ lctrBisCtx_t *lctrAllocBisCtx(lctrBigCtx_t *pBigCtx)
pBisCtx->pBigCtx = pBigCtx;
pBisCtx->bisNum = pBigCtx->numBis + 1;
pBisCtx->path = LL_ISO_DATA_PATH_DISABLED;
if (pBigCtx->role == LL_ROLE_MASTER)
{
pBisCtx->roleData.mst.dataPathOutCtx.id = LL_ISO_DATA_PATH_DISABLED;
}
else
{
pBisCtx->roleData.slv.dataPathInCtx.id = LL_ISO_DATA_PATH_DISABLED;
}
/* Parent context. */
pBigCtx->pBisCtx[pBigCtx->numBis++] = pBisCtx;
@ -384,17 +391,6 @@ lctrBisCtx_t *lctrAllocBisCtx(lctrBigCtx_t *pBigCtx)
return NULL;
}
/*************************************************************************************************/
/*!
* \brief Cleanup BIS context, clean BIG context if necessary for slave.
*
* \param pBisCtx BIS context to free.
*/
/*************************************************************************************************/
void lctrCleanupBisCtx(lctrBisCtx_t *pBisCtx)
{
}
/*************************************************************************************************/
/*!
* \brief Free a BIS context.
@ -413,11 +409,18 @@ void lctrFreeBisCtx(lctrBisCtx_t *pBisCtx)
switch (pBisCtx->pBigCtx->role)
{
case LL_ROLE_MASTER:
while ((pPdu = lctrBisDequeueRxDataPdu(pBisCtx, NULL)) != NULL)
while ((pPdu = lctrBisDequeueRxDataPduTop(pBisCtx)) != NULL)
{
lctrBisRxIsoDataPduFree(pPdu);
}
uint8_t *pIsoSdu;
while ((pIsoSdu = lctrBisRxIsoSduDeq(pBisCtx)) != NULL)
{
WsfMsgFree(pIsoSdu);
lctrIsoDataRxIncAvailBuf(1);
}
lctrIsoalRxDataPathClear(&pBisCtx->roleData.mst.isoalRxCtx, pBisCtx->pBigCtx->framing);
break;
case LL_ROLE_SLAVE:
@ -585,7 +588,10 @@ void lctrSetupBisContext(lctrBisCtx_t *pBisCtx, uint32_t seedAccAddr, uint16_t b
pBisCtx->chan.enc.dir = 1;
pBisCtx->chan.enc.type = PAL_BB_TYPE_BIS;
lctrInitCipherBlkHdlr(&pBisCtx->chan.enc, pBisCtx->handle, 1);
if (lctrInitCipherBlkHdlr)
{
lctrInitCipherBlkHdlr(&pBisCtx->chan.enc, pBisCtx->handle, 1);
}
}
}
@ -602,15 +608,25 @@ void lctrSelectBigChannels(lctrBigCtx_t *pBigCtx)
for (unsigned int i = 0; i < pBigCtx->numBis; i++)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[i];
pBisCtx->chan.chanIdx = LmgrSelectNextChannel(&pBisCtx->chSelInfo, pBigCtx->eventCounter, 0, TRUE);
if (pBisCtx)
{
pBisCtx->chan.chanIdx = LmgrSelectNextChannel(&pBisCtx->chSelInfo, pBigCtx->eventCounter, 0, TRUE);
}
}
/* Select BIG Control channel. */
pBigCtx->ctrChan.chanIdx = LmgrSelectNextChannel(&pBigCtx->ctrChSelInfo, pBigCtx->eventCounter, 0, TRUE);
/* Setup BOD for next BIG Event. */
pBigCtx->bleData.chan.chanIdx = pBigCtx->pBisCtx[0]->chan.chanIdx;
if (pBigCtx->role == LL_ROLE_SLAVE)
{
pBigCtx->bleData.chan.chanIdx = pBigCtx->pBisCtx[0]->chan.chanIdx;
}
else /* LL_ROLE_MASTER */
{
pBigCtx->bleData.chan.chanIdx = pBigCtx->roleData.mst.pFirstBisCtx->chan.chanIdx;
}
}
/*************************************************************************************************/
@ -627,8 +643,12 @@ void lctrRemapBigChannels(lctrBigCtx_t *pBigCtx, uint64_t chanMap)
for (unsigned int i = 0; i < pBigCtx->numBis; i++)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[i];
pBisCtx->chSelInfo.chanMask = chanMap;
LmgrBuildRemapTable(&pBisCtx->chSelInfo);
if (pBisCtx)
{
pBisCtx->chSelInfo.chanMask = chanMap;
LmgrBuildRemapTable(&pBisCtx->chSelInfo);
}
}
/* Select BIG Control channel. */
@ -653,7 +673,8 @@ void lctrBisTxIsoPduQueue(lctrBisCtx_t *pBisCtx, lctrIsoHdr_t *pIsoHdr, uint8_t
{
LL_TRACE_ERR1("Failed to allocate transmit buffer descriptor: bisHandle=%u", pIsoHdr->handle);
WsfMsgFree(pIsoSdu);
if (!pBisCtx->test.enabled)
if (lmgrPersistCb.sendIsoCompCback &&
!pBisCtx->test.enabled)
{
uint16_t handle = pIsoHdr->handle;
uint16_t numSdu = 1;
@ -773,7 +794,7 @@ void lctrBisTxQueuePopCleanup(lctrBisCtx_t *pBisCtx, uint8_t numFrag)
lctrFreeIsoTxBufDesc(pDesc);
lctrIsoSduTxIncAvailBuf();
if (pBisCtx->path == LL_ISO_DATA_PATH_HCI)
if (pBisCtx->roleData.slv.dataPathInCtx.id == LL_ISO_DATA_PATH_HCI)
{
/* ISO Test does not send Tx Complete notifications. */
if (!pBisCtx->test.enabled)
@ -931,8 +952,8 @@ uint8_t *lctrBisRxIsoDataPduAlloc(void)
/* Return start of ISO Data PDU. */
pPdu += LCTR_ISO_SDU_START_OFFSET;
/* Do not claim buffer until committed. */
/* lctrIsoDataRxDecAvailBuf(); */
/* Do not claim buffer until SDU is committed. */
/* lctrIsoDataRxDecAvailBuf(); */ /* SDU committed in lctrBisRxIsoSduEnq(). */
}
return pPdu;
@ -952,25 +973,29 @@ uint8_t *lctrBisRxIsoDataPduAlloc(void)
uint8_t *lctrBisRxIsoSduDeq(lctrBisCtx_t *pBisCtx)
{
wsfHandlerId_t bisHandle;
uint8_t *pSdu = NULL;
uint8_t *pSdu = WsfMsgDeq(&pBisCtx->roleData.mst.rxIsoSduQ, &bisHandle);
if (pBisCtx->test.enabled)
{
pSdu = WsfMsgDeq(&pBisCtx->roleData.mst.dataPathOutCtx.cfg.hci.rxDataQ, &bisHandle);
return pSdu;
}
switch (pBisCtx->roleData.mst.dataPathOutCtx.id)
{
case LL_ISO_DATA_PATH_HCI:
pSdu = WsfMsgDeq(&pBisCtx->roleData.mst.dataPathOutCtx.cfg.hci.rxDataQ, &bisHandle);
break;
case LL_ISO_DATA_PATH_VS:
pSdu = WsfMsgDeq(&pBisCtx->roleData.mst.dataPathOutCtx.cfg.codec.rxDataQ, &bisHandle);
break;
default:
break;
}
return pSdu;
}
/*************************************************************************************************/
/*!
* \brief Enqueue a received ISO SDU buffer.
*
* \param pBisCtx BIS context.
* \param pSdu BIS Data SDU buffer.
*/
/*************************************************************************************************/
void lctrBisRxIsoSduEnq(lctrBisCtx_t *pBisCtx, uint8_t *pSdu)
{
WsfMsgEnq(&pBisCtx->roleData.mst.rxIsoSduQ, pBisCtx->handle, pSdu);
lctrIsoDataRxDecAvailBuf();
}
/*************************************************************************************************/
/*!
@ -991,12 +1016,43 @@ void lctrBisRxIsoDataPduFree(uint8_t *pPdu)
*
* \param pBisCtx BIS context.
* \param pRxBuf Received PDU data buffer to queue.
* \param evtCtr Event counter when packet was received.
* \param burstIdx Burst index.
*/
/*************************************************************************************************/
void lctrBisEnqueueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t *pRxBuf, uint64_t evtCtr)
void lctrBisEnqueueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t *pRxBuf, uint8_t burstIdx)
{
WsfMsgEnq(&pBisCtx->roleData.mst.rxDataQ, (uint8_t)evtCtr, pRxBuf - LCTR_ISO_SDU_START_OFFSET);
WsfMsgEnq(&pBisCtx->roleData.mst.rxDataQ, burstIdx, pRxBuf - LCTR_ISO_SDU_START_OFFSET);
}
/*************************************************************************************************/
/*!
* \brief Pop top element from Tx queue if it matches given \a bnIdx.
*
* \param pBisCtx BIS context.
* \param bnIdx Burst Number index.
*
* \return Pointer to ISO Data PDU.
*/
/*************************************************************************************************/
uint8_t *lctrBisDequeueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t burstIdx)
{
uint8_t *pBuf;
uint8_t actBurstIdx;
if (WsfMsgPeek(&pBisCtx->roleData.mst.rxDataQ, &actBurstIdx) == NULL)
{
return NULL;
}
if (actBurstIdx != burstIdx)
{
return NULL;
}
pBuf = WsfMsgDeq(&pBisCtx->roleData.mst.rxDataQ, &actBurstIdx);
return pBuf + LCTR_ISO_SDU_START_OFFSET;
}
/*************************************************************************************************/
@ -1004,22 +1060,16 @@ void lctrBisEnqueueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t *pRxBuf, uint64_t ev
* \brief Pop top element from Tx queue.
*
* \param pBisCtx BIS context.
* \param pEvtCtrLsb Least significant byte of the event counter.
*
* \return Pointer to ISO Data PDU.
*/
/*************************************************************************************************/
uint8_t *lctrBisDequeueRxDataPdu(lctrBisCtx_t *pBisCtx, uint8_t *pEvtCtrLsb)
uint8_t *lctrBisDequeueRxDataPduTop(lctrBisCtx_t *pBisCtx)
{
uint8_t *pBuf;
uint8_t temp8;
if (pEvtCtrLsb == NULL)
{
pEvtCtrLsb = &temp8;
}
if ((pBuf = WsfMsgDeq(&pBisCtx->roleData.mst.rxDataQ, pEvtCtrLsb)) == NULL)
if ((pBuf = WsfMsgDeq(&pBisCtx->roleData.mst.rxDataQ, &temp8)) == NULL)
{
return NULL;
}
@ -1074,6 +1124,7 @@ uint8_t lctrBisTxTest(lctrBisCtx_t *pBisCtx, uint8_t pldType)
* \param pldType Payload length type.
*
* \return Status error code.
*
*/
/*************************************************************************************************/
uint8_t lctrBisRxTest(lctrBisCtx_t *pBisCtx, uint8_t pldType)
@ -1189,7 +1240,8 @@ void lctrNotifyIsoTxComplete(lctrBigCtx_t *pBigCtx)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[i];
if (pBisCtx->path == LL_ISO_DATA_PATH_HCI)
if (pBisCtx &&
(pBisCtx->roleData.slv.dataPathInCtx.id == LL_ISO_DATA_PATH_HCI))
{
if (pBisCtx->roleData.slv.numTxSduComp)
{
@ -1201,7 +1253,7 @@ void lctrNotifyIsoTxComplete(lctrBigCtx_t *pBigCtx)
}
}
if (numHandles)
if (lmgrPersistCb.sendIsoCompCback && numHandles)
{
/* Notify host completed SDUs. */
lmgrPersistCb.sendIsoCompCback(numHandles, handle, numSdu);
@ -1237,86 +1289,6 @@ void lctrBisCalcGroupSessionKey(const uint8_t *pGSKD, const uint8_t *pBC, uint8_
PalCryptoAesCmac(ik, pGSK, big3, 4);
}
/*************************************************************************************************/
/*!
* \brief Set the BIS data path.
*
* \param pBisCtx BIS context.
* \param dpDir Data path direction.
* \param dpId Data path ID.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t lctrBisSetDataPath(lctrBisCtx_t *pBisCtx, LlIsoDataPathDir_t dpDir, LlIsoDataPath_t dpId)
{
if (pBisCtx->path == dpId)
{
/* No change. */
return LL_SUCCESS;
}
/*** Stop current data path. ***/
switch (pBisCtx->path)
{
case LL_ISO_DATA_PATH_VS:
if (!lctrCodecHdlr.stop)
{
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
lctrCodecHdlr.stop(pBisCtx->handle);
break;
case LL_ISO_DATA_PATH_DISABLED:
case LL_ISO_DATA_PATH_HCI:
default:
/* No action required. */
break;
}
/*** Start new data path. ***/
pBisCtx->path = dpId;
switch (dpId)
{
case LL_ISO_DATA_PATH_VS:
if (lctrCodecHdlr.start)
{
PalCodecSreamParam_t param =
{
.dir = (dpDir == LL_ISO_DATA_DIR_INPUT) ? PAL_CODEC_DIR_INPUT : PAL_CODEC_DIR_OUTPUT,
.chMask = PAL_CODEC_CH_LEFT_BIT | PAL_CODEC_CH_RIGHT_BIT,
.intervalUsec = pBisCtx->pBigCtx->isoInterUsec,
.pktCtr = (pBisCtx->pBigCtx->eventCounter + 1) * pBisCtx->pBigCtx->bn,
.rdyCback = lctrIsoSendCodecSdu
};
if (!lctrCodecHdlr.start(pBisCtx->handle, &param))
{
LL_TRACE_WARN1("Failed to start the codec, dpId=%u", dpId);
pBisCtx->path = LL_ISO_DATA_PATH_DISABLED;
return LL_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES;
}
}
else
{
LL_TRACE_WARN1("Codec not found, dpId=%u", dpId);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
break;
case LL_ISO_DATA_PATH_DISABLED:
case LL_ISO_DATA_PATH_HCI:
/* No action required. */
break;
default:
LL_TRACE_WARN1("Unknown Data Path, dpId=%u", dpId);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
return LL_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Calculate next subevent index values, using sequential packing.
@ -1328,7 +1300,7 @@ uint8_t lctrBisSetDataPath(lctrBisCtx_t *pBisCtx, LlIsoDataPathDir_t dpDir, LlIs
* \return TRUE if more subevents pending, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t lctrSlvBisCalcNextIdxSequential(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts)
bool_t lctrBisCalcNextIdxSequential(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts)
{
/* Burst loop. */
@ -1382,7 +1354,7 @@ bool_t lctrSlvBisCalcNextIdxSequential(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCt
* \return TRUE if more subevents pending, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t lctrSlvBisCalcNextIdxInterleaved(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts)
bool_t lctrBisCalcNextIdxInterleaved(lctrBigCtx_t *pBigCtx, lctrSeCtx_t *pSeCtx, uint8_t numSePkts)
{
/* BIS loop. */

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -122,7 +122,7 @@ void LctrMstBisInit(void)
/* Set supported features. */
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_5_1)
{
lmgrPersistCb.featuresDefault |= LL_FEAT_ISO_BROADCASTER;
lmgrPersistCb.featuresDefault |= LL_FEAT_ISO_SYNC;
}
}
@ -150,7 +150,7 @@ uint8_t LctrMstBigCreateSync(LlBigCreateSync_t *pParam)
if (lctrFindBigByHandle(pParam->bigHandle) != NULL)
{
LL_TRACE_WARN1("LctrMstBigCreateSync: bigHandle=%u already in use", pParam->bigHandle);
return LL_ERROR_CODE_UNSUPPORTED_FEATURE_PARAM_VALUE;
return LL_ERROR_CODE_CMD_DISALLOWED;
}
pPerScanCtx = LCTR_GET_PER_SCAN_CTX(pParam->syncHandle);
@ -175,6 +175,17 @@ uint8_t LctrMstBigCreateSync(LlBigCreateSync_t *pParam)
}
pBigInfo = &pPerScanCtx->acadParams[LCTR_ACAD_ID_BIG_INFO].bigInfo;
if (pParam->numBis > pBigInfo->numBis)
{
LL_TRACE_WARN2("LctrMstBigCreateSync: invalid value for numBis=%u for this sync handle, validRange=1..%u", pParam->numBis, pBigInfo->numBis);
return LL_ERROR_CODE_UNSUPPORTED_FEATURE_PARAM_VALUE;
}
if (pParam->numBis > LL_MAX_BIS)
{
LL_TRACE_WARN2("LctrMstBigCreateSync: invalid value for numBis=%u, validRange=1..%u", pParam->numBis, LL_MAX_BIS);
return LL_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES;
}
if (pParam->numBis > lctrGetNumAvailBisCtx())
{
@ -182,12 +193,6 @@ uint8_t LctrMstBigCreateSync(LlBigCreateSync_t *pParam)
return LL_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES;
}
if (pParam->numBis > WSF_MIN(pBigInfo->numBis, LL_MAX_BIS))
{
LL_TRACE_WARN2("LctrMstBigCreateSync: invalid value for numBis=%u, validRange=1..%u", pParam->numBis, WSF_MIN(pBigInfo->numBis, LL_MAX_BIS));
return LL_ERROR_CODE_UNSUPPORTED_FEATURE_PARAM_VALUE;
}
for (unsigned int i = 0; i < pParam->numBis; i++)
{
if ((pParam->bis[i] < LL_MIN_BIS) ||
@ -286,7 +291,7 @@ void LctrMstBigTerminateSync(uint8_t bigHandle)
/*************************************************************************************************/
void lctrMstBigBuildOp(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[0];
lctrBisCtx_t * const pBisCtx = pBigCtx->roleData.mst.pFirstBisCtx;
BbOpDesc_t * const pOp = &pBigCtx->bod;
BbBleData_t * const pBle = &pBigCtx->bleData;
@ -302,7 +307,7 @@ void lctrMstBigBuildOp(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
pOp->protId = BB_PROT_BLE;
pOp->prot.pBle = pBle;
pOp->endCback = lctrMstBigEndOp;
pOp->abortCback = lctrMstBigEndOp;
pOp->abortCback = lctrMstBigAbortOp;
pOp->pCtx = pBigCtx;
/*** BLE General Setup ***/
@ -337,17 +342,18 @@ void lctrMstBigBuildOp(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
pBigCtx->roleData.mst.anchorPoint = pBigInfo->bigAnchorPoint;
pBigCtx->roleData.mst.rxSyncTime = pBigCtx->roleData.mst.anchorPoint - pBigCtx->isoInterUsec;
/* Expand receive window for initial synchronization due to resolution uncertainty. */
pBigCtx->roleData.mst.extraWwUsec = (pBigInfo->bigOffsUnits == 0) ? 30 : 300;
pBigCtx->roleData.mst.initWwUsec = (pBigInfo->bigOffsUnits == 0) ? 30 : 300;
uint32_t unsyncTimeUsec = 0;
while (TRUE)
{
uint32_t wwTotalUsec = lctrCalcWindowWideningUsec(unsyncTimeUsec, pBigCtx->roleData.mst.totalAcc);
uint32_t wwTotalUsec = lctrCalcWindowWideningUsec(unsyncTimeUsec, pBigCtx->roleData.mst.totalAcc)
+ pBigCtx->roleData.mst.initWwUsec;
/* TODO Limit to half the ISO Interval size */
pOp->dueUsec = pBigCtx->roleData.mst.anchorPoint - wwTotalUsec;
pOp->dueUsec = pBigCtx->roleData.mst.anchorPoint + pBigCtx->roleData.mst.firstBisOffsUsec - wwTotalUsec;
/* Multiply 2 for before and after BIG Anchor Point. */
pBis->rxSyncDelayUsec = (wwTotalUsec << 1) + pBigCtx->roleData.mst.extraWwUsec;
pBis->rxSyncDelayUsec = (wwTotalUsec << 1);
lctrSelectBigChannels(pBigCtx);
@ -356,7 +362,7 @@ void lctrMstBigBuildOp(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
break;
}
LL_TRACE_WARN1("!!! BIG schedule conflict handle=%u", pBigCtx->handle);
LL_TRACE_WARN2("!!! BIG schedule conflict handle=%u, ec[15:0]=%u", pBigCtx->handle, pBigCtx->eventCounter);
/* Advance to next interval. */
pBigCtx->eventCounter += 1;
@ -443,14 +449,15 @@ void lctrMstSetupBigContext(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
/*************************************************************************************************/
void lctrMstSetupBigChannel(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
{
pBigCtx->ctrChSelInfo.chanMask = pBigInfo->chanMap;
pBigCtx->ctrChSelInfo.usedChSel = LL_CH_SEL_2;
pBigCtx->ctrChSelInfo.chIdentifier = (uint16_t)(LL_BIG_CONTROL_ACCESS_ADDR >> 16) ^
(uint16_t)(LL_BIG_CONTROL_ACCESS_ADDR >> 0);
LmgrBuildRemapTable(&pBigCtx->ctrChSelInfo);
pBigCtx->ctrChan.opType = BB_BLE_OP_MST_BIS_EVENT;
pBigCtx->ctrChan.accAddr = lctrComputeBisAccessAddr(pBigInfo->seedAccAddr, 0);
pBigCtx->ctrChSelInfo.chanMask = pBigInfo->chanMap;
pBigCtx->ctrChSelInfo.usedChSel = LL_CH_SEL_2;
pBigCtx->ctrChSelInfo.chIdentifier = (uint16_t)(pBigCtx->ctrChan.accAddr >> 16) ^
(uint16_t)(pBigCtx->ctrChan.accAddr >> 0);
LmgrBuildRemapTable(&pBigCtx->ctrChSelInfo);
pBigCtx->ctrChan.crcInit = (pBigCtx->baseCrcInit << 8) | 0;
pBigCtx->ctrChan.rxPhy = pBigCtx->phy;
@ -468,10 +475,10 @@ void lctrMstSetupBigChannel(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
pBigCtx->ctrChan.enc.nonceMode = PAL_BB_NONCE_MODE_EXT64_CNTR;
memcpy(pBigCtx->ctrChan.enc.iv, pBigCtx->giv, LL_IV_LEN);
pBigCtx->ctrChan.enc.iv[0] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 0;
pBigCtx->ctrChan.enc.iv[1] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 8;
pBigCtx->ctrChan.enc.iv[2] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 16;
pBigCtx->ctrChan.enc.iv[3] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 24;
pBigCtx->ctrChan.enc.iv[0] ^= pBigCtx->ctrChan.accAddr >> 0;
pBigCtx->ctrChan.enc.iv[1] ^= pBigCtx->ctrChan.accAddr >> 8;
pBigCtx->ctrChan.enc.iv[2] ^= pBigCtx->ctrChan.accAddr >> 16;
pBigCtx->ctrChan.enc.iv[3] ^= pBigCtx->ctrChan.accAddr >> 24;
memcpy(pBigCtx->ctrChan.enc.sk, pBigCtx->bleData.chan.enc.sk, PAL_CRYPTO_LL_KEY_LEN);
@ -479,7 +486,10 @@ void lctrMstSetupBigChannel(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
pBigCtx->ctrChan.enc.dir = 1;
pBigCtx->ctrChan.enc.type = PAL_BB_TYPE_BIS;
lctrInitCipherBlkHdlr(&pBigCtx->ctrChan.enc, LCTR_BIG_CTRL_ENC_ID(pBigCtx), 1);
if (lctrInitCipherBlkHdlr)
{
lctrInitCipherBlkHdlr(&pBigCtx->ctrChan.enc, LCTR_BIG_CTRL_ENC_ID(pBigCtx), 1);
}
}
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -124,8 +124,8 @@ static void lctrSlvSetupBigContext(lctrBigCtx_t *pBigCtx, LlCreateBig_t *pCreate
case LL_PACKING_INTERLEAVED:
{
pBigCtx->bisSpaceUsec = lctrBisCalcMaxPduTimeUsec(pBigCtx->phy, pBigCtx->maxPdu, pCreateBig->encrypt);
pBigCtx->subInterUsec = pBigCtx->bisSpaceUsec * pBigCtx->nse;
pBigCtx->syncDelayUsec = pCreateBig->numBis * pBigCtx->subInterUsec;
pBigCtx->subInterUsec = pBigCtx->bisSpaceUsec * pCreateBig->numBis;
pBigCtx->syncDelayUsec = (pCreateBig->numBis * pBigCtx->subInterUsec) - LL_BLE_TMSS_US;
break;
}
@ -134,7 +134,7 @@ static void lctrSlvSetupBigContext(lctrBigCtx_t *pBigCtx, LlCreateBig_t *pCreate
{
pBigCtx->subInterUsec = lctrBisCalcMaxPduTimeUsec(pBigCtx->phy, pBigCtx->maxPdu, pCreateBig->encrypt);
pBigCtx->bisSpaceUsec = pBigCtx->subInterUsec * pBigCtx->nse;
pBigCtx->syncDelayUsec = pCreateBig->numBis * pBigCtx->bisSpaceUsec;
pBigCtx->syncDelayUsec = (pCreateBig->numBis * pBigCtx->bisSpaceUsec) - LL_BLE_TMSS_US;
break;
}
}
@ -142,9 +142,18 @@ static void lctrSlvSetupBigContext(lctrBigCtx_t *pBigCtx, LlCreateBig_t *pCreate
/* Ensure successful divide. */
if (pBigCtx->bn || pBigCtx->sduInterUsec)
{
pBigCtx->transLatUsec = pBigCtx->syncDelayUsec +
pBigCtx->pto * (pBigCtx->nse / pBigCtx->bn - pBigCtx->irc) * pBigCtx->isoInterUsec +
((pBigCtx->isoInterUsec / pBigCtx->sduInterUsec) - 1) * pBigCtx->sduInterUsec;
if (pBigCtx->framing == LL_ISO_PDU_TYPE_FRAMED)
{
pBigCtx->transLatUsec = pBigCtx->syncDelayUsec +
pBigCtx->pto * (pBigCtx->nse / pBigCtx->bn - pBigCtx->irc) * pBigCtx->isoInterUsec +
pBigCtx->isoInterUsec + pBigCtx->sduInterUsec;
}
else
{
pBigCtx->transLatUsec = pBigCtx->syncDelayUsec +
pBigCtx->pto * (pBigCtx->nse / pBigCtx->bn - pBigCtx->irc) * pBigCtx->isoInterUsec +
((pBigCtx->isoInterUsec / pBigCtx->sduInterUsec) - 1) * pBigCtx->sduInterUsec;
}
}
else
{
@ -188,15 +197,15 @@ static void lctrSlvSetupBigTestContext(lctrBigCtx_t *pBigCtx, LlCreateBigTest_t
pBigCtx->bn = pCreateBigTest->bn;
pBigCtx->irc = pCreateBigTest->irc;
pBigCtx->pto = pCreateBigTest->pto;
pBigCtx->nse = (pBigCtx->bn + pBigCtx->pto) * pBigCtx->irc;
pBigCtx->nse = pCreateBigTest->nse;
switch (pBigCtx->packing)
{
case LL_PACKING_INTERLEAVED:
{
pBigCtx->bisSpaceUsec = lctrBisCalcMaxPduTimeUsec(pBigCtx->phy, pBigCtx->maxPdu, pCreateBigTest->encrypt);
pBigCtx->subInterUsec = pBigCtx->bisSpaceUsec * pBigCtx->nse;
pBigCtx->syncDelayUsec = pCreateBigTest->numBis * pBigCtx->subInterUsec;
pBigCtx->subInterUsec = pBigCtx->bisSpaceUsec * pCreateBigTest->numBis;
pBigCtx->syncDelayUsec = (pCreateBigTest->numBis * pBigCtx->subInterUsec) - LL_BLE_TMSS_US;
break;
}
@ -205,7 +214,7 @@ static void lctrSlvSetupBigTestContext(lctrBigCtx_t *pBigCtx, LlCreateBigTest_t
{
pBigCtx->subInterUsec = lctrBisCalcMaxPduTimeUsec(pBigCtx->phy, pBigCtx->maxPdu, pCreateBigTest->encrypt);
pBigCtx->bisSpaceUsec = pBigCtx->subInterUsec * pBigCtx->nse;
pBigCtx->syncDelayUsec = pCreateBigTest->numBis * pBigCtx->bisSpaceUsec;
pBigCtx->syncDelayUsec = (pCreateBigTest->numBis * pBigCtx->bisSpaceUsec) - LL_BLE_TMSS_US;
break;
}
}
@ -213,9 +222,18 @@ static void lctrSlvSetupBigTestContext(lctrBigCtx_t *pBigCtx, LlCreateBigTest_t
/* Ensure successful divide. */
if (pBigCtx->bn || pBigCtx->sduInterUsec)
{
pBigCtx->transLatUsec = pBigCtx->syncDelayUsec +
pBigCtx->pto * (pBigCtx->nse / pBigCtx->bn - pBigCtx->irc) * pBigCtx->isoInterUsec +
((pBigCtx->isoInterUsec / pBigCtx->sduInterUsec) - 1) * pBigCtx->sduInterUsec;
if (pBigCtx->framing == LL_ISO_PDU_TYPE_FRAMED)
{
pBigCtx->transLatUsec = pBigCtx->syncDelayUsec +
pBigCtx->pto * (pBigCtx->nse / pBigCtx->bn - pBigCtx->irc) * pBigCtx->isoInterUsec +
pBigCtx->isoInterUsec + pBigCtx->sduInterUsec;
}
else
{
pBigCtx->transLatUsec = pBigCtx->syncDelayUsec +
pBigCtx->pto * (pBigCtx->nse / pBigCtx->bn - pBigCtx->irc) * pBigCtx->isoInterUsec +
((pBigCtx->isoInterUsec / pBigCtx->sduInterUsec) - 1) * pBigCtx->sduInterUsec;
}
}
else
{
@ -236,15 +254,15 @@ static void lctrSlvSetupBigChannel(lctrBigCtx_t *pBigCtx)
pBigCtx->seedAccAddr = lctrComputeSeedAccessAddr();
pBigCtx->baseCrcInit = lctrComputeCrcInit() >> 8;
pBigCtx->ctrChSelInfo.chanMask = lmgrCb.chanClass;
pBigCtx->ctrChSelInfo.usedChSel = LL_CH_SEL_2;
pBigCtx->ctrChSelInfo.chIdentifier = (uint16_t)(LL_BIG_CONTROL_ACCESS_ADDR >> 16) ^
(uint16_t)(LL_BIG_CONTROL_ACCESS_ADDR >> 0);
LmgrBuildRemapTable(&pBigCtx->ctrChSelInfo);
pBigCtx->ctrChan.opType = BB_BLE_OP_SLV_BIS_EVENT;
pBigCtx->ctrChan.accAddr = lctrComputeBisAccessAddr(pBigCtx->seedAccAddr, 0);
pBigCtx->ctrChSelInfo.chanMask = lmgrCb.chanClass;
pBigCtx->ctrChSelInfo.usedChSel = LL_CH_SEL_2;
pBigCtx->ctrChSelInfo.chIdentifier = (uint16_t)(pBigCtx->ctrChan.accAddr >> 16) ^
(uint16_t)(pBigCtx->ctrChan.accAddr >> 0);
LmgrBuildRemapTable(&pBigCtx->ctrChSelInfo);
pBigCtx->ctrChan.crcInit = (pBigCtx->baseCrcInit << 8) | 0;
pBigCtx->ctrChan.txPower = lmgrCb.advTxPwr;
pBigCtx->ctrChan.txPhy = pBigCtx->phy;
@ -266,10 +284,10 @@ static void lctrSlvSetupBigChannel(lctrBigCtx_t *pBigCtx)
pBigCtx->ctrChan.enc.nonceMode = PAL_BB_NONCE_MODE_EXT64_CNTR;
memcpy(pBigCtx->ctrChan.enc.iv, pBigCtx->giv, LL_IV_LEN);
pBigCtx->ctrChan.enc.iv[0] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 0;
pBigCtx->ctrChan.enc.iv[1] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 8;
pBigCtx->ctrChan.enc.iv[2] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 16;
pBigCtx->ctrChan.enc.iv[3] ^= LL_BIG_CONTROL_ACCESS_ADDR >> 24;
pBigCtx->ctrChan.enc.iv[0] ^= pBigCtx->ctrChan.accAddr >> 0;
pBigCtx->ctrChan.enc.iv[1] ^= pBigCtx->ctrChan.accAddr >> 8;
pBigCtx->ctrChan.enc.iv[2] ^= pBigCtx->ctrChan.accAddr >> 16;
pBigCtx->ctrChan.enc.iv[3] ^= pBigCtx->ctrChan.accAddr >> 24;
memcpy(pBigCtx->ctrChan.enc.sk, pBigCtx->bleData.chan.enc.sk, PAL_CRYPTO_LL_KEY_LEN);
@ -277,7 +295,10 @@ static void lctrSlvSetupBigChannel(lctrBigCtx_t *pBigCtx)
pBigCtx->ctrChan.enc.dir = 1;
pBigCtx->ctrChan.enc.type = PAL_BB_TYPE_BIS;
lctrInitCipherBlkHdlr(&pBigCtx->ctrChan.enc, LCTR_BIG_CTRL_ENC_ID(pBigCtx), 1);
if (lctrInitCipherBlkHdlr)
{
lctrInitCipherBlkHdlr(&pBigCtx->ctrChan.enc, LCTR_BIG_CTRL_ENC_ID(pBigCtx), 1);
}
}
}
@ -508,7 +529,7 @@ void LctrSlvBisInit(void)
/* Set supported features. */
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_5_1)
{
lmgrPersistCb.featuresDefault |= LL_FEAT_ISO_BROADCASTER;
lmgrPersistCb.featuresDefault |= LL_FEAT_ISO_SYNC;
}
}
@ -574,7 +595,8 @@ uint8_t LctrSlvBisCreateBig(LlCreateBig_t *pCreateBig)
if (pBisCtx)
{
lctrSetupBisContext(pBisCtx, pBigCtx->seedAccAddr, pBigCtx->baseCrcInit, lmgrCb.chanClass, pBigCtx->phy);
lctrSetupBisContext(pBisCtx, pBigCtx->seedAccAddr, pBigCtx->baseCrcInit, lmgrCb.chanClass,
(LlPhy_t)pBigCtx->phy);
}
else
{
@ -663,7 +685,8 @@ uint8_t LctrSlvBisCreateBigTest(LlCreateBigTest_t *pCreateBigTest)
if (pBisCtx)
{
lctrSetupBisContext(pBisCtx, pBigCtx->seedAccAddr, pBigCtx->baseCrcInit, lmgrCb.chanClass, pBigCtx->phy);
lctrSetupBisContext(pBisCtx, pBigCtx->seedAccAddr, pBigCtx->baseCrcInit, lmgrCb.chanClass,
(LlPhy_t)pBigCtx->phy);
}
else
{
@ -932,10 +955,10 @@ uint8_t lctrSlvBigBuildOp(lctrBigCtx_t *pBigCtx)
return LL_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES;
}
const uint32_t curTime = PalBbGetCurrentTime();
uint32_t offsetUsec = SchRmGetOffsetUsec(pOp->minDurUsec,
LCTR_BIG_TO_RM_HANDLE(pBigCtx), curTime);
pOp->dueUsec = curTime + offsetUsec;
const uint32_t refTime = pBigCtx->roleData.slv.pAdvSet->advBod.dueUsec;
uint32_t offsetUsec = SchRmGetOffsetUsec(pBigCtx->isoInterUsec,
LCTR_BIG_TO_RM_HANDLE(pBigCtx), refTime);
pOp->dueUsec = refTime + offsetUsec;
while (TRUE)
{

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -143,6 +143,38 @@ void lctrCleanupCtx(lctrCisCtx_t *pCisCtx)
lctrCigCtx_t *pCigCtx = lctrFindCigById(pCisCtx->cigId);
WSF_ASSERT(pCigCtx);
uint8_t *pBuf;
uint8_t numTxBufs;
wsfHandlerId_t handlerId;
pCisCtx->cisEvtCounter = 0;
pCisCtx->firstFromPeer = FALSE;
pCisCtx->connEst = FALSE;
/* Must do one at a time in case one datapath is not used. */
LctrRemoveIsoDataPath(pCisCtx->cisHandle, LL_ISO_DATA_PATH_INPUT_BIT);
LctrRemoveIsoDataPath(pCisCtx->cisHandle, LL_ISO_DATA_PATH_OUTPUT_BIT);
/* Flush remaining transmit packets. */
numTxBufs = lctrCisTxQueueClear(pCisCtx);
/* Flush remaining transmit packets. */
while ((pBuf = WsfMsgDeq(&pCisCtx->txIsoQ, &handlerId)) != NULL)
{
lctrDataTxIncAvailBuf();
numTxBufs++;
WsfMsgFree(pBuf);
}
/* Flush remaining Tx/Rx flush timeout list. */
lctrCisFtListClear(&pCisCtx->txFtParamList);
lctrCisFtListClear(&pCisCtx->rxFtParamList);
/* Cleanup timers. */
WsfTimerStop(&pCisCtx->tmrSupTimeout);
WsfTimerStop(&pCisCtx->tmrProcRsp);
if (lctrCisIsHeadCis(&pCigCtx->list, pCisCtx) == TRUE)
{
pCigCtx->headCisRmved = TRUE;
@ -177,6 +209,11 @@ void lctrCleanupCtx(lctrCisCtx_t *pCisCtx)
if (lctrCisIsListEmpty(&pCigCtx->list))
{
/* Refresh CIG context to get ready for re-starting CIS. */
pCigCtx->headCisRmved = FALSE;
pCigCtx->isBodBuilt = FALSE;
pCigCtx->isBodStarted = FALSE;
if (pCigCtx->isRmAdded == TRUE)
{
SchRmRemove(LCTR_GET_CIG_RM_HANDLE(pCigCtx));
@ -204,7 +241,6 @@ void lctrCleanupCtx(lctrCisCtx_t *pCisCtx)
}
void *pIsoBuf;
uint8_t handlerId;
while ((pIsoBuf = WsfMsgDeq(&pCisCtx->isoalTxCtx.pendingSduQ, &handlerId)) != NULL)
{
WsfMsgFree(pIsoBuf);
@ -222,36 +258,8 @@ void lctrCleanupCtx(lctrCisCtx_t *pCisCtx)
/*************************************************************************************************/
void lctrFreeCisCtx(lctrCisCtx_t *pCisCtx)
{
uint8_t *pBuf;
uint8_t numTxBufs;
wsfHandlerId_t handlerId;
WSF_ASSERT(pCisCtx->enabled);
pCisCtx->enabled = FALSE;
/* Clean up receive context. */
lctrIsoOutDataPathClear(&pCisCtx->dataPathOutCtx);
/* Flush remaining transmit packets. */
numTxBufs = lctrCisTxQueueClear(pCisCtx);
/* Flush remaining transmit packets. */
while ((pBuf = WsfMsgDeq(&pCisCtx->txIsoQ, &handlerId)) != NULL)
{
lctrDataTxIncAvailBuf();
numTxBufs++;
WsfMsgFree(pBuf);
}
/* Flush remaining Tx/Rx flush timeout list. */
lctrCisFtListClear(&pCisCtx->txFtParamList);
lctrCisFtListClear(&pCisCtx->rxFtParamList);
/* Cleanup timers. */
WsfTimerStop(&pCisCtx->tmrSupTimeout);
WsfTimerStop(&pCisCtx->tmrProcRsp);
}
/*************************************************************************************************/
@ -444,7 +452,6 @@ uint16_t LctrInitCisMem(uint8_t *pFreeMem, uint32_t freeMemSize)
pLctrCisTbl = (lctrCisCtx_t *)pAvailMem;
pAvailMem += sizeof(lctrCisCtx_t) * pLctrRtCfg->maxCis;
if (((uint32_t)pAvailMem) & 3)
{
/* Align to next word. */
@ -493,7 +500,7 @@ void lctrCisInitFtParam(lctrFtParam_t *pFtParam, uint8_t bn, uint8_t ft, uint8_t
if (bn == 1)
{
/* BN = 1, numSubEvtFt[0] = BN * NSE */
pFtParam->lastSubEvtFt[0] = bn * nse;
pFtParam->lastSubEvtFt[0] = nse;
pFtParam->isPduDone[0] = FALSE;
pFtParam->pduType[0] = LCTR_CIS_PDU_DEFAULT;
}
@ -784,7 +791,6 @@ void lctrCisSetupEncrypt(lctrCisCtx_t *pCisCtx)
PalCryptoAesEcb(pCtx->ltk, pEnc->sk, pCtx->skd);
WSF_ASSERT(lctrInitCipherBlkHdlr);
memcpy(pEnc->iv, pCtx->iv, sizeof(pEnc->iv));
uint8_t *pTemp, accAddr[4];
pTemp = accAddr;
@ -796,7 +802,10 @@ void lctrCisSetupEncrypt(lctrCisCtx_t *pCisCtx)
pEnc->dir = (pCisCtx->role == LL_ROLE_MASTER) ? 1 : 0; /* master = 1; slave = 0 */
pEnc->type = PAL_BB_TYPE_CIS;
lctrInitCipherBlkHdlr(pEnc, pCisCtx->cisHandle, pEnc->dir);
if (lctrInitCipherBlkHdlr)
{
lctrInitCipherBlkHdlr(pEnc, pCisCtx->cisHandle, pEnc->dir);
}
pEnc->enaEncrypt = pCtx->bleData.chan.enc.enaEncrypt;
pEnc->enaDecrypt = pCtx->bleData.chan.enc.enaDecrypt;
@ -1638,7 +1647,14 @@ uint32_t lctrCisCalcSubEvtDurationUsecSeq(uint8_t phyMToS, uint8_t phySToM, uint
duration += LL_DATA_LEN_TO_TIME_2M(plMToS, TRUE);
break;
case BB_PHY_BLE_CODED:
duration += LL_DATA_LEN_TO_TIME_CODED_S8(plMToS, TRUE);
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2))
{
duration += LL_DATA_LEN_TO_TIME_CODED_S2(plMToS, TRUE);
}
else
{
duration += LL_DATA_LEN_TO_TIME_CODED_S8(plMToS, TRUE);
}
break;
}
@ -1655,7 +1671,14 @@ uint32_t lctrCisCalcSubEvtDurationUsecSeq(uint8_t phyMToS, uint8_t phySToM, uint
duration += LL_DATA_LEN_TO_TIME_2M(plSToM, TRUE);
break;
case BB_PHY_BLE_CODED:
duration += LL_DATA_LEN_TO_TIME_CODED_S8(plSToM, TRUE);
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2))
{
duration += LL_DATA_LEN_TO_TIME_CODED_S2(plSToM, TRUE);
}
else
{
duration += LL_DATA_LEN_TO_TIME_CODED_S8(plSToM, TRUE);
}
break;
}
@ -1745,65 +1768,168 @@ void lctrCisTxTestPayloadHandler(lctrCisCtx_t * pCisCtx)
/*************************************************************************************************/
/*!
* \brief Action function for cis power monitoring.
* \brief Generate a lost/invalid SDU in case of flushed SDU.
*
* \param rssi CIS RX RSSI.
* \param status rx status.
* \param phy phy.
* \param pConnCtx Connection context.
*************************************************************************************************/
void lctrCisPowerMonitorCheckRssi(int8_t rssi, uint8_t status, uint8_t phy, lctrConnCtx_t *pConnCtx)
* \param pCisCtx CIS context.
*/
/*************************************************************************************************/
void lctrCisCheckUnframedFlush(lctrCisCtx_t *pCisCtx)
{
if (!(pConnCtx->usedFeatSet & LL_FEAT_POWER_CONTROL_REQUEST))
/*** Send up error SDU ***/
uint8_t handlerId;
uint8_t *pSdu;
uint8_t numHandles = 0;
uint16_t handles[1] = { pCisCtx->cisHandle };
uint16_t numSdu[1] = { 0 };
/* NULL signals lost PDU; release previously stored fragments. */
if (lctrRecombineRxUnframedSdu(&pCisCtx->isoalRxCtx, NULL))
{
while ((pSdu = WsfMsgDeq(&pCisCtx->isoalRxCtx.data.unframed.pendSduQ, &handlerId)) != NULL)
{
/* Enqueue SDU for processing. */
if (!lctrIsoRxConnEnq(&pCisCtx->dataPathOutCtx, pCisCtx->cisHandle,
pCisCtx->rxPktCounter, pSdu))
{
/* The buffer was not freed, so free it now. */
WsfMsgFree(pSdu);
}
numHandles = 1;
numSdu[0]++;
}
}
else
{
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_ISO_LOST_NOTIFY) &&
(((pCisCtx->role == LL_ROLE_SLAVE) && (pCisCtx->data.slv.rxFromMaster == FALSE)) ||
((pCisCtx->role == LL_ROLE_MASTER) && (pCisCtx->data.mst.rxFromSlave == FALSE))))
{
/* No prior fragments; send lost SDU. */
if ((pSdu = lctrRxSduAlloc()) != NULL)
{
/* TODO: This code path increases this twice: once in lctrRxSduAlloc and lctrIsoRxConnEnq.
* Change to only increase once.
*/
lctrIsoDataRxIncAvailBuf(1);
lctrIsoHdr_t isoHdr =
{
/* ISO header */
.handle = pCisCtx->cisHandle,
.pb = LCTR_PB_COMP,
.tsFlag = FALSE,
.len = 0,
/* Data load */
.ts = 0,
.pktSn = pCisCtx->rxPktCounter,
.sduLen = 0,
.ps = LCTR_PS_LOST
};
lctrIsoPackHdr(pSdu, &isoHdr);
/* Enqueue SDU for processing. */
if (!lctrIsoRxConnEnq(&pCisCtx->dataPathOutCtx, pCisCtx->cisHandle,
pCisCtx->rxPktCounter, pSdu))
{
/* The buffer was not freed, so free it now. */
WsfMsgFree(pSdu);
}
numHandles = 1;
numSdu[0]++;
}
else
{
LL_TRACE_WARN0("SDU Could not be allocated.");
}
}
}
if (lmgrPersistCb.recvIsoPendCback && numHandles)
{
/* Notify host received SDUs. */
lmgrPersistCb.recvIsoPendCback(numHandles, handles, numSdu);
}
}
/*************************************************************************************************/
/*!
* \brief Service function for CIS power control.
*
* \param pConnCtx Connection context.
*
*************************************************************************************************/
void lctrCisServicePowerMonitor(lctrConnCtx_t *pConnCtx)
{
if (!(pConnCtx->usedFeatSet & LL_FEAT_POWER_CONTROL_REQUEST) ||
lmgrGetOpFlag(LL_OP_MODE_FLAG_DIS_POWER_MONITOR))
{
pConnCtx->monitoringState = LCTR_PC_MONITOR_DISABLED;
return;
}
if (lmgrCb.opModeFlags & LL_OP_MODE_DISABLE_POWER_MONITOR)
{
return;
}
int8_t sendReqDelta = 0;
lctrCisCtx_t *pCisCtx = NULL;
if ((rssi < pConnCtx->pclMonitorParam.autoMonitor.lowThreshold) ||
(status != BB_STATUS_SUCCESS))
for (unsigned int i = 0; i < pLctrRtCfg->maxCis; i++)
{
pConnCtx->cisRssiExtremeTimeSpent++;
pCisCtx = &pLctrCisTbl[i];
if (pConnCtx->cisRssiExtremeTimeSpent >= pConnCtx->pclMonitorParam.autoMonitor.minTimeSpent)
if ((pCisCtx->aclHandle == LCTR_GET_CONN_HANDLE(pConnCtx)) &&
(pCisCtx->enabled) && (pCisCtx->connEst))
{
if (!(pConnCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MAX_BIT))
if (((pCisCtx->role == LL_ROLE_SLAVE) && (pCisCtx->phyMToS == pConnCtx->bleData.chan.rxPhy)) ||
((pCisCtx->role == LL_ROLE_MASTER) && (pCisCtx->phySToM == pConnCtx->bleData.chan.rxPhy)))
{
LL_TRACE_INFO1("RSSI too low, requesting increase in power. phy=%u", phy);
sendReqDelta = pConnCtx->pclMonitorParam.autoMonitor.requestVal;
/* This power is already managed by ACL, so no need to run management on CIS. */
return;
}
pConnCtx->cisRssiExtremeTimeSpent = 0;
goto CisManageRssiPower;
}
}
else if (rssi > pConnCtx->pclMonitorParam.autoMonitor.highThreshold)
{
pConnCtx->cisRssiExtremeTimeSpent++;
return;
if (pConnCtx->cisRssiExtremeTimeSpent >= pConnCtx->pclMonitorParam.autoMonitor.minTimeSpent)
{
if (!(pConnCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MIN_BIT))
{
LL_TRACE_INFO1("RSSI too high, requesting decrease in power. phy=%u", phy);
sendReqDelta = -(pConnCtx->pclMonitorParam.autoMonitor.requestVal);
}
pConnCtx->cisRssiExtremeTimeSpent = 0;
}
}
else
CisManageRssiPower:
lctrRssiAddAveragePoint(&pConnCtx->cisRunAvg, -((int8_t) (pConnCtx->cisAccumulatedRssi / pConnCtx->cisTotalAccumulatedRssi)));
pConnCtx->cisAccumulatedRssi = 0;
pConnCtx->cisTotalAccumulatedRssi = 0;
if (pConnCtx->cisRunAvg.avgCount >= LL_PC_TBL_LEN)
{
pConnCtx->cisRssiExtremeTimeSpent = 0;
int8_t averageRunning = lctrRssiGetAverage(&pConnCtx->cisRunAvg);
if ((averageRunning > pConnCtx->pclMonitorParam.autoMonitor.highThreshold) &&
!(pConnCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MIN_BIT))
{
sendReqDelta = -(pConnCtx->pclMonitorParam.autoMonitor.requestVal);
}
else if ((averageRunning < pConnCtx->pclMonitorParam.autoMonitor.lowThreshold) &&
!(pConnCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MAX_BIT))
{
sendReqDelta = pConnCtx->pclMonitorParam.autoMonitor.requestVal;
}
}
if (sendReqDelta != 0)
{
if ((pConnCtx->llcpActiveProc == LCTR_PROC_PWR_CTRL) ||
(pConnCtx->llcpPendMask & (1 << LCTR_PROC_PWR_CTRL)))
{
LL_TRACE_WARN0("Power control LLCP already ongoing or pended upon attempt to start new power control process.");
return;
}
lctrMsgPwrCtrlReq_t *pMsg;
uint8_t phy = ((pCisCtx->role == LL_ROLE_MASTER) ? pCisCtx->phySToM : pCisCtx->phyMToS);
/* Decide to request S8 or S2 PHY. */
phy += (((phy == LL_PHY_LE_CODED) &&
(pCisCtx->bleData.chan.initTxPhyOptions == LL_PHY_OPTIONS_S2_PREFERRED)) ? 1 : 0);
if ((pMsg = (lctrMsgPwrCtrlReq_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = LCTR_GET_CONN_HANDLE(pConnCtx);
@ -1814,6 +1940,8 @@ void lctrCisPowerMonitorCheckRssi(int8_t rssi, uint8_t status, uint8_t phy, lctr
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
}
pConnCtx->cisRunAvg.avgCount = 0;
}
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -207,7 +207,11 @@ static void lctrSetCis(lctrCisCtx_t *pCisCtx, LlCisCigParams_t *pSetCigParam, Ll
pCisCtx->ftMToS = LlMathDivideUint32(pSetCigParam->transLatMToS * 1000, LCTR_ISO_INT_TO_US(pCisCtx->isoInterval));
pCisCtx->ftSToM = LlMathDivideUint32(pSetCigParam->transLatSToM * 1000, LCTR_ISO_INT_TO_US(pCisCtx->isoInterval));
if (pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen * pCisCtx->localDataPdu.maxTxLen < pCisCtx->sduSizeMToS)
if (pCisCtx->localDataPdu.maxTxLen == 0)
{
pCisCtx->bnMToS = 0;
}
else if (pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen * pCisCtx->localDataPdu.maxTxLen < pCisCtx->sduSizeMToS)
{
pCisCtx->bnMToS = pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen + 1;
}
@ -216,7 +220,11 @@ static void lctrSetCis(lctrCisCtx_t *pCisCtx, LlCisCigParams_t *pSetCigParam, Ll
pCisCtx->bnMToS = pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen;
}
if (pCisCtx->sduSizeSToM / pCisCtx->localDataPdu.maxRxLen * pCisCtx->localDataPdu.maxRxLen < pCisCtx->sduSizeSToM)
if (pCisCtx->localDataPdu.maxRxLen == 0)
{
pCisCtx->bnSToM = 0;
}
else if (pCisCtx->sduSizeSToM / pCisCtx->localDataPdu.maxRxLen * pCisCtx->localDataPdu.maxRxLen < pCisCtx->sduSizeSToM)
{
pCisCtx->bnSToM = pCisCtx->sduSizeSToM / pCisCtx->localDataPdu.maxRxLen + 1;
}
@ -255,7 +263,11 @@ static void lctrSetCis(lctrCisCtx_t *pCisCtx, LlCisCigParams_t *pSetCigParam, Ll
pCisCtx->ftMToS = LlMathDivideUint32(pSetCigParam->transLatMToS * 1000, LCTR_ISO_INT_TO_US(pCisCtx->isoInterval));
pCisCtx->ftSToM = LlMathDivideUint32(pSetCigParam->transLatSToM * 1000, LCTR_ISO_INT_TO_US(pCisCtx->isoInterval));
if (pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen * pCisCtx->localDataPdu.maxTxLen < pCisCtx->sduSizeMToS)
if (pCisCtx->localDataPdu.maxTxLen == 0)
{
pCisCtx->bnMToS = 0;
}
else if (pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen * pCisCtx->localDataPdu.maxTxLen < pCisCtx->sduSizeMToS)
{
pCisCtx->bnMToS = pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen + 1;
}
@ -264,7 +276,11 @@ static void lctrSetCis(lctrCisCtx_t *pCisCtx, LlCisCigParams_t *pSetCigParam, Ll
pCisCtx->bnMToS = pCisCtx->sduSizeMToS / pCisCtx->localDataPdu.maxTxLen;
}
if (pCisCtx->sduSizeSToM / pCisCtx->localDataPdu.maxRxLen * pCisCtx->localDataPdu.maxRxLen < pCisCtx->sduSizeSToM)
if (pCisCtx->localDataPdu.maxRxLen == 0)
{
pCisCtx->bnSToM = 0;
}
else if (pCisCtx->sduSizeSToM / pCisCtx->localDataPdu.maxRxLen * pCisCtx->localDataPdu.maxRxLen < pCisCtx->sduSizeSToM)
{
pCisCtx->bnSToM = pCisCtx->sduSizeSToM / pCisCtx->localDataPdu.maxRxLen + 1;
}
@ -359,6 +375,7 @@ static void lctrSetCig(lctrCigCtx_t *pCigCtx, LlCisCigParams_t *pSetCigParam)
pCisCtx = lctrFindCisById(pSetCigParam->cigId, pSetCigParam->pCisParam[i].cisId);
WSF_ASSERT(pCisCtx);
pCisCtx->cisSyncDelayUsec = 0;
for (unsigned int j = i; j < pSetCigParam->numCis; j++)
{
@ -569,6 +586,40 @@ uint8_t LctrSetCigParam(LlCisCigParams_t *pSetCigParam, uint16_t *pCisHandles)
pCisHandles[i] = pCisCtx->cisHandle;
}
lctrSetCig(pCigCtx, pSetCigParam);
/* Invalid CIG parameters. Attempt adjusting of CIG parameters. */
bool_t paramsChanged = TRUE;
if (pCigCtx->isValid == FALSE)
{
LL_TRACE_WARN1("LctrSetCigParam, invalid parameters in cigID=%u; adjust parameters", pSetCigParam->cigId);
}
while ((pCigCtx->isValid == FALSE) && (paramsChanged == TRUE))
{
paramsChanged = FALSE;
for (unsigned int i = 0; i < pSetCigParam->numCis; i++)
{
/* Try to adjust CIS RTE to lower than host-reccomended value. */
pCisCtx = lctrFindCisByHandle(pCisHandles[i]);
if (pSetCigParam->pCisParam[i].rteMToS > 0)
{
pSetCigParam->pCisParam[i].rteMToS--;
paramsChanged = TRUE;
}
if (pSetCigParam->pCisParam[i].rteSToM > 0)
{
pSetCigParam->pCisParam[i].rteSToM--;
paramsChanged = TRUE;
}
/* Re-apply parameters. */
lctrSetCis(pCisCtx, pSetCigParam, &pSetCigParam->pCisParam[i]);
lctrSetCig(pCigCtx, pSetCigParam);
if (pCigCtx->isValid)
{
break;
}
}
}
}
}
else
@ -597,6 +648,40 @@ uint8_t LctrSetCigParam(LlCisCigParams_t *pSetCigParam, uint16_t *pCisHandles)
}
lctrSetCig(pCigCtx, pSetCigParam);
}
/* Invalid CIG parameters. Attempt adjusting of CIG parameters. */
bool_t paramsChanged = TRUE;
if (pCigCtx->isValid == FALSE)
{
LL_TRACE_WARN1("LctrSetCigParam: invalid parameters in cigID=%u; adjust parameters", pSetCigParam->cigId);
}
while ((pCigCtx->isValid == FALSE) && (paramsChanged == TRUE))
{
paramsChanged = FALSE;
for (unsigned int i = 0; i < pSetCigParam->numCis; i++)
{
/* Try to adjust CIS RTE to lower than host-reccomended value. */
pCisCtx = lctrFindCisByHandle(pCisHandles[i]);
if (pSetCigParam->pCisParam[i].rteMToS > 0)
{
pSetCigParam->pCisParam[i].rteMToS--;
paramsChanged = TRUE;
}
if (pSetCigParam->pCisParam[i].rteSToM > 0)
{
pSetCigParam->pCisParam[i].rteSToM--;
paramsChanged = TRUE;
}
/* Re-apply parameters. */
lctrSetCis(pCisCtx, pSetCigParam, &pSetCigParam->pCisParam[i]);
lctrSetCig(pCigCtx, pSetCigParam);
if (pCigCtx->isValid)
{
break;
}
}
}
}
pCigCtx->roleData.mst.numCis = pSetCigParam->numCis;
@ -772,6 +857,7 @@ void LctrMstCisInit(void)
/* Add CIS function pointers */
LctrUpdateCisChanMapFn = LctrCisUpdateChanMap;
lctrRegisterChClassHandler(lctrMstCisChClassUpdate);
lctrCisServicePowerMonitorFn = lctrCisServicePowerMonitor;
/* Add CIS event handlers. */
lctrEventHdlrTbl[LCTR_EVENT_CIS_TX_PENDING] = lctrIsoTxPendingHandler;
@ -826,6 +912,8 @@ uint8_t LctrCreateCis(uint8_t numCis, LlCisCreateCisParams_t *pCreateCisParam)
LL_TRACE_WARN0("LctrCreateCis, CIS is already established");
return LL_ERROR_CODE_ACL_CONN_ALREADY_EXISTS;
}
pCisCtx->isClosing = FALSE;
}
lmgrCisMstCb.createCisPend = TRUE;
@ -873,6 +961,7 @@ void lctrMstCisBuildCigOp(lctrCigCtx_t *pCigCtx)
BbBleData_t * const pBle = &pCisCtx->bleData;
BbBleMstCisEvent_t * const pCis = &pBle->op.mstCis;
lctrConnCtx_t * pConnCtx = LCTR_GET_CONN_CTX(pCisCtx->aclHandle);
memset(pOp, 0, sizeof(BbOpDesc_t));
memset(pBle, 0, sizeof(BbBleData_t));
@ -897,8 +986,18 @@ void lctrMstCisBuildCigOp(lctrCigCtx_t *pCigCtx)
pBle->chan.peerTxStableModIdx = TRUE;
pBle->chan.peerRxStableModIdx = TRUE;
/* Set PHY options to mirror acl connection option. */
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S8;
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2))
{
/* Force Coded PHY option to S2. */
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
pBle->chan.tifsTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
}
else
{
/* Set PHY options to mirror ACL connection option. */
pBle->chan.initTxPhyOptions = pConnCtx->bleData.chan.initTxPhyOptions;
pBle->chan.tifsTxPhyOptions = pConnCtx->bleData.chan.tifsTxPhyOptions;
}
#if (LL_ENABLE_TESTER)
pBle->chan.accAddrRx = pCisCtx->accessAddr ^ llTesterCb.cisAccessAddrRx;
@ -916,8 +1015,7 @@ void lctrMstCisBuildCigOp(lctrCigCtx_t *pCigCtx)
/*** General setup ***/
/* pOp->minDurUsec = pFirstCisCtx->subIntervUsec * WSF_MAX(pFirstCisCtx->bnMToS, pFirstCisCtx->bnSToM); */ /* Guarantee at least Max BN */
pOp->minDurUsec = pCigCtx->cigSyncDelayUsec;
pOp->minDurUsec = pCisCtx->subIntervUsec * WSF_MAX(pCisCtx->bnMToS, pCisCtx->bnSToM); /* Guarantee at least Max BN */
pOp->maxDurUsec = pCigCtx->cigSyncDelayUsec;
/* pOp->due = 0 */ /* set in lctrMstCisCigOpCommit() */
@ -931,6 +1029,7 @@ void lctrMstCisBuildCigOp(lctrCigCtx_t *pCigCtx)
/*** BLE stream setup ***/
pCis->checkContOpCback = lctrMstCisCheckContOp;
pCis->checkContOpPostCback = lctrMstCisCheckContOpPostCback;
pCis->execCback = lctrMstCisCigBeginOp;
pCis->contExecCback = lctrMstCisCigContOp;
pCis->postSubEvtCback = lctrMstCisCigPostSubEvt;
@ -979,15 +1078,17 @@ void lctrMstCisBuildCisData(lctrCisCtx_t *pCisCtx)
pBle->chan.peerTxStableModIdx = TRUE;
pBle->chan.peerRxStableModIdx = TRUE;
/* Set PHY options to mirror acl connection option. */
if (pConnCtx->bleData.chan.tifsTxPhyOptions != BB_PHY_OPTIONS_DEFAULT)
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2))
{
/* Set PHY options to host defined behavior. */
pBle->chan.initTxPhyOptions = pConnCtx->bleData.chan.tifsTxPhyOptions;
/* Force Coded PHY option to S2. */
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
pBle->chan.tifsTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
}
else
{
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S8;
/* Set PHY options to mirror ACL connection option. */
pBle->chan.initTxPhyOptions = pConnCtx->bleData.chan.initTxPhyOptions;
pBle->chan.tifsTxPhyOptions = pConnCtx->bleData.chan.tifsTxPhyOptions;
}
#if (LL_ENABLE_TESTER)
@ -1007,6 +1108,7 @@ void lctrMstCisBuildCisData(lctrCisCtx_t *pCisCtx)
/*** BLE stream setup ***/
pCis->checkContOpCback = lctrMstCisCheckContOp;
pCis->checkContOpPostCback = lctrMstCisCheckContOpPostCback;
pCis->execCback = lctrMstCisCigBeginOp;
pCis->contExecCback = lctrMstCisCigContOp;
pCis->postSubEvtCback = lctrMstCisCigPostSubEvt;
@ -1034,8 +1136,9 @@ void lctrMstCisCigOpCommit(lctrCigCtx_t *pCigCtx, lctrConnCtx_t *pCtx, lctrCisCt
{
/* Recalculate the CE ref if it is already past. */
pCisCtx->ceRef = pCtx->eventCounter +
LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency; /* ensure slave will listen to this packet */
((LL_MIN_INSTANT + 1 + /* +1 for next CE */
pCtx->maxLatency) * /* ensure slave will listen to this packet */
pCtx->ecu.srFactor); /* include subrating factor */
refTime = pConnBod->dueUsec + (pCisCtx->ceRef - pCtx->eventCounter) * LCTR_CONN_IND_US(pCtx->connInterval);

View File

@ -71,12 +71,11 @@ void LctrCisSlvInit(void)
lctrResetHdlrTbl[LCTR_DISP_CIS] = lctrSlvCisResetHandler;
/* Add connection message dispatcher. */
if (lctrMsgDispTbl[LCTR_DISP_CIS] != NULL)
{
lctrMsgDispTbl[LCTR_DISP_CIS] = (LctrMsgDisp_t)lctrCisDisp;
}
lctrMsgDispTbl[LCTR_DISP_CIS] = (LctrMsgDisp_t)lctrCisDisp;
lctrCisDefaults();
/* Add CIS function pointers */
LctrUpdateCisChanMapFn = LctrCisUpdateChanMap;
lctrCisServicePowerMonitorFn = lctrCisServicePowerMonitor;
/* Add connection event handlers. */
lctrEventHdlrTbl[LCTR_EVENT_CIS_RX_PENDING] = lctrCisRxPendingHandler;
@ -86,6 +85,8 @@ void LctrCisSlvInit(void)
lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_EST] = lctrSlvLlcpExecuteCisEstSm;
lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM] = lctrLlcpExecuteCisTermSm;
lctrCisDefaults();
/* Set supported features. */
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_5_1)
{
@ -207,6 +208,7 @@ void lctrSlvCisBuildCigOp(lctrCigCtx_t *pCigCtx)
BbBleData_t * const pBle = &pCisCtx->bleData;
BbBleSlvCisEvent_t * const pCis = &pBle->op.slvCis;
lctrConnCtx_t * const pConnCtx = LCTR_GET_CONN_CTX(pCisCtx->aclHandle);
memset(pOp, 0, sizeof(BbOpDesc_t));
memset(pBle, 0, sizeof(BbBleData_t));
@ -235,8 +237,18 @@ void lctrSlvCisBuildCigOp(lctrCigCtx_t *pCigCtx)
pBle->chan.peerTxStableModIdx = TRUE;
pBle->chan.peerRxStableModIdx = TRUE;
/* Set PHY options to mirror acl connection option. */
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S8;
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2))
{
/* Force Coded PHY option to S2. */
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
pBle->chan.tifsTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
}
else
{
/* Set PHY options to mirror ACL connection option. */
pBle->chan.initTxPhyOptions = pConnCtx->bleData.chan.initTxPhyOptions;
pBle->chan.tifsTxPhyOptions = pConnCtx->bleData.chan.tifsTxPhyOptions;
}
#if (LL_ENABLE_TESTER)
pBle->chan.accAddrRx = pCisCtx->accessAddr ^ llTesterCb.cisAccessAddrRx;
@ -254,7 +266,8 @@ void lctrSlvCisBuildCigOp(lctrCigCtx_t *pCigCtx)
/*** General setup ***/
pOp->minDurUsec = pCisCtx->subIntervUsec * WSF_MAX(pCisCtx->bnMToS, pCisCtx->bnSToM); /* Guarantee at least Max BN */
/* Use small minDurUsec to improve scheduling. */
pOp->minDurUsec = pCisCtx->subIntervUsec;
pOp->maxDurUsec = pCigCtx->cigSyncDelayUsec;
/* pOp->due = 0 */ /* set in lctrCisMstCigOpCommit() */
@ -268,6 +281,7 @@ void lctrSlvCisBuildCigOp(lctrCigCtx_t *pCigCtx)
/*** BLE stream setup ***/
pCis->checkContOpCback = lctrSlvCisCheckContOp;
pCis->checkContOpPostCback = lctrSlvCisCheckContOpPostCback;
pCis->execCback = lctrSlvCisCigBeginOp;
pCis->contExecCback = lctrSlvCisCigContOp;
pCis->postSubEvtCback = lctrSlvCisCigPostSubEvt;
@ -292,7 +306,7 @@ void lctrSlvCisBuildCisData(lctrCisCtx_t *pCisCtx)
{
BbBleData_t * const pBle = &pCisCtx->bleData;
BbBleSlvCisEvent_t * const pCis = &pBle->op.slvCis;
lctrConnCtx_t * pConnCtx = LCTR_GET_CONN_CTX(pCisCtx->aclHandle);
lctrConnCtx_t * const pConnCtx = LCTR_GET_CONN_CTX(pCisCtx->aclHandle);
memset(pBle, 0, sizeof(BbBleData_t));
memset(pCis, 0, sizeof(BbBleMstCisEvent_t));
@ -316,15 +330,17 @@ void lctrSlvCisBuildCisData(lctrCisCtx_t *pCisCtx)
pBle->chan.peerTxStableModIdx = TRUE;
pBle->chan.peerRxStableModIdx = TRUE;
/* Set PHY options to mirror acl connection option. */
if (pConnCtx->bleData.chan.tifsTxPhyOptions != BB_PHY_OPTIONS_DEFAULT)
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_FORCE_CIS_CODED_PHY_S2))
{
/* Set PHY options to host defined behavior. */
pBle->chan.initTxPhyOptions = pConnCtx->bleData.chan.tifsTxPhyOptions;
/* Force Coded PHY option to S2. */
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
pBle->chan.tifsTxPhyOptions = BB_PHY_OPTIONS_BLE_S2;
}
else
{
pBle->chan.initTxPhyOptions = BB_PHY_OPTIONS_BLE_S8;
/* Set PHY options to mirror ACL connection option. */
pBle->chan.initTxPhyOptions = pConnCtx->bleData.chan.initTxPhyOptions;
pBle->chan.tifsTxPhyOptions = pConnCtx->bleData.chan.tifsTxPhyOptions;
}
#if (LL_ENABLE_TESTER)
@ -344,6 +360,7 @@ void lctrSlvCisBuildCisData(lctrCisCtx_t *pCisCtx)
/*** BLE stream setup ***/
pCis->checkContOpCback = lctrSlvCisCheckContOp;
pCis->checkContOpPostCback = lctrSlvCisCheckContOpPostCback;
pCis->execCback = lctrSlvCisCigBeginOp;
pCis->contExecCback = lctrSlvCisCigContOp;
pCis->postSubEvtCback = lctrSlvCisCigPostSubEvt;

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -91,8 +91,8 @@ lctrLlcpEh_t lctrStorePeriodicSyncTrsfFn = NULL;
/*! \brief Pointer to lctrReceivePeriodicSyncInd function. */
lctrLlcpEh_t lctrReceivePeriodicSyncIndFn = NULL;
/*! \brief Power monitoring scheme action table. */
lctrPcMonAct_t lctrPcActTbl[LCTR_PC_MONITOR_SCHEME_TOTAL];
/*! \brief Pointer to path lctrPathLossMonitorAct function. */
lctrPcMonAct_t lctrPathLossMonitorActFn = NULL;
/*! \brief Pointer to lctrSendPowerChangeInd function. */
lctrPcPowInd_t lctrSendPowerChangeIndCback = NULL;
@ -100,6 +100,18 @@ lctrPcPowInd_t lctrSendPowerChangeIndCback = NULL;
/*! \brief Pointer to lctrNotifyPowerReportInd function. */
lctrPcNotifyPwr_t lctrNotifyPowerReportIndCback = NULL;
/*! \brief Pointer to lctrCisServicePowerMonitor Function. */
lctrCisServicePowerMonitor_t lctrCisServicePowerMonitorFn = NULL;
/*! \brief Last channel class map since host update (Used for slave channel status indications). */
static uint64_t lastChanClassMap = LL_CHAN_DATA_ALL;
/*! \brief Calculate number of subrated connection events. */
lctrCalcSubrateConnEvents_t lctrCalcSubrateConnEventsFn = NULL;
/*! \brief Calculate number of subrated connection events. */
lctrCheckLlcpOverride_t lctrSlvCheckEncOverridePhyUpdateFn = NULL;
/*************************************************************************************************/
/*!
* \brief Return PHYs supported by LL.
@ -287,6 +299,44 @@ bool_t LctrIsProcActPended(uint16_t handle, uint8_t event)
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Check whether a feature exchange procedure was host-initiated, or initiated as a result of connection startup.
*
* \param handle Connection handle.
*
* \return TRUE if the procedure was host-initiated. FALSE if not.
*/
/*************************************************************************************************/
bool_t LctrIsFeatExchHostInit(uint16_t handle)
{
lctrConnCtx_t *pCtx = LCTR_GET_CONN_CTX(handle);
if (!pCtx->enabled)
{
/* Should not happen. */
return FALSE;
}
return (pCtx->llcpNotifyMask & (1 << LCTR_PROC_CMN_FEAT_EXCH)) ? TRUE : FALSE;
}
/*************************************************************************************************/
/*!
* \brief Set controller to notify host when feature exchange completes.
*
* \param handle Connection handle.
*
*/
/*************************************************************************************************/
void LctrSetHostNotifyFeatExch(uint16_t handle)
{
lctrConnCtx_t *pCtx = LCTR_GET_CONN_CTX(handle);
pCtx->llcpNotifyMask |= (1 << LCTR_PROC_CMN_FEAT_EXCH);
}
/*************************************************************************************************/
/*!
* \brief Get encryption mode used in a connection.
@ -415,6 +465,13 @@ lctrConnCtx_t *lctrAllocConnCtx(void)
pMsg->dispId = LCTR_DISP_CONN;
pMsg->event = LCTR_CONN_TMR_AUTH_PAYLOAD_EXP;
/* Setup power control timer. */
pCtx->tmrPowerCtrl.handlerId = lmgrPersistCb.handlerId;
pMsg = (lctrMsgHdr_t *)&pCtx->tmrPowerCtrl.msg;
pMsg->handle = connIdx;
pMsg->dispId = LCTR_DISP_CONN;
pMsg->event = LCTR_CONN_LLCP_PWR_CTRL_SERVICE;
/* Default packet lengths. */
pCtx->localDataPdu.maxTxLen = lmgrConnCb.maxTxLen;
pCtx->localDataPdu.maxRxLen = WSF_MIN(LCTR_MAX_DATA_LEN_MAX, pLctrRtCfg->maxAclLen);
@ -457,17 +514,33 @@ lctrConnCtx_t *lctrAllocConnCtx(void)
}
/* Power control initialization. */
if (pCtx->usedFeatSet & LL_FEAT_POWER_CONTROL_REQUEST)
if ((pCtx->usedFeatSet & LL_FEAT_POWER_CONTROL_REQUEST) &&
!lmgrGetOpFlag(LL_OP_MODE_FLAG_DIS_POWER_MONITOR))
{
pCtx->powerMonitorScheme = LCTR_PC_MONITOR_AUTO;
pCtx->monitoringState = LCTR_PC_MONITOR_ENABLED;
pCtx->pclMonitorParam.autoMonitor.highThreshold = LCTR_RSSI_HIGH_THRESHOLD;
pCtx->pclMonitorParam.autoMonitor.lowThreshold = LCTR_RSSI_LOW_THRESHOLD;
pCtx->pclMonitorParam.autoMonitor.minTimeSpent = LCTR_PC_MIN_TIME;
pCtx->pclMonitorParam.autoMonitor.requestVal = LCTR_PC_REQUEST_VAL;
pCtx->pclMonitorParam.autoMonitor.curTimeSpent = 0;
pCtx->pclMonitorParam.autoMonitor.highThreshold = pLctrRtCfg->pcHighThreshold;
pCtx->pclMonitorParam.autoMonitor.lowThreshold = pLctrRtCfg->pcLowThreshold;
pCtx->pclMonitorParam.autoMonitor.requestVal = LL_PC_REQ_CHANGE_DBM;
/* Reset average counters. */
pCtx->pclMonitorParam.autoMonitor.accumulatedRssi = 0;
pCtx->pclMonitorParam.autoMonitor.totalAccumulatedRssi = 0;
pCtx->pclMonitorParam.autoMonitor.rssiRunAvg.avgCount = 0;
pCtx->cisAccumulatedRssi = 0;
pCtx->cisTotalAccumulatedRssi = 0;
pCtx->cisRunAvg.avgCount = 0;
}
/* Default Enhanced Connection Update. */
pCtx->ecu.srFactor = 1;
/* pCtx->ecu.contNum = 0; */
pCtx->ecu.defSrMin = lmgrConnCb.defSrMin;
pCtx->ecu.defSrMax = lmgrConnCb.defSrMax;
pCtx->ecu.defMaxLatency = lmgrConnCb.defMaxLatency;
pCtx->ecu.defContNum = lmgrConnCb.defContNum;
pCtx->ecu.defSvt = lmgrConnCb.defSvt;
LmgrIncResetRefCount();
lmgrCb.numConnEnabled++;
@ -519,6 +592,7 @@ void lctrFreeConnCtx(lctrConnCtx_t *pCtx)
WsfTimerStop(&pCtx->tmrProcRsp);
WsfTimerStop(&pCtx->tmrPingTimeout);
WsfTimerStop(&pCtx->tmrAuthTimeout);
WsfTimerStop(&pCtx->tmrPowerCtrl);
uint16_t handle = LCTR_GET_CONN_HANDLE(pCtx);
@ -695,18 +769,10 @@ void lctrConnRxPendingHandler(void)
lctrUnpackDataPduHdr(&rxHdr, pRxBuf);
/* Decrypt PDU. */
if (lctrPktDecryptHdlr)
if (pCtx->bleData.chan.enc.enaDecrypt)
{
if (lctrPktDecryptHdlr(&pCtx->bleData.chan.enc, pRxBuf))
{
if (pCtx->bleData.chan.enc.enaDecrypt)
{
/* Restart authentication timers. */
WsfTimerStartMs(&pCtx->tmrAuthTimeout, pCtx->authTimeoutMs);
WsfTimerStartMs(&pCtx->tmrPingTimeout, pCtx->pingPeriodMs);
}
}
else
if (lctrPktDecryptHdlr &&
(!lctrPktDecryptHdlr(&pCtx->bleData.chan.enc, pRxBuf)))
{
LL_TRACE_ERR1("!!! MIC verification failed on connHandle=%u", connHandle);
lctrRxPduFree(pRxBuf);
@ -714,6 +780,10 @@ void lctrConnRxPendingHandler(void)
lctrSendConnMsg(pCtx, LCTR_CONN_TERM_MIC_FAILED);
continue;
}
/* Restart authentication timers. */
WsfTimerStartMs(&pCtx->tmrAuthTimeout, pCtx->authTimeoutMs);
WsfTimerStartMs(&pCtx->tmrPingTimeout, pCtx->pingPeriodMs);
}
/* Demux PDU. */
@ -1076,7 +1146,7 @@ void LctrSetTxPowerLevel(uint16_t handle, int8_t level)
{
if (lctrNotifyPowerReportIndCback)
{
lctrNotifyPowerReportIndCback(pCtx, LL_POWER_REPORT_REASON_LOCAL, phy, adjustedLevel,
lctrNotifyPowerReportIndCback(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_LOCAL, phy, adjustedLevel,
lctrGetPowerLimits(adjustedLevel),
adjustedLevel - txPwrOld[phy]);
}
@ -1144,7 +1214,7 @@ void LctrSetPhyTxPowerLevel(uint16_t handle, int8_t level, uint8_t phy)
{
if (lctrNotifyPowerReportIndCback)
{
lctrNotifyPowerReportIndCback(pCtx, LL_POWER_REPORT_REASON_LOCAL, pBle->chan.txPhy, adjustedLevel,
lctrNotifyPowerReportIndCback(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_LOCAL, pBle->chan.txPhy, adjustedLevel,
lctrGetPowerLimits(pBle->chan.txPower),
delta);
}
@ -1211,6 +1281,30 @@ uint8_t LctrGetRxPhy(uint16_t handle)
return pLctrConnTbl[handle].bleData.chan.rxPhy;
}
/*************************************************************************************************/
/*!
* \brief Get status of CIS termination procedure.
*
* \param handle Connection handle.
*
* \return TRUE if termination is currently pending, FALSE if not.
*/
/*************************************************************************************************/
bool_t LctrCisTerminationInProgress(uint16_t handle)
{
WSF_ASSERT(handle < pLctrRtCfg->maxConn);
lctrConnCtx_t *pCtx = &pLctrConnTbl[handle];
if ((pCtx->llcpActiveProc == LCTR_PROC_CIS_TERM) ||
(pCtx->llcpPendMask & (1 << LCTR_PROC_CIS_TERM)))
{
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Get peer minimum number of used channels.
@ -1327,7 +1421,7 @@ BbOpDesc_t *lctrConnResolveConflict(BbOpDesc_t *pNewOp, BbOpDesc_t *pExistOp)
!((pExistOp->prot.pBle->chan.opType == BB_BLE_OP_SLV_CONN_EVENT) ||
(pExistOp->prot.pBle->chan.opType == BB_BLE_OP_MST_CONN_EVENT)))
{
LL_TRACE_WARN1("!!! Scheduling conflict, BLE connections: incoming handle=%u prioritized over non-BLE operation", LCTR_GET_CONN_HANDLE(pNewCtx));
LL_TRACE_WARN1("!!! Scheduling conflict, BLE connections: incoming handle=%u prioritized over non-connection operation", LCTR_GET_CONN_HANDLE(pNewCtx));
return pNewOp;
}
@ -1603,11 +1697,17 @@ uint8_t lctrSetPowerMonitorEnable(uint16_t handle, bool_t enable)
pCtx->powerMonitorScheme = LCTR_PC_MONITOR_AUTO;
pCtx->monitoringState = enable;
pCtx->pclMonitorParam.autoMonitor.highThreshold = LCTR_RSSI_HIGH_THRESHOLD;
pCtx->pclMonitorParam.autoMonitor.lowThreshold = LCTR_RSSI_LOW_THRESHOLD;
pCtx->pclMonitorParam.autoMonitor.minTimeSpent = LCTR_PC_MIN_TIME;
pCtx->pclMonitorParam.autoMonitor.requestVal = LCTR_PC_REQUEST_VAL;
pCtx->pclMonitorParam.autoMonitor.curTimeSpent = 0;
pCtx->pclMonitorParam.autoMonitor.highThreshold = pLctrRtCfg->pcHighThreshold;
pCtx->pclMonitorParam.autoMonitor.lowThreshold = pLctrRtCfg->pcLowThreshold;
pCtx->pclMonitorParam.autoMonitor.requestVal = LL_PC_REQ_CHANGE_DBM;
/* Initialize average function. */
pCtx->pclMonitorParam.autoMonitor.accumulatedRssi = 0;
pCtx->pclMonitorParam.autoMonitor.totalAccumulatedRssi = 0;
pCtx->pclMonitorParam.autoMonitor.rssiRunAvg.avgCount = 0;
pCtx->cisAccumulatedRssi = 0;
pCtx->cisTotalAccumulatedRssi = 0;
pCtx->cisRunAvg.avgCount = 0;
return LL_SUCCESS;
}
@ -1648,3 +1748,75 @@ uint8_t lctrGetPowerLimits(int8_t txPower)
return 0;
}
}
/*************************************************************************************************/
/*!
* \brief Host channel class update handler for connections.
*
* \param chanMap Updated channel map.
*
* \return Status code.
*/
/*************************************************************************************************/
uint8_t lctrConnChClassUpdate(uint64_t chanMap)
{
lctrChanMapUpdate_t *pMsg;
lctrConnCtx_t *pCtx;
uint16_t handle;
uint8_t status = LL_SUCCESS;
/* Update for connections */
for (handle = 0; handle < pLctrRtCfg->maxConn; handle++)
{
if (LctrIsConnHandleEnabled(handle))
{
if (LctrGetRole(handle) == LL_ROLE_MASTER)
{
/* Update the channel map for CIS master as well. */
if (LctrUpdateCisChanMapFn)
{
LctrUpdateCisChanMapFn(handle);
}
if (LctrIsProcActPended(handle, LCTR_CONN_MSG_API_CHAN_MAP_UPDATE) == TRUE)
{
status = LL_ERROR_CODE_CMD_DISALLOWED;
}
if ((pMsg = (lctrChanMapUpdate_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = handle;
pMsg->hdr.dispId = LCTR_DISP_CONN;
pMsg->hdr.event = LCTR_CONN_MSG_API_CHAN_MAP_UPDATE;
pMsg->chanMap = chanMap;
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
}
else
{
LL_TRACE_ERR0("lctrConnChClassUpdate: out of message buffers");
return LL_ERROR_CODE_CMD_DISALLOWED;
}
}
else /* LL_ROLE_SLAVE */
{
if (lastChanClassMap != chanMap)
{
pCtx = LCTR_GET_CONN_CTX(handle);
if ((pCtx->usedFeatSet & LL_FEAT_CHANNEL_CLASSIFICATION) &&
pCtx->chanStatRptEnable)
{
pCtx->data.slv.queuedChanStatusTs = PalBbGetCurrentTime();
/* Update is sent to host in lctrSlvConnEndOp(). */
}
lastChanClassMap = chanMap;
}
}
}
}
return status;
}

View File

@ -606,6 +606,8 @@ void lctrTxDataPduQueue(lctrConnCtx_t *pCtx, uint16_t fragLen, lctrAclHdr_t *pAc
/*************************************************************************************************/
void lctrTxCtrlPduQueue(lctrConnCtx_t *pCtx, uint8_t *pBuf)
{
pCtx->numTxPendCtrlPdu++;
#if (LL_ENABLE_TESTER)
uint16_t connHandle = LCTR_GET_CONN_HANDLE(pCtx);
#endif

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -192,59 +192,6 @@ static void lctrMstConnDisp(lctrConnMsg_t *pMsg)
}
}
/*************************************************************************************************/
/*!
* \brief Host channel class update handler for connections.
*
* \param chanMap Updated channel map.
*
* \return Status code.
*/
/*************************************************************************************************/
static uint8_t lctrConnChClassUpdate(uint64_t chanMap)
{
lctrChanMapUpdate_t *pMsg;
uint16_t handle;
uint8_t status = LL_SUCCESS;
/* Update for connections */
for (handle = 0; handle < pLctrRtCfg->maxConn; handle++)
{
if ((LctrIsConnHandleEnabled(handle)) &&
(LctrGetRole(handle) == LL_ROLE_MASTER))
{
/* Update the channel map for CIS master as well. */
if (LctrUpdateCisChanMapFn)
{
LctrUpdateCisChanMapFn(handle);
}
if (LctrIsProcActPended(handle, LCTR_CONN_MSG_API_CHAN_MAP_UPDATE) == TRUE)
{
status = LL_ERROR_CODE_CMD_DISALLOWED;
}
if ((pMsg = (lctrChanMapUpdate_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = handle;
pMsg->hdr.dispId = LCTR_DISP_CONN;
pMsg->hdr.event = LCTR_CONN_MSG_API_CHAN_MAP_UPDATE;
pMsg->chanMap = chanMap;
WsfMsgSend(lmgrPersistCb.handlerId, pMsg);
}
else
{
LL_TRACE_ERR0("lctrConnChClassUpdate: out of message buffers");
return LL_ERROR_CODE_CMD_DISALLOWED;
}
}
}
return status;
}
/*************************************************************************************************/
/*!
* \brief Build a connection operation.
@ -357,8 +304,10 @@ void lctrMstSetEstablishConn(lctrConnCtx_t *pCtx)
const uint16_t txWinOffsetCnt = pConnInd->txWinOffset + LCTR_DATA_CHAN_DLY;
/* Initially use fast termination. */
/* The first CE starts after transmitWindowDelay + transmitWindowOffset + transmitWindowSize.
Then an additional 5 CI are required + the duration of the last connection event. */
uint32_t fastTermCnt = txWinOffsetCnt + pConnInd->txWinSize +
(LCTR_FAST_TERM_CNT * pConnInd->interval);
((LCTR_FAST_TERM_CNT - 1) * pConnInd->interval) + (pConnInd->interval >> 1);
WsfTimerStartMs(&pCtx->tmrSupTimeout, LCTR_CONN_IND_MS(fastTermCnt));
/* Set initial channel. */
@ -371,6 +320,7 @@ void lctrMstSetEstablishConn(lctrConnCtx_t *pCtx)
LL_TRACE_INFO1(" >>> Connection established, handle=%u <<<", LCTR_GET_CONN_HANDLE(pCtx));
LL_TRACE_INFO1(" connIntervalUsec=%u", LCTR_CONN_IND_US(pCtx->connInterval));
LL_TRACE_INFO1(" dueUsec=%u", pCtx->connBod.dueUsec);
LL_TRACE_INFO1(" pBod=0x%08x", &pCtx->connBod);
}
/*************************************************************************************************/
@ -401,6 +351,7 @@ void LctrMstConnInit(void)
/* Add channel selection handler. */
lctrChSelHdlr[LL_CH_SEL_1] = lctrSelectNextDataChannel;
/* Register channel class update handler. */
lctrRegisterChClassHandler(lctrConnChClassUpdate);
lctrConnDefaults();
@ -426,7 +377,13 @@ void LctrMstConnInit(void)
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_5_1)
{
lmgrPersistCb.featuresDefault |=
(LL_FEAT_PAST_SENDER | LL_FEAT_SCA_UPDATE);
LL_FEAT_PAST_SENDER |
LL_FEAT_SCA_UPDATE;
}
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_SYDNEY)
{
lmgrPersistCb.featuresDefault |=
LL_FEAT_CHANNEL_CLASSIFICATION;
}
}

View File

@ -375,6 +375,7 @@ void lctrSlvConnBuildOp(lctrConnCtx_t *pCtx)
LL_TRACE_INFO1(" connIntervalUsec=%u", LCTR_CONN_IND_US(pCtx->connInterval));
LL_TRACE_INFO1(" dueUsec=%u", pOp->dueUsec);
LL_TRACE_INFO1(" minDurUsec=%u", pOp->minDurUsec);
LL_TRACE_INFO1(" pBod=0x%08x", pOp);
break;
}
@ -432,6 +433,9 @@ void LctrSlvConnInit(void)
/* Add channel selection handler. */
lctrChSelHdlr[LL_CH_SEL_1] = lctrSelectNextDataChannel;
/* Register channel class update handler. */
lctrRegisterChClassHandler(lctrConnChClassUpdate);
lctrConnDefaults();
/* Set supported features. */
@ -455,7 +459,13 @@ void LctrSlvConnInit(void)
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_5_1)
{
lmgrPersistCb.featuresDefault |=
(LL_FEAT_PAST_SENDER | LL_FEAT_SCA_UPDATE);
LL_FEAT_PAST_SENDER |
LL_FEAT_SCA_UPDATE;
}
if (pLctrRtCfg->btVer >= LL_VER_BT_CORE_SPEC_SYDNEY)
{
lmgrPersistCb.featuresDefault |=
LL_FEAT_CHANNEL_CLASSIFICATION;
}
}

View File

@ -105,16 +105,18 @@ void LctrMstConnEncInit(void)
lctrCtrlPduHdlr = lctrMstEncProcessDataPdu;
/* Add packet encryption handlers. */
#if (!(BB_ENABLE_INLINE_ENC_TX && BB_ENABLE_INLINE_DEC_RX))
lctrInitCipherBlkHdlr = PalCryptoAesEnable;
#endif
#if (!BB_ENABLE_INLINE_ENC_TX)
lctrPktEncryptHdlr = PalCryptoAesCcmEncrypt;
#else
lctrSetEncryptPktCountHdlr = PalCryptoSetEncryptPacketCount;
lctrSetEncryptPktCountHdlr = PalBbBleSetInlineEncryptPacketCount;
#endif
#if (!BB_ENABLE_INLINE_DEC_RX)
lctrPktDecryptHdlr = PalCryptoAesCcmDecrypt;
#else
lctrSetDecryptPktCountHdlr = PalCryptoSetDecryptPacketCount;
lctrSetDecryptPktCountHdlr = PalBbBleSetInlineDecryptPacketCount;
#endif
/* Set supported features. */

View File

@ -84,16 +84,18 @@ void LctrSlvConnEncInit(void)
}
/* Add packet encryption handlers. */
#if (!(BB_ENABLE_INLINE_ENC_TX && BB_ENABLE_INLINE_DEC_RX))
lctrInitCipherBlkHdlr = PalCryptoAesEnable;
#endif
#if (!BB_ENABLE_INLINE_ENC_TX)
lctrPktEncryptHdlr = PalCryptoAesCcmEncrypt;
#else
lctrSetEncryptPktCountHdlr = PalCryptoSetEncryptPacketCount;
lctrSetEncryptPktCountHdlr = PalBbBleSetInlineEncryptPacketCount;
#endif
#if (!BB_ENABLE_INLINE_DEC_RX)
lctrPktDecryptHdlr = PalCryptoAesCcmDecrypt;
#else
lctrSetDecryptPktCountHdlr = PalCryptoSetDecryptPacketCount;
lctrSetDecryptPktCountHdlr = PalBbBleSetInlineDecryptPacketCount;
#endif
/* Set supported features. */

View File

@ -242,6 +242,9 @@ void lctrMstInitiateOpCommit(void)
SchInsertNextAvailable(pOp);
lctrMstInit.scanWinStartUsec = pOp->dueUsec;
LL_TRACE_INFO1(" >>> Initiate started, dueUsec=%u <<<", pOp->dueUsec);
LL_TRACE_INFO1(" pBod=0x%08x", pOp);
}
/*************************************************************************************************/

View File

@ -398,6 +398,9 @@ void lctrMstExtInitiateOpCommit(lctrExtScanCtx_t *pExtInitCtx)
SchInsertNextAvailable(pOp);
pExtInitCtx->data.init.scanWinStartUsec = pOp->dueUsec;
LL_TRACE_INFO1(" >>> ExtInitiate started, dueUsec=%u <<<", pOp->dueUsec);
LL_TRACE_INFO1(" pBod=0x%08x", pOp);
}
/*************************************************************************************************/
@ -460,6 +463,7 @@ uint8_t lctrMstAuxInitiateBuildOp(lctrExtScanCtx_t *pExtInitCtx, LlConnSpec_t *p
/*** BLE Scan Setup: Rx packets ***/
pAuxScan->isInit = TRUE;
pAuxScan->rxAuxAdvCback = lctrMstInitiateRxAuxAdvPktHandler;
pAuxScan->rxAuxAdvPostCback = NULL;
/*** BLE Scan Setup: Tx connect request packet ***/

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -58,7 +58,7 @@ static void lctrIsoProcessRxTestData(lctrCisCtx_t *pCisCtx, uint8_t *pDataBuf, u
uint16_t pldType = 0;
uint64_t plTestCounter = pCisCtx->rxPktCounter;
if (pCisCtx->rxPendInit)
if (pCisCtx->rxPendInit && (dataLen >= LL_ISO_TEST_VAR_MIN_LEN))
{
memcpy(&pCisCtx->expectedPkt, pDataBuf, 4);
pCisCtx->rxPendInit = FALSE;
@ -94,12 +94,15 @@ static void lctrIsoProcessRxTestData(lctrCisCtx_t *pCisCtx, uint8_t *pDataBuf, u
if ((dataLen == pldType) &&
(pktNum == pCisCtx->expectedPkt))
{
pCisCtx->expectedPkt++;
pCisCtx->numRxSuccess++;
}
else
{
pCisCtx->expectedPkt = pktNum + 1;
pCisCtx->numRxFailed++;
}
break;
@ -107,7 +110,8 @@ static void lctrIsoProcessRxTestData(lctrCisCtx_t *pCisCtx, uint8_t *pDataBuf, u
if ((dataLen >= LL_ISO_TEST_VAR_MIN_LEN) &&
(pktNum == pCisCtx->expectedPkt))
{
pCisCtx->numRxSuccess++;
pCisCtx->numRxSuccess++;
pCisCtx->expectedPkt++;
}
else
{
@ -224,7 +228,7 @@ void LctrInitCodec(void)
/* Add codec. */
lctrCodecHdlr.start = PalCodecDataStartStream;
lctrCodecHdlr.stop = PalCodecDataStopStream;
lctrCodecHdlr.in = PalCodecDataStreamIn;
lctrCodecHdlr.inReq = PalCodecDataStreamIn;
lctrCodecHdlr.out = PalCodecDataStreamOut;
}
@ -269,9 +273,8 @@ void lctrIsoTxCompletedHandler(void)
WSF_CS_EXIT(cs);
if (numHandles)
if (lmgrPersistCb.sendIsoCompCback && numHandles)
{
/* Notify host. */
lmgrPersistCb.sendIsoCompCback(numHandles, handle, numSdu);
}
}
@ -285,14 +288,14 @@ void lctrCisRxPendingHandler(void)
{
uint16_t cisHandle = 0;
uint8_t *pRxBuf;
lctrCisCtx_t *pCisCtx;
/* Route and demux received Data PDUs. */
while ((pRxBuf = lctrCisRxDeq(&cisHandle)) != NULL)
{
WSF_ASSERT(pRxBuf);
lctrCisCtx_t *pCisCtx = lctrFindCisByHandle(cisHandle);
pCisCtx = lctrFindCisByHandle(cisHandle);
lctrIsoalRxCtx_t *pRxCtx = &pCisCtx->isoalRxCtx;
if (!pCisCtx->enabled)
@ -317,18 +320,31 @@ void lctrCisRxPendingHandler(void)
lctrSendCisMsg(pCisCtx, LCTR_CIS_MSG_CIS_TERM_MIC_FAILED);
continue;
}
/* Increase packet counter after decryption. */
lctrCisIncPacketCounterRx(pCisCtx);
}
/* Increase packet counter after decryption. */
lctrCisIncPacketCounterRx(pCisCtx);
lctrCisDataPduHdr_t cisDataHdr;
lctrCisUnpackDataPduHdr(&cisDataHdr, pRxBuf);
/* Demux PDU. */
if (pCisCtx->framing == LL_ISO_PDU_TYPE_UNFRAMED)
{
lctrIsoHdr_t isoHdr = { 0 };
lctrIsoHdr_t isoHdr =
{
/* ISO header */
.handle = cisHandle,
.len = pRxBuf[LCTR_ISO_DATA_PDU_LEN_OFFSET],
/* .pb = 0, */ /* assigned below */
.tsFlag = FALSE,
/* Data load */
.ts = 0,
/* .pktSn = 0, */ /* assigned below */
.sduLen = pRxBuf[LCTR_ISO_DATA_PDU_LEN_OFFSET],
.ps = LCTR_PS_VALID
};
switch (rxHdr.llid)
{
/* Received a end/complete PDU. */
@ -346,6 +362,7 @@ void lctrCisRxPendingHandler(void)
lctrCisRxPduFree(pRxBuf);
LL_TRACE_ERR2("!!! Invalid rxState; dropping Rx data PDU, connHandle=%u, rxState=%u", cisHandle, pRxCtx->rxState);
pRxCtx->rxState = LL_ISO_SDU_STATE_NEW;
continue;
}
break;
@ -359,24 +376,7 @@ void lctrCisRxPendingHandler(void)
default:
lctrCisRxPduFree(pRxBuf);
LL_TRACE_ERR2("!!! Invalid LLID; dropping Rx data PDU, connHandle=%u llid=%u", cisHandle, rxHdr.llid);
break;
}
/* If the packet was flushed, change the packet status flag to warn host of errors. */
if (pRxCtx->pduFlushed)
{
switch (pRxCtx->rxState)
{
case LL_ISO_SDU_STATE_CONT:
/* Lost data since last transfer; invalidate packet. */
pRxCtx->data.unframed.ps = LCTR_PS_INVALID;
break;
case LL_ISO_SDU_STATE_NEW:
/* This may be a fragmented packet with the end fragment, but no way to tell, so process as normal. */
pRxCtx->data.unframed.ps = (rxHdr.llid == LL_LLID_ISO_UNF_END_PDU) ? LCTR_PS_INVALID : LCTR_PS_LOST;
break;
}
pRxCtx->pduFlushed = FALSE;
continue;
}
/* Pack isoHdr and queue PDU. */
@ -384,34 +384,34 @@ void lctrCisRxPendingHandler(void)
{
uint8_t * pSduBuf = pRxBuf - LCTR_CIS_DATA_PDU_START_OFFSET - HCI_ISO_DL_MAX_LEN;
/* Pack current packet. */
isoHdr.handle = cisHandle;
isoHdr.tsFlag = ((isoHdr.pb == LCTR_PB_COMP) || (isoHdr.pb == LCTR_PB_FIRST)) ? 1 : 0;
if (isoHdr.tsFlag)
if ((isoHdr.pb == LCTR_PB_COMP) || (isoHdr.pb == LCTR_PB_FIRST))
{
isoHdr.ts = 0xFF;
}
isoHdr.len = pRxBuf[LCTR_ISO_DATA_PDU_LEN_OFFSET];
/* isoHdr.pktSn = 0; */
isoHdr.tsFlag = TRUE;
isoHdr.ts = PalBbGetCurrentTime();
/* LCTR_PB_COMP and LCTR_PB_FIRST will have their headers re-packed in lctrIsoUnframedRxSduPendQueue. */
pRxCtx->packetSequence++;
}
isoHdr.pktSn = pRxCtx->packetSequence;
/* LCTR_PB_COMP and LCTR_PB_FIRST will have their headers re-packed in lctrRecombineRxUnframedSdu(). */
uint8_t headerOffset = lctrIsoPackHdr(pSduBuf, &isoHdr);
/* Process received buffer for Rx testing purpose. */
/* TODO: Optimize test packet dataflow. */
if (pCisCtx->rxTestEnabled == TRUE)
{
lctrIsoProcessRxTestData(pCisCtx, pRxBuf + LL_DATA_HDR_LEN, rxHdr.len);
}
/* TODO optimize memory layout */
/* Move payload next to header. */
if (LCTR_CIS_DATA_PDU_START_OFFSET + LL_ISO_DATA_HDR_LEN > HCI_ISO_HDR_LEN)
if ((LCTR_CIS_DATA_PDU_START_OFFSET + LL_ISO_DATA_HDR_LEN) > HCI_ISO_HDR_LEN)
{
/* TODO optimize memory layout */
memmove(pSduBuf + headerOffset , pRxBuf + LL_DATA_HDR_LEN, rxHdr.len);
}
/* Put onto pending queue until whole SDU is ready to be sent. */
if (!lctrIsoUnframedRxSduPendQueue(pRxCtx, pSduBuf, cisHandle, rxHdr.len, rxHdr.llid))
if (!lctrRecombineRxUnframedSdu(pRxCtx, pSduBuf))
{
break;
}
@ -421,7 +421,8 @@ void lctrCisRxPendingHandler(void)
while ((pSduBuf = WsfMsgDeq(&pRxCtx->data.unframed.pendSduQ, &handlerId)) != NULL)
{
/* Enqueue SDU for processing. */
if (!lctrIsoRxConnEnq(&pCisCtx->dataPathOutCtx, pCisCtx->cisHandle, pSduBuf))
if (!lctrIsoRxConnEnq(&pCisCtx->dataPathOutCtx, pCisCtx->cisHandle,
pCisCtx->rxPktCounter - 1, pSduBuf))
{
/* The buffer was not freed, so free it now. */
WsfMsgFree(pSduBuf);
@ -437,12 +438,13 @@ void lctrCisRxPendingHandler(void)
{
pCisCtx->dataPathOutCtx.cfg.hci.numRxPend += lctrAssembleRxFramedSdu(pRxCtx, &pCisCtx->dataPathOutCtx.cfg.hci.rxDataQ, pCisCtx->cisHandle, pRxBuf, cisDataHdr.len);
/* Consume and process packets for iso test mode */
/* Consume packets if needed */
lctrIsoHdr_t isoHdr;
/* ISO test mode. */
if (pCisCtx->rxTestEnabled == TRUE)
{
while (pCisCtx->dataPathOutCtx.cfg.hci.numRxPend)
{
lctrIsoHdr_t isoHdr;
uint8_t *pTestRxBuf = lctrIsoRxConnDeq(&pCisCtx->dataPathOutCtx);
lctrIsoUnpackHdr(&isoHdr, pTestRxBuf);
lctrIsoProcessRxTestData(pCisCtx, pTestRxBuf+ HCI_ISO_HDR_LEN + HCI_ISO_DL_MAX_LEN, isoHdr.sduLen);
@ -451,6 +453,19 @@ void lctrCisRxPendingHandler(void)
pCisCtx->dataPathOutCtx.cfg.hci.numRxPend--;
}
}
/* Codec output */
else if (pCisCtx->dataPathOutCtx.id == LL_ISO_DATA_PATH_VS)
{
while (pCisCtx->dataPathOutCtx.cfg.hci.numRxPend)
{
uint8_t *pSduBuf = lctrIsoRxConnDeq(&pCisCtx->dataPathOutCtx);
lctrIsoUnpackHdr(&isoHdr, pSduBuf);
lctrCodecHdlr.out(pCisCtx->dataPathOutCtx.cfg.codec.streamId, isoHdr.pSdu, isoHdr.sduLen, isoHdr.ts);
WsfMsgFree(pSduBuf);
LctrRxIsoComplete(1);
}
}
lctrCisRxPduFree(pRxBuf);
break;
}
@ -473,23 +488,21 @@ void lctrCisRxPendingHandler(void)
WSF_CS_ENTER(cs);
for (unsigned int i = 0; i < pLctrRtCfg->maxCis; i++)
{
lctrCisCtx_t *pCisCtx = &pLctrCisTbl[i];
pCisCtx = &pLctrCisTbl[i];
if (pCisCtx->enabled &&
(pCisCtx->dataPathOutCtx.id == LL_ISO_DATA_PATH_HCI) &&
pCisCtx->dataPathOutCtx.cfg.hci.numRxPend)
{
if (pCisCtx->dataPathOutCtx.id == LL_ISO_DATA_PATH_HCI)
{
handle[numHandles] = pCisCtx->cisHandle;
numSdu[numHandles] = pCisCtx->dataPathOutCtx.cfg.hci.numRxPend;
pCisCtx->dataPathOutCtx.cfg.hci.numRxPend = 0;
numHandles++;
}
handle[numHandles] = pCisCtx->cisHandle;
numSdu[numHandles] = pCisCtx->dataPathOutCtx.cfg.hci.numRxPend;
pCisCtx->dataPathOutCtx.cfg.hci.numRxPend = 0;
numHandles++;
}
}
WSF_CS_EXIT(cs);
if (numHandles)
if (lmgrPersistCb.recvIsoPendCback && numHandles)
{
/* Notify host. */
lmgrPersistCb.recvIsoPendCback(numHandles, handle, numSdu);
@ -551,7 +564,10 @@ void LctrTxIso(uint8_t *pIsoBuf)
{
LL_TRACE_ERR2("Invalid ISO header: invalid packet length, actLen=%u, maxLen=%u", isoHdr.sduLen, pLctrRtCfg->maxIsoSduLen);
WsfMsgFree(pIsoBuf);
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
if (lmgrPersistCb.sendCompCback)
{
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
}
return;
}
@ -559,16 +575,22 @@ void LctrTxIso(uint8_t *pIsoBuf)
{
LL_TRACE_ERR1("ISO Tx path flow controlled, handle=%u", isoHdr.handle);
WsfMsgFree(pIsoBuf);
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
if (lmgrPersistCb.sendCompCback)
{
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
}
return;
}
uint16_t expIsoLen = isoHdr.len - HCI_ISO_DL_MIN_LEN + ((isoHdr.tsFlag) ? HCI_ISO_TS_LEN : 0);
uint16_t expIsoLen = isoHdr.len - HCI_ISO_DL_MIN_LEN - ((isoHdr.tsFlag) ? HCI_ISO_TS_LEN : 0);
if (isoHdr.sduLen != expIsoLen)
{
LL_TRACE_ERR2("Invalid ISO header: packet length mismatch, expSduLen=%u, actSduLen=%u", expIsoLen, isoHdr.sduLen);
WsfMsgFree(pIsoBuf);
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
if (lmgrPersistCb.sendCompCback)
{
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
}
return;
}
@ -582,7 +604,10 @@ void LctrTxIso(uint8_t *pIsoBuf)
if (!lctrCheckIsCisEstCis(pCisCtx->cisHandle))
{
LL_TRACE_ERR1("Invalid ISO handle: link not established cisHandle=%u; dropping packet", isoHdr.handle);
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
if (lmgrPersistCb.sendCompCback)
{
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
}
WsfMsgFree(pIsoBuf);
return;
}
@ -593,7 +618,10 @@ void LctrTxIso(uint8_t *pIsoBuf)
{
LL_TRACE_ERR1("Invalid CIS state: handle=%u does not accept transmissions; dropping packet", isoHdr.handle);
WsfMsgFree(pIsoBuf);
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
if (lmgrPersistCb.sendCompCback)
{
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
}
return;
}
@ -620,7 +648,10 @@ void LctrTxIso(uint8_t *pIsoBuf)
{
LL_TRACE_ERR2("Invalid ISO header: invalid packet length, actLen=%u, maxSdu=%u", isoHdr.sduLen, pBisCtx->pBigCtx->maxSdu);
WsfMsgFree(pIsoBuf);
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
if (lmgrPersistCb.sendCompCback)
{
lmgrPersistCb.sendCompCback(isoHdr.handle, 1);
}
return;
}
@ -662,7 +693,7 @@ uint8_t *LctrRxIso(void)
{
lctrCisCtx_t *pCisCtx = &pLctrCisTbl[i];
if ((pCisCtx->enabled) &&
if ((pCisCtx->enabled) && (pCisCtx->dataPathOutCtx.id == LL_ISO_DATA_PATH_HCI) &&
((pBuf = lctrIsoRxConnDeq(&pCisCtx->dataPathOutCtx)) != NULL))
{
return pBuf;
@ -677,6 +708,7 @@ uint8_t *LctrRxIso(void)
(pBisCtx->pBigCtx->role == LL_ROLE_MASTER) &&
((pBuf = lctrBisRxIsoSduDeq(pBisCtx)) != NULL))
{
/* Postpone lctrIsoDataRxIncAvailBuf() until client consumes buffer, cf. LctrRxIsoComplete(). */
return pBuf;
}
}
@ -742,7 +774,37 @@ uint8_t LctrReadIsoTxSync(uint16_t handle, uint16_t *pPktSn, uint32_t *pTs, uint
/*************************************************************************************************/
/*!
* \brief Used to identify and enable the isochronous data path between the host and the controller for each connected isochronous stream or broadcast isochronous stream.
* \brief Used to request the Controller to configure the data transport path in a given
* direction between the Controller and the Host.
*
* \param pConfigDataPath Parameters for configure data path.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t LctrConfigureDataPath(LlIsoConfigDataPath_t *pConfigDataPath)
{
switch (pConfigDataPath->dpId)
{
case LL_ISO_DATA_PATH_DISABLED:
case LL_ISO_DATA_PATH_HCI:
/* No action required. */
break;
case LL_ISO_DATA_PATH_VS:
/* No action required. */
break;
default:
LL_TRACE_WARN2("LlConfigureDataPath: unknown data path, dpDir=%u, dpId=%u", pConfigDataPath->dpDir, pConfigDataPath->dpId);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
return LL_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Used to identify and enable the isochronous data path between the host and the
* controller for each connected isochronous stream or broadcast isochronous stream.
*
* \param pSetupDataPath Parameters for setup ISO data path.
*
@ -751,65 +813,76 @@ uint8_t LctrReadIsoTxSync(uint16_t handle, uint16_t *pPktSn, uint32_t *pTs, uint
/*************************************************************************************************/
uint8_t LctrSetupIsoDataPath(LlIsoSetupDataPath_t *pSetupDataPath)
{
uint8_t status = LL_SUCCESS;
lctrCisCtx_t *pCisCtx;
lctrBisCtx_t *pBisCtx;
lctrDataPathCtx_t *pDataPathDir;
lctrDpParams_t dpParam;
if ((pCisCtx = lctrFindCisByHandle(pSetupDataPath->handle)) != NULL)
{
dpParam.handle = pCisCtx->cisHandle;
dpParam.isoInt = (pCisCtx->role == LL_ROLE_SLAVE) ? pCisCtx->sduIntervalSToM : pCisCtx->sduIntervalMToS;
dpParam.pktCtr = pCisCtx->txPktCounter + 1;
dpParam.dpDir = pSetupDataPath->dpDir;
switch (pSetupDataPath->dpDir)
{
case LL_ISO_DATA_DIR_INPUT:
pDataPathDir = (lctrDataPathCtx_t *) (&pCisCtx->dataPathInCtx);
dpParam.pDataPathCtx = (lctrDataPathCtx_t *) (&pCisCtx->dataPathInCtx);
break;
case LL_ISO_DATA_DIR_OUTPUT:
pDataPathDir = (lctrDataPathCtx_t *) (&pCisCtx->dataPathOutCtx);
dpParam.pDataPathCtx = (lctrDataPathCtx_t *) (&pCisCtx->dataPathOutCtx);
break;
default:
LL_TRACE_WARN2("LctrSetupIsoDataPath: handle=%u invalid direction dpDir=%u", pSetupDataPath->handle, pSetupDataPath->dpDir);
return LL_ERROR_CODE_CMD_DISALLOWED;
}
return lctrSetupIsoDataPath(pSetupDataPath, pDataPathDir);
}
else if ((pBisCtx = lctrFindBisByHandle(pSetupDataPath->handle)) != NULL)
{
dpParam.handle = pBisCtx->handle;
dpParam.isoInt = pBisCtx->pBigCtx->isoInterUsec;
dpParam.pktCtr = (pBisCtx->pBigCtx->eventCounter + 1) * pBisCtx->pBigCtx->bn;
dpParam.dpDir = pSetupDataPath->dpDir;
switch (pSetupDataPath->dpDir)
{
case LL_ISO_DATA_DIR_INPUT:
if (pBisCtx->pBigCtx->role == LL_ROLE_SLAVE)
{
status = lctrBisSetDataPath(pBisCtx, pSetupDataPath->dpDir, pSetupDataPath->dpId);
dpParam.pDataPathCtx = (lctrDataPathCtx_t *) (&pBisCtx->roleData.slv.dataPathInCtx);
}
else
{
LL_TRACE_WARN1("LctrSetupIsoDataPath: handle=%u invalid input direction for master", pSetupDataPath->handle);
status = LL_ERROR_CODE_CMD_DISALLOWED;
return LL_ERROR_CODE_CMD_DISALLOWED;
}
break;
case LL_ISO_DATA_DIR_OUTPUT:
if (pBisCtx->pBigCtx->role == LL_ROLE_MASTER)
{
status = lctrBisSetDataPath(pBisCtx, pSetupDataPath->dpDir, pSetupDataPath->dpId);
dpParam.pDataPathCtx = (lctrDataPathCtx_t *) (&pBisCtx->roleData.mst.dataPathOutCtx);
}
else
{
LL_TRACE_WARN1("LctrSetupIsoDataPath: handle=%u invalid output direction for slave", pSetupDataPath->handle);
status = LL_ERROR_CODE_CMD_DISALLOWED;
return LL_ERROR_CODE_CMD_DISALLOWED;
}
break;
default:
LL_TRACE_WARN2("LctrSetupIsoDataPath: handle=%u invalid direction dpDir=%u", pSetupDataPath->handle, pSetupDataPath->dpDir);
return LL_ERROR_CODE_CMD_DISALLOWED;
break;
}
}
else
{
LL_TRACE_WARN1("LctrSetupIsoDataPath: handle=%u not found", pSetupDataPath->handle);
status = LL_ERROR_CODE_UNKNOWN_CONN_ID;
return LL_ERROR_CODE_UNKNOWN_CONN_ID;
}
return status;
return lctrIsoSetupDataPath(&dpParam, pSetupDataPath);
}
/*************************************************************************************************/
@ -828,18 +901,27 @@ uint8_t LctrRemoveIsoDataPath(uint16_t handle, uint8_t dpDir)
uint8_t status = LL_SUCCESS;
lctrCisCtx_t *pCisCtx;
lctrBisCtx_t *pBisCtx;
lctrDpParams_t dpParam;
if ((pCisCtx = lctrFindCisByHandle(handle)) != NULL)
{
/* Check to make sure parameters are valid. */
if ((dpDir & ~(LL_ISO_DATA_PATH_INPUT_BIT | LL_ISO_DATA_PATH_OUTPUT_BIT)) ||
(dpDir == 0))
{
LL_TRACE_WARN2("LctrRemoveIsoDataPath: handle=%u invalid direction dpDir=0x%08x", handle, dpDir);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
/* Check for validity of parameters before operating on them. */
if (dpDir | LL_ISO_DATA_PATH_INPUT_BIT)
if (dpDir & LL_ISO_DATA_PATH_INPUT_BIT)
{
if (pCisCtx->dataPathInCtx.id == LL_ISO_DATA_PATH_DISABLED)
{
return LL_ERROR_CODE_CMD_DISALLOWED;
}
}
if (dpDir | LL_ISO_DATA_PATH_OUTPUT_BIT)
if (dpDir & LL_ISO_DATA_PATH_OUTPUT_BIT)
{
if (pCisCtx->dataPathOutCtx.id == LL_ISO_DATA_PATH_DISABLED)
{
@ -847,18 +929,70 @@ uint8_t LctrRemoveIsoDataPath(uint16_t handle, uint8_t dpDir)
}
}
if (dpDir | LL_ISO_DATA_PATH_INPUT_BIT)
if (dpDir & LL_ISO_DATA_PATH_INPUT_BIT)
{
/* Stop input data path. */
dpParam.handle = pCisCtx->cisHandle;
dpParam.pDataPathCtx = (lctrDataPathCtx_t *)&pCisCtx->dataPathInCtx;
/* Other parameters are unused in data path clearing. */
lctrIsoInDataPathClear(&dpParam);
pCisCtx->dataPathInCtx.id = LL_ISO_DATA_PATH_DISABLED;
}
if (dpDir | LL_ISO_DATA_PATH_OUTPUT_BIT)
if (dpDir & LL_ISO_DATA_PATH_OUTPUT_BIT)
{
/* Stop output data path. */
dpParam.handle = pCisCtx->cisHandle;
dpParam.pDataPathCtx = (lctrDataPathCtx_t *)&pCisCtx->dataPathOutCtx;
/* Other parameters are unused in data path clearing. */
lctrIsoOutDataPathClear(&dpParam);
pCisCtx->dataPathOutCtx.id = LL_ISO_DATA_PATH_DISABLED;
}
}
else if ((pBisCtx = lctrFindBisByHandle(handle)) != NULL)
{
pBisCtx->path = LL_ISO_DATA_PATH_DISABLED;
if (dpDir & LL_ISO_DATA_PATH_INPUT_BIT)
{
if (pBisCtx->roleData.slv.dataPathInCtx.id == LL_ISO_DATA_PATH_DISABLED)
{
return LL_ERROR_CODE_CMD_DISALLOWED;
}
}
if (dpDir & LL_ISO_DATA_PATH_OUTPUT_BIT)
{
if (pBisCtx->roleData.mst.dataPathOutCtx.id == LL_ISO_DATA_PATH_DISABLED)
{
return LL_ERROR_CODE_CMD_DISALLOWED;
}
}
dpParam.handle = pBisCtx->handle;
if (pBisCtx->pBigCtx->role == LL_ROLE_MASTER)
{
if (pBisCtx->roleData.mst.dataPathOutCtx.id == LL_ISO_DATA_PATH_DISABLED)
{
return LL_ERROR_CODE_CMD_DISALLOWED;
}
dpParam.pDataPathCtx = (lctrDataPathCtx_t *)&pBisCtx->roleData.mst.dataPathOutCtx;
/* Other parameters are unused in data path clearing. */
lctrIsoOutDataPathClear(&dpParam);
pBisCtx->roleData.mst.dataPathOutCtx.id = LL_ISO_DATA_PATH_DISABLED;
}
else
{
if (pBisCtx->roleData.slv.dataPathInCtx.id == LL_ISO_DATA_PATH_DISABLED)
{
return LL_ERROR_CODE_CMD_DISALLOWED;
}
dpParam.pDataPathCtx = (lctrDataPathCtx_t *)&pBisCtx->roleData.slv.dataPathInCtx;
/* Other parameters are unused in data path clearing. */
lctrIsoInDataPathClear(&dpParam);
pBisCtx->roleData.slv.dataPathInCtx.id = LL_ISO_DATA_PATH_DISABLED;
}
}
else
{
@ -1100,48 +1234,23 @@ void lctrNotifyHostIsoEventComplete(uint8_t handle, uint32_t evtCtr)
/*!
* \brief Send Codec SDU data.
*
* \param handle Stream ID.
* \param handle ISO Handle.
*/
/*************************************************************************************************/
void lctrIsoSendCodecSdu(uint16_t handle)
void lctrIsoSendCodecSdu(uint16_t id, uint32_t pktCtr, uint32_t ts, uint8_t *pData, uint16_t actLen)
{
lctrBisCtx_t *pBisCtx;
if ((pBisCtx = lctrFindBisByHandle(handle)) == NULL)
{
LL_TRACE_WARN1("lctrIsoSendCodecSdu: handle=%u not found", handle);
return;
}
uint8_t *pSduBuf;
if ((pSduBuf = WsfMsgAlloc(pLctrRtCfg->maxIsoSduLen + HCI_ISO_DL_MAX_LEN)) == NULL)
{
LL_TRACE_ERR1("!!! Out of memory; dropping input SDU, stream=%u", handle);
return;
}
uint16_t len;
uint32_t pktCtr;
WSF_ASSERT(lctrCodecHdlr.in);
if ((len = lctrCodecHdlr.in(handle, pSduBuf + HCI_ISO_HDR_LEN + HCI_ISO_DL_MAX_LEN,
pBisCtx->pBigCtx->maxSdu, &pktCtr)) == 0)
{
LL_TRACE_WARN1("ISO audio stream data not available, stream=%u", handle);
WsfMsgFree(pSduBuf);
return;
}
/* Recover SDU buffer. */
uint8_t *pSduBuf = pData - HCI_ISO_HDR_LEN - HCI_ISO_DL_MAX_LEN;
lctrIsoHdr_t hdr =
{
.handle = handle,
.handle = id,
.pb = LCTR_PB_COMP,
.tsFlag = TRUE,
.len = len,
.len = actLen,
.ts = 0,
.pktSn = pktCtr,
.sduLen = len,
.sduLen = actLen,
.ps = LCTR_PS_VALID
};
@ -1153,37 +1262,42 @@ void lctrIsoSendCodecSdu(uint16_t handle)
/*!
* \brief Setup ISO data path.
*
* \param pDpParam Parameters to set up data path.
* \param pSetupDataPath Data path setup parameters.
* \param pDataPathCtx Generic data path context.
*/
/*************************************************************************************************/
uint8_t lctrSetupIsoDataPath(LlIsoSetupDataPath_t *pSetupDataPath, lctrDataPathCtx_t *pDataPathCtx)
uint8_t lctrIsoSetupDataPath(lctrDpParams_t *pDpParam, LlIsoSetupDataPath_t *pSetupDataPath)
{
uint8_t status = LL_SUCCESS;
switch (pSetupDataPath->dpDir)
{
case LL_ISO_DATA_DIR_INPUT:
{
if (pSetupDataPath->dpId == pDataPathCtx->in.id)
if (pSetupDataPath->dpId == pDpParam->pDataPathCtx->in.id)
{
/* No change. */
return LL_SUCCESS;
}
/* No teardown needed. */
pDataPathCtx->in.id = pSetupDataPath->dpId;
/* No setup needed. */
lctrIsoInDataPathClear(pDpParam);
pDpParam->pDataPathCtx->in.id = pSetupDataPath->dpId;
status = lctrIsoInDataPathSetup(pDpParam, pSetupDataPath);
break;
}
case LL_ISO_DATA_DIR_OUTPUT:
{
if (pSetupDataPath->dpId == pDataPathCtx->out.id)
if (pSetupDataPath->dpId == pDpParam->pDataPathCtx->out.id)
{
/* No change. */
return LL_SUCCESS;
}
lctrIsoOutDataPathClear(&pDataPathCtx->out);
pDataPathCtx->out.id = pSetupDataPath->dpId;
lctrIsoOutDataPathSetup(&pDataPathCtx->out);
lctrIsoOutDataPathClear(pDpParam);
pDpParam->pDataPathCtx->out.id = pSetupDataPath->dpId;
status = lctrIsoOutDataPathSetup(pDpParam, pSetupDataPath);
break;
}
@ -1192,5 +1306,5 @@ uint8_t lctrSetupIsoDataPath(LlIsoSetupDataPath_t *pSetupDataPath, lctrDataPathC
break;
}
return LL_SUCCESS;
return status;
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -69,7 +69,6 @@ static void lctrAssembleCisDataPdu(lctrIsoHdr_t *pIsoHdr, uint8_t *pBuf, uint8_t
lctrCisPackDataPduHdr(pBuf, &dataHdr);
}
/*************************************************************************************************/
/*!
* \brief Initialize the transmit memory resources.
@ -181,7 +180,8 @@ void lctrCisTxDataPduQueue(lctrCisCtx_t *pCisCtx, lctrIsoHdr_t *pIsoHdr, uint8_t
{
LL_TRACE_ERR1("Failed to allocate transmit buffer descriptor: cisHandle=%u", pIsoHdr->handle);
WsfMsgFree(pIsoBuf);
if (pCisCtx->txTestEnabled == FALSE)
if (lmgrPersistCb.sendIsoCompCback &&
(pCisCtx->txTestEnabled == FALSE))
{
uint16_t handle = pIsoHdr->handle;
uint16_t numSdu = 1;
@ -411,15 +411,15 @@ uint8_t lctrCisTxQueueClear(lctrCisCtx_t *pCisCtx)
* \return Pointer to the start of the PDU data buffer.
*/
/*************************************************************************************************/
uint8_t *lctrCisRxPduAlloc(uint16_t maxRxLen)
uint8_t *lctrCisRxPduAlloc()
{
/* LCTR_DATA_PDU_MAX_LEN includes LL_DATA_MIC_LEN if required. */
const uint16_t allocLen = WSF_MAX(BB_FIXED_DATA_PKT_LEN, LCTR_CIS_DATA_PDU_LEN(maxRxLen)) + LCTR_CIS_DATA_PDU_START_OFFSET;
const uint16_t allocLen = LCTR_CIS_DATA_PDU_START_OFFSET + HCI_ISO_DL_MAX_LEN + pLctrRtCfg->maxIsoSduLen + BB_DATA_PDU_TAILROOM;
uint8_t *pBuf;
/* Include ISO header. */
if ((pBuf = WsfMsgAlloc(HCI_ISO_DL_MAX_LEN + allocLen)) != NULL)
if ((pBuf = WsfMsgAlloc(allocLen)) != NULL)
{
/* Return start of data PDU. */
pBuf += LCTR_CIS_DATA_PDU_START_OFFSET + HCI_ISO_DL_MAX_LEN;
@ -454,12 +454,16 @@ void lctrCisRxPduFree(uint8_t *pBuf)
/*************************************************************************************************/
void lctrCisRxEnq(uint8_t *pBuf, uint16_t eventCounter, uint16_t cisHandle)
{
/* Stamp packet with event counter. */
pBuf -= LCTR_CIS_DATA_PDU_START_OFFSET;
UINT16_TO_BUF(pBuf, eventCounter);
if (pBuf != NULL)
{
/* Stamp packet with event counter. */
pBuf -= LCTR_CIS_DATA_PDU_START_OFFSET;
UINT16_TO_BUF(pBuf, eventCounter);
/* Queue LE Data PDU. */
WsfMsgEnq(&lmgrIsoCb.rxDataQ, cisHandle, pBuf);
}
/* Queue LE Data PDU. */
WsfMsgEnq(&lmgrIsoCb.rxDataQ, cisHandle, pBuf);
WsfSetEvent(lmgrPersistCb.handlerId, (1 << LCTR_EVENT_CIS_RX_PENDING));
}
@ -497,12 +501,15 @@ uint8_t *lctrCisRxDeq(uint16_t *pCisHandle)
* \param pBuf SDU buffer.
*
* \return TRUE if buffer successfully handled and will be used.
* FALSE if buffer was not handled and needs to be disposed.
* FALSE needs to be disposed.
*
*/
/*************************************************************************************************/
bool_t lctrIsoRxConnEnq(lctrOutDataPathCtx_t *pOutDataPathCtx, uint16_t handle, uint8_t *pBuf)
bool_t lctrIsoRxConnEnq(lctrOutDataPathCtx_t *pOutDataPathCtx, uint16_t handle, uint32_t pktCtr, uint8_t *pBuf)
{
lctrIsoHdr_t isoHdr;
lctrIsoUnpackHdr(&isoHdr, pBuf);
switch (pOutDataPathCtx->id)
{
case LL_ISO_DATA_PATH_HCI:
@ -513,6 +520,10 @@ bool_t lctrIsoRxConnEnq(lctrOutDataPathCtx_t *pOutDataPathCtx, uint16_t handle,
return TRUE;
case LL_ISO_DATA_PATH_VS:
WSF_ASSERT(lctrCodecHdlr.out);
lctrCodecHdlr.out(pOutDataPathCtx->cfg.codec.streamId, isoHdr.pSdu, isoHdr.sduLen, isoHdr.ts);
return FALSE;
default:
return FALSE;
}
@ -533,34 +544,84 @@ uint8_t *lctrIsoRxConnDeq(lctrOutDataPathCtx_t *pOutCtx)
{
wsfHandlerId_t handle;
if (pOutCtx->id != LL_ISO_DATA_PATH_HCI)
{
return NULL;
}
return WsfMsgDeq(&pOutCtx->cfg.hci.rxDataQ, &handle);
}
/*************************************************************************************************/
/*!
* \brief Setup a datapath context.
* \brief Setup an input data path context.
*
* \param pOutCtx Output datapath context.
* \param pDpParam Data path parameters.
* \param pSetupDataPath Data path setup parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
void lctrIsoOutDataPathSetup(lctrOutDataPathCtx_t *pOutCtx)
uint8_t lctrIsoInDataPathSetup(lctrDpParams_t *pDpParam, LlIsoSetupDataPath_t *pSetupDataPath)
{
switch (pOutCtx->id)
lctrInDataPathCtx_t *pInCtx = &pDpParam->pDataPathCtx->in;
switch (pInCtx->id)
{
case LL_ISO_DATA_PATH_HCI:
pOutCtx->cfg.hci.numRxPend = 0;
WSF_QUEUE_INIT(&pOutCtx->cfg.hci.rxDataQ);
break;
case LL_ISO_DATA_PATH_VS:
/* No action. */
pInCtx->cfg.codec.streamId = pDpParam->handle;
if (lctrCodecHdlr.start)
{
PalCodecStreamParam_t param =
{
.dir = PAL_CODEC_DIR_INPUT,
.pktCtr = pDpParam->pktCtr,
.codecId = pSetupDataPath->codecId,
.inCback = lctrIsoSendCodecSdu
};
if (!lctrCodecHdlr.start(pInCtx->cfg.codec.streamId, &param))
{
LL_TRACE_WARN1("Failed to start the codec, dpId=%u", pInCtx->id);
pInCtx->id = LL_ISO_DATA_PATH_DISABLED;
return LL_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES;
}
}
else
{
LL_TRACE_WARN1("Codec not found, dpId=%u", pInCtx->id);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
break;
case LL_ISO_DATA_PATH_DISABLED:
case LL_ISO_DATA_PATH_HCI:
/* No action required. */
break;
default:
LL_TRACE_WARN1("Unknown Data Path, dpId=%u", pInCtx->id);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
return LL_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Clear an input data path context.
*
* \param pOutCtx Output data path context.
*/
/*************************************************************************************************/
void lctrIsoInDataPathClear(lctrDpParams_t *pDpParam)
{
lctrInDataPathCtx_t *pInCtx = &pDpParam->pDataPathCtx->in;
switch (pInCtx->id)
{
case LL_ISO_DATA_PATH_VS:
WSF_ASSERT(lctrCodecHdlr.stop);
lctrCodecHdlr.stop(pInCtx->cfg.codec.streamId, PAL_CODEC_DIR_INPUT);
break;
case LL_ISO_DATA_PATH_HCI:
default:
/* No action. */
break;
@ -569,19 +630,81 @@ void lctrIsoOutDataPathSetup(lctrOutDataPathCtx_t *pOutCtx)
/*************************************************************************************************/
/*!
* \brief Clear a datapath context.
* \brief Setup a data path context.
*
* \param pOutCtx Output datapath context.
* \param pDpParam Data path parameters.
* \param pSetupDataPath Data path setup parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
void lctrIsoOutDataPathClear(lctrOutDataPathCtx_t *pOutCtx)
uint8_t lctrIsoOutDataPathSetup(lctrDpParams_t *pDpParam, LlIsoSetupDataPath_t *pSetupDataPath)
{
lctrOutDataPathCtx_t *pOutCtx = &pDpParam->pDataPathCtx->out;
switch (pOutCtx->id)
{
case LL_ISO_DATA_PATH_VS:
pOutCtx->cfg.codec.streamId = pDpParam->handle;
if (lctrCodecHdlr.start)
{
PalCodecStreamParam_t param =
{
.dir = PAL_CODEC_DIR_OUTPUT,
.pktCtr = pDpParam->pktCtr,
.codecId = pSetupDataPath->codecId
};
if (!lctrCodecHdlr.start(pOutCtx->cfg.codec.streamId, &param))
{
LL_TRACE_WARN1("Failed to start the codec, dpId=%u", pOutCtx->id);
pOutCtx->id = LL_ISO_DATA_PATH_DISABLED;
return LL_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES;
}
}
else
{
LL_TRACE_WARN1("Codec not found, dpId=%u", pOutCtx->id);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
break;
case LL_ISO_DATA_PATH_HCI:
pOutCtx->cfg.hci.numRxPend = 0;
WSF_QUEUE_INIT(&pOutCtx->cfg.hci.rxDataQ);
break;
case LL_ISO_DATA_PATH_DISABLED:
/* No action required. */
break;
default:
LL_TRACE_WARN1("Unknown Data Path, dpId=%u", pOutCtx->id);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
return LL_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Clear a data path context.
*
* \param pOutCtx Output data path context.
*/
/*************************************************************************************************/
void lctrIsoOutDataPathClear(lctrDpParams_t *pDpParam)
{
lctrOutDataPathCtx_t *pOutCtx = &pDpParam->pDataPathCtx->out;
switch (pOutCtx->id)
{
case LL_ISO_DATA_PATH_HCI:
{
uint8_t *pBuf;
wsfHandlerId_t handlerId;
while ((pBuf = WsfMsgDeq(&pOutCtx->cfg.hci.rxDataQ, &handlerId)) != NULL)
{
WsfMsgFree(pBuf);
@ -591,8 +714,20 @@ void lctrIsoOutDataPathClear(lctrOutDataPathCtx_t *pOutCtx)
}
case LL_ISO_DATA_PATH_VS:
/* No action. */
{
WSF_ASSERT(lctrCodecHdlr.stop);
lctrCodecHdlr.stop(pOutCtx->cfg.codec.streamId, PAL_CODEC_DIR_OUTPUT);
uint8_t *pBuf;
wsfHandlerId_t handlerId;
while ((pBuf = WsfMsgDeq(&pOutCtx->cfg.codec.rxDataQ, &handlerId)) != NULL)
{
WsfMsgFree(pBuf);
lctrIsoDataRxIncAvailBuf(1);
}
break;
}
default:
/* No action. */
@ -678,11 +813,9 @@ uint8_t *lctrGenerateIsoTestData(uint16_t handle, LlIsoPldType_t pldType, uint16
break;
default:
{
LL_TRACE_ERR1("Invalid value pldType=%u", pldType);
len = 0;
break;
}
}
/* Pack ISO header. */
@ -810,7 +943,7 @@ uint8_t *lctrTxIsoDataPduAlloc(void)
/* Use LL_ISO_PDU_MAX_LEN to ensure use of data buffers located in the large pool. */
if ((pPdu = (uint8_t*)WsfMsgAlloc(allocLen)) == NULL)
{
LL_TRACE_WARN1("lctrTxIsoDataPduAlloc: Unable to allocate framed Tx buffer, allocSize=%u", allocLen);
LL_TRACE_WARN1("lctrTxIsoDataPduAlloc: Unable to allocate Tx buffer, allocSize=%u", allocLen);
}
return pPdu;
@ -841,13 +974,12 @@ uint8_t lctrAssembleTxFramedPdu(lctrIsoalTxCtx_t *pIsoalTxCtx, uint8_t *pPduBuf,
/* Set offset of pPduBuf */
pPduBuf += HCI_ISO_HDR_LEN + HCI_ISO_DL_MIN_LEN;
/*** Loop through and pack SDUs. ***/
/* Loop through and pack SDUs. */
while (remLen)
{
uint8_t *pSduBuf = WsfMsgPeek(pSduQ, &handlerId);
/* The buffer is empty, process the completed PDU */
/* The buffer is empty, process the completed PDU. */
if (pSduBuf == NULL)
{
break;
@ -855,7 +987,7 @@ uint8_t lctrAssembleTxFramedPdu(lctrIsoalTxCtx_t *pIsoalTxCtx, uint8_t *pPduBuf,
lctrIsoHdr_t isoHdr;
/*** Disassemble ISO packet. ***/
/*** Disassemble ISO packet ***/
lctrIsoUnpackHdr(&isoHdr, pSduBuf);
@ -878,7 +1010,7 @@ uint8_t lctrAssembleTxFramedPdu(lctrIsoalTxCtx_t *pIsoalTxCtx, uint8_t *pPduBuf,
segHdrLen += LL_ISO_SEG_TO_LEN;
}
/*** Compute segment parameters. ***/
/*** Compute segment parameters ***/
/* There is enough room for the entire SDU. */
if (remLen >= (isoHdr.sduLen + segHdrLen))
@ -951,7 +1083,7 @@ uint8_t lctrAssembleTxFramedPdu(lctrIsoalTxCtx_t *pIsoalTxCtx, uint8_t *pPduBuf,
* \return Pointer to the start of the ISO Data PDU buffer, NULL if allocation failed.
*/
/*************************************************************************************************/
static uint8_t *lctrRxSduAlloc(void)
uint8_t *lctrRxSduAlloc(void)
{
uint8_t *pSdu;
@ -971,59 +1103,102 @@ static uint8_t *lctrRxSduAlloc(void)
* \brief Queue the received SDU into the pending queue.
*
* \param pRxCtx ISOAL receive context.
* \param pSdu SDU buffer.
* \param pSdu SDU fragment.
* \param handle CIS connection handle.
* \param dataLen Data length.
* \param llid Rx LLID.
*
* \return TRUE if pending queue ready to be sent to host.
*/
/*************************************************************************************************/
bool_t lctrIsoUnframedRxSduPendQueue(lctrIsoalRxCtx_t *pRxCtx, uint8_t *pSdu, uint16_t handle,
uint16_t dataLen, uint8_t llid)
bool_t lctrRecombineRxUnframedSdu(lctrIsoalRxCtx_t *pRxCtx, uint8_t *pSduFrag)
{
/* Save data for head packet. */
/* pRxCtx->data.unframed.pendSduIsoHdr.ps = 0; */ /* Should be done in calling function. */
pRxCtx->data.unframed.curLen += dataLen;
bool_t result = FALSE;
WsfMsgEnq(&pRxCtx->data.unframed.pendSduQ, handle, pSdu);
uint8_t handlerId;
uint8_t *pSdu = WsfMsgPeek(&pRxCtx->data.unframed.pendSduQ, &handlerId);
/* If we received the last PDU, pack the head packet with the packet status and sdu length. */
if (llid == LL_LLID_ISO_UNF_END_PDU)
if (pSduFrag)
{
uint8_t *pHeadPkt;
uint8_t handlerId;
lctrIsoHdr_t isoHdr = {0};
lctrIsoHdr_t fragHdr;
lctrIsoUnpackHdr(&fragHdr, pSduFrag);
pHeadPkt = WsfMsgPeek(&pRxCtx->data.unframed.pendSduQ, &handlerId);
WSF_ASSERT(pHeadPkt);
switch (fragHdr.pb)
{
case LCTR_PB_COMP:
result = TRUE;
/* Fallthrough */
case LCTR_PB_FIRST:
if (pSdu)
{
LL_TRACE_ERR1("Previous SDU was not flushed, dropping SDU, handle=%u", fragHdr.handle);
lctrIsoUnpackHdr(&isoHdr, pHeadPkt);
isoHdr.pktSn = pRxCtx->packetSequence++;
pSdu = WsfMsgDeq(&pRxCtx->data.unframed.pendSduQ, &handlerId);
WsfMsgFree(pSdu);
pSdu = NULL;
}
/* Store first fragment. */
pRxCtx->data.unframed.curLen = fragHdr.sduLen;
WsfMsgEnq(&pRxCtx->data.unframed.pendSduQ, fragHdr.handle, pSduFrag);
break;
case LCTR_PB_LAST:
result = TRUE;
/* Fallthrough */
case LCTR_PB_CONT:
if (pSdu == NULL)
{
/* Store first fragment. */
pRxCtx->data.unframed.curLen = fragHdr.len;
WsfMsgEnq(&pRxCtx->data.unframed.pendSduQ, fragHdr.handle, pSduFrag);
/* Missing first fragment. */
pRxCtx->data.unframed.ps = LCTR_PS_INVALID;
}
else
{
lctrIsoHdr_t isoHdr;
lctrIsoUnpackHdr(&isoHdr, pSdu);
/* Append continuation fragment (recombine). */
memcpy(isoHdr.pSdu + pRxCtx->data.unframed.curLen, fragHdr.pSdu, fragHdr.len);
WsfMsgFree(pSduFrag);
pRxCtx->data.unframed.curLen += fragHdr.len;
}
break;
default:
break;
}
}
else
{
/* NULL fragment indicates unexpected flush. */
if (pSdu)
{
/* Complete pending SDU fragment. */
pRxCtx->data.unframed.ps = LCTR_PS_INVALID;
result = TRUE;
}
}
if (result && pSdu)
{
/* Update ISO header. */
lctrIsoHdr_t isoHdr;
lctrIsoUnpackHdr(&isoHdr, pSdu);
isoHdr.pb = LCTR_PB_COMP;
isoHdr.len = pRxCtx->data.unframed.curLen;
isoHdr.sduLen = pRxCtx->data.unframed.curLen;
isoHdr.ps = pRxCtx->data.unframed.ps;
isoHdr.len -= + HCI_ISO_DL_MAX_LEN;
/* Reset the packet boundary in case a missed packet leaves it undefined. */
uint8_t rfu; /* Used to peek into msg queue. */
if (WsfMsgNPeek(&pRxCtx->data.unframed.pendSduQ, 1, &rfu))
{
isoHdr.pb = LCTR_PB_FIRST;
}
else
{
isoHdr.pb = LCTR_PB_COMP;
}
lctrIsoPackHdr(pHeadPkt, &isoHdr);
lctrIsoPackHdr(pSdu, &isoHdr);
/* Clean up context */
pRxCtx->data.unframed.curLen = 0;
pRxCtx->data.unframed.ps = 0;
return TRUE;
pRxCtx->data.unframed.ps = LCTR_PS_VALID;
}
return FALSE;
return result;
}
/*************************************************************************************************/
@ -1044,17 +1219,19 @@ uint8_t lctrAssembleRxFramedSdu(lctrIsoalRxCtx_t *pIsoalRxCtx, wsfQueue_t *pRxQu
{
uint8_t totalSduQueued = 0;
/* Last PDU was flushed. SDU data is lost and will be flushed. */
/* Last PDU was flushed. */
if (pIsoalRxCtx->pduFlushed)
{
pIsoalRxCtx->pduFlushed = FALSE;
/* There was a lost SDU due to a fragment being flushed. */
if (pIsoalRxCtx->pPendSduBuf)
{
/* Flush SDU. */
WsfMsgFree(pIsoalRxCtx->pPendSduBuf);
pIsoalRxCtx->pPendSduBuf = NULL;
return 0;
}
pIsoalRxCtx->pduFlushed = FALSE;
return 0;
}
uint8_t *pDataBuf = pIsoBuf + LL_DATA_HDR_LEN;
@ -1160,6 +1337,7 @@ uint8_t lctrAssembleRxFramedSdu(lctrIsoalRxCtx_t *pIsoalRxCtx, wsfQueue_t *pRxQu
uint8_t *pIsoHdrBuf = (pIsoalRxCtx->pPendSduBuf);
lctrIsoPackHdr(pIsoHdrBuf, &isoHdr);
/* TODO: when adding codec data path, change this to enque or consume based on data path. */
/* Queue SDU. */
WsfMsgEnq(pRxQueue, handle, pIsoalRxCtx->pPendSduBuf);
/* lctrIsoDataRxDecAvailBuf(); */ /* Handled in lctrRxSduAlloc. */

View File

@ -4,7 +4,7 @@
*
* \brief Link layer controller power control implementation file.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -42,11 +42,10 @@ void LctrPowerControlInit(void)
{
/* Initialize power control. */
lmgrPersistCb.featuresDefault |= (LL_FEAT_POWER_CHANGE_IND | LL_FEAT_POWER_CONTROL_REQUEST);
lctrPcActTbl[LCTR_PC_MONITOR_AUTO] = lctrAutoPowerMonitorAct;
/* Initialize path loss. */
lmgrPersistCb.featuresDefault |= (LL_FEAT_PATH_LOSS_MONITOR);
lctrPcActTbl[LCTR_PC_MONITOR_PATH_LOSS] = lctrPathLossMonitorAct;
lctrPathLossMonitorActFn = lctrPathLossMonitorAct;
/* Initialize state machines. */
lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PC] = lctrLlcpExecutePclSm;
@ -209,7 +208,6 @@ uint8_t lctrSetPathLossReportingEnable(uint16_t handle, uint8_t enable)
return LL_ERROR_CODE_CMD_DISALLOWED;
}
/* If peer Tx power is unavailable, read the peer tx power. */
if (pCtx->peerTxPower == LL_PWR_CTRL_TXPOWER_UNAVAILABLE)
{
@ -255,7 +253,7 @@ void lctrNotifyHostPathLossRpt(lctrConnCtx_t *pCtx)
const uint16_t handle = LCTR_GET_CONN_HANDLE(pCtx);
uint8_t curPathLoss = lctrCalcPathLoss(pCtx);
LlPathLossThresholdEvt_t evt =
LlPathLossThresholdInd_t evt =
{
.hdr =
{
@ -311,7 +309,7 @@ void lctrPathLossMonitorAct(lctrConnCtx_t *pCtx)
if (pCtx->pclMonitorParam.pathLoss.curTimeSpent >=
pCtx->pclMonitorParam.pathLoss.minTimeSpent)
{
LL_TRACE_INFO2("lctrPathLossMonitorAct, New zone entered. newZone=%u, pathLoss=%u", newZone, lctrCalcPathLoss(pCtx));
LL_TRACE_INFO2("lctrPathLossMonitorAct: new zone entered. newZone=%u, pathLoss=%u", newZone, lctrCalcPathLoss(pCtx));
pCtx->pclMonitorParam.pathLoss.curTimeSpent = 0;
pCtx->pclMonitorParam.pathLoss.curZone = newZone;

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,10 +30,18 @@
#include "wsf_assert.h"
#include "ll_math.h"
#include "wsf_trace.h"
#include "uECC_ll.h"
#include "pal_bb_ble.h"
#include <string.h>
#if ENABLE_UECC
#include "uECC_ll.h"
#endif
#if ENABLE_UECC_TINYCRYPT
#include "tinycrypt/ecc.h"
#include "tinycrypt/ecc_dh.h"
#endif
/*************************************************************************************************/
/*!
* \brief Baseband driver ECC service function.
@ -117,6 +125,34 @@ static void lctrReverse(uint8_t *p, uint16_t len)
}
}
/*************************************************************************************************/
/*!
* \brief Notify host of key generation.
*
* \param pDhKey Diffie-Hellman key.
*/
/*************************************************************************************************/
static void lctrNotifyGenerateDhKeyInd(const uint8_t *pDhKey)
{
LlGenerateDhKeyInd_t evt =
{
.hdr =
{
.param = 0,
.event = LL_GENERATE_DHKEY_CMPL_IND,
.status = LL_SUCCESS
}
};
evt.status = lmgrScCb.pubKeyValid ? LL_SUCCESS : LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
memcpy(evt.dhKey, pDhKey, sizeof(evt.dhKey));
LL_TRACE_INFO0("### LlEvent ### LL_GENERATE_DHKEY_CMPL_IND, status=LL_SUCCESS");
LmgrSendEvent((LlEvt_t *)&evt);
}
#if ENABLE_UECC
/*************************************************************************************************/
/*!
* \brief Start generating P-256 key pair.
@ -193,6 +229,7 @@ void lctrGenerateP256KeyPairComplete(uint8_t *pPubKey, uint8_t *pPrivKey)
lctrReverse(pPubKey + LL_ECC_KEY_LEN, LL_ECC_KEY_LEN);
lctrReverse(pPrivKey, LL_ECC_KEY_LEN);
}
#endif
/*************************************************************************************************/
/*!
@ -213,12 +250,30 @@ void lctrGenerateDhKeyStart(const uint8_t *pPubKey, const uint8_t *pPrivKey)
lctrReverseCopy(privKey, pPrivKey, LL_ECC_KEY_LEN);
/* Start shared secret generation. */
#if ENABLE_UECC
uECC_set_rng_ll(lctrRng);
uECC_shared_secret_start(pubKey, privKey);
lctrScBbDrvEcc(LL_MATH_ECC_OP_GENERATE_DH_KEY);
#endif
#if ENABLE_UECC_TINYCRYPT
uint8_t dhKey[LL_ECC_KEY_LEN];
uECC_set_rng(lctrRng);
const struct uECC_Curve_t* pCurve = uECC_secp256r1();
uECC_shared_secret(pPubKey, pPrivKey, dhKey, pCurve);
/* Reverse shared secret (to little endian). */
lctrReverse(dhKey, LL_ECC_KEY_LEN);
/* Notify host that the key was generated. */
lctrNotifyGenerateDhKeyInd(dhKey);
lmgrScCb.eccOpActive = FALSE;
#endif
}
#if ENABLE_UECC
/*************************************************************************************************/
/*!
* \brief Continue generating Diffie-Hellman key.
@ -252,6 +307,7 @@ void lctrGenerateDhKeyComplete(uint8_t *pDhKey)
/* Reverse shared secret (to little endian). */
lctrReverse(pDhKey, LL_ECC_KEY_LEN);
}
#endif
/*************************************************************************************************/
/*!
@ -272,7 +328,14 @@ bool_t lctrValidatePublicKey(const uint8_t *pPubKey, bool_t generateKey)
lctrReverseCopy(pubKey, pPubKey, LL_ECC_KEY_LEN);
lctrReverseCopy(pubKey + LL_ECC_KEY_LEN, pPubKey + LL_ECC_KEY_LEN, LL_ECC_KEY_LEN);
#if ENABLE_UECC
pubKeyValid = (bool_t)uECC_valid_public_key_ll(pubKey);
#endif
#if ENABLE_UECC_TINYCRYPT
const struct uECC_Curve_t* pCurve = uECC_secp256r1();
pubKeyValid = (bool_t)uECC_valid_public_key(pubKey, pCurve);
#endif
if (!pubKeyValid && generateKey)
{
@ -310,33 +373,7 @@ static void lctrNotifyReadLocalP256PubKeyInd(const uint8_t *pPubKey)
LmgrSendEvent((LlEvt_t *)&evt);
}
/*************************************************************************************************/
/*!
* \brief Notify host of key generation.
*
* \param pDhKey Diffie-Hellman key.
*/
/*************************************************************************************************/
static void lctrNotifyGenerateDhKeyInd(const uint8_t *pDhKey)
{
LlGenerateDhKeyInd_t evt =
{
.hdr =
{
.param = 0,
.event = LL_GENERATE_DHKEY_CMPL_IND,
.status = LL_SUCCESS
}
};
evt.status = lmgrScCb.pubKeyValid ? LL_SUCCESS : LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
memcpy(evt.dhKey, pDhKey, sizeof(evt.dhKey));
LL_TRACE_INFO0("### LlEvent ### LL_GENERATE_DHKEY_CMPL_IND, status=LL_SUCCESS");
LmgrSendEvent((LlEvt_t *)&evt);
}
#if ENABLE_UECC
/*************************************************************************************************/
/*!
* \brief P-256 key pair generation.
@ -388,6 +425,7 @@ static void lctrScGenerateDhKeyContinue(void)
lmgrScCb.eccOpActive = FALSE;
}
}
#endif
/*************************************************************************************************/
/*!
@ -409,6 +447,8 @@ uint8_t LctrGenerateP256KeyPair(void)
/* Start operation. */
lmgrScCb.eccOpActive = TRUE;
#if ENABLE_UECC
if (lmgrScCb.privKeySet)
{
lctrGenerateP256PublicKeyStart(lmgrScCb.privKey);
@ -417,6 +457,37 @@ uint8_t LctrGenerateP256KeyPair(void)
{
lctrGenerateP256KeyPairStart();
}
#endif
#if ENABLE_UECC_TINYCRYPT
uint8_t pubKey[LL_ECC_KEY_LEN * 2];
uint8_t privKey[LL_ECC_KEY_LEN];
if (lmgrScCb.privKeySet)
{
/* Reverse private key (to big endian). */
lctrReverseCopy(privKey, lmgrScCb.privKey, LL_ECC_KEY_LEN);
}
else
{
/* Generate private key. */
lctrRng(privKey, sizeof(privKey));
}
uECC_set_rng(lctrRng);
const struct uECC_Curve_t* pCurve = uECC_secp256r1();
uECC_make_key(pubKey, privKey, pCurve);
/* Reverse keys (to little endian). */
lctrReverse(pubKey, LL_ECC_KEY_LEN);
lctrReverse(pubKey + LL_ECC_KEY_LEN, LL_ECC_KEY_LEN);
lctrReverseCopy(lmgrScCb.privKey, privKey, LL_ECC_KEY_LEN);
/* Notify host that the key was generated. */
lctrNotifyReadLocalP256PubKeyInd(pubKey);
lmgrScCb.eccOpActive = FALSE;
#endif
return LL_SUCCESS;
}
@ -471,23 +542,23 @@ uint8_t LctrGenerateDhKey(const uint8_t *pPubKey, const uint8_t *pPrivKey)
uint8_t LctrGenerateDebugDhKey()
{
const uint8_t privKey[LL_ECC_KEY_LEN] = {
0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,
0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,
0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74,
0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f
0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,
0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,
0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74,
0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f
};
const uint8_t pubKey[LL_ECC_KEY_LEN * 2] = {
/* pubDebugKey_x */
0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,
/* pubDebuKey_y */
0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,
0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,
0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc
/* pubDebugKey_x */
0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,
/* pubDebuKey_y */
0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,
0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,
0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc
};
/* Allow only one key pair generation at a time. */
@ -529,8 +600,10 @@ uint8_t LctrSetValidatePublicKeyMode(uint8_t validateMode)
/*************************************************************************************************/
void LctrScInit(void)
{
#if ENABLE_UECC
lctrEventHdlrTbl[LCTR_EVENT_SC_GENERATE_P256_KEY_PAIR] = lctrScGenerateP256KeyPairContinue;
lctrEventHdlrTbl[LCTR_EVENT_SC_GENERATE_DHKEY] = lctrScGenerateDhKeyContinue;
#endif
lmgrPersistCb.featuresDefault |= LL_FEAT_REMOTE_PUB_KEY_VALIDATION;
lmgrScCb.validatePubKeyMode = KEY_VALIDATE_MODE_ALT2;

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2016-2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,4 +36,6 @@ void LctrSlvPhyConnInit(void)
{
/* Add LLCP SM handler. */
lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD] = lctrSlvLlcpExecutePhyUpdateSm;
lctrSlvCheckEncOverridePhyUpdateFn = lctrSlvCheckEncOverridePhyUpdate;
}

View File

@ -22,6 +22,7 @@
*/
/*************************************************************************************************/
#include "ll_api.h"
#include "lctr_pdu_adv_ae.h"
#include "lctr_pdu_adv.h"
#include "lctr_int_adv_slave.h"
@ -190,11 +191,13 @@ static uint8_t lctrPackExtAdvHeader(lctrAdvSet_t *pAdvSet, uint8_t manExtHdrFlag
}
if ((manExtHdrFlags & LL_EXT_HDR_ADI_BIT) ||
((optExtHdrFlags & LL_EXT_HDR_ADI_BIT) && (!(pAdvSet->extHdrFlags & LL_EXT_HDR_ADI_BIT))))
((optExtHdrFlags & LL_EXT_HDR_ADI_BIT) &&
(!(pAdvSet->extHdrFlags & LL_EXT_HDR_ADI_BIT) || (isPeriodic && pAdvSet->perParam.enableAdi))))
{
/* Pack AdvDataInfo */
extHdrFlags |= LL_EXT_HDR_ADI_BIT;
UINT16_TO_BSTREAM(pBuf, (pAdvSet->param.advSID << 12) | ((pAdvSet->param.advDID & 0x0FFF) << 0));
uint8_t did = isPeriodic ? pAdvSet->perParam.advDID : pAdvSet->param.advDID;
UINT16_TO_BSTREAM(pBuf, (pAdvSet->param.advSID << 12) | ((did & 0x0FFF) << 0));
#if (LL_ENABLE_TESTER == TRUE)
if ((llTesterCb.extHdr.pduMatchMask & (1 << pPduHdr->pduType)) &&
@ -610,6 +613,7 @@ uint8_t lctrPackAuxAdvIndPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, lctrAdvDat
}
/*** Host allowed options ***/
lctrChooseSetAdvA(&pduHdr, pBle, pAdvSet);
lctrChooseSetPeerA(&pduHdr, pBle, pAdvSet);
@ -744,6 +748,11 @@ void lctrPackAuxPtr(lctrAdvSet_t const *pAdvSet, uint32_t offsUsec, uint8_t chId
auxOffset = LL_MATH_DIV_300(offsUsec);
}
if (auxOffset > LCTR_AUX_PTR_MAX_OFFSET)
{
LL_TRACE_ERR1("AUX Offset exceeds max allowed value: %u", auxOffset);
}
pAuxPtr[0] = chIdx | /* LL Channel */
(ca << 6) | /* CA */
(offsUnits << 7); /* Offset Units */
@ -932,6 +941,7 @@ uint8_t lctrPackSyncIndPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, lctrAdvDataB
uint8_t manExtHdrFlags = 0;
uint8_t optExtHdrFlags = LL_EXT_HDR_AUX_PTR_BIT |
((lmgrCb.features & LL_FEAT_PER_ADV_ADI_SUP) ? LL_EXT_HDR_ADI_BIT : 0) |
((pAdvSet->perParam.advEventProp & LL_EXT_HDR_TX_PWR_BIT) ? LL_EXT_HDR_TX_PWR_BIT : 0);
return lctrPackExtAdvHeader(pAdvSet, manExtHdrFlags, optExtHdrFlags,

View File

@ -129,6 +129,57 @@ static inline bool_t lctrIsSetMinUsedChanParamValid(lctrMinUsedChanInd_t *pParam
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Check whether the subrate request parameters are valid.
*
* \param pParam Subrate request parameter.
*
* \return TRUE if parameters are valid, FALSE otherwise.
*/
/*************************************************************************************************/
static inline bool_t lctrIsSubrateReqParamValid(lctrSubrateReq_t *pParam)
{
if ((pParam->srMin < LCTR_MIN_SUBRATE) ||
(pParam->srMin > LCTR_MAX_SUBRATE) ||
(pParam->srMax < LCTR_MIN_SUBRATE) ||
(pParam->srMax > LCTR_MAX_SUBRATE) ||
(pParam->srMin > pParam->srMax) ||
(pParam->maxLatency > (LCTR_MAX_SUBRATE - 1)) ||
(pParam->contNum > (LCTR_MAX_SUBRATE - 1)) ||
(pParam->svt < LL_MIN_SUP_TIMEOUT) ||
(pParam->svt > LL_MAX_SUP_TIMEOUT))
{
return FALSE;
}
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Check whether the subrate indication parameters are valid.
*
* \param pParam Subrate indication parameter.
*
* \return TRUE if parameters are valid, FALSE otherwise.
*/
/*************************************************************************************************/
static inline bool_t lctrIsSubrateIndParamValid(lctrSubrateInd_t *pParam)
{
if ((pParam->srFactor < LCTR_MIN_SUBRATE) ||
(pParam->srFactor > LCTR_MAX_SUBRATE) ||
(pParam->latency > (LCTR_MAX_SUBRATE - 1)) ||
(pParam->contNum > (LCTR_MAX_SUBRATE - 1)) ||
(pParam->svt < LL_MIN_SUP_TIMEOUT) ||
(pParam->svt > LL_MAX_SUP_TIMEOUT))
{
return FALSE;
}
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Pack an ACL header.
@ -745,7 +796,7 @@ uint8_t lctrUnpackCisTermPdu(lctrCisTermInd_t *pPdu, const uint8_t *pBuf)
/*************************************************************************************************/
static uint8_t lctrUnpackPwrChngIndPdu(lctrPwrChngInd_t *pPdu, const uint8_t *pBuf)
{
const uint8_t len = LL_PWR_CHNG_IND_LEN;
const uint8_t len = LL_PWR_CHANGE_IND_LEN;
pBuf += 1; /* skip opcode */
BSTREAM_TO_UINT8 (pPdu->phy, pBuf);
@ -800,6 +851,103 @@ static uint8_t lctrUnpackPwrCtrlRspPdu(lctrPwrCtrlRsp_t *pPdu, const uint8_t *pB
return len;
}
/*************************************************************************************************/
/*!
* \brief Unpack a subrate request PDU.
*
* \param pPdu Subrate request PDU.
* \param pBuf Packed packet buffer.
*
* \return PDU length.
*/
/*************************************************************************************************/
static uint8_t lctrUnpackSubrateReqPdu(lctrSubrateReq_t *pPdu, const uint8_t *pBuf)
{
const uint8_t len = LL_SUBRATE_REQ_LEN;
pBuf += 1; /* skip opcode */
BSTREAM_TO_UINT16(pPdu->srMin, pBuf);
BSTREAM_TO_UINT16(pPdu->srMax, pBuf);
BSTREAM_TO_UINT16(pPdu->maxLatency, pBuf);
BSTREAM_TO_UINT16(pPdu->contNum, pBuf);
BSTREAM_TO_UINT16(pPdu->svt, pBuf);
return len;
}
/*************************************************************************************************/
/*!
* \brief Unpack a subrate indication PDU.
*
* \param pPdu Subrate indication PDU.
* \param pBuf Packed packet buffer.
*
* \return PDU length.
*/
/*************************************************************************************************/
static uint8_t lctrUnpackSubrateIndPdu(lctrSubrateInd_t *pPdu, const uint8_t *pBuf)
{
const uint8_t len = LL_SUBRATE_IND_LEN;
pBuf += 1; /* skip opcode */
BSTREAM_TO_UINT16(pPdu->srFactor, pBuf);
BSTREAM_TO_UINT16(pPdu->srBaseEvent, pBuf);
BSTREAM_TO_UINT16(pPdu->latency, pBuf);
BSTREAM_TO_UINT16(pPdu->contNum, pBuf);
BSTREAM_TO_UINT16(pPdu->svt, pBuf);
return len;
}
/*************************************************************************************************/
/*!
* \brief Unpack a channel reporting indication pdu
*
* \param pPdu Channel reporting indication PDU.
* \param pBuf Packed packet buffer.
*
* \return PDU length.
*/
/*************************************************************************************************/
static uint8_t lctrUnpackChanRptIndPdu(lctrChanRptInd_t *pPdu, const uint8_t *pBuf)
{
const uint8_t len = LL_CH_REPORTING_LEN;
pBuf += 1; /* skip opcode */
BSTREAM_TO_UINT8 (pPdu->enable, pBuf);
BSTREAM_TO_UINT8 (pPdu->minSpacing, pBuf);
BSTREAM_TO_UINT8 (pPdu->maxDelay, pBuf);
return len;
}
/*************************************************************************************************/
/*!
* \brief Unpack a channel status indication pdu
*
* \param pPdu Channel status indication PDU.
* \param pBuf Packed packet buffer.
*
* \return PDU length.
*/
/*************************************************************************************************/
static uint8_t lctrUnpackChanStatusIndPdu(lctrChanStatusInd_t *pPdu, const uint8_t *pBuf)
{
const uint8_t len = LL_CH_STATUS_LEN;
uint8_t i = 0;
pBuf += 1; /* skip opcode */
for (i = 0; i < (LL_CH_STATUS_LEN - 1); i++)
{
/* Leave channel status map packed, unpack as needed. */
BSTREAM_TO_UINT8 (pPdu->chanStatusMap[i], pBuf);
}
return len;
}
/*************************************************************************************************/
/*!
* \brief Decode an LE-C channel buffer.
@ -1051,7 +1199,7 @@ uint8_t lctrDecodeCtrlPdu(lctrDataPdu_t *pPdu, const uint8_t *pBuf, uint8_t role
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
break;
case LL_PDU_PWR_CHNG_IND:
case LL_PDU_PWR_CHANGE_IND:
if ((lmgrCb.features & LL_FEAT_POWER_CHANGE_IND) == 0)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
@ -1081,6 +1229,54 @@ uint8_t lctrDecodeCtrlPdu(lctrDataPdu_t *pPdu, const uint8_t *pBuf, uint8_t role
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
break;
case LL_PDU_SUBRATE_REQ:
if ((lmgrCb.features & LL_FEAT_CONN_SUBRATE) == 0)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
if (lctrUnpackSubrateReqPdu(&pPdu->pld.subrateReq, pBuf) != pPdu->hdr.len)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
if (lctrIsSubrateReqParamValid(&pPdu->pld.subrateReq) == FALSE)
{
return LL_ERROR_CODE_INVALID_LMP_PARAMS;
}
break;
case LL_PDU_SUBRATE_IND:
if ((lmgrCb.features & LL_FEAT_CONN_SUBRATE) == 0)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
if (lctrUnpackSubrateIndPdu(&pPdu->pld.subrateInd, pBuf) != pPdu->hdr.len)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
if (lctrIsSubrateIndParamValid(&pPdu->pld.subrateInd) == FALSE)
{
return LL_ERROR_CODE_INVALID_LMP_PARAMS;
}
break;
case LL_PDU_CH_REPORTING_IND:
if ((lmgrCb.features & LL_FEAT_CHANNEL_CLASSIFICATION) == 0)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
if (lctrUnpackChanRptIndPdu(&pPdu->pld.chanRptInd, pBuf) != pPdu->hdr.len)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
break;
case LL_PDU_CH_STATUS_IND:
if ((lmgrCb.features & LL_FEAT_CHANNEL_CLASSIFICATION) == 0)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
if (lctrUnpackChanStatusIndPdu(&pPdu->pld.chanStatusInd, pBuf) != pPdu->hdr.len)
{
return LL_ERROR_CODE_UNKNOWN_LMP_PDU;
}
break;
default:
result = LL_ERROR_CODE_UNKNOWN_LMP_PDU;

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019 Packetcraft, Inc.
* Copyright (c) 2019-2020 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -154,32 +154,32 @@ typedef struct
/*! \brief Data length request or response PDU. */
typedef struct
{
uint16_t maxRxLen; /*!< Maximum receive length. */
uint16_t maxRxTime; /*!< Maximum receive time. */
uint16_t maxTxLen; /*!< Maximum transmit length. */
uint16_t maxTxTime; /*!< Maximum transmit time. */
uint16_t maxRxLen; /*!< Maximum receive length. */
uint16_t maxRxTime; /*!< Maximum receive time. */
uint16_t maxTxLen; /*!< Maximum transmit length. */
uint16_t maxTxTime; /*!< Maximum transmit time. */
} lctrDataLen_t;
/*! \brief PHY request or response PDU. */
typedef struct
{
uint8_t txPhys; /*!< Transmitter PHYs. */
uint8_t rxPhys; /*!< Receiver PHYs. */
uint8_t txPhys; /*!< Transmitter PHYs. */
uint8_t rxPhys; /*!< Receiver PHYs. */
} lctrPhy_t;
/*! \brief PHY update indication PDU. */
typedef struct
{
uint8_t masterToSlavePhy; /*!< Master-to-slave PHY. */
uint8_t slaveToMasterPhy; /*!< Slave-to-master PHY. */
uint16_t instant; /*!< Instant. */
uint8_t masterToSlavePhy; /*!< Master-to-slave PHY. */
uint8_t slaveToMasterPhy; /*!< Slave-to-master PHY. */
uint16_t instant; /*!< Instant. */
} lctrPhyUpdInd_t;
/*! \brief Minimum number of used channels indication PDU. */
typedef struct
{
uint8_t phys; /*!< Bitmask for the affected PHYs. */
uint8_t minUsedChan; /*!< Minimum number of used channels. */
uint8_t phys; /*!< Bitmask for the affected PHYs. */
uint8_t minUsedChan; /*!< Minimum number of used channels. */
} lctrMinUsedChanInd_t;
/*! \brief Periodic sync indication PDU. */
@ -200,61 +200,81 @@ typedef struct
/*! \brief Peer SCA response PDU. */
typedef struct
{
uint8_t sca; /*!< Peer SCA. */
uint8_t sca; /*!< Peer SCA. */
} lctrPeerSca_t;
/*! \brief CIS request PDU. */
typedef struct
{
uint8_t cigId; /*!< CIG identifier. */
uint8_t cisId; /*!< CIS identifier. */
uint8_t phyMToS; /*!< Master to slave PHY. */
uint8_t phySToM; /*!< Slave to Master PHY. */
uint8_t framing; /*!< PDU framing type. */
uint16_t sduSizeMToS; /*!< Maximum SDU size from the master Host. */
uint16_t sduSizeSToM; /*!< Maximum SDU size from the slave Host. */
uint32_t sduIntervalMToS; /*!< Time interval between the start of consecutive SDUs from the master Host */
uint32_t sduIntervalSToM; /*!< Time interval between the start of consecutive SDUs from the master Host */
uint16_t plMToS; /*!< Master to slave payload. */
uint16_t plSToM; /*!< Slave to master payload. */
uint8_t nse; /*!< Number of subevent. */
uint32_t subIntervUsec; /*!< Contain the time between the start of a subevent and the start of the next subevent, 24 significant bits. */
uint8_t bnMToS; /*!< Master to slave burst number, 4 significant bits. */
uint8_t bnSToM; /*!< Slave to master burst number, 4 significant bits. */
uint8_t ftMToS; /*!< Master to slave flush time. */
uint8_t ftSToM; /*!< Slave to master flush time. */
uint16_t isoInterval; /*!< Contain the time between two CIS anchor points in 1.25msec unit. */
uint32_t cisOffMinUsec; /*!< Contain the minimum time between the CE and the first CIS anchor point. */
uint32_t cisOffMaxUsec; /*!< Contain the maximum time between the CE and the first CIS anchor point. */
uint16_t ceRef; /*!< Contain the reference CE where offsets are applied. */
uint8_t cigId; /*!< CIG identifier. */
uint8_t cisId; /*!< CIS identifier. */
uint8_t phyMToS; /*!< Master to slave PHY. */
uint8_t phySToM; /*!< Slave to Master PHY. */
uint8_t framing; /*!< PDU framing type. */
uint16_t sduSizeMToS; /*!< Maximum SDU size from the master Host. */
uint16_t sduSizeSToM; /*!< Maximum SDU size from the slave Host. */
uint32_t sduIntervalMToS; /*!< Time interval between the start of consecutive SDUs from the master Host */
uint32_t sduIntervalSToM; /*!< Time interval between the start of consecutive SDUs from the master Host */
uint16_t plMToS; /*!< Master to slave payload. */
uint16_t plSToM; /*!< Slave to master payload. */
uint8_t nse; /*!< Number of subevent. */
uint32_t subIntervUsec; /*!< Contain the time between the start of a subevent and the start of the next subevent, 24 significant bits. */
uint8_t bnMToS; /*!< Master to slave burst number, 4 significant bits. */
uint8_t bnSToM; /*!< Slave to master burst number, 4 significant bits. */
uint8_t ftMToS; /*!< Master to slave flush time. */
uint8_t ftSToM; /*!< Slave to master flush time. */
uint16_t isoInterval; /*!< Contain the time between two CIS anchor points in 1.25msec unit. */
uint32_t cisOffMinUsec; /*!< Contain the minimum time between the CE and the first CIS anchor point. */
uint32_t cisOffMaxUsec; /*!< Contain the maximum time between the CE and the first CIS anchor point. */
uint16_t ceRef; /*!< Contain the reference CE where offsets are applied. */
} lctrCisReq_t;
/*! \brief CIS response PDU. */
typedef struct
{
uint32_t cisOffMinUsec; /*!< Contain the minimum time between the CE and the first CIS anchor point. */
uint32_t cisOffMaxUsec; /*!< Contain the maximum time between the CE and the first CIS anchor point. */
uint16_t ceRef; /*!< Contain the reference CE where offsets are applied. */
uint32_t cisOffMinUsec; /*!< Contain the minimum time between the CE and the first CIS anchor point. */
uint32_t cisOffMaxUsec; /*!< Contain the maximum time between the CE and the first CIS anchor point. */
uint16_t ceRef; /*!< Contain the reference CE where offsets are applied. */
} lctrCisRsp_t;
/*! \brief CIS indication PDU. */
typedef struct
{
uint32_t accessAddr; /*!< Contain the access address of the CIS. */
uint32_t cisOffUsec; /*!< Contain the time from the start of the referenced CE to the first CIS anchor point. */
uint32_t cigSyncDelayUsec; /*!< CIG synchronization delay in usec. */
uint32_t cisSyncDelayUsec; /*!< CIG synchronization delay in usec. */
uint16_t ceRef; /*!< Contain the reference CE where offsets are applied. */
uint32_t accessAddr; /*!< Contain the access address of the CIS. */
uint32_t cisOffUsec; /*!< Contain the time from the start of the referenced CE to the first CIS anchor point. */
uint32_t cigSyncDelayUsec; /*!< CIG synchronization delay in usec. */
uint32_t cisSyncDelayUsec; /*!< CIG synchronization delay in usec. */
uint16_t ceRef; /*!< Contain the reference CE where offsets are applied. */
} lctrCisInd_t;
/*! \brief CIS terminate PDU. */
typedef struct
{
uint8_t cigId; /*!< CIG identifier. */
uint8_t cisId; /*!< CIS identifier. */
uint8_t reason; /*!< Reason for termination. */
uint8_t cigId; /*!< CIG identifier. */
uint8_t cisId; /*!< CIS identifier. */
uint8_t reason; /*!< Reason for termination. */
} lctrCisTermInd_t;
/*! \brief Subrate request PDU. */
typedef struct
{
uint16_t srMin; /*!< Subrate minimum value. */
uint16_t srMax; /*!< Subrate maximum value. */
uint16_t maxLatency; /*!< Maximum latency. */
uint16_t contNum; /*!< Continuation number. */
uint16_t svt; /*!< Supervision timeout in 10ms units. */
} lctrSubrateReq_t;
/*! \brief Subrate indication PDU. */
typedef struct
{
uint16_t srFactor; /*!< Subrate factor. */
uint16_t srBaseEvent; /*!< Subrate base event. */
uint16_t latency; /*!< Latency. */
uint16_t contNum; /*!< Continuation number. */
uint16_t svt; /*!< Supervision timeout in 10ms units. */
} lctrSubrateInd_t;
/*! \brief Power control request PDU. */
typedef struct
{
@ -281,6 +301,21 @@ typedef struct
int8_t txPower; /*!< Local txPower. */
} lctrPwrChngInd_t;
/*! \brief Channel reporting indication PDU. */
typedef struct
{
uint8_t enable; /*!< Enable. */
uint8_t minSpacing; /*!< Minimum spacing. */
uint8_t maxDelay; /*!< Maximum delay. */
} lctrChanRptInd_t;
/*! \brief Channel status indication PDU. */
typedef struct
{
uint8_t chanStatusMap[LL_CH_STATUS_LEN - 1];
/*!< Map of current peer channel status. */
} lctrChanStatusInd_t;
/*! \brief Data channel control PDU. */
typedef struct
{
@ -314,6 +349,11 @@ typedef struct
lctrPwrCtrlReq_t pwrCtrlReq; /*!< Power control request. */
lctrPwrCtrlRsp_t pwrCtrlRsp; /*!< Power control response. */
lctrPwrChngInd_t pwrChngInd; /*!< Power change indication. */
lctrChanRptInd_t chanRptInd; /*!< Channel report indication. */
lctrChanStatusInd_t chanStatusInd;
/*!< Channel status indication. */
lctrSubrateReq_t subrateReq; /*!< Subrate request. */
lctrSubrateInd_t subrateInd; /*!< Subrate indication. */
} pld; /*!< Unpacked PDU payload. */
} lctrDataPdu_t;

View File

@ -37,9 +37,9 @@
* \return Header length.
*/
/*************************************************************************************************/
uint8_t lctrIsoUnpackHdr(lctrIsoHdr_t *pHdr, const uint8_t *pBuf)
uint8_t lctrIsoUnpackHdr(lctrIsoHdr_t *pHdr, uint8_t *pBuf)
{
uint8_t len = HCI_ISO_HDR_LEN + HCI_ISO_DL_MIN_LEN;
uint8_t len = HCI_ISO_HDR_LEN;
uint16_t field16;
@ -50,21 +50,34 @@ uint8_t lctrIsoUnpackHdr(lctrIsoHdr_t *pHdr, const uint8_t *pBuf)
BSTREAM_TO_UINT16(pHdr->len, pBuf);
if (pHdr->tsFlag)
switch (pHdr->pb)
{
BSTREAM_TO_UINT32(pHdr->ts, pBuf);
len += HCI_ISO_TS_LEN;
}
else
{
pHdr->ts = 0;
}
case LCTR_PB_COMP:
case LCTR_PB_FIRST:
len += HCI_ISO_DL_MIN_LEN;
if (pHdr->tsFlag)
{
BSTREAM_TO_UINT32(pHdr->ts, pBuf);
len += HCI_ISO_TS_LEN;
}
else
{
pHdr->ts = 0;
}
BSTREAM_TO_UINT16(pHdr->pktSn, pBuf);
BSTREAM_TO_UINT16(field16, pBuf);
BSTREAM_TO_UINT16(pHdr->pktSn, pBuf);
BSTREAM_TO_UINT16(field16, pBuf);
pHdr->sduLen = (field16 >> 0) & 0x0FFF;
pHdr->ps = (field16 >> 14) & 0x03;
pHdr->sduLen = (field16 >> 0) & 0x0FFF;
pHdr->ps = (field16 >> 14) & 0x03;
break;
default:
pHdr->ts = 0;
pHdr->sduLen = 0;
pHdr->ps = 0;
break;
}
pHdr->pSdu = pBuf;

View File

@ -82,7 +82,7 @@ typedef struct
uint16_t pktSn; /*!< Packet sequence number. */
uint16_t sduLen; /*!< SDU length. */
lctrPktStatus_t ps:8; /*!< Packet status. */
const uint8_t *pSdu; /*!< First byte of ISO SDU. */
uint8_t *pSdu; /*!< First byte of ISO SDU. */
} lctrIsoHdr_t;
/*! \brief ISO SDU descriptor. */
@ -136,7 +136,7 @@ uint8_t lctrBisPackBigChannelMapInd(uint8_t *pBuf, uint64_t chanMap, uint16_t in
uint8_t lctrBisPackBigTerminateInd(uint8_t *pBuf, uint8_t reason, uint16_t instance);
/* Unpack */
uint8_t lctrIsoUnpackHdr(lctrIsoHdr_t *pHdr, const uint8_t *pBuf);
uint8_t lctrIsoUnpackHdr(lctrIsoHdr_t *pHdr, uint8_t *pBuf);
uint8_t lctrCisUnpackDataPduHdr(lctrCisDataPduHdr_t *pHdr, const uint8_t *pBuf);
uint8_t lctrBisUnpackDataPduHdr(lctrBisDataPduHdr_t *pHdr, const uint8_t *pBuf);
uint8_t lctrBisUnpackBigChannelMapInd(uint64_t *pChanMap, uint16_t *pInstance, const uint8_t *pBuf);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2019 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -60,6 +60,7 @@ static uint8_t lctrRemapEvent(lctrCisCtx_t *pCisCtx, uint8_t event)
case LCTR_CONN_MSG_API_DISCONNECT:
{
pCisCtx->hostInitTerm = TRUE;
lctrCisStoreDisconnectReason(pCisCtx);
return LCTR_CIS_MSG_CIS_DISC;
}

View File

@ -249,7 +249,12 @@ bool_t lctrMstLlcpExecuteCisEstSm(lctrConnCtx_t *pCtx, uint8_t event)
}
lctrCisCtx_t *pCisCtx = lctrFindCisByHandle(pCtx->llcpCisHandle);
WSF_ASSERT(pCisCtx != NULL)
if (pCisCtx == NULL)
{
LL_TRACE_WARN1("lctrMstLlcpExecuteCisEstSm: CIS context not found cis_handle=%u", pCtx->llcpCisHandle);
/* TRUE to prevent further processing of this message. */
return TRUE;
}
switch (pCtx->llcpState)
{

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -38,6 +38,7 @@
#include "lctr_int_conn.h"
#include "lctr_int_conn_slave.h"
#include "ll_init_api.h"
#include "lmgr_api.h"
#include "util/bstream.h"
#include "wsf_trace.h"
@ -142,6 +143,24 @@ const lctrLlcpEh_t lctrCmnProcTbl[LCTR_PROC_CMN_TOTAL][LCTR_PROC_CMN_ACT_TOTAL]
lctrStorePeerSca, /* LCTR_PROC_CMN_ACT_RECV_REQ */
lctrSendPeerScaRsp, /* LCTR_PROC_CMN_ACT_SEND_RSP */
lctrStorePeerSca, /* LCTR_PROC_CMN_ACT_RECV_RSP */
},
/* LCTR_PROC_CMN_CH_CLASS_REPORTING */
{
NULL, /* LCTR_PROC_CMN_ACT_API_PARAM */
lctrSendChannelReportingInd,
/* LCTR_PROC_CMN_ACT_SEND_REQ */
lctrStoreChannelReportingInd,
/* LCTR_PROC_CMN_ACT_RECV_REQ */
NULL, /* LCTR_PROC_CMN_ACT_SEND_RSP */
NULL /* LCTR_PROC_CMN_ACT_RECV_RSP */
},
/* LCTR_PROC_CMN_CH_STATUS_REPORT */
{
NULL, /* LCTR_PROC_CMN_ACT_API_PARAM */
lctrSendChannelStatusInd, /* LCTR_PROC_CMN_ACT_SEND_REQ */
lctrStoreChannelStatusInd, /* LCTR_PROC_CMN_ACT_RECV_REQ */
NULL, /* LCTR_PROC_CMN_ACT_SEND_RSP */
NULL /* LCTR_PROC_CMN_ACT_RECV_RSP */
}
};
@ -270,6 +289,12 @@ static uint8_t lctrGetCmnProcId(lctrConnCtx_t *pCtx, uint8_t event)
case LCTR_CONN_LLCP_LENGTH_EXCH:
return LCTR_PROC_CMN_DATA_LEN_UPD;
case LCTR_CONN_LLCP_CHANNEL_STATUS:
return LCTR_PROC_CMN_CH_STATUS_REPORT;
case LCTR_CONN_LLCP_CHANNEL_REPORTING:
return LCTR_PROC_CMN_CH_CLASS_REPORTING;
case LCTR_CONN_LLCP_PROC_CMPL:
return pCtx->llcpActiveProc;
@ -304,6 +329,12 @@ static uint8_t lctrGetCmnProcId(lctrConnCtx_t *pCtx, uint8_t event)
case LL_PDU_PEER_SCA_RSP:
return LCTR_PROC_CMN_REQ_PEER_SCA;
case LL_PDU_CH_REPORTING_IND:
return LCTR_PROC_CMN_CH_CLASS_REPORTING;
case LL_PDU_CH_STATUS_IND:
return LCTR_PROC_CMN_CH_STATUS_REPORT;
case LL_PDU_UNKNOWN_RSP:
switch (lctrDataPdu.pld.unknownRsp.unknownType)
{
@ -325,6 +356,19 @@ static uint8_t lctrGetCmnProcId(lctrConnCtx_t *pCtx, uint8_t event)
case LL_PDU_LENGTH_RSP:
return LCTR_PROC_CMN_DATA_LEN_UPD;
case LL_PDU_PWR_CHANGE_IND:
return LCTR_PROC_PWR_IND;
case LL_PDU_PWR_CTRL_RSP:
case LL_PDU_PWR_CTRL_REQ:
return LCTR_PROC_PWR_CTRL;
case LL_PDU_CH_REPORTING_IND:
return LCTR_PROC_CMN_CH_CLASS_REPORTING;
case LL_PDU_CH_STATUS_IND:
return LCTR_PROC_CMN_CH_STATUS_REPORT;
default:
break;
}
@ -381,6 +425,8 @@ static uint8_t lctrRemapCmnProcEvent(lctrConnCtx_t *pCtx, uint8_t event)
case LCTR_CONN_LLCP_VERSION_EXCH:
case LCTR_CONN_LLCP_LENGTH_EXCH:
case LCTR_CONN_LLCP_TERM:
case LCTR_CONN_LLCP_CHANNEL_STATUS:
case LCTR_CONN_LLCP_CHANNEL_REPORTING:
return LCTR_PROC_CMN_EVT_INT_START;
case LCTR_CONN_LLCP_PROC_CMPL:
@ -397,6 +443,8 @@ static uint8_t lctrRemapCmnProcEvent(lctrConnCtx_t *pCtx, uint8_t event)
case LL_PDU_SLV_FEATURE_REQ:
case LL_PDU_LENGTH_REQ:
case LL_PDU_PEER_SCA_REQ:
case LL_PDU_CH_REPORTING_IND:
case LL_PDU_CH_STATUS_IND:
return LCTR_PROC_CMN_EVT_RECV_REQ;
case LL_PDU_TERMINATE_IND:
@ -541,6 +589,14 @@ static bool_t lctrFeatureAvail(lctrConnCtx_t *pCtx, uint8_t proc, uint8_t event)
result = FALSE;
}
break;
case LCTR_PROC_CMN_CH_CLASS_REPORTING:
case LCTR_PROC_CMN_CH_STATUS_REPORT:
if ((pCtx->usedFeatSet & LL_FEAT_CHANNEL_CLASSIFICATION) == 0)
{
LL_TRACE_WARN1("Requested LL_FEAT_CHANNEL_CLASSIFICATION not available, usedFeatSet=0x%08x", pCtx->usedFeatSet);
result = FALSE;
}
break;
case LCTR_PROC_CMN_TERM:
default:
break;
@ -575,7 +631,14 @@ static void lctrNotifyHostReadRemoteFeatCnf(lctrConnCtx_t *pCtx, uint8_t status)
};
uint8_t *pBuf = evt.features;
UINT64_TO_BSTREAM(pBuf, pCtx->usedFeatSet);
if (BT_VER < LL_VER_BT_CORE_SPEC_5_0)
{
UINT64_TO_BSTREAM(pBuf, pCtx->usedFeatSet);
}
else
{
UINT64_TO_BSTREAM(pBuf, pCtx->peerFeatures);
}
LL_TRACE_INFO2("### LlEvent ### LL_READ_REMOTE_FEAT_CNF, handle=%u, status=%u", handle, status);

View File

@ -53,13 +53,13 @@ enum
LCTR_CU_EVENT_HOST_NEG_REPLY, /*!< Received host connection parameter negative reply. */
LCTR_CU_EVENT_PEER_CONN_PARAM_REQ, /*!< Received peer LL_CONN_PARAM_REQ. */
LCTR_CU_EVENT_PEER_CONN_PARAM_RSP, /*!< Received peer LL_CONN_PARAM_RSP. */
LCTR_CU_EVENT_PEER_REJECT, /*!< Received peer LL_REJECT_IND OR LL_UNKNOWN_RSP. */
LCTR_CU_EVENT_PEER_REJECT, /*!< Received peer LL_REJECT_IND or LL_UNKNOWN_RSP. */
LCTR_CU_EVENT_INT_PROC_COMP, /*!< Procedure completion event. */
LCTR_CU_EVENT_INT_SKIP_CONN_PARAM, /*!< Skip connection parameter procedure. */
LCTR_CU_EVENT_INT_START_CONN_UPD, /*!< Start pending host connection update procedure. */
LCTR_CU_EVENT_INT_START_CONN_PARAM, /*!< Start pending peer connection parameter procedure. */
LCTR_CU_EVENT_INT_REJECT_CONN_UPD, /*!< Reject connection update procedure. */
LCTR_CU_EVENT_TOTAL, /*!< Total connection parameter/update states. */
LCTR_CU_EVENT_TOTAL, /*!< Total connection parameter/update events. */
LCTR_CU_EVENT_INVALID = 0xFF /*!< Invalid event. */
};
@ -638,14 +638,15 @@ void lctrMstLlcpExecuteSm(lctrConnCtx_t *pCtx, uint8_t event)
break;
}
if (!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_PING] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_PING](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_EST] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_EST](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_PC] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_PC](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CMN] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CMN](pCtx, event)))
if (!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_PING] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_PING](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_ENH_CONN_UPD] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_ENH_CONN_UPD](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_EST] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_EST](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_PC] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_PC](pCtx, event)) &&
!(lctrMstLlcpSmTbl[LCTR_LLCP_SM_CMN] && lctrMstLlcpSmTbl[LCTR_LLCP_SM_CMN](pCtx, event)))
{
lctrLlcpStatelessEventHandler(pCtx, event);
}

View File

@ -50,10 +50,10 @@ enum
LCTR_CU_EVENT_HOST_REPLY, /*!< Received host connection parameter reply. */
LCTR_CU_EVENT_HOST_NEG_REPLY, /*!< Received host connection parameter negative reply. */
LCTR_CU_EVENT_PEER_CONN_UPD_IND, /*!< Received peer LL_CONN_UPD_IND. */
LCTR_CU_EVENT_PEER_REJECT, /*!< Received peer LL_REJECT_IND OR LL_UNKNOWN_RSP. */
LCTR_CU_EVENT_PEER_REJECT, /*!< Received peer LL_REJECT_IND or LL_UNKNOWN_RSP. */
LCTR_CU_EVENT_INT_PROC_COMP, /*!< Procedure completion event. */
LCTR_CU_EVENT_INT_START_CONN_UPD, /*!< Start pending connection update procedure. */
LCTR_CU_EVENT_TOTAL, /*!< Total connection parameter/update states. */
LCTR_CU_EVENT_TOTAL, /*!< Total connection parameter/update events. */
LCTR_CU_EVENT_INVALID = 0xFF /*!< Invalid event. */
};
@ -670,14 +670,15 @@ void lctrSlvLlcpExecuteSm(lctrConnCtx_t *pCtx, uint8_t event)
break;
}
if (!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PING] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PING](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_EST] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_EST](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PC] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PC](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CMN] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CMN](pCtx, event)) )
if (!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_ENCRYPT](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PING] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PING](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_ENH_CONN_UPD] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_ENH_CONN_UPD](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CONN_UPD](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PHY_UPD](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_EST] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_EST](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CIS_TERM](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PC] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_PC](pCtx, event)) &&
!(lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CMN] && lctrSlvLlcpSmTbl[LCTR_LLCP_SM_CMN](pCtx, event)) )
{
lctrLlcpStatelessEventHandler(pCtx, event);
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2013-2018 Arm Ltd. All Rights Reserved.
*
* Copyright (c) 2019-2020 Packetcraft, Inc.
* Copyright (c) 2019-2021 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,6 +25,7 @@
#include "lctr_int_enc_slave.h"
#include "lctr_int_conn.h"
#include "lctr_int_conn_slave.h"
#include "lctr_int_slave_phy.h"
#include "lmgr_api.h"
#include "wsf_trace.h"
@ -428,7 +429,8 @@ static void lctrSlvCheckProcOverride(lctrConnCtx_t *pCtx, uint8_t event)
{
case LCTR_ENC_EVENT_PEER_ENC_REQ:
if (lctrSlvCheckEncOverrideConnParam(pCtx) ||
lctrSlvCheckEncOverrideCommonParam(pCtx))
lctrSlvCheckEncOverrideCommonParam(pCtx) ||
((lctrSlvCheckEncOverridePhyUpdateFn == NULL) || lctrSlvCheckEncOverridePhyUpdateFn(pCtx)))
{
pCtx->llcpPendMask |= 1 << pCtx->llcpActiveProc;
pCtx->llcpActiveProc = LCTR_PROC_ENCRYPT;

Some files were not shown because too many files have changed in this diff Show More