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"
@ -147,6 +148,13 @@ public:
*/
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. */
@ -292,6 +309,7 @@ typedef struct
typedef struct
{
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. */
@ -307,6 +325,7 @@ typedef struct
typedef struct
{
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. */
@ -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.

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,9 +215,8 @@ static void bbMstAuxScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, u
#endif
uint32_t auxOffsetUsec;
if (pAuxScan->rxAuxAdvCback(pCur, bbAuxAdvBuf))
{
if (pAuxScan->pTxAuxReqBuf)
bool_t txScanReq = pAuxScan->rxAuxAdvCback(pCur, bbAuxAdvBuf);
if ((txScanReq) && (pAuxScan->pTxAuxReqBuf))
{
/* Tx response PDU. */
@ -210,8 +229,19 @@ static void bbMstAuxScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, u
bbBleSetTifs();
PalBbBleTxTifsData(&desc, 1);
}
else
{
PalBbBleCancelTifs();
}
else if ((pAuxScan->rxAuxChainCback) &&
if (pAuxScan->rxAuxAdvPostCback)
{
pAuxScan->rxAuxAdvPostCback(pCur, bbAuxAdvBuf);
}
if (!txScanReq)
{
if ((pAuxScan->rxAuxChainCback) &&
((auxOffsetUsec = pAuxScan->rxAuxChainCback(pCur, bbAuxAdvBuf)) > 0))
{
/* Rx chain indication PDU. */
@ -244,6 +274,7 @@ static void bbMstAuxScanRxCompCback(uint8_t status, int8_t rssi, uint32_t crc, u
}
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

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

View File

@ -136,8 +136,15 @@ void BbBleBisSlaveInit(void)
*/
/*************************************************************************************************/
void BbBleBisTxData(PalBbBleTxBufDesc_t descs[], uint8_t cnt, uint32_t nextPduTime, PalBbBleChan_t *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)
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;
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);
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);
}
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);
}
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);
}
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.
@ -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,6 +416,8 @@ void lctrCisActDisc(lctrCisCtx_t *pCisCtx)
{
lctrCisDisc_t *pMsg;
if (!LctrCisTerminationInProgress(pCisCtx->aclHandle))
{
if ((pMsg = (lctrCisDisc_t *)WsfMsgAlloc(sizeof(*pMsg))) != NULL)
{
pMsg->hdr.handle = pCisCtx->aclHandle;
@ -388,6 +428,18 @@ void lctrCisActDisc(lctrCisCtx_t *pCisCtx)
pMsg->reason = pCisCtx->reason;
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

@ -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);

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,14 +179,17 @@ 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;
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
};
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,15 +564,14 @@ 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,
lctrNotifyPowerReportInd(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_REMOTE,
pCtx->bleData.chan.rxPhy, pPdu->txPower, pPdu->limits,
pPdu->txPower - pCtx->peerTxPower);
}
@ -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->pclMonitorParam.autoMonitor.rssiRunAvg.avgCount >= LL_PC_TBL_LEN)
{
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)
{
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;
}
}
else
else if ((averageRunning < pCtx->pclMonitorParam.autoMonitor.lowThreshold) &&
!(pCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MAX_BIT))
{
pCtx->pclMonitorParam.autoMonitor.curTimeSpent = 0;
sendReqDelta = pCtx->pclMonitorParam.autoMonitor.requestVal;
}
}
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.
@ -69,14 +69,15 @@ typedef struct
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. */
lctrIsoalRxCtx_t isoalRxCtx; /*!< ISOAL receive context. */
lctrOutDataPathCtx_t dataPathOutCtx; /*!< Output data path context. */
/* ISO test */
LlIsoTestCtrs_t stats; /*!< Rx statistics. */
@ -94,21 +95,20 @@ typedef struct
struct
{
uint32_t payloadCtr; /*!< Payload counter for framed transmissions. */
} framed; /*!< Framed context. */
} framed;
struct
{
uint8_t payloadOffset; /*!< Payload offset for unframed transmissions. */
} unframed; /*!< Unframed context. */
} util; /*!< Role-based utility variables. */
uint8_t burstIdx; /*!< BN Index for unframed transmissions. */
} unframed;
} util;
LlIsoPldType_t pldType:8; /*!< Test payload type. */
} test; /*!< ISO Test data. */
} 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,17 +164,24 @@ 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. */
uint32_t bigSyncTimeoutMs; /*!< Synchronization timeout in microseconds. */
/* Encryption */
uint8_t bcstCode[LL_BC_LEN]; /*!< Broadcast Code. Array address should be word-aligned. */
/* Event state */
uint16_t totalAcc; /*!< Total clock accuracy. */
uint16_t extraWwUsec; /*!< Extra window widening time in microseconds. */
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. */
/* Encryption */
uint8_t bcstCode[LL_BC_LEN]; /*!< Broadcast Code. */
/* Reception status. */
bool_t lastPduMissed; /*!< Rx failure on last PDU. */
} mst; /*!< BIG master specific data. */
} roleData; /*!< Role-specific data. */
@ -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. */
@ -407,6 +414,39 @@ typedef struct
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,16 +480,26 @@ 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. */
@ -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,22 +142,37 @@ typedef struct
/*! \brief Input datapath context. */
typedef struct
{
LlIsoDataPath_t id; /*!< Input data path ID. */
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. */
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. */
@ -167,6 +182,16 @@ typedef union
lctrOutDataPathCtx_t out; /*!< Output context. */
} 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);
@ -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);
(void)result;
SchRemove(&pAdvSet->auxAdvBod);
}
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);
SchRemove(&pAdvSet->advBod);
(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

@ -4,7 +4,7 @@
*
* \brief Link layer controller master BIG ISR callbacks.
*
* 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,6 +43,9 @@ static struct
uint8_t *pCtrlBuf; /*!< Received BIS Control PDU buffer. */
uint8_t *pDataBuf[LL_MAX_BIS][LL_MAX_BN];
/*!< Received data buffers. */
uint8_t numRxPdus[LL_MAX_BIS];
/*!< Number of successfully received packets for each BIS. */
uint8_t curChanIdx; /*!< Current channel index. */
} lctrMstBisIsr;
/**************************************************************************************************
@ -54,13 +57,23 @@ static struct
* \brief Update loop counters for sequential packing.
*
* \param pBigCtx BIG context.
* \param pReAcqTrain Returns TRUE if re-acquisition is required, unchanged otherwise.
*
* \return TRUE if more Rx pending, FALSE otherwise.
*/
/*************************************************************************************************/
static bool_t lctrMstBisLoopCounterSequential(lctrBigCtx_t *pBigCtx)
static bool_t lctrMstBisLoopCounterSequential(lctrBigCtx_t *pBigCtx, bool_t *pReAcqTrain)
{
size_t numSePkts = (pBigCtx->bn * pBigCtx->irc) + lctrMstBisIsr.se.ptIdx;
int numSkipSe = -1;
PalBbBleChan_t *pCurChan = NULL;
uint32_t curSeOffs;
do
{
numSkipSe++;
uint8_t numSeIntervals = 1;
unsigned int numSePkts = (pBigCtx->bn * pBigCtx->irc) + lctrMstBisIsr.se.ptIdx;
/* BIG Event limit (beyond BIS Control SubEvent). */
@ -69,7 +82,7 @@ static bool_t lctrMstBisLoopCounterSequential(lctrBigCtx_t *pBigCtx)
return FALSE;
}
if (!lctrSlvBisCalcNextIdxSequential(pBigCtx, &lctrMstBisIsr.se, numSePkts))
if (!lctrBisCalcNextIdxSequential(pBigCtx, &lctrMstBisIsr.se, numSePkts))
{
if (!lctrMstBisIsr.cstf)
{
@ -77,10 +90,23 @@ static bool_t lctrMstBisLoopCounterSequential(lctrBigCtx_t *pBigCtx)
}
}
/* Compute next channel. */
lctrSeCtx_t nextSe = lctrMstBisIsr.se;
if (lctrSlvBisCalcNextIdxSequential(pBigCtx, &nextSe, numSePkts))
if (lctrMstBisIsr.se.bisEvtIdx < pBigCtx->numBis)
{
/* Compute next channel. */
pCurChan = lctrMstBisIsr.pNextChan;
lctrSeCtx_t nextSe = lctrMstBisIsr.se;
while (TRUE)
{
if (lctrBisCalcNextIdxSequential(pBigCtx, &nextSe, numSePkts))
{
if (pBigCtx->pBisCtx[nextSe.bisEvtIdx] == NULL)
{
/* Filtered BIS. */
numSeIntervals++;
continue;
}
WSF_ASSERT(pBigCtx->pBisCtx[nextSe.bisEvtIdx] != NULL);
lctrMstBisIsr.pNextChan = &pBigCtx->pBisCtx[nextSe.bisEvtIdx]->chan;
}
else
@ -88,8 +114,29 @@ static bool_t lctrMstBisLoopCounterSequential(lctrBigCtx_t *pBigCtx)
lctrMstBisIsr.pNextChan = &pBigCtx->ctrChan;
}
break;
}
}
/* Compute next packet time. */
lctrMstBisIsr.nextSeOffs += pBigCtx->subInterUsec;
curSeOffs = lctrMstBisIsr.nextSeOffs;
lctrMstBisIsr.nextSeOffs += pBigCtx->subInterUsec * numSeIntervals;
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_BIS_RECV_DUP))
{
/* Always receive duplicates. */
break;
}
/* Skip SE if data already received; do not receive duplicates. */
} while (lctrMstBisIsr.pDataBuf[lctrMstBisIsr.se.bisEvtIdx][lctrMstBisIsr.se.burstIdx] != NULL);
if ((numSkipSe > 0) && pCurChan)
{
/* Re-acquire the receive train. */
BbBleBisRxDataReAcq(pBigCtx->roleData.mst.anchorPoint + pBigCtx->roleData.mst.firstBisOffsUsec + curSeOffs, pCurChan);
*pReAcqTrain = TRUE;
}
return TRUE;
}
@ -99,13 +146,22 @@ static bool_t lctrMstBisLoopCounterSequential(lctrBigCtx_t *pBigCtx)
* \brief Update loop counters for interleaved packing.
*
* \param pBigCtx BIG context.
* \param pReAcqTrain Returns TRUE if re-acquisition is required, unchanged otherwise.
*
* \return TRUE if more Rx pending, FALSE otherwise.
*/
/*************************************************************************************************/
static bool_t lctrMstBisLoopCounterInterleaved(lctrBigCtx_t *pBigCtx)
static bool_t lctrMstBisLoopCounterInterleaved(lctrBigCtx_t *pBigCtx, bool_t *pReAcqTrain)
{
size_t numSePkts = (pBigCtx->bn * pBigCtx->irc) + lctrMstBisIsr.se.ptIdx;
int numSkipSe = -1;
PalBbBleChan_t *pCurChan;
uint32_t curSeOffs;
do
{
numSkipSe++;
unsigned int numSePkts = (pBigCtx->bn * pBigCtx->irc) + lctrMstBisIsr.se.ptIdx;
/* BIG Event limit (beyond BIS Control SubEvent). */
@ -114,7 +170,7 @@ static bool_t lctrMstBisLoopCounterInterleaved(lctrBigCtx_t *pBigCtx)
return FALSE;
}
if (!lctrSlvBisCalcNextIdxInterleaved(pBigCtx, &lctrMstBisIsr.se, numSePkts))
if (!lctrBisCalcNextIdxInterleaved(pBigCtx, &lctrMstBisIsr.se, numSePkts))
{
if (!lctrMstBisIsr.cstf)
{
@ -123,8 +179,10 @@ static bool_t lctrMstBisLoopCounterInterleaved(lctrBigCtx_t *pBigCtx)
}
/* Compute next channel. */
pCurChan = lctrMstBisIsr.pNextChan;
curSeOffs = lctrMstBisIsr.nextSeOffs;
lctrSeCtx_t nextSe = lctrMstBisIsr.se;
if (lctrSlvBisCalcNextIdxInterleaved(pBigCtx, &nextSe, numSePkts))
if (lctrBisCalcNextIdxInterleaved(pBigCtx, &nextSe, numSePkts))
{
lctrMstBisIsr.pNextChan = &pBigCtx->pBisCtx[nextSe.bisEvtIdx]->chan;
}
@ -136,6 +194,22 @@ static bool_t lctrMstBisLoopCounterInterleaved(lctrBigCtx_t *pBigCtx)
/* Compute next packet time. */
lctrMstBisIsr.nextSeOffs += pBigCtx->bisSpaceUsec;
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_BIS_RECV_DUP))
{
/* Always receive duplicates. */
break;
}
/* Skip SE if data already received; do not receive duplicates. */
} while (lctrMstBisIsr.pDataBuf[lctrMstBisIsr.se.bisEvtIdx][lctrMstBisIsr.se.burstIdx] != NULL);
if (numSkipSe > 0)
{
/* Re-acquire the receive train. */
BbBleBisRxDataReAcq(pBigCtx->roleData.mst.anchorPoint + pBigCtx->roleData.mst.firstBisOffsUsec + curSeOffs, pCurChan);
*pReAcqTrain = TRUE;
}
return TRUE;
}
@ -161,18 +235,47 @@ static bool_t lctrMstBisRxData(lctrBigCtx_t *pBigCtx, bool_t reAcqSync, uint8_t
return FALSE;
}
/*** Commit transmission ***/
/*** Commit reception ***/
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[lctrMstBisIsr.se.bisEvtIdx];
BbBleBisRxData(pBuf, LL_ISO_DATA_HDR_LEN + BB_DATA_PLD_MAX_LEN,
pBigCtx->roleData.mst.anchorPoint + lctrMstBisIsr.nextSeOffs,
/* Set the inline decryption packet counter. */
if (pBigCtx->encrypt && lctrSetDecryptPktCountHdlr)
{
uint64_t pktCtr;
/* Check if this is the control subevent. */
if (lctrMstBisIsr.pNextChan == &pBigCtx->ctrChan)
{
/* Set packet counter to the bisPayloadCounter of the first subevent. */
pktCtr = pBigCtx->eventCounter * pBigCtx->bn;
lctrSetDecryptPktCountHdlr(pktCtr);
}
else
{
/* Set packet counter to the current bisPayloadCounter. */
pktCtr = (pBigCtx->eventCounter * pBigCtx->bn) + lctrMstBisIsr.se.burstIdx;
lctrSetDecryptPktCountHdlr(pktCtr);
}
}
BbBleBisRxData(pBuf, LL_ISO_DATA_HDR_LEN + pBigCtx->maxPdu + (pBigCtx->encrypt ? LL_DATA_MIC_LEN : 0),
pBigCtx->roleData.mst.anchorPoint + pBigCtx->roleData.mst.firstBisOffsUsec + lctrMstBisIsr.nextSeOffs,
lctrMstBisIsr.pNextChan,
reAcqSync);
/*** Post-commit calculation ***/
if (lctrMstBisIsr.se.bisEvtIdx < pBigCtx->numBis)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[lctrMstBisIsr.se.bisEvtIdx];
if (pBisCtx && pBisCtx->enabled)
{
lctrMstBisIsr.curChanIdx = pBisCtx->chan.chanIdx;
/* Now that channel data is set in BB, compute next channel information. */
pBisCtx->chan.chanIdx = LmgrSelectNextSubEvtChannel(&pBisCtx->chSelInfo);
}
}
return TRUE;
}
@ -272,6 +375,7 @@ static void lctrMstBigControlPostProcess(lctrBigCtx_t *pBigCtx)
}
lctrBisRxIsoDataPduFree(lctrMstBisIsr.pCtrlBuf);
lctrMstBisIsr.pCtrlBuf = NULL;
}
/*************************************************************************************************/
@ -314,7 +418,7 @@ static void lctrMstBigControlProcedureHandler(lctrBigCtx_t *pBigCtx)
* \param rxEvtCtr Received event counter.
*/
/*************************************************************************************************/
static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr, uint32_t sduRef)
{
uint8_t numHandles = 0;
uint16_t handles[LL_MAX_BIS] = { 0 };
@ -322,20 +426,26 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
uint64_t pktCtrBase = rxEvtCtr * pBigCtx->bn;
lctrIsoalRxCtx_t *pRxCtx;
for (unsigned int i = 0; i < pBigCtx->numBis; i++)
for (unsigned int bisIdx = 0; bisIdx < pBigCtx->numBis; bisIdx++)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[i];
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[bisIdx];
if (pBisCtx == NULL)
{
/* Filtered BIS. */
continue;
}
pRxCtx = &pBisCtx->roleData.mst.isoalRxCtx;
uint8_t *pDataPdu;
uint8_t pldCtrOffs;
while ((pDataPdu = lctrBisDequeueRxDataPdu(pBisCtx, &pldCtrOffs)) != NULL)
for (uint8_t burstIdx = 0; burstIdx < pBigCtx->bn; burstIdx++)
{
uint64_t pktCtr = pktCtrBase + pldCtrOffs;
uint8_t *pDataPdu = lctrBisDequeueRxDataPdu(pBisCtx, burstIdx);
uint64_t pktCtr = pktCtrBase + burstIdx;
pBisCtx->chan.enc.pRxPktCounter = &pktCtr;
if (lctrPktDecryptHdlr)
if (pDataPdu && lctrPktDecryptHdlr)
{
if (!lctrPktDecryptHdlr(&pBisCtx->chan.enc, pDataPdu))
{
@ -347,9 +457,11 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
}
if (pBisCtx->pBigCtx->framing == LL_ISO_PDU_TYPE_UNFRAMED)
{
if (pDataPdu)
{
/* Store payload offset for test transit. */
pBisCtx->test.util.unframed.payloadOffset = pldCtrOffs;
pBisCtx->test.util.unframed.burstIdx = burstIdx;
lctrBisDataPduHdr_t pduHdr;
lctrBisUnpackDataPduHdr(&pduHdr, pDataPdu);
@ -358,10 +470,6 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
uint8_t * const pIsoSdu = pDataPdu - LCTR_ISO_SDU_START_OFFSET;
switch (pBisCtx->path)
{
case LL_ISO_DATA_PATH_HCI:
{
lctrIsoHdr_t isoHdr =
{
/* ISO header */
@ -371,17 +479,12 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
.tsFlag = FALSE,
/* Data load */
.ts = 0,
.ts = sduRef,
.pktSn = pktCtr,
.sduLen = pduHdr.len,
.ps = LCTR_PS_VALID
};
if (pBigCtx->lastPduMissed)
{
pRxCtx->data.unframed.ps = LCTR_PS_INVALID;
}
switch (pBisCtx->lastLlid)
{
case LL_LLID_ISO_UNF_END_PDU:
@ -392,10 +495,12 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
default:
isoHdr.pb = LCTR_PB_COMP;
isoHdr.tsFlag = TRUE;
isoHdr.ts = PalBbGetCurrentTime();
break;
case LL_LLID_ISO_UNF_CONT_PDU:
isoHdr.pb = LCTR_PB_FIRST;
isoHdr.tsFlag = TRUE;
isoHdr.ts = PalBbGetCurrentTime();
break;
}
break;
@ -415,7 +520,7 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
break;
}
default:
LL_TRACE_WARN2("Unexpected LLID recieved; dropping Rx ISO PDU, bigHandle=%u, pktCtr[15:0]=%u", pBigCtx->handle, pktCtr);
LL_TRACE_WARN2("Unexpected LLID received; dropping Rx ISO PDU, bigHandle=%u, pktCtr[15:0]=%u", pBigCtx->handle, pktCtr);
WsfMsgFree(pIsoSdu);
continue;
}
@ -425,48 +530,147 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
uint8_t hdrLen;
hdrLen = lctrIsoPackHdr(pIsoSdu, &isoHdr);
/* Adjust SDU payload to start immediately after the header. */
/* TODO optimize memory layout, cf. lctrRecombineRxUnframedSdu(). */
memmove(pIsoSdu + hdrLen, pDataPdu + LL_ISO_DATA_HDR_LEN, isoHdr.sduLen);
/* Move to temporary queue to collect SDU fragments until complete. */
if (!lctrIsoUnframedRxSduPendQueue(pRxCtx, pIsoSdu, pBisCtx->handle, isoHdr.sduLen, pduHdr.llid))
/* Store fragment until complete fragment received. */
if (!lctrRecombineRxUnframedSdu(pRxCtx, pIsoSdu))
{
break;
}
/* Complete SDU ready to go out. Empty the temp queue and send it out. */
/* Deliver the SDU fragments. */
uint8_t handlerId;
uint8_t *pSduFrag;
while ((pSduFrag = WsfMsgDeq(&pRxCtx->data.unframed.pendSduQ, &handlerId)) != NULL)
uint8_t *pSdu;
while ((pSdu = WsfMsgDeq(&pRxCtx->data.unframed.pendSduQ, &handlerId)) != NULL)
{
lctrBisRxIsoSduEnq(pBisCtx, pSduFrag);
if (pBisCtx->test.enabled) /* In cases of test mode, queue it here. */
{
lctrOutDataPathCtx_t *pOutDataPathCtx = &pBisCtx->roleData.mst.dataPathOutCtx;
WSF_ASSERT(pOutDataPathCtx->id != LL_ISO_DATA_PATH_VS);
WsfMsgEnq(&pOutDataPathCtx->cfg.hci.rxDataQ, pBisCtx->handle, pSdu);
pOutDataPathCtx->cfg.hci.numRxPend++;
/* TODO optimize counter, accounting upon allocation. */
lctrIsoDataRxDecAvailBuf();
}
else if (lctrIsoRxConnEnq(&pBisCtx->roleData.mst.dataPathOutCtx,
pBisCtx->handle, pktCtr, pSdu))
{
/* Implies HCI data path. */
numSdu[numHandles]++;
}
break;
}
case LL_ISO_DATA_PATH_VS:
else
{
WSF_ASSERT(lctrCodecHdlr.out);
lctrCodecHdlr.out(pBisCtx->handle, pDataPdu + LL_ISO_DATA_HDR_LEN, pDataPdu[LCTR_ISO_DATA_PDU_LEN_OFFSET], pktCtr);
WsfMsgFree(pIsoSdu); /* TODO Resolve PDU free in Audio layer */
break;
WsfMsgFree(pSdu);
}
default:
}
}
else /* (pDataPdu == NULL) */
{
/* Indicate SDU has missing data. */
pRxCtx->data.unframed.ps = LCTR_PS_INVALID;
/* End fragment lost. */
if ((burstIdx + 1) == pBigCtx->bn)
{
/* NULL signals lost PDU; release previously stored fragments. */
if (lctrRecombineRxUnframedSdu(pRxCtx, NULL))
{
/* Deliver the SDU fragments. */
uint8_t handlerId;
uint8_t *pSdu;
while ((pSdu = WsfMsgDeq(&pRxCtx->data.unframed.pendSduQ, &handlerId)) != NULL)
{
if (pBisCtx->test.enabled) /* In cases of test mode, queue it here. */
{
lctrOutDataPathCtx_t *pOutDataPathCtx = &pBisCtx->roleData.mst.dataPathOutCtx;
WSF_ASSERT(pOutDataPathCtx->id != LL_ISO_DATA_PATH_VS);
WsfMsgEnq(&pOutDataPathCtx->cfg.hci.rxDataQ, pBisCtx->handle, pSdu);
pOutDataPathCtx->cfg.hci.numRxPend++;
/* TODO optimize counter, accounting upon allocation. */
lctrIsoDataRxDecAvailBuf();
}
else if (lctrIsoRxConnEnq(&pBisCtx->roleData.mst.dataPathOutCtx,
pBisCtx->handle, pktCtr, pSdu))
{
/* Implies HCI data path. */
numSdu[numHandles]++;
}
else
{
WsfMsgFree(pSdu);
}
}
}
else
{
if (lmgrGetOpFlag(LL_OP_MODE_FLAG_ENA_ISO_LOST_NOTIFY) &&
(lctrMstBisIsr.numRxPdus[bisIdx] == 0))
{
/* No prior fragments; send lost SDU. */
uint8_t *pSdu = lctrBisRxIsoDataPduAlloc();
if (pSdu)
{
uint8_t *pIsoSdu = pSdu - LCTR_ISO_SDU_START_OFFSET;
lctrIsoHdr_t isoHdr =
{
/* ISO header */
.handle = pBisCtx->handle,
.pb = LCTR_PB_COMP,
.tsFlag = FALSE,
.len = 0,
/* Data load */
.ts = sduRef,
.pktSn = pktCtr,
.sduLen = 0,
.ps = LCTR_PS_LOST
};
lctrIsoPackHdr(pIsoSdu, &isoHdr);
if (pBisCtx->test.enabled) /* In cases of test mode, queue it here. */
{
lctrOutDataPathCtx_t *pOutDataPathCtx = &pBisCtx->roleData.mst.dataPathOutCtx;
WSF_ASSERT(pOutDataPathCtx->id != LL_ISO_DATA_PATH_VS);
WsfMsgEnq(&pOutDataPathCtx->cfg.hci.rxDataQ, pBisCtx->handle, pSdu);
pOutDataPathCtx->cfg.hci.numRxPend++;
/* TODO optimize counter, accounting upon allocation. */
lctrIsoDataRxDecAvailBuf();
}
else if (lctrIsoRxConnEnq(&pBisCtx->roleData.mst.dataPathOutCtx,
pBisCtx->handle, pktCtr, pIsoSdu))
{
/* Implies HCI data path. */
numSdu[numHandles]++;
}
else
{
LL_TRACE_WARN2("Data path disabled; dropping Rx ISO PDU, bigHandle=%u, pktCtr[15:0]=%u", pBigCtx->handle, pktCtr);
WsfMsgFree(pIsoSdu);
break;
}
}
else
{
LL_TRACE_WARN2("ISO SDU data flow controlled, lost SDU sync packet delivery failed, bigHandle=%u, pktCtr[15:0]=%u", pBigCtx->handle, pktCtr);
}
}
}
}
}
}
else /* LL_ISO_PDU_TYPE_FRAMED */
{
switch (pBisCtx->path)
if (pDataPdu)
{
switch (pBisCtx->roleData.mst.dataPathOutCtx.id)
{
case LL_ISO_DATA_PATH_HCI:
{
numSdu[numHandles] += lctrAssembleRxFramedSdu(&pBisCtx->roleData.mst.isoalRxCtx, &pBisCtx->roleData.mst.rxIsoSduQ,
numSdu[numHandles] += lctrAssembleRxFramedSdu(&pBisCtx->roleData.mst.isoalRxCtx, &pBisCtx->roleData.mst.dataPathOutCtx.cfg.hci.rxDataQ,
pBisCtx->handle, pDataPdu, pDataPdu[LCTR_ISO_DATA_PDU_LEN_OFFSET]);
break;
@ -475,7 +679,7 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
{
WSF_ASSERT(lctrCodecHdlr.out);
lctrAssembleRxFramedSdu(&pBisCtx->roleData.mst.isoalRxCtx, &pBisCtx->roleData.mst.rxIsoSduQ,
lctrAssembleRxFramedSdu(&pBisCtx->roleData.mst.isoalRxCtx, &pBisCtx->roleData.mst.dataPathOutCtx.cfg.codec.rxDataQ,
pBisCtx->handle, pDataPdu, pDataPdu[LCTR_ISO_DATA_PDU_LEN_OFFSET]);
uint8_t *pIsoBuf;
@ -484,24 +688,38 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
lctrIsoHdr_t isoHdr;
lctrIsoUnpackHdr(&isoHdr, pIsoBuf);
lctrCodecHdlr.out(pBisCtx->handle, isoHdr.pSdu, isoHdr.sduLen, pktCtr);
WsfMsgFree(pIsoBuf); /* TODO Resolve PDU free in Audio layer */
lctrCodecHdlr.out(pBisCtx->handle, isoHdr.pSdu, isoHdr.sduLen, isoHdr.ts);
WsfMsgFree(pIsoBuf);
lctrIsoDataRxIncAvailBuf(1);
}
break;
}
default:
{
if (pBisCtx->test.enabled)
{
numSdu[numHandles] += lctrAssembleRxFramedSdu(&pBisCtx->roleData.mst.isoalRxCtx, &pBisCtx->roleData.mst.dataPathOutCtx.cfg.hci.rxDataQ,
pBisCtx->handle, pDataPdu, pDataPdu[LCTR_ISO_DATA_PDU_LEN_OFFSET]);
break;
}
LL_TRACE_WARN2("Data path disabled; dropping Rx ISO PDU, bigHandle=%u, pktCtr[15:0]=%u", pBigCtx->handle, pktCtr);
break;
}
}
lctrBisRxIsoDataPduFree(pDataPdu);
}
else /* (pDataPdu == NULL) */
{
/* TODO Send NULL audio sync to ISOAL assembler */
}
}
}
if (numSdu[numHandles])
{
if (!pBisCtx->test.enabled)
if (!pBisCtx->test.enabled && (pBisCtx->roleData.mst.dataPathOutCtx.id != LL_ISO_DATA_PATH_VS))
{
handles[numHandles] = pBisCtx->handle;
numHandles++;
@ -513,7 +731,7 @@ static void lctrMstBisRxDataPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
}
}
if (numHandles)
if (lmgrPersistCb.recvIsoPendCback && numHandles)
{
/* Notify host received SDUs. */
lmgrPersistCb.recvIsoPendCback(numHandles, handles, numSdu);
@ -534,7 +752,13 @@ static void lctrMstBisRxTestPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[i];
/* Consume data for RX test. */
if (pBisCtx == NULL)
{
/* Filtered BIS. */
continue;
}
/* Consume data for Rx test. */
if (pBisCtx->test.enabled)
{
if (!pBisCtx->test.term)
@ -557,13 +781,11 @@ static void lctrMstBisRxTestPduHandler(lctrBigCtx_t *pBigCtx, uint32_t rxEvtCtr)
pBisCtx->test.pendInit = FALSE;
}
LL_TRACE_INFO1("COUNTER = %d", pBisCtx->test.util.framed.payloadCtr);
expPayloadCtr = pBisCtx->test.util.framed.payloadCtr++;
}
else /* LL_ISO_PDU_TYPE_UNFRAMED */
{
expPayloadCtr = (rxEvtCtr * pBigCtx->bn) +
pBisCtx->test.util.unframed.payloadOffset;
expPayloadCtr = (rxEvtCtr * pBigCtx->bn) + pBisCtx->test.util.unframed.burstIdx;
}
lctrValidateIsoTestData((uint8_t *)isoHdr.pSdu, isoHdr.sduLen, &pBisCtx->roleData.mst.stats,
@ -609,6 +831,10 @@ void lctrMstBisRxCompletion(BbOpDesc_t *pOp, uint8_t *pBuf, uint8_t status)
if (status == BB_STATUS_SUCCESS)
{
lctrMstBisIsr.numRcvdPkt++;
lctrMstBisIsr.numRxPdus[lctrMstBisIsr.se.bisEvtIdx]++;
/* Extra WW only needed for initial received packet. */
pBigCtx->roleData.mst.initWwUsec = 0;
}
if (pBigCtx->state != LCTR_MST_BIG_STATE_SYNCED)
@ -619,11 +845,32 @@ void lctrMstBisRxCompletion(BbOpDesc_t *pOp, uint8_t *pBuf, uint8_t status)
switch (status)
{
case BB_STATUS_CRC_FAILED:
LL_TRACE_WARN3("BB failed with status=CRC_FAILED, bigHandle=%u, bleChan=%u, eventCounter=%u", pBigCtx->handle, lctrMstBisIsr.curChanIdx, pBigCtx->eventCounter);
LL_TRACE_WARN3(" bisEvtIdx=%u, burstIdx=%u, repIdx=%u", lctrMstBisIsr.se.bisEvtIdx, lctrMstBisIsr.se.burstIdx, lctrMstBisIsr.se.repIdx);
break;
case BB_STATUS_RX_TIMEOUT:
LL_TRACE_WARN3("BB failed with status=RX_TIMEOUT, bigHandle=%u, bleChan=%u, eventCounter=%u", pBigCtx->handle, lctrMstBisIsr.curChanIdx, pBigCtx->eventCounter);
LL_TRACE_WARN3(" bisEvtIdx=%u, burstIdx=%u, repIdx=%u", lctrMstBisIsr.se.bisEvtIdx, lctrMstBisIsr.se.burstIdx, lctrMstBisIsr.se.repIdx);
break;
case BB_STATUS_MIC_FAILED:
LL_TRACE_WARN2("lctrMstBisRxCompletion: BB failed with status MIC_FAILED Data/Control PDU received, bigHandle=%u", pBigCtx->handle, pBigCtx->eventCounter);
lctrMstBigSendMsg(pBigCtx, LCTR_MST_BIG_INT_MIC_FAILED);
BbSetBodTerminateFlag();
goto RxPostProcess;
break;
case BB_STATUS_FAILED:
LL_TRACE_ERR3("BB failed with status=FAILED, bigHandle=%u, bleChan=%u, eventCounter=%u", pBigCtx->handle, lctrMstBisIsr.curChanIdx, pBigCtx->eventCounter);
LL_TRACE_ERR3(" bisEvtIdx=%u, burstIdx=%u, repIdx=%u", lctrMstBisIsr.se.bisEvtIdx, lctrMstBisIsr.se.burstIdx, lctrMstBisIsr.se.repIdx);
/* Fallthrough */
case BB_STATUS_CANCELED:
/* Continue to next BIG Event. */
BbSetBodTerminateFlag();
goto RxPostProcess;
break;
default:
break;
@ -640,7 +887,7 @@ void lctrMstBisRxCompletion(BbOpDesc_t *pOp, uint8_t *pBuf, uint8_t status)
case BB_STATUS_SUCCESS:
case BB_STATUS_CRC_FAILED:
/* Store peer's timing info for synchronizing next BIS Events and ISO Events. */
pBigCtx->roleData.mst.anchorPoint = pBigCtx->roleData.mst.rxSyncTime = pBis->startTsUsec;
pBigCtx->roleData.mst.anchorPoint = pBigCtx->roleData.mst.rxSyncTime = pBis->startTsUsec - pBigCtx->roleData.mst.firstBisOffsUsec;
break;
default:
@ -682,10 +929,9 @@ void lctrMstBisRxCompletion(BbOpDesc_t *pOp, uint8_t *pBuf, uint8_t status)
{
case BB_STATUS_RX_TIMEOUT:
/* Re-acquire the receive train. */
BbBleBisRxDataReAcq(pBigCtx->roleData.mst.anchorPoint + lctrMstBisIsr.nextSeOffs,
BbBleBisRxDataReAcq(pBigCtx->roleData.mst.anchorPoint + pBigCtx->roleData.mst.firstBisOffsUsec + lctrMstBisIsr.nextSeOffs,
lctrMstBisIsr.pNextChan);
reAcqTrain = TRUE;
pBigCtx->lastPduMissed = TRUE;
break;
default:
@ -697,7 +943,7 @@ void lctrMstBisRxCompletion(BbOpDesc_t *pOp, uint8_t *pBuf, uint8_t status)
switch (pBigCtx->packing)
{
case LL_PACKING_INTERLEAVED:
if (!lctrMstBisLoopCounterInterleaved(pBigCtx))
if (!lctrMstBisLoopCounterInterleaved(pBigCtx, &reAcqTrain))
{
/* Continue to next BIG Event. */
BbSetBodTerminateFlag();
@ -707,7 +953,7 @@ void lctrMstBisRxCompletion(BbOpDesc_t *pOp, uint8_t *pBuf, uint8_t status)
case LL_PACKING_SEQUENTIAL:
default:
if (!lctrMstBisLoopCounterSequential(pBigCtx))
if (!lctrMstBisLoopCounterSequential(pBigCtx, &reAcqTrain))
{
/* Continue to next BIG Event. */
BbSetBodTerminateFlag();
@ -742,7 +988,7 @@ RxPostProcess:
}
else if (hdr.cssn == pBigCtx->bcp.cssn)
{
LL_TRACE_WARN1("Unexpected duplicate BIS Control PDU recieved, bigHandle=%u", pBigCtx->handle);
LL_TRACE_WARN1("Unexpected duplicate BIS Control PDU received, bigHandle=%u", pBigCtx->handle);
}
else
{
@ -788,22 +1034,23 @@ void lctrMstBigBeginOp(BbOpDesc_t *pOp)
}
memset(&lctrMstBisIsr, 0, sizeof(lctrMstBisIsr));
lctrMstBisIsr.se.bisEvtIdx = pBigCtx->roleData.mst.firstBisEvtIdx;
/* Compute next packet time. */
lctrMstBisIsr.pNextChan = NULL;
switch (pBigCtx->packing)
{
case LL_PACKING_INTERLEAVED:
if (pBigCtx->numBis > 1)
{
lctrMstBisIsr.pNextChan = &pBigCtx->pBisCtx[1]->chan;
if (pBigCtx->roleData.mst.pSecondBisCtx)
{
lctrMstBisIsr.pNextChan = &pBigCtx->roleData.mst.pSecondBisCtx->chan;
}
}
else if (pBigCtx->nse > 1)
{
lctrMstBisIsr.pNextChan = &pBigCtx->pBisCtx[0]->chan;
}
else
{
lctrMstBisIsr.pNextChan = &pBigCtx->ctrChan;
lctrMstBisIsr.pNextChan = &pBigCtx->roleData.mst.pFirstBisCtx->chan;
}
lctrMstBisIsr.nextSeOffs = pBigCtx->bisSpaceUsec;
@ -813,21 +1060,25 @@ void lctrMstBigBeginOp(BbOpDesc_t *pOp)
default:
if (pBigCtx->nse > 1)
{
lctrMstBisIsr.pNextChan = &pBigCtx->pBisCtx[0]->chan;
lctrMstBisIsr.pNextChan = &pBigCtx->roleData.mst.pFirstBisCtx->chan;
}
else if (pBigCtx->numBis > 1)
{
lctrMstBisIsr.pNextChan = &pBigCtx->pBisCtx[1]->chan;
}
else
if (pBigCtx->roleData.mst.pSecondBisCtx)
{
lctrMstBisIsr.pNextChan = &pBigCtx->ctrChan;
lctrMstBisIsr.pNextChan = &pBigCtx->roleData.mst.pSecondBisCtx->chan;
}
}
lctrMstBisIsr.nextSeOffs = pBigCtx->subInterUsec;
break;
}
if (lctrMstBisIsr.pNextChan == NULL)
{
lctrMstBisIsr.pNextChan = &pBigCtx->ctrChan;
}
lctrMstBisIsr.cstf = TRUE; /* receive Control PDU by default */
lctrMstBisIsr.cssn = 0xFF;
@ -838,6 +1089,26 @@ void lctrMstBigBeginOp(BbOpDesc_t *pOp)
}
}
/*************************************************************************************************/
/*!
* \brief Abort a BIS operation.
*
* \param pOp Aborted operation.
*/
/*************************************************************************************************/
void lctrMstBigAbortOp(BbOpDesc_t *pOp)
{
WSF_ASSERT(pOp->protId == BB_PROT_BLE);
WSF_ASSERT(pOp->prot.pBle->chan.opType == BB_BLE_OP_MST_BIS_EVENT);
LL_TRACE_WARN1("!!! BIG Synchronizer BOD aborted, eventCounter=%u", ((lctrBigCtx_t *)pOp->pCtx)->eventCounter);
/* Clear state since abort is called without lctrMstBigBeginOp() initializing state. */
memset(&lctrMstBisIsr, 0, sizeof(lctrMstBisIsr));
lctrMstBigEndOp(pOp);
}
/*************************************************************************************************/
/*!
* \brief End a BIS operation.
@ -850,12 +1121,7 @@ void lctrMstBigEndOp(BbOpDesc_t *pOp)
lctrBigCtx_t * const pBigCtx = pOp->pCtx;
BbBleData_t * const pBle = &pBigCtx->bleData;
BbBleMstBisEvent_t * const pBis = &pBle->op.mstBis;
if (pBigCtx->state != LCTR_MST_BIG_STATE_SYNCED)
{
lctrMstBigSendMsg(pBigCtx, LCTR_MST_BIG_INT_TERMINATED_SYNC);
WsfTimerStop(&pBigCtx->roleData.mst.bigSyncTmr);
return;
}
uint32_t sduRef = pBigCtx->roleData.mst.anchorPoint;
/* Enqueue BIS Data PDUs. */
@ -863,16 +1129,38 @@ void lctrMstBigEndOp(BbOpDesc_t *pOp)
for (unsigned int bisIdx = 0; bisIdx < pBigCtx->numBis; bisIdx++)
{
for (unsigned int bnIdx = 0; bnIdx < pBigCtx->bn; bnIdx++)
for (unsigned int burstIdx = 0; burstIdx < pBigCtx->bn; burstIdx++)
{
if (lctrMstBisIsr.pDataBuf[bisIdx][bnIdx])
if (lctrMstBisIsr.pDataBuf[bisIdx][burstIdx])
{
if (pBigCtx->pBisCtx[bisIdx])
{
lctrBisEnqueueRxDataPdu(pBigCtx->pBisCtx[bisIdx],
lctrMstBisIsr.pDataBuf[bisIdx][bnIdx],
bnIdx); /* payload counter offset from rxEventCounter */
lctrMstBisIsr.pDataBuf[bisIdx][burstIdx],
burstIdx);
}
else
{
lctrBisRxIsoDataPduFree(lctrMstBisIsr.pDataBuf[bisIdx][burstIdx]);
}
}
}
}
if (pBigCtx->state != LCTR_MST_BIG_STATE_SYNCED)
{
/* Terminate after PDUs are queued by lctrBisEnqueueRxDataPdu(). */
lctrMstBigSendMsg(pBigCtx, LCTR_MST_BIG_INT_TERMINATED_SYNC);
WsfTimerStop(&pBigCtx->roleData.mst.bigSyncTmr);
if (lctrMstBisIsr.pCtrlBuf)
{
lctrBisRxIsoDataPduFree(lctrMstBisIsr.pCtrlBuf);
lctrMstBisIsr.pCtrlBuf = NULL;
}
return;
}
/* BIG Control procedure. */
@ -884,6 +1172,7 @@ void lctrMstBigEndOp(BbOpDesc_t *pOp)
}
else
{
/* No need to continue Rx process on MIC errors. */
goto RxPostProcess;
}
}
@ -907,10 +1196,10 @@ void lctrMstBigEndOp(BbOpDesc_t *pOp)
unsyncTimeUsec += pBigCtx->isoInterUsec;
uint32_t wwTotalUsec = lctrCalcWindowWideningUsec(unsyncTimeUsec, pBigCtx->roleData.mst.totalAcc)
+ pBigCtx->roleData.mst.extraWwUsec;
+ 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;
pBis->rxSyncDelayUsec = wwTotalUsec << 1; /* multiply 2 for before and after BIG Anchor Point */
lctrSelectBigChannels(pBigCtx);
@ -927,7 +1216,7 @@ void lctrMstBigEndOp(BbOpDesc_t *pOp)
RxPostProcess:
/* Consume ISO Data PDU. */
lctrMstBisRxDataPduHandler(pBigCtx, rxEventCounter);
lctrMstBisRxDataPduHandler(pBigCtx, rxEventCounter, sduRef);
lctrMstBisRxTestPduHandler(pBigCtx, rxEventCounter);
if (lmgrCb.sendIsoCmplEvt)

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,14 +503,21 @@ 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
{
if (lctrSlvBisIsr.pCtrlBuf == NULL)
{
lctrSlvBisIsr.pNextChan = NULL;
}
else
{
lctrSlvBisIsr.pNextChan = &pBigCtx->ctrChan;
}
}
/* Compute next packet time. */
lctrSlvBisIsr.nextSeOffs += pBigCtx->subInterUsec;
@ -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,14 +573,21 @@ 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
{
if (lctrSlvBisIsr.pCtrlBuf == NULL)
{
lctrSlvBisIsr.pNextChan = NULL;
}
else
{
lctrSlvBisIsr.pNextChan = &pBigCtx->ctrChan;
}
}
/* Compute next packet time. */
lctrSlvBisIsr.nextSeOffs += pBigCtx->bisSpaceUsec;
@ -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)
{
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++;
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++;
}
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);
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,9 +70,16 @@ static void lctrMstCisInitIsr(lctrCisCtx_t *pCisCtx)
pCisCtx->txDataCounter = 0;
pCisCtx->rxDataCounter = 0;
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter = 0;
/* List may be empty if BN_S_To_M is 0 */
if (pCisCtx->rxFtParamList.pHead != NULL)
{
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;
@ -81,6 +88,11 @@ static void lctrMstCisInitIsr(lctrCisCtx_t *pCisCtx)
{
pCisCtx->isTxDone = FALSE;
}
}
else
{
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,16 +218,21 @@ 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
{
pCisCtx->isoLinkQualStats.retransmitPkt++;
}
}
/* Set the flag to send NULL packet. */
bool_t removeFromList = TRUE;
@ -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,8 +1190,11 @@ void lctrMstCisCigTxCompletion(BbOpDesc_t *pOp, uint8_t status)
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
lctrCisCtx_t *pCisCtx = pCigCtx->pCisCtx;
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;
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;
}

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,8 +72,16 @@ static void lctrSlvCisInitIsr(lctrCisCtx_t *pCisCtx)
pCisCtx->txDataCounter = 0;
pCisCtx->rxDataCounter = 0;
pCisCtx->txFtParamList.pHead->ftParam.subEvtCounter = 0;
/* List may be empty if BN M_S is 0 */
if (pCisCtx->rxFtParamList.pHead != NULL)
{
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)
{
@ -83,6 +91,11 @@ static void lctrSlvCisInitIsr(lctrCisCtx_t *pCisCtx)
{
pCisCtx->isTxDone = FALSE;
}
}
else
{
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,6 +1133,8 @@ 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);
@ -1078,8 +1179,11 @@ void lctrSlvCisCigTxCompletion(BbOpDesc_t *pOp, uint8_t status)
lctrCigCtx_t * const pCigCtx = pOp->pCtx;
lctrCisCtx_t *pCisCtx = pCigCtx->pCisCtx;
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;
if (pCisCtx->rxFtParamList.pHead != NULL)
{
pCisCtx->rxFtParamList.pHead->ftParam.subEvtCounter++;
pCisCtx->txFtParamList.pHead->ftParam.pduAcked = FALSE;
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))
{
/* If a packet did not receive for whatever reason, add a datapoint with the lowest RSSI. */
if (pCtx->lastRxStatus != BB_STATUS_SUCCESS)
{
pCtx->rssi = 0x80; /* Most negative 8 bit number. */
}
if ((pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->lastRxStatus == BB_STATUS_SUCCESS))
switch (pCtx->powerMonitorScheme)
{
if (lctrPcActTbl[pCtx->powerMonitorScheme])
case LCTR_PC_MONITOR_AUTO:
{
lctrPcActTbl[pCtx->powerMonitorScheme](pCtx);
/* 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[]. */
}
@ -383,7 +428,6 @@ void lctrMstConnEndOp(BbOpDesc_t *pOp)
/*** Update for next operation ***/
uint32_t anchorPointUsec = pOp->dueUsec;
uint16_t numIntervals = 0;
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)
{
if ((pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->lastRxStatus == BB_STATUS_SUCCESS))
/* If a packet did not receive for whatever reason, add a datapoint with the lowest RSSI. */
if (pCtx->lastRxStatus != BB_STATUS_SUCCESS)
{
if (lctrPcActTbl[pCtx->powerMonitorScheme])
pCtx->rssi = 0x80; /* Most negative 8 bit number. */
}
switch (pCtx->powerMonitorScheme)
{
lctrPcActTbl[pCtx->powerMonitorScheme](pCtx);
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->maxLatency &&
pCtx->data.slv.initAckRcvd &&
pCtx->data.slv.rxFromMaster &&
(WsfQueueEmpty(&pCtx->txArqQ)) &&
(pCtx->state != LCTR_CONN_STATE_TERMINATING)))
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) &&
@ -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.
@ -450,51 +450,6 @@ static uint8_t lctrSetExtAdvDataSm(lctrAdvSet_t *pAdvSet, lctrAdvDataBuf_t *pDat
case LL_ADV_DATA_OP_COMP:
/*** Complete single fragment buffer (no reassembly required) while advertising is enabled. ***/
if (pAdvSet->state == LCTR_EXT_ADV_STATE_ENABLED)
{
bool_t isCancelled = FALSE;
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);
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;
@ -502,6 +457,17 @@ static uint8_t lctrSetExtAdvDataSm(lctrAdvSet_t *pAdvSet, lctrAdvDataBuf_t *pDat
pDataBuf->alt.ext.did = lctrCalcDID(pFragBuf, fragLen);
pDataBuf->alt.ext.fragPref = fragPref;
pDataBuf->alt.ext.modified = TRUE;
/* Renew BOD's to make the data updated immediately if possible. */
if (SchIsBodCancellable(&pAdvSet->advBod) &&
((pAdvSet->auxBodUsed == FALSE) || SchIsBodCancellable(&pAdvSet->auxAdvBod)))
{
/* Remove BOD's; remove completes in abortCback(). */
if (pAdvSet->auxBodUsed)
{
SchRemove(&pAdvSet->auxAdvBod);
}
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;
}
@ -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;
}
@ -1057,10 +1035,10 @@ static void lctrSlvAuxCommitOp(lctrAdvSet_t *pAdvSet, BbOpDesc_t * const pOp)
(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 */
}
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,9 +588,12 @@ void lctrSetupBisContext(lctrBisCtx_t *pBisCtx, uint32_t seedAccAddr, uint16_t b
pBisCtx->chan.enc.dir = 1;
pBisCtx->chan.enc.type = PAL_BB_TYPE_BIS;
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];
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. */
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,9 +643,13 @@ void lctrRemapBigChannels(lctrBigCtx_t *pBigCtx, uint64_t chanMap)
for (unsigned int i = 0; i < pBigCtx->numBis; i++)
{
lctrBisCtx_t * const pBisCtx = pBigCtx->pBisCtx[i];
if (pBisCtx)
{
pBisCtx->chSelInfo.chanMask = chanMap;
LmgrBuildRemapTable(&pBisCtx->chSelInfo);
}
}
/* Select BIG Control channel. */
pBigCtx->ctrChSelInfo.chanMask = chanMap;
@ -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,9 +486,12 @@ void lctrMstSetupBigChannel(lctrBigCtx_t *pBigCtx, LctrAcadBigInfo_t *pBigInfo)
pBigCtx->ctrChan.enc.dir = 1;
pBigCtx->ctrChan.enc.type = PAL_BB_TYPE_BIS;
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,18 +134,27 @@ 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;
}
}
/* Ensure successful divide. */
if (pBigCtx->bn || 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
{
LL_TRACE_ERR0("Invalid BN or sduInterUsec value");
@ -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,18 +214,27 @@ 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;
}
}
/* Ensure successful divide. */
if (pBigCtx->bn || 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
{
LL_TRACE_ERR0("Invalid BN or sduInterUsec value");
@ -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,9 +295,12 @@ static void lctrSlvSetupBigChannel(lctrBigCtx_t *pBigCtx)
pBigCtx->ctrChan.enc.dir = 1;
pBigCtx->ctrChan.enc.type = PAL_BB_TYPE_BIS;
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;
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:
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:
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)
int8_t sendReqDelta = 0;
lctrCisCtx_t *pCisCtx = NULL;
for (unsigned int i = 0; i < pLctrRtCfg->maxCis; i++)
{
pCisCtx = &pLctrCisTbl[i];
if ((pCisCtx->aclHandle == LCTR_GET_CONN_HANDLE(pConnCtx)) &&
(pCisCtx->enabled) && (pCisCtx->connEst))
{
if (((pCisCtx->role == LL_ROLE_SLAVE) && (pCisCtx->phyMToS == pConnCtx->bleData.chan.rxPhy)) ||
((pCisCtx->role == LL_ROLE_MASTER) && (pCisCtx->phySToM == pConnCtx->bleData.chan.rxPhy)))
{
/* This power is already managed by ACL, so no need to run management on CIS. */
return;
}
int8_t sendReqDelta = 0;
if ((rssi < pConnCtx->pclMonitorParam.autoMonitor.lowThreshold) ||
(status != BB_STATUS_SUCCESS))
{
pConnCtx->cisRssiExtremeTimeSpent++;
if (pConnCtx->cisRssiExtremeTimeSpent >= pConnCtx->pclMonitorParam.autoMonitor.minTimeSpent)
{
if (!(pConnCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MAX_BIT))
{
LL_TRACE_INFO1("RSSI too low, requesting increase in power. phy=%u", phy);
sendReqDelta = pConnCtx->pclMonitorParam.autoMonitor.requestVal;
}
pConnCtx->cisRssiExtremeTimeSpent = 0;
goto CisManageRssiPower;
}
}
else if (rssi > pConnCtx->pclMonitorParam.autoMonitor.highThreshold)
{
pConnCtx->cisRssiExtremeTimeSpent++;
return;
if (pConnCtx->cisRssiExtremeTimeSpent >= pConnCtx->pclMonitorParam.autoMonitor.minTimeSpent)
CisManageRssiPower:
lctrRssiAddAveragePoint(&pConnCtx->cisRunAvg, -((int8_t) (pConnCtx->cisAccumulatedRssi / pConnCtx->cisTotalAccumulatedRssi)));
pConnCtx->cisAccumulatedRssi = 0;
pConnCtx->cisTotalAccumulatedRssi = 0;
if (pConnCtx->cisRunAvg.avgCount >= LL_PC_TBL_LEN)
{
if (!(pConnCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MIN_BIT))
int8_t averageRunning = lctrRssiGetAverage(&pConnCtx->cisRunAvg);
if ((averageRunning > pConnCtx->pclMonitorParam.autoMonitor.highThreshold) &&
!(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
else if ((averageRunning < pConnCtx->pclMonitorParam.autoMonitor.lowThreshold) &&
!(pConnCtx->peerPwrLimits & LL_PWR_CONTROL_LIMIT_MAX_BIT))
{
pConnCtx->cisRssiExtremeTimeSpent = 0;
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;
}
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 (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;
@ -108,6 +111,7 @@ static void lctrIsoProcessRxTestData(lctrCisCtx_t *pCisCtx, uint8_t *pDataBuf, u
(pktNum == pCisCtx->expectedPkt))
{
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,10 +320,9 @@ void lctrCisRxPendingHandler(void)
lctrSendCisMsg(pCisCtx, LCTR_CIS_MSG_CIS_TERM_MIC_FAILED);
continue;
}
}
/* Increase packet counter after decryption. */
lctrCisIncPacketCounterRx(pCisCtx);
}
lctrCisDataPduHdr_t cisDataHdr;
lctrCisUnpackDataPduHdr(&cisDataHdr, pRxBuf);
@ -328,7 +330,21 @@ void lctrCisRxPendingHandler(void)
/* 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,12 +488,11 @@ 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;
@ -486,10 +500,9 @@ void lctrCisRxPendingHandler(void)
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);
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);
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);
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);
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);
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);
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;
@ -453,6 +453,8 @@ void lctrCisRxPduFree(uint8_t *pBuf)
*/
/*************************************************************************************************/
void lctrCisRxEnq(uint8_t *pBuf, uint16_t eventCounter, uint16_t cisHandle)
{
if (pBuf != NULL)
{
/* Stamp packet with event counter. */
pBuf -= LCTR_CIS_DATA_PDU_START_OFFSET;
@ -460,6 +462,8 @@ void lctrCisRxEnq(uint8_t *pBuf, uint16_t eventCounter, uint16_t cisHandle)
/* 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,38 +544,147 @@ 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);
}
return WsfMsgDeq(&pOutCtx->cfg.hci.rxDataQ, &handle);
/*************************************************************************************************/
/*!
* \brief Setup an input data path context.
*
* \param pDpParam Data path parameters.
* \param pSetupDataPath Data path setup parameters.
*
* \return Status error code.
*/
/*************************************************************************************************/
uint8_t lctrIsoInDataPathSetup(lctrDpParams_t *pDpParam, LlIsoSetupDataPath_t *pSetupDataPath)
{
lctrInDataPathCtx_t *pInCtx = &pDpParam->pDataPathCtx->in;
switch (pInCtx->id)
{
case LL_ISO_DATA_PATH_VS:
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;
}
}
/*************************************************************************************************/
/*!
* \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 lctrIsoOutDataPathSetup(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_VS:
/* No action. */
case LL_ISO_DATA_PATH_DISABLED:
/* No action required. */
break;
default:
/* No action. */
break;
LL_TRACE_WARN1("Unknown Data Path, dpId=%u", pOutCtx->id);
return LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS;
}
return LL_SUCCESS;
}
/*************************************************************************************************/
@ -574,14 +694,17 @@ void lctrIsoOutDataPathSetup(lctrOutDataPathCtx_t *pOutCtx)
* \param pOutCtx Output data path context.
*/
/*************************************************************************************************/
void lctrIsoOutDataPathClear(lctrOutDataPathCtx_t *pOutCtx)
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,12 +813,10 @@ 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. */
lctrIsoHdr_t isoHdr;
@ -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);
/* 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)
{
uint8_t *pHeadPkt;
uint8_t handlerId;
lctrIsoHdr_t isoHdr = {0};
uint8_t *pSdu = WsfMsgPeek(&pRxCtx->data.unframed.pendSduQ, &handlerId);
pHeadPkt = WsfMsgPeek(&pRxCtx->data.unframed.pendSduQ, &handlerId);
WSF_ASSERT(pHeadPkt);
lctrIsoUnpackHdr(&isoHdr, pHeadPkt);
isoHdr.pktSn = pRxCtx->packetSequence++;
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))
if (pSduFrag)
{
isoHdr.pb = LCTR_PB_FIRST;
lctrIsoHdr_t fragHdr;
lctrIsoUnpackHdr(&fragHdr, pSduFrag);
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);
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
{
isoHdr.pb = LCTR_PB_COMP;
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;
}
}
lctrIsoPackHdr(pHeadPkt, &isoHdr);
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;
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,18 +1219,20 @@ 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;
}
pIsoalRxCtx->pduFlushed = FALSE;
return 0;
}
}
uint8_t *pDataBuf = pIsoBuf + LL_DATA_HDR_LEN;
uint8_t *pSduBuf;
@ -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;
}
@ -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.
@ -255,6 +255,26 @@ typedef struct
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,6 +50,11 @@ uint8_t lctrIsoUnpackHdr(lctrIsoHdr_t *pHdr, const uint8_t *pBuf)
BSTREAM_TO_UINT16(pHdr->len, pBuf);
switch (pHdr->pb)
{
case LCTR_PB_COMP:
case LCTR_PB_FIRST:
len += HCI_ISO_DL_MIN_LEN;
if (pHdr->tsFlag)
{
BSTREAM_TO_UINT32(pHdr->ts, pBuf);
@ -65,6 +70,14 @@ uint8_t lctrIsoUnpackHdr(lctrIsoHdr_t *pHdr, const uint8_t *pBuf)
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;
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. */
};
@ -640,6 +640,7 @@ void lctrMstLlcpExecuteSm(lctrConnCtx_t *pCtx, uint8_t 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)) &&

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. */
};
@ -672,6 +672,7 @@ void lctrSlvLlcpExecuteSm(lctrConnCtx_t *pCtx, uint8_t 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)) &&

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;

View File

@ -40,54 +40,54 @@ enum
LCTR_PC_PROC_TOTAL /*!< Total power control procedures. */
};
/*! \brief Common LLCP actions. */
/*! \brief Power control LLCP actions. */
enum
{
LCTR_PROC_CMN_ACT_API_PARAM, /*!< Store host API parameter action. */
LCTR_PROC_CMN_ACT_SEND_REQ, /*!< Send request action. */
LCTR_PROC_CMN_ACT_RECV_REQ, /*!< Receive request action. */
LCTR_PROC_CMN_ACT_SEND_RSP, /*!< Send response action. */
LCTR_PROC_CMN_ACT_RECV_RSP, /*!< Receive response action. */
LCTR_PROC_CMN_ACT_TOTAL /*!< Total common procedure actions. */
LCTR_PC_ACT_API_PARAM, /*!< Store host API parameter action. */
LCTR_PC_ACT_SEND_REQ, /*!< Send request action. */
LCTR_PC_ACT_RECV_REQ, /*!< Receive request action. */
LCTR_PC_ACT_SEND_RSP, /*!< Send response action. */
LCTR_PC_ACT_RECV_RSP, /*!< Receive response action. */
LCTR_PC_ACT_TOTAL /*!< Total power control procedure actions. */
};
/*! \brief Common LLCP events. */
/*! \brief Power control LLCP events. */
enum
{
LCTR_PROC_CMN_EVT_HOST_START, /*!< Host initiated start procedure event. */
LCTR_PROC_CMN_EVT_INT_START, /*!< LL initiated start procedure event. */
LCTR_PROC_CMN_EVT_INT_INCOMP, /*!< Complete an interrupted procedure event. */
LCTR_PROC_CMN_EVT_RECV_IND, /*!< Receive indication event. */
LCTR_PROC_CMN_EVT_RECV_REQ, /*!< Receive request event. */
LCTR_PROC_CMN_EVT_RECV_RSP, /*!< Receive response event. */
LCTR_PROC_CMN_EVT_PROC_COMP, /*!< Procedure completed event. */
LCTR_PROC_CMN_EVT_REJECT, /*!< Procedure rejected event. */
LCTR_PROC_CMN_EVT_TOTAL, /*!< Total common procedure events. */
LCTR_PROC_CMN_EVT_INVALID = 0xFF /*!< Invalid event. */
LCTR_PC_EVT_HOST_START, /*!< Host initiated start procedure event. */
LCTR_PC_EVT_INT_START, /*!< LL initiated start procedure event. */
LCTR_PC_EVT_INT_INCOMP, /*!< Complete an interrupted procedure event. */
LCTR_PC_EVT_RECV_IND, /*!< Receive indication event. */
LCTR_PC_EVT_RECV_REQ, /*!< Receive request event. */
LCTR_PC_EVT_RECV_RSP, /*!< Receive response event. */
LCTR_PC_EVT_PROC_COMP, /*!< Procedure completed event. */
LCTR_PC_EVT_REJECT, /*!< Procedure rejected event. */
LCTR_PC_EVT_TOTAL, /*!< Total power control procedure events. */
LCTR_PC_EVT_INVALID = 0xFF /*!< Invalid event. */
};
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/*! \brief Common procedure state machine action table. */
const lctrLlcpEh_t lctrPclProcTbl[LCTR_PC_PROC_TOTAL][LCTR_PROC_CMN_ACT_TOTAL] =
/*! \brief Power control procedure state machine action table. */
const lctrLlcpEh_t lctrPclProcTbl[LCTR_PC_PROC_TOTAL][LCTR_PC_ACT_TOTAL] =
{
/* LCTR_PROC_PWR_IND */
{
NULL, /* LCTR_PROC_CMN_ACT_API_PARAM */
NULL, /* LCTR_PROC_CMN_ACT_SEND_REQ */
lctrStorePeerPowerInd, /* LCTR_PROC_CMN_ACT_RECV_REQ */
lctrSendPeerPowerRsp, /* LCTR_PROC_CMN_ACT_SEND_RSP */
NULL /* LCTR_PROC_CMN_ACT_RECV_RSP */
NULL, /* LCTR_PC_ACT_API_PARAM */
NULL, /* LCTR_PC_ACT_SEND_REQ */
lctrStorePeerPowerInd, /* LCTR_PC_ACT_RECV_REQ */
lctrSendPeerPowerRsp, /* LCTR_PC_ACT_SEND_RSP */
NULL, /* LCTR_PC_ACT_RECV_RSP */
},
/* LCTR_PROC_PWR_CTRL */
{
lctrStorePowerControlAction, /* LCTR_PROC_CMN_ACT_API_PARAM */
lctrSendPeerPowerControlReq, /* LCTR_PROC_CMN_ACT_SEND_REQ */
lctrStorePeerPowerControlReq, /* LCTR_PROC_CMN_ACT_RECV_REQ */
lctrSendPeerPowerControlRsp, /* LCTR_PROC_CMN_ACT_SEND_RSP */
lctrStorePeerPowerControlRsp /* LCTR_PROC_CMN_ACT_RECV_RSP */
lctrStorePowerControlAction, /* LCTR_PC_ACT_API_PARAM */
lctrSendPeerPowerControlReq, /* LCTR_PC_ACT_SEND_REQ */
lctrStorePeerPowerControlReq, /* LCTR_PC_ACT_RECV_REQ */
lctrSendPeerPowerControlRsp, /* LCTR_PC_ACT_SEND_RSP */
lctrStorePeerPowerControlRsp, /* LCTR_PC_ACT_RECV_RSP */
}
};
@ -156,7 +156,7 @@ static uint8_t lctrGetPclProcId(lctrConnCtx_t *pCtx, uint8_t event)
case LCTR_CONN_MSG_RX_LLCP:
switch (lctrDataPdu.opcode)
{
case LL_PDU_PWR_CHNG_IND:
case LL_PDU_PWR_CHANGE_IND:
return LCTR_PROC_PWR_IND;
case LL_PDU_PWR_CTRL_REQ:
@ -167,6 +167,16 @@ static uint8_t lctrGetPclProcId(lctrConnCtx_t *pCtx, uint8_t event)
case LL_PDU_REJECT_EXT_IND:
return pCtx->llcpActiveProc;
case LL_PDU_UNKNOWN_RSP:
switch (lctrDataPdu.pld.unknownRsp.unknownType)
{
case LL_PDU_PWR_CTRL_REQ:
case LL_PDU_PWR_CTRL_RSP:
case LL_PDU_PWR_CHANGE_IND:
return LCTR_PC_EVT_REJECT;
}
break;
default:
break;
}
@ -195,63 +205,63 @@ static uint8_t lctrGetPclProcId(lctrConnCtx_t *pCtx, uint8_t event)
/*************************************************************************************************/
/*!
* \brief Get remapped common LLCP procedure event.
* \brief Get remapped power control LLCP procedure event.
*
* \param pCtx Connection context.
* \param event Subsystem event.
*
* \return Common LLCP procedure action ID.
* \return Power control LLCP procedure action ID.
*
* This routine remaps events for the common LLCP procedure state machine for optimized
* This routine remaps events for the power control LLCP procedure state machine for optimized
* compressed state tables.
*/
/*************************************************************************************************/
static uint8_t lctrRemapCmnProcEvent(lctrConnCtx_t *pCtx, uint8_t event)
static uint8_t lctrRemapPcEvent(lctrConnCtx_t *pCtx, uint8_t event)
{
switch (event)
{
case LCTR_CONN_MSG_API_PWR_CTRL_REQ:
return LCTR_PROC_CMN_EVT_HOST_START;
return LCTR_PC_EVT_HOST_START;
case LCTR_CONN_MSG_RX_LLCP_UNKNOWN:
return LCTR_PROC_CMN_EVT_RECV_REQ;
return LCTR_PC_EVT_RECV_REQ;
case LCTR_CONN_MSG_RX_LLCP:
switch (lctrDataPdu.opcode)
{
case LL_PDU_PWR_CTRL_REQ:
return LCTR_PROC_CMN_EVT_RECV_REQ;
return LCTR_PC_EVT_RECV_REQ;
case LL_PDU_PWR_CHNG_IND:
return LCTR_PROC_CMN_EVT_RECV_IND;
case LL_PDU_PWR_CHANGE_IND:
return LCTR_PC_EVT_RECV_IND;
case LL_PDU_PWR_CTRL_RSP:
return LCTR_PROC_CMN_EVT_RECV_RSP;
return LCTR_PC_EVT_RECV_RSP;
case LL_PDU_UNKNOWN_RSP:
case LL_PDU_REJECT_IND:
case LL_PDU_REJECT_EXT_IND:
return LCTR_PROC_CMN_EVT_REJECT;
return LCTR_PC_EVT_REJECT;
default:
return LCTR_PROC_CMN_EVT_INVALID;
return LCTR_PC_EVT_INVALID;
}
case LCTR_CONN_LLCP_START_PENDING:
if (pCtx->llcpIncompMask)
{
return LCTR_PROC_CMN_EVT_INT_INCOMP;
return LCTR_PC_EVT_INT_INCOMP;
}
else
{
return LCTR_PROC_CMN_EVT_INT_START;
return LCTR_PC_EVT_INT_START;
}
default:
break;
}
return LCTR_PROC_CMN_EVT_INVALID;
return LCTR_PC_EVT_INVALID;
}
/*************************************************************************************************/
@ -314,7 +324,7 @@ static void lctrNotifyHostSuccess(lctrConnCtx_t *pCtx, uint8_t proc)
case LCTR_PROC_PWR_CTRL:
if (pCtx->readRemoteTxPower)
{
lctrNotifyPowerReportInd(pCtx, LL_POWER_REPORT_REASON_READ_REMOTE,
lctrNotifyPowerReportInd(pCtx, LL_SUCCESS, LL_POWER_REPORT_REASON_READ_REMOTE,
pCtx->reqPhy, pCtx->peerTxPower, pCtx->peerPwrLimits,
pCtx->delta);
pCtx->readRemoteTxPower = FALSE;
@ -341,11 +351,47 @@ static void lctrNotifyHostReject(lctrConnCtx_t *pCtx, uint8_t proc)
}
pCtx->llcpNotifyMask &= ~(1 << proc);
uint8_t reason = LL_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE;
switch (lctrDataPdu.opcode)
{
case LL_PDU_REJECT_IND:
case LL_PDU_REJECT_EXT_IND:
reason = lctrDataPdu.pld.rejInd.reason;
break;
case LL_PDU_UNKNOWN_RSP:
/* Do not transmit another PCL request if the peer does not recognize it. */
if (proc == LCTR_PROC_PWR_CTRL)
{
pCtx->usedFeatSet &= ~LL_FEAT_POWER_CONTROL_REQUEST;
}
if (proc == LCTR_PROC_PWR_IND)
{
pCtx->usedFeatSet &= ~LL_FEAT_POWER_CHANGE_IND;
}
break;
default:
break;
}
switch (proc)
{
case LCTR_PROC_PWR_CTRL:
if (pCtx->readRemoteTxPower)
{
lctrNotifyPowerReportInd(pCtx, reason, LL_POWER_REPORT_REASON_READ_REMOTE, 0, 0, 0, 0);
}
break;
case LCTR_PROC_PWR_IND:
break;
default:
break;
}
}
/*************************************************************************************************/
/*!
* \brief Execute common LLCP state machine.
* \brief Execute power control LLCP state machine.
*
* \param pCtx Connection context.
* \param event State machine event.
@ -358,7 +404,37 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
uint8_t proc;
uint8_t llEvent = event;
if ((event = lctrRemapCmnProcEvent(pCtx, event)) == LCTR_PROC_CMN_EVT_INVALID)
/*** State-less events ***/
if (event == LCTR_CONN_LLCP_PWR_CTRL_SERVICE)
{
proc = LCTR_PROC_PWR_CTRL;
if (lctrFeatureAvail(pCtx, proc, event) &&
(pCtx->monitoringState == LCTR_PC_MONITOR_ENABLED) &&
(pCtx->powerMonitorScheme == LCTR_PC_MONITOR_AUTO))
{
/* Restart timer. */
WsfTimerStartMs(&pCtx->tmrPowerCtrl, LL_PC_SERVICE_MS);
lctrConnServicePowerMonitor(pCtx);
/* If CIS is enabled, monitor those power levels if needed. */
if (lctrCisServicePowerMonitorFn)
{
lctrCisServicePowerMonitorFn(pCtx);
}
}
else
{
WsfTimerStop(&pCtx->tmrPowerCtrl);
}
return TRUE;
}
/*** LLCP state machine ***/
if ((event = lctrRemapPcEvent(pCtx, event)) == LCTR_PC_EVT_INVALID)
{
return FALSE;
}
@ -375,14 +451,14 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
switch (event)
{
case LCTR_PROC_CMN_EVT_HOST_START:
case LCTR_PC_EVT_HOST_START:
pCtx->llcpNotifyMask |= 1 << proc;
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_API_PARAM);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_API_PARAM);
/* Fallthrough */
case LCTR_PROC_CMN_EVT_INT_START:
case LCTR_PC_EVT_INT_START:
if (lctrFeatureAvail(pCtx, proc, event))
{
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_SEND_REQ);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_SEND_REQ);
lctrStartLlcpTimer(pCtx);
pCtx->llcpActiveProc = proc;
pCtx->cmnState = LCTR_CMN_STATE_BUSY;
@ -394,20 +470,20 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
}
break;
case LCTR_PROC_CMN_EVT_INT_INCOMP:
case LCTR_PROC_CMN_EVT_RECV_IND:
case LCTR_PROC_CMN_EVT_RECV_REQ:
case LCTR_PC_EVT_INT_INCOMP:
case LCTR_PC_EVT_RECV_IND:
case LCTR_PC_EVT_RECV_REQ:
if (lctrFeatureAvail(pCtx, proc, event))
{
if (event != LCTR_PROC_CMN_EVT_INT_INCOMP)
if (event != LCTR_PC_EVT_INT_INCOMP)
{
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_RECV_REQ);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_RECV_REQ);
}
if (lctrPclProcTbl[lctrGetPclProcSmIndex(proc)][LCTR_PROC_CMN_ACT_SEND_RSP])
if (lctrPclProcTbl[lctrGetPclProcSmIndex(proc)][LCTR_PC_ACT_SEND_RSP])
{
/* Procedure completes; no transition to BUSY. */
lctrPclProcTbl[lctrGetPclProcSmIndex(proc)][LCTR_PROC_CMN_ACT_SEND_RSP](pCtx);
lctrPclProcTbl[lctrGetPclProcSmIndex(proc)][LCTR_PC_ACT_SEND_RSP](pCtx);
}
else
{
@ -424,9 +500,9 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
}
break;
case LCTR_PROC_CMN_EVT_RECV_RSP:
case LCTR_PROC_CMN_EVT_PROC_COMP:
case LCTR_PROC_CMN_EVT_REJECT:
case LCTR_PC_EVT_RECV_RSP:
case LCTR_PC_EVT_PROC_COMP:
case LCTR_PC_EVT_REJECT:
default:
/* No action required. */
break;
@ -438,11 +514,11 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
switch (event)
{
case LCTR_PROC_CMN_EVT_HOST_START:
case LCTR_PROC_CMN_EVT_INT_START:
case LCTR_PC_EVT_HOST_START:
case LCTR_PC_EVT_INT_START:
if (lctrFeatureAvail(pCtx, proc, event))
{
if (event == LCTR_PROC_CMN_EVT_HOST_START)
if (event == LCTR_PC_EVT_HOST_START)
{
pCtx->llcpNotifyMask |= 1 << proc;
}
@ -452,9 +528,9 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
LL_TRACE_INFO1("Pending procedure in progress: activeProc=%u", pCtx->llcpActiveProc);
pCtx->llcpPendMask |= 1 << proc;
}
if (event == LCTR_PROC_CMN_EVT_HOST_START)
if (event == LCTR_PC_EVT_HOST_START)
{
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_API_PARAM);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_API_PARAM);
}
}
else
@ -463,23 +539,23 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
}
break;
case LCTR_PROC_CMN_EVT_RECV_IND: /* Completion from message */
case LCTR_PC_EVT_RECV_IND: /* Completion from message */
if (proc != pCtx->llcpActiveProc)
{
if (lctrFeatureAvail(pCtx, proc, event))
{
LL_TRACE_WARN1("Procedure collision; pending incomplete request, activeProc=%u", pCtx->llcpActiveProc);
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_RECV_REQ);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_RECV_REQ);
pCtx->llcpIncompMask |= 1 << proc;
}
break;
}
/* Fallthrough */
case LCTR_PROC_CMN_EVT_RECV_RSP:
case LCTR_PC_EVT_RECV_RSP:
if (proc == pCtx->llcpActiveProc)
{
/* Incoming procedure matches the active one. */
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_RECV_RSP);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_RECV_RSP);
}
else if (pCtx->llcpPendMask & (1 << proc))
{
@ -489,7 +565,7 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
{
pCtx->llcpIsOverridden = FALSE;
}
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_RECV_RSP);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_RECV_RSP);
lctrNotifyHostSuccess(pCtx, proc);
break;
}
@ -499,9 +575,9 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
break;
}
/* Fallthrough */
case LCTR_PROC_CMN_EVT_PROC_COMP: /* Completion from CE */
case LCTR_PROC_CMN_EVT_REJECT: /* Failed completion */
if (event == LCTR_PROC_CMN_EVT_REJECT)
case LCTR_PC_EVT_PROC_COMP: /* Completion from CE */
case LCTR_PC_EVT_REJECT: /* Failed completion */
if (event == LCTR_PC_EVT_REJECT)
{
lctrNotifyHostReject(pCtx, proc);
}
@ -519,12 +595,12 @@ bool_t lctrLlcpExecutePclSm(lctrConnCtx_t *pCtx, uint8_t event)
lctrStartPendingLlcp(pCtx);
break;
case LCTR_PROC_CMN_EVT_RECV_REQ:
case LCTR_PC_EVT_RECV_REQ:
LL_TRACE_WARN1("Procedure collision; pending incomplete request, activeProc=%u", pCtx->llcpActiveProc);
lctrExecAction(pCtx, proc, LCTR_PROC_CMN_ACT_RECV_REQ);
lctrExecAction(pCtx, proc, LCTR_PC_ACT_RECV_REQ);
if (lctrFeatureAvail(pCtx, proc, event))
{
lctrPclProcTbl[lctrGetPclProcSmIndex(proc)][LCTR_PROC_CMN_ACT_SEND_RSP](pCtx);
lctrPclProcTbl[lctrGetPclProcSmIndex(proc)][LCTR_PC_ACT_SEND_RSP](pCtx);
}
else
{

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