THB2/bthome_phy6222/SDK/lib/rf/patch_ext_adv.c
froloffw7 7c15dcf891
Update patch_ext_adv.c
- исправил ошибки компиляции
- добавил функции
2024-02-01 18:53:48 +01:00

2007 lines
77 KiB
C

/*******************************************************************************
Filename: patch_ext_adv.c, updated base on ll.c
Revised:
Revision:
Description: This file contains the Link Layer (LL) API for the Bluetooth
Low Energy (BLE) Controller. It provides the defines, types,
and functions for all supported Bluetooth Low Energy (BLE)
commands.
This API is based on the Bluetooth Core Specification,
V4.0.0, Vol. 6.
SDK_LICENSE
*******************************************************************************/
//#define DEBUG_LL
/*******************************************************************************
INCLUDES
*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "ll_buf.h"
#include "ll.h"
#include "ll_def.h"
#include "ll_common.h"
#include "ll_hw_drv.h"
#include "OSAL.h"
#include "OSAL_PwrMgr.h"
#include "osal_bufmgr.h"
#include "bus_dev.h"
#include "jump_function.h"
#include "global_config.h"
#include "ll_debug.h"
#include "ll_enc.h"
#include "rf_phy_driver.h"
#include "time.h"
// DEFINES
// #define OWN_PUBLIC_ADDR_POS 0x11004000
#define LL_HW_MODE_STX 0x00
#define LL_HW_MODE_SRX 0x01
#define LL_HW_MODE_TRX 0x02
#define LL_HW_MODE_RTX 0x03
#define LL_HW_MODE_TRLP 0x04
#define LL_HW_MODE_RTLP 0x05
extern uint32 g_timer4_irq_pending_time;
extern uint8 llSecondaryState;
extern uint8 isTimer1Running(void);
extern uint8 isTimer4Running(void);
extern int clear_timer_int(AP_TIM_TypeDef* TIMx);
extern void clear_timer(AP_TIM_TypeDef* TIMx);
//------------------------------------------------------------------------------------
//extern rom function
//
extern uint8 ll_processExtAdvIRQ(uint32_t irq_status);
extern uint8 ll_processPrdAdvIRQ(uint32_t irq_status);
extern uint8 ll_processExtScanIRQ(uint32_t irq_status);
extern uint8 ll_processExtInitIRQ(uint32_t irq_status);
extern uint8 ll_processPrdScanIRQ(uint32_t irq_status);
extern uint8 ll_processBasicIRQ(uint32_t irq_status);
// global configuration in SRAM, it could be change by application
// ================== VARIABLES ==================================
extern uint32 global_config[];
// patch.c
extern uint32 ISR_entry_time;
extern uint32 read_ll_adv_remainder_time(void);
extern uint8_t ll_hw_read_rfifo1(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1);
// ll.c
extern uint32 g_interAuxPduDuration;
// FUNCTIONS
extern uint32 llWaitingIrq;
extern uint8 ll_hw_get_tr_mode(void);
extern int ll_hw_get_rfifo_depth(void);
// ll_hwItf.c
/*******************************************************************************
CONSTANTS
*/
// Master Sleep Clock Accurracy, in PPM
// Note: Worst case range value is assumed.
extern const uint16 SCA[] ; //= {500, 250, 150, 100, 75, 50, 30, 20};
extern uint8 ownPublicAddr[]; // index 0..5 is LSO..MSB
extern uint8 ownRandomAddr[];
//
extern volatile uint8_t g_same_rf_channel_flag;
// ====== RPA
extern uint8 g_currentLocalRpa[LL_DEVICE_ADDR_LEN];
extern uint8 g_currentPeerRpa[LL_DEVICE_ADDR_LEN];
extern uint8 g_currentPeerAddrType;
extern uint8 g_currentLocalAddrType;
void ll_hw_tx2rx_timing_config(uint8 pkt);
void ll_hw_trx_settle_config(uint8 pkt);
// ======= A2 multi-connection ========================
extern struct buf_tx_desc g_tx_adv_buf;
extern struct buf_tx_desc g_tx_ext_adv_buf;
extern struct buf_tx_desc tx_scanRsp_desc;
extern struct buf_rx_desc g_rx_adv_buf;
extern syncInfo_t syncInfo;
// RF path compensation, to be move to rf_phy_driver.c ?
extern int16 g_rfTxPathCompensation;
extern int16 g_rfRxPathCompensation;
// EXTERNAL FUNCTIONS
void llWaitUs(uint32_t wtTime);
void llPrdAdvDecideNextChn(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv);
void llSetupSyncInfo(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv);
// New
uint16_t extscanrsp_offset;
void ll_adv_scheduler0(void)
{
uint32 T2, T3, delta;
uint32 minAuxPduTime, minPriPduTime;
uint8 minIndexAux, minIndexPri;
uint8 done = FALSE;
int i;
llAdvScheduleInfo_t* p_scheduler;
extAdvInfo_t* pAdvInfo;
if (g_currentExtAdv == LL_INVALID_ADV_SET_HANDLE) {
return;
}
// calculate elapse time since last timer trigger
T2 = read_current_fine_time();
delta = LL_TIME_DELTA(g_timerExpiryTick, T2);
p_scheduler = &g_pAdvSchInfo[g_currentExtAdv];
pAdvInfo = p_scheduler->pAdvInfo;
// if current adv is not active, delete it from task list
if (pAdvInfo->active == FALSE) {
ll_delete_adv_task(g_currentExtAdv);
return;
}
// the advertisement scheduler will schedule next task according to current adv's next advertise channel
// case 1: not finish primary ADV channel or AUX_XXX_IND chain, continue advertise current adv task
if (pAdvInfo->currentChn > LL_ADV_CHAN_FIRST && // next channel in primary adv channel
pAdvInfo->active == TRUE && // add 04-01, legacy adv may stop when receive conn_req
!ll_isFirstAdvChn(pAdvInfo->parameter.priAdvChnMap, pAdvInfo->currentChn)) // not the 1st primary ADV channel
{
ll_ext_adv_schedule_next_event(pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] - delta);
done = TRUE;
}
else if (pAdvInfo->currentChn < LL_ADV_CHAN_FIRST // broadcast in aux adv chn
&& pAdvInfo->currentAdvOffset > 0) // offset in adv data set greater than 0 means next PDU is AUX_CHAIN_IND PDU
{
// g_interAuxPduDuration is the time between the edge of AUX_ADV_IND & AUX_CHAIN_IND,
// delta consider the time between timer expiry time and new timer trigger point,
// the time from TO to ll_hw_trigger is not consider, this time denote as alpha below.
// If alpha for AUX_ADV_IND and AUX_CHAIN_IND is the same, then no compensation is required
// but if the alpha for AUX_ADV_IND and AUX_CHAIN_IND is different, using pGlobal_config[LL_EXT_ADV_INTER_SEC_COMP]
// to compensate it
if (extscanrsp_offset != 100) {
delta = (g_interAuxPduDuration - delta);
} else {
delta = (g_interAuxPduDuration - delta) - 125;
}
ll_ext_adv_schedule_next_event(delta);
done = TRUE;
}
// update scheduler task list
ll_updateExtAdvRemainderTime(delta);
if (done) // next task schedule done
return;
// case 2: finish broadcast in primary adv channel/aux adv channel. Check ext adv scheduler to get the earliest task
// search the nearest expiry task and PDU type
minAuxPduTime = g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder;
minPriPduTime = g_pAdvSchInfo[g_currentExtAdv].nextEventRemainder;
minIndexAux = g_currentExtAdv;
minIndexPri = g_currentExtAdv;
for (i = 0; i < g_extAdvNumber; i++) {
if (g_pAdvSchInfo[i].adv_handler != LL_INVALID_ADV_SET_HANDLE)
{
if (g_pAdvSchInfo[i].auxPduRemainder < minAuxPduTime) {
minIndexAux = i;
minAuxPduTime = g_pAdvSchInfo[i].auxPduRemainder;
}
if (g_pAdvSchInfo[i].nextEventRemainder < minPriPduTime) {
minIndexPri = i;
minPriPduTime = g_pAdvSchInfo[i].nextEventRemainder;
}
}
}
T3 = read_current_fine_time();
delta = LL_TIME_DELTA(T2, T3);
// compare the minimum AUX channel remainder time & minimum Primary channel PDU remainder time,
// AUX channel PDU could add some pre-emphesis here
uint32 auxPduEmphesis = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] * 3; // add 03-31
if ( (minAuxPduTime != LL_INVALID_TIME) &&
(minAuxPduTime < (minPriPduTime + auxPduEmphesis)) ) // next schedule task is aux PDU
{
ll_ext_adv_schedule_next_event(minAuxPduTime - delta);
g_currentExtAdv = minIndexAux;
}
else // next schedule task is pri PDU
{
ll_ext_adv_schedule_next_event(minPriPduTime - delta);
g_currentExtAdv = minIndexPri;
}
// update scheduler task list
ll_updateExtAdvRemainderTime(delta);
}
void ll_add_adv_task0(extAdvInfo_t * pExtAdv)
{
int i, spare;
llAdvScheduleInfo_t* p_scheduler = NULL, *p_current_scheduler;
uint32 remainder;
uint8 chanNumber, temp;
uint8 isLegacy = ll_isLegacyAdv(pExtAdv);
temp = pExtAdv->parameter.priAdvChnMap;
chanNumber = (temp & 0x01) + ((temp & 0x02) >> 1) + ((temp & 0x04) >> 2);
// init new Ext adv event context
pExtAdv->currentChn = ((temp & ((~temp) + 1)) >> 1) + 37; // calculate 1st adv channel
pExtAdv->adv_event_counter = 0;
pExtAdv->currentAdvOffset = 0;
pExtAdv->adv_event_duration = 0;
// ======== case 1: the 1st adv task
if (g_currentExtAdv == LL_INVALID_ADV_SET_HANDLE) // if (!isTimer4Running())
{
g_schExtAdvNum = 1;
g_currentExtAdv = 0; // scheduler index = 0
p_current_scheduler = &g_pAdvSchInfo[g_currentExtAdv];
if (isLegacy) // Legacy Adv PDU has no aux PDU
{
g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder = LL_INVALID_TIME;
}
else
{
if ( pExtAdv->data.advertisingDataLength ||
(pExtAdv->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK) ||
(pExtAdv->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK) )
ll_allocAuxAdvTimeSlot(g_currentExtAdv); // g_currentExtAdv == 0
else
g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder = LL_INVALID_TIME;
}
// LOG("[%d] ", g_pAdvSchInfo[i].auxPduRemainder);
if (llWaitingIrq)
{
g_currentAdvTimer = pGlobal_config[LL_CONN_TASK_DURATION];
}
else
{
if ( isTimer1Running() &&
((remainder = read_LL_remainder_time()) < pGlobal_config[LL_EXT_ADV_TASK_DURATION]) ) // timer1 for connection or legacy adv
{
g_currentAdvTimer = pGlobal_config[LL_CONN_TASK_DURATION] + remainder;
}
else
{
if (chanNumber > 1)
g_currentAdvTimer = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT];
else
g_currentAdvTimer = (p_current_scheduler->auxPduRemainder < p_current_scheduler->pAdvInfo->primary_advertising_interval) ?
p_current_scheduler->auxPduRemainder : p_current_scheduler->pAdvInfo->primary_advertising_interval;
g_timerExpiryTick = read_current_fine_time();
// invoke set up ext adv function
llSetupExtAdvEvent(pExtAdv);
}
}
//ll_ext_adv_schedule_next_event(g_currentAdvTimer);
//g_timerExpiryTick = read_current_fine_time(); // fake timer expiry tick
p_current_scheduler->pAdvInfo = pExtAdv;
p_current_scheduler->adv_handler = pExtAdv->advHandle;
p_current_scheduler->nextEventRemainder = p_current_scheduler->pAdvInfo->primary_advertising_interval; // add some random delay between 0-10ms?
pExtAdv->active = TRUE;
return;
}
// ===== case 2: there are ongoing adv
p_current_scheduler = &g_pAdvSchInfo[g_currentExtAdv];
// get the 1st spare scheduler slot
for (i = 0; i < g_extAdvNumber; i++) // bug fixed 04-07
{
if (g_pAdvSchInfo[i].adv_handler == LL_INVALID_ADV_SET_HANDLE)
{
p_scheduler = &g_pAdvSchInfo[i];
spare = i;
break;
}
}
// no empty scheduler slot, return
if (p_scheduler == NULL)
return;
g_schExtAdvNum ++;
pExtAdv->active = TRUE;
// arrange the timing of AUX_XXX_IND, it is independent to EXT_ADV_IND
// add 03-31
if (!isLegacy && pExtAdv->data.advertisingDataLength)
ll_allocAuxAdvTimeSlot(spare);
else
g_pAdvSchInfo[spare].auxPduRemainder = LL_INVALID_TIME;
if (isTimer4Running())
{
read_ll_adv_remainder_time();
read_current_fine_time();
}
if (isTimer1Running())
{
read_LL_remainder_time();
}
// case 2.2: no enough time, start new adv after current one
// add new adv to adv scheduler list, not change current adv task
p_scheduler->nextEventRemainder = p_current_scheduler[g_currentExtAdv].nextEventRemainder
+ (g_advSlotPeriodic >> 2)
* (spare > g_currentExtAdv ?
spare - g_currentExtAdv :
g_extAdvNumber + spare - g_currentExtAdv);
p_scheduler->adv_handler = pExtAdv->advHandle;
p_scheduler->pAdvInfo = pExtAdv;
return;
}
void ll_delete_adv_task0(uint8 index)
{
uint32 T1, T2, delta, remainder, elapse_time;
uint32 minAuxPduTime, minPriPduTime;
uint8 minIndexAux, minIndexPri;
int i;
// LOG("=== adv task % deleted \r\n", index);
g_pAdvSchInfo[index].adv_handler = LL_INVALID_ADV_SET_HANDLE;
g_pAdvSchInfo[index].pAdvInfo = NULL;
g_pAdvSchInfo[index].auxPduRemainder = LL_INVALID_TIME;
g_pAdvSchInfo[index].nextEventRemainder = LL_INVALID_TIME;
g_schExtAdvNum --;
// only 1 task case, clear scheduler info and stop timer
if (g_schExtAdvNum == 0) {
g_currentExtAdv = LL_INVALID_ADV_SET_HANDLE;
g_schExtAdvNum = 0;
clear_timer(AP_TIM4);
return;
}
// current awaiting adv is disable, and there are more than 1 task
if ( (index == g_currentExtAdv) &&
isTimer4Running())
{
remainder = read_ll_adv_remainder_time();
T1 = read_current_fine_time();
elapse_time = g_currentAdvTimer - remainder;
minAuxPduTime = g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder; // LL_INVALID_TIME
minPriPduTime = g_pAdvSchInfo[g_currentExtAdv].nextEventRemainder;
minIndexAux = g_currentExtAdv;
minIndexPri = g_currentExtAdv;
for (i = 0; i < g_extAdvNumber; i++)
{
if (g_pAdvSchInfo[i].adv_handler != LL_INVALID_ADV_SET_HANDLE)
{
if (g_pAdvSchInfo[i].auxPduRemainder < minAuxPduTime)
{
minIndexAux = i;
minAuxPduTime = g_pAdvSchInfo[i].auxPduRemainder;
}
if (g_pAdvSchInfo[i].nextEventRemainder < minPriPduTime)
{
minIndexPri = i;
minPriPduTime = g_pAdvSchInfo[i].nextEventRemainder;
}
}
}
// start new timer
T2 = read_current_fine_time();
delta = LL_TIME_DELTA(T1, T2);
if (minAuxPduTime < minPriPduTime) // next schedule task is aux PDU
{
ll_ext_adv_schedule_next_event(minAuxPduTime - elapse_time - delta);
g_currentExtAdv = minIndexAux;
}
else // next schedule task is pri PDU
{
ll_ext_adv_schedule_next_event(minPriPduTime - elapse_time - delta);
g_currentExtAdv = minIndexPri;
}
// update the scheduler list
ll_updateExtAdvRemainderTime(elapse_time + delta);
}
}
uint8 llSetupExtAdvEvent0(extAdvInfo_t * pAdvInfo)
{
uint8 ch_idx, pktFmt, auxPduIndFlag = FALSE;
int i;
uint32 T2, T1, delta, temp;
ch_idx = pAdvInfo->currentChn;
T1 = read_current_fine_time();
//LOG("%d ", pAdvInfo->currentChn);
if (ch_idx >= LL_ADV_CHAN_FIRST && ch_idx <= LL_ADV_CHAN_LAST ) // advertise at primary channel case
{
llSetupAdvExtIndPDU(pAdvInfo, NULL);
// decide next adv channel
i = ch_idx - LL_ADV_CHAN_FIRST + 1;
while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++; // search channel map for next adv channel number
if (i == 3) // finish primary adv channel broadcast
{
if ((g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder != LL_INVALID_TIME) &&
(g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder > g_pAdvSchInfo[g_currentExtAdv].nextEventRemainder))
pAdvInfo->currentChn = ll_getFirstAdvChn(pAdvInfo->parameter.priAdvChnMap);
else
pAdvInfo->currentChn = pAdvInfo->auxChn;
}
else
pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i;
// config primary PHY
pktFmt = pAdvInfo->parameter.primaryAdvPHY;
}
else // advertise at primary channel case
{
// Note: if the Ext adv has no aux pdu, llSetupExtAdv should not be invoked
if (((extscanrsp_offset == 0) ||
(pAdvInfo->scanRspMaxLength <= extscanrsp_offset)) &&
(pAdvInfo->currentAdvOffset == 0)) // 1st AUX PDU. AUX_ADV_IND should include advData
{
llSetupAuxAdvIndPDU(pAdvInfo, NULL);
auxPduIndFlag = TRUE;
}
else
llSetupAuxChainIndPDU(pAdvInfo, NULL);
// config secondary PHY
pktFmt = pAdvInfo->parameter.secondaryAdvPHY;
}
if (pAdvInfo->parameter.secondaryAdvPHY == 3) // coded PHY
pktFmt = PKT_FMT_BLR125K; //
HAL_ENTER_CRITICAL_SECTION();
// if there is ongoing LL HW task, skip this task
if (llWaitingIrq)
{
// g_pmCounters.ll_tbd_cnt1++;
HAL_EXIT_CRITICAL_SECTION();
return FALSE;
}
//============== configure and trigger LL HW engine, LL HW work in Single Tx mode ==================
g_rfPhyPktFmt = pktFmt;
rf_phy_change_cfg0(pktFmt);
ll_hw_tx2rx_timing_config(pktFmt);
set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels
set_access_address(ADV_SYNCH_WORD); // access address
set_channel(ch_idx); // channel
set_whiten_seed(ch_idx); // whiten seed
set_max_length(50); // rx PDU max length
// reset Rx/Tx FIFO
ll_hw_rst_rfifo();
ll_hw_rst_tfifo();
// for AUX_ADV_IND, connectable/scannable case, should configure TRX
if ((auxPduIndFlag == TRUE) && // AUX_ADV_IND
((pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK) ||
(pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK)))
{
ll_hw_trx_settle_config(g_rfPhyPktFmt);
ll_hw_set_trx();
if ((g_rfPhyPktFmt == PKT_FMT_BLE1M) || (g_rfPhyPktFmt == PKT_FMT_BLE2M))
ll_hw_set_rx_timeout(500);
else
ll_hw_set_rx_timeout(3000);
}
else
{
ll_hw_set_stx();
}
ll_hw_ign_rfifo(LL_HW_IGN_EMP | LL_HW_IGN_CRC); //set the rfifo ign control
//write Tx FIFO
ll_hw_write_tfifo((uint8*)&(g_tx_ext_adv_buf.txheader), ((g_tx_ext_adv_buf.txheader & 0xff00) >> 8) + 2);
T2 = read_current_fine_time();
delta = LL_TIME_DELTA(T1, T2);
temp = ( pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] > delta) ? (pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] - delta) : 0;
llWaitUs(temp); // insert delay to make process time equal PROCESS_TARGET
ll_hw_go();
llWaitingIrq = TRUE;
llTaskState = LL_TASK_EXTENDED_ADV;
HAL_EXIT_CRITICAL_SECTION();
return TRUE;
}
//#define LL_PERIOD_ADV_EXT_PART_DURATION 20000
// ADV_EXT_IND PDU construction function
void llSetupAdvExtIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv)
{
uint8 advMode, extHeaderFlag, length, extHdrLength;
uint8 offset = 0;
// set AdvMode
if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK)
advMode = LL_EXT_ADV_MODE_CONN;
else if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK)
advMode = LL_EXT_ADV_MODE_SC;
else
advMode = LL_EXT_ADV_MODE_NOCONN_NOSC;
// adv PDU header
g_tx_ext_adv_buf.txheader = 0;
// PDU type, 4 bits
SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK);
// RFU, ChSel, TxAdd, RxAdd
if ((pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) ||
(pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM))
{
if ((adv_param.ownAddr[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR)
SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK);
}
else // This will cutoff ownAddrType high bit
SET_BITS(g_tx_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK);
if (pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW)
SET_BITS(g_tx_adv_buf.txheader, 1, CHSEL_SHIFT, CHSEL_MASK);
extHdrLength = 0;
// == step 1. decide what fields should be present in extended header
// extended header
extHeaderFlag = 0;
extHdrLength ++;
if ( (pAdvInfo->isPeriodic == FALSE) &&
(pAdvInfo->data.dataComplete == TRUE) &&
(pAdvInfo->data.advertisingDataLength == 0) &&
(advMode == LL_EXT_ADV_MODE_NOCONN_NOSC) )
{
extHeaderFlag |= LE_EXT_HDR_ADVA_PRESENT_BITMASK;
extHdrLength += 6;
if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_DIRECT_BITMASK)
{
extHeaderFlag |= LE_EXT_HDR_TARGETA_PRESENT_BITMASK;
extHdrLength += 6;
}
}
else
{
extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK;
extHdrLength += 2;
extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK;
extHdrLength += 3;
}
if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_TX_POWER_BITMASK)
{
extHeaderFlag |= LE_EXT_HDR_TX_PWR_PRESENT_BITMASK;
extHdrLength ++;
}
length = 1 + extHdrLength; // 1: extended header len(6bits) + advMode(2bit)
// Length
SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK);
// === step 2. fill AUX_ADV_IND PDU
// Extended header length + AdvMode(1 octet)
g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F);
offset ++;
g_tx_ext_adv_buf.data[offset] = extHeaderFlag;
offset ++;
// AdvA (6 octets)
if (extHeaderFlag & LE_EXT_HDR_ADVA_PRESENT_BITMASK)
{
if (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE)
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN);
else // public address
memcpy(&g_tx_ext_adv_buf.data[offset], adv_param.ownAddr, LL_DEVICE_ADDR_LEN);
offset += LL_DEVICE_ADDR_LEN;
}
// TargetA(6 octets)
if (extHeaderFlag & LE_EXT_HDR_TARGETA_PRESENT_BITMASK)
{
if (g_currentTimerTask)
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.peerAddress, LL_DEVICE_ADDR_LEN);
else
memcpy(&g_tx_ext_adv_buf.data[offset], g_currentPeerRpa, LL_DEVICE_ADDR_LEN);
offset += LL_DEVICE_ADDR_LEN;
}
// AdvDataInfo(ADI)(2 octets)
if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK)
{
uint16 adi;
adi = ((pAdvInfo->parameter.advertisingSID & 0x0F) << 12) | (pAdvInfo->data.DIDInfo & 0x0FFF);
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&adi, 2);
offset += 2;
}
// AuxPtr(3 octets)
if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK)
{
uint8 chn_idx, ca, offset_unit, aux_phy;
uint16 aux_offset;
uint32 temp = 0;
chn_idx = 3 + (pAdvInfo->advHandle & 0x0F); // temp set
ca = 0; // 50-500ppm
aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum
// for extenede adv case, the offset is calculated by auxPduRemainder
if (pAdvInfo->isPeriodic == FALSE)
{
if (g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder >= 245700)
offset_unit = 1; // 300us, for aux offset >= 245700us
else
offset_unit = 0; // 30us, for aux offset < 245700us
// calculate elapse time since last timer trigger
//aux_offset = (g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder - elapse_time) / ((offset_unit == 1) ? 300 : 30);
aux_offset = g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder / ((offset_unit == 1) ? 300 : 30);
}
// for periodic adv case, the offset is fixed 1500us + 5000 * adv channel left
else
{
uint8_t temp, number;
temp = 1 << (pPrdAdv->currentChn - LL_ADV_CHAN_FIRST); // current bit mask
temp = ~(temp | (temp - 1));
temp = pAdvInfo->parameter.priAdvChnMap & temp; // channel in the chan map to be broadcast
number = (temp & 0x0001) +
((temp & 0x0002) >> 1) +
((temp & 0x0004) >> 2);
// the interval between chan 37<->38, 38<->39 is 5000us, primary adv->aux adv chn is 1500us
offset_unit = 0; // 30us, for aux offset < 245700us
aux_offset = (number * pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] + g_interAuxPduDuration) / 30;
}
// LOG("#%d#%d# ", g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder - elapse_time, aux_offset);
temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT;
temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT;
temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT;
temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT;
temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT;
temp &= 0x00FFFFFF;
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3);
pAdvInfo->auxChn = chn_idx; // save secondary channel index
pAdvInfo->currentAdvOffset = 0; // reset offset in adv data set
offset += 3;
}
if (extHeaderFlag & LE_EXT_HDR_TX_PWR_PRESENT_BITMASK)
{
short radio_pwr = pAdvInfo->tx_power * 10 + g_rfTxPathCompensation;
if (radio_pwr < -1270)
radio_pwr = -1270;
else if (radio_pwr > 1270)
radio_pwr = 1270;
g_tx_ext_adv_buf.data[offset] = radio_pwr / 10;;
}
pAdvInfo->currentAdvOffset = 0;
}
void LL_slave_conn_event1(void)
{
uint16_t ll_rdCntIni;
uint32_t tx_num, rx_num;
llConnState_t* connPtr;
g_ll_conn_ctx.timerExpiryTick = read_current_fine_time(); // A2 multiconnection
// hal_gpio_write(GPIO_P14, 1);
connPtr = &conn_param[g_ll_conn_ctx.currentConn];
// time critical process, disable interrupt
HAL_ENTER_CRITICAL_SECTION();
tx_num = pGlobal_config[LL_TX_PKTS_PER_CONN_EVT];
rx_num = pGlobal_config[LL_RX_PKTS_PER_CONN_EVT];
if (tx_num > g_maxPktPerEventTx || tx_num == 0) tx_num = g_maxPktPerEventTx;
if (rx_num > g_maxPktPerEventRx || rx_num == 0) rx_num = g_maxPktPerEventRx;
connPtr->pmCounter.ll_conn_event_cnt ++;
//ZQ 20191209
//restore the currentChan for disable slavelatency
//ZQ20200207 should use nextChan
connPtr->lastCurrentChan = connPtr->nextChan;
// counter for one connection event
llResetRfCounters();
//support rf phy change
rf_phy_change_cfg(connPtr->llRfPhyPktFmt);
ll_hw_tx2rx_timing_config(connPtr->llRfPhyPktFmt);
ll_hw_rst_rfifo();
ll_hw_rst_tfifo();
// channel physical configuration
set_crc_seed(connPtr->initCRC); // crc seed for data PDU is from CONNECT_REQ
set_access_address(connPtr->accessAddr); // access address
set_channel(connPtr->currentChan); // set channel
set_whiten_seed(connPtr->currentChan); // set whiten seed
// A2-multiconn
ll_hw_set_rx_timeout(88);
if ( (connPtr->llRfPhyPktFmt == PKT_FMT_BLR125K) ||
(connPtr->llRfPhyPktFmt == PKT_FMT_BLR500K) )
ll_hw_set_rx_timeout(350);
else
ll_hw_set_rx_timeout(88);
set_max_length(0xff);
// win size for 1st packet
if (connPtr->firstPacket) // not received the 1st packet, CRC error or correct
{
//ll_hw_set_rx_timeout_1st(conn_param[connId].curParam.winSize * 625 + conn_param[connId].timerDrift * 2 );
//20180412 enlarge the connectInd or connect_update timing tolerence
uint32_t first_window_timout=pGlobal_config[LL_SMART_WINDOW_FIRST_WINDOW] + connPtr->curParam.winSize * 625 + connPtr->timerDrift * 2 ;
//The transmitWindowOffset shall be a multiple of 1.25 ms in the range of 0 ms
//to connInterval. The transmitWindowSize shall be a multiple of 1.25 ms in the
//range of 1.25 ms to the lesser of 10 ms and (connInterval - 1.25 ms).
//ZQ 20200208
uint32_t winSizeLimt = MIN(10000, (connPtr->curParam.connInterval * 625 - 1250) );
if (winSizeLimt < first_window_timout)
first_window_timout = winSizeLimt;
ll_hw_set_rx_timeout_1st(first_window_timout);
}
else // A1 ROM metal change , 2018 - 1 - 3
{
if (connPtr->rx_timeout) // timeout case
ll_hw_set_rx_timeout_1st(pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT] + pGlobal_config[SLAVE_CONN_DELAY_BEFORE_SYNC] * 2 + (connPtr->timerDrift + connPtr->accuTimerDrift) * 2 );
else
ll_hw_set_rx_timeout_1st(pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT] + pGlobal_config[SLAVE_CONN_DELAY] * 2 + connPtr->timerDrift * 2 );
}
// configure loop timeout
// considering the dle case
uint32_t temp = connPtr->curParam.connInterval * 625 - connPtr->llPduLen.local.MaxRxTime- pGlobal_config[LL_HW_RTLP_TO_GAP]; // 500us: margin for timer1 IRQ
ll_hw_set_loop_timeout(temp > pGlobal_config[LL_HW_RTLP_LOOP_TIMEOUT] ?
pGlobal_config[LL_HW_RTLP_LOOP_TIMEOUT] : temp); // 2018-6-20, global config for the parameter
// now we support 4 RT in one RTLP, if PDU size is 256Byte, need (256*8 + 150) * 8 = 17684us,
// not consider Rx packet size
ll_hw_trx_settle_config(connPtr->llRfPhyPktFmt);
ll_hw_set_loop_nack_num(4);
ll_hw_ign_rfifo(LL_HW_IGN_ALL);
tx_num = ll_generateTxBuffer(tx_num, &ll_rdCntIni);
// TODO: consider Rx flow control here
// if (LL_RX_FLOW_CONTROL_ENABLED == rxFifoFlowCtrl)
// {
// // configure LL HW to keep NESN
// }
ll_hw_config( LL_HW_RTLP, //connPtr->llMode,
connPtr->sn_nesn, // sn,nesn init
tx_num, // ll_txNum
rx_num, // ll_rxNum
1, // ll_mdRx
ll_rdCntIni); // rdCntIni
uint8 temp_rf_fmt = g_rfPhyPktFmt;
g_rfPhyPktFmt = connPtr->llRfPhyPktFmt;
ll_hw_go();
llWaitingIrq = 1;
g_rfPhyPktFmt = temp_rf_fmt;
HAL_EXIT_CRITICAL_SECTION();
// hal_gpio_write(GPIO_P14, 0);
// LOG("%d-%d ", g_ll_conn_ctx.numLLConns, g_ll_conn_ctx.currentConn);
// LOG("%d ", g_ll_conn_ctx.currentConn);
ll_debug_output(DEBUG_LL_HW_SET_RTLP);
}
void llSetupAuxAdvIndPDU1(extAdvInfo_t * pAdvInfo, periodicAdvInfo_t * pPrdAdv)
{
uint8 advMode, extHeaderFlag, length, extHdrLength, advDataLen;
uint8 offset = 0;
// uint32 T2, elapse_time;
// set AdvMode
if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK)
advMode = LL_EXT_ADV_MODE_CONN;
else if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK)
advMode = LL_EXT_ADV_MODE_SC;
else
advMode = LL_EXT_ADV_MODE_NOCONN_NOSC;
length = 0;
// adv PDU header
g_tx_ext_adv_buf.txheader = 0;
// PDU type, 4 bits
SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK);
//
SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK);
if (pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW)
SET_BITS(g_tx_adv_buf.txheader, 1, CHSEL_SHIFT, CHSEL_MASK);
extHdrLength = 0;
// == step 1. decide what fields should be present in extended header
// extended header
extHeaderFlag = 0;
extHdrLength ++;
// CTEInfo(1 octets), not present for AUX_ADV_IND
extHeaderFlag |= LE_EXT_HDR_ADI_PRESENT_BITMASK;
extHdrLength += 2;
if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_DIRECT_BITMASK)
{
extHeaderFlag |= LE_EXT_HDR_TARGETA_PRESENT_BITMASK;
extHdrLength += 6;
}
// if (advMode != LL_EXT_ADV_MODE_NOCONN_NOSC) // This field is C4 for LL_EXT_ADV_MODE_NOCONN_NOSC, we will not send AdvA in EXT_ADV_IND, so it is mandatory here
// {
extHeaderFlag |= LE_EXT_HDR_ADVA_PRESENT_BITMASK;
extHdrLength += 6;
// }
if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_TX_POWER_BITMASK)
{
extHeaderFlag |= LE_EXT_HDR_TX_PWR_PRESENT_BITMASK;
extHdrLength ++;
}
if (pAdvInfo->isPeriodic == TRUE)
{
extHeaderFlag |= LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK;
extHdrLength += 18;
}
if (pAdvInfo->data.dataComplete == TRUE)
{
if (advMode == LL_EXT_ADV_MODE_NOCONN_NOSC
&& (pAdvInfo->isPeriodic == FALSE)
&& (pAdvInfo->data.advertisingDataLength > (255 - 1 - extHdrLength)))
{
extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK;
extHdrLength += 3;
// maximum payload length = 255: header len (= 1), ext header len(extHdrLength), adv data(advDataLen)
advDataLen = (255 - 1) - extHdrLength; // adv data length. TODO: check spec
}
else
{
// put all adv data in field "Adv Data"
advDataLen = (255 - 1) - extHdrLength;
if (advDataLen > pAdvInfo->data.advertisingDataLength)
advDataLen = pAdvInfo->data.advertisingDataLength;
}
}
else // update 04-13, consider update adv data case
advDataLen = 0;
length = 1 + extHdrLength + advDataLen; // 1: extended header len(6bits) + advMode(2bit)
// Length
SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK);
SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK);
// === step 2. fill AUX_ADV_IND PDU
// Extended header length + AdvMode(1 octet)
g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F);
offset ++;
g_tx_ext_adv_buf.data[offset] = extHeaderFlag;
offset ++;
// AdvA (6 octets)
if (extHeaderFlag & LE_EXT_HDR_ADVA_PRESENT_BITMASK)
{
if ( (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM) &&
(pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) )
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN);
else // public address
memcpy(&g_tx_ext_adv_buf.data[offset], ownPublicAddr, LL_DEVICE_ADDR_LEN);
offset += LL_DEVICE_ADDR_LEN;
}
// TargetA(6 octets)
if (extHeaderFlag & LE_EXT_HDR_TARGETA_PRESENT_BITMASK)
{
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.peerAddress, LL_DEVICE_ADDR_LEN);
offset += LL_DEVICE_ADDR_LEN;
}
// CTEInfo(1 octets), not present for AUX_ADV_IND
if (extHeaderFlag & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK)
{
// offset += 1;
}
// AdvDataInfo(ADI)(2 octets)
if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK)
{
uint16 adi;
adi = ((pAdvInfo->parameter.advertisingSID & 0x0F) << 12) | (pAdvInfo->data.DIDInfo & 0x0FFF);
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&adi, 2);
offset += 2;
}
// AuxPtr(3 octets)
if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK)
{
uint8 chn_idx, ca, offset_unit, aux_phy;
uint16 aux_offset;
uint32 temp = 0;
// if (pAdvInfo->isPeriodic == FALSE) // no periodic adv case
// {
chn_idx = llGetNextAuxAdvChn(pAdvInfo->currentChn);
ca = 0; // 50-500ppm
offset_unit = 0; // 30us, for aux offset < 245700us
aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum
aux_offset = g_interAuxPduDuration / 30;
pAdvInfo->currentChn = chn_idx;
// }
// else // AUX_PTR field is not required for periodic adv AUX_ADV_IND
// {
// }
temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT;
temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT;
temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT;
temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT;
temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT;
temp &= 0x00FFFFFF;
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3);
offset += 3;
}
else if (pAdvInfo->isPeriodic == FALSE) // only applicable to extended adv case
{
// no more aux PDU, update next channel number
int i = 0;
while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++;
pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i;
}
else // periodic adv case
{
llPrdAdvDecideNextChn(pAdvInfo, pPrdAdv);
}
// SyncInfo(18 octets)
if (extHeaderFlag & LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK)
{
// TODO
llSetupSyncInfo(pAdvInfo, pPrdAdv);
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&syncInfo, 18);
offset += 18;
}
// TxPower(1 octets)
if (extHeaderFlag & LE_EXT_HDR_TX_PWR_PRESENT_BITMASK) // Tx power is optional, could we only filled it in AUX_ADV_IND?
{
int16 radio_pwr;
radio_pwr = pAdvInfo->tx_power * 10 + g_rfTxPathCompensation;
if (radio_pwr > 1270) radio_pwr = 1270;
else if (radio_pwr < -1270) radio_pwr = -1270;
g_tx_ext_adv_buf.data[offset] = (uint8)(radio_pwr / 10);
offset += 1;
}
// ACAD(varies), not present
// copy adv data
if (pAdvInfo->isPeriodic == FALSE)
{
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&pAdvInfo->data.advertisingData[pAdvInfo->currentAdvOffset], advDataLen);
pAdvInfo->currentAdvOffset += advDataLen;
}
}
void llSetupAuxChainIndPDU1(extAdvInfo_t * pAdvInfo, periodicAdvInfo_t * pPrdAdv)
{
uint8 advMode, extHeaderFlag, length, extHdrLength, advDataLen;
uint8 offset = 0;
// set AdvMode
advMode = 0;
length = 0;
// adv PDU header
g_tx_ext_adv_buf.txheader = 0;
// PDU type, 4 bits
SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK);
// RFU, ChSel, TxAdd, RxAdd
SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK);
extHdrLength = 0;
// extended header
extHeaderFlag = 0;
extHdrLength ++;
// 2020-02-10 add for Connectionless CTE Info
// CTEInfo field is C5: Optional
if( pPrdAdv->PrdCTEInfo.enable == LL_CTE_ENABLE )
{
if( pPrdAdv->PrdCTEInfo.CTE_Count > pPrdAdv->PrdCTEInfo.CTE_Count_Idx )
{
extHeaderFlag |= LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK;
extHdrLength ++;
}
}
// ADI field is C3, it is present in our implementation
if (pAdvInfo->isPeriodic == FALSE)
{
extHeaderFlag |= LE_EXT_HDR_ADI_PRESENT_BITMASK;
extHdrLength += 2;
}
// comment out because for periodic adv, tx pwr field is in AUX_SYNC_IND. for extended adv, txPwr field in AUX_ADV_IND
// if (((pAdvInfo->isPeriodic == FALSE) && (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_TX_POWER_BITMASK))
// || ((pAdvInfo->isPeriodic == TRUE) && (pPrdAdv->adv_event_properties & LE_ADV_PROP_TX_POWER_BITMASK)))
// {
// extHeaderFlag |= LE_EXT_HDR_TX_PWR_PRESENT_BITMASK;
// extHdrLength ++;
// }
// if Adv Data could not be sent completely in this PDU, need AuxPtr
if (pAdvInfo->isPeriodic == FALSE)
{
if ( extscanrsp_offset &&
(extscanrsp_offset < pAdvInfo->scanRspMaxLength) )
advDataLen = pAdvInfo->scanRspMaxLength - extscanrsp_offset;
else
if (pAdvInfo->data.dataComplete == TRUE)
advDataLen = pAdvInfo->data.advertisingDataLength - pAdvInfo->currentAdvOffset; // put all remain adv data in field "Adv Data"
else
// update 04-13, adv data may be reconfigured during advertising, include no data in such case
advDataLen = 0;
}
else
{
if (pAdvInfo->data.dataComplete == TRUE)
advDataLen = pAdvInfo->data.advertisingDataLength - pAdvInfo->currentAdvOffset; // put all remain adv data in field "Adv Data"
else
// update 04-13, adv data may be reconfigured during advertising, include no data in such case
advDataLen = 0;
}
// TODO Check this condition more precise
if ( advDataLen > (255 - 1 - extHdrLength) )
{
extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK;
extHdrLength += 3;
// maximum payload length = 255, header len = 1, ADI len = 2, AUX_PTR len = 2
advDataLen = 255 - 1 - extHdrLength;;
}
length = 1 + extHdrLength + advDataLen; // 1: extended header len(6bits) + advMode(2bit)
// Length
SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK);
// fill extended header
offset = 0;
// Extended header length + AdvMode(1 octet)
g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F);
offset ++;
g_tx_ext_adv_buf.data[offset] = extHeaderFlag;
offset ++;
// CTEInfo(1 octets), not present for AUX_ADV_IND
if (extHeaderFlag & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK)
{
//LOG("\n SyC \n");
g_tx_ext_adv_buf.data[offset] = ( ( pPrdAdv->PrdCTEInfo.CTE_Type << 6 ) | \
( pPrdAdv->PrdCTEInfo.CTE_Length));
pPrdAdv->PrdCTEInfo.CTE_Count_Idx ++;
offset += 1;
}
// AdvDataInfo(ADI)(2 octets)
if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK)
{
uint16 adi;
adi = ((pAdvInfo->parameter.advertisingSID & 0x0F) << 12) | (pAdvInfo->data.DIDInfo & 0x0FFF);
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&adi, 2);
offset += 2;
}
// AuxPtr(3 octets)
if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK)
{
uint8 chn_idx, ca, offset_unit, aux_phy;
uint16 aux_offset;
uint32 temp = 0;
chn_idx = llGetNextAuxAdvChn(pAdvInfo->currentChn);
ca = 0; // 50-500ppm
offset_unit = 0; // 30us, for aux offset < 245700us
aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum
aux_offset = g_interAuxPduDuration / 30;
temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT;
temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT;
temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT;
temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT;
temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT;
temp &= 0x00FFFFFF;
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3);
pAdvInfo->currentChn = chn_idx; // save secondary channel index
pPrdAdv->currentChn = chn_idx;
offset += 3;
}
else
{
// no more aux PDU, update next channel number
if (pAdvInfo->isPeriodic == FALSE)
{
int i = 0;
while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++;
pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i;
}
else // periodic adv case
{
llPrdAdvDecideNextChn(pAdvInfo, pPrdAdv);
}
}
// ACAD(varies), not present
// copy adv data
if (pAdvInfo->isPeriodic == 0) {
if (!extscanrsp_offset || (extscanrsp_offset > pAdvInfo->scanRspMaxLength))
{
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->data.advertisingData + pAdvInfo->currentAdvOffset, advDataLen);
pAdvInfo->currentAdvOffset = pAdvInfo->currentAdvOffset + advDataLen;
}
else
{
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->scanRspData + extscanrsp_offset, advDataLen);
if (pAdvInfo->scanRspMaxLength == (extscanrsp_offset + advDataLen))
extscanrsp_offset = 0;
else
extscanrsp_offset += advDataLen;
}
}
else // periodic adv case
{
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&pPrdAdv->data.advertisingData[pPrdAdv->currentAdvOffset], advDataLen);
pPrdAdv->currentAdvOffset += advDataLen;
// if finish broad current periodic adv event, revert the read pointer of adv data
if (pPrdAdv->currentAdvOffset == pPrdAdv->data.advertisingDataLength)
{
// 2020-02-10 add logic for CTE info
if( pPrdAdv->PrdCTEInfo.enable == LL_CTE_ENABLE )
{
if( pPrdAdv->PrdCTEInfo.CTE_Count_Idx >= pPrdAdv->PrdCTEInfo.CTE_Count )
{
// already send all CTE info, then reset pPrdAdv->currentAdvOffset
pPrdAdv->currentAdvOffset = 0;
pPrdAdv->PrdCTEInfo.CTE_Count_Idx = 0;
// length set to zero means stop CTE
ll_hw_set_cte_txSupp( CTE_SUPP_LEN_SET | 0x0 );
}
}
else
{
// 2020-02-21 bug fix: If CTE is not enabled, then
// subsequent packets will not be sent
pPrdAdv->currentAdvOffset = 0;
}
}
}
}
void llSetupAuxScanRspPDU1(extAdvInfo_t * pAdvInfo)
{
uint8 advMode, extHeaderFlag, length, extHdrLength, advDataLen;
uint8 offset = 0;
// set AdvMode
advMode = 0;
length = 0;
// adv PDU header
g_tx_ext_adv_buf.txheader = 0;
// PDU type, 4 bits
SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK);
// RFU, ChSel, TxAdd, RxAdd
if ((pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) ||
(pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM))
{
if ((adv_param.ownAddr[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR)
SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK);
}
else // This will cutoff ownAddrType high bit
SET_BITS(g_tx_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK);
extHdrLength = 0;
// extended header
extHeaderFlag = 0; // for AUX_SYNC_IND PDU: CTE info, AuxPtr, Tx power, ACAD, Adv Data are optional, other fields are absent
extHdrLength ++;
extHeaderFlag |= LE_EXT_HDR_ADVA_PRESENT_BITMASK;
extHdrLength += 6;
extHeaderFlag |= LE_EXT_HDR_ADI_PRESENT_BITMASK;
extHdrLength += 2;
advDataLen = pAdvInfo->scanRspMaxLength - extscanrsp_offset;
if (advDataLen > 100)
{
extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK;
extHdrLength += 3;
advDataLen = 100;
}
length = 1 + extHdrLength + advDataLen; // 1: extended header len(6bits) + advMode(2bit)
// Length
SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK);
// fill extended header
offset = 0;
// Extended header length + AdvMode(1 octet)
g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F);
offset ++;
g_tx_ext_adv_buf.data[offset] = extHeaderFlag;
offset ++;
// AdvA (6 octets)
if (extHeaderFlag & LE_EXT_HDR_ADVA_PRESENT_BITMASK)
{
if ( (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RANDOM) &&
(pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) )
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN);
else // public address
memcpy(&g_tx_ext_adv_buf.data[offset], adv_param.ownAddr, LL_DEVICE_ADDR_LEN);
offset += LL_DEVICE_ADDR_LEN;
}
// AdvDataInfo(ADI)(2 octets)
if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK)
{
uint16 adi;
adi = ((pAdvInfo->parameter.advertisingSID & 0x0F) << 12) | (pAdvInfo->data.DIDInfo & 0x0FFF);
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&adi, 2);
offset += 2;
}
// AuxPtr(3 octets)
if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK)
{
uint8 chn_idx, ca, offset_unit, aux_phy;
uint16 aux_offset;
uint32 temp = 0;
chn_idx = llGetNextAuxAdvChn(pAdvInfo->currentChn);
ca = 0; // 50-500ppm
offset_unit = 0; // 30us, for aux offset < 245700us
aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum
aux_offset = g_interAuxPduDuration / 30;
temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT;
temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT;
temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT;
temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT;
temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT;
temp &= 0x00FFFFFF;
memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3);
pAdvInfo->currentChn = chn_idx; // save secondary channel index
offset += 3;
}
// copy adv data
memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->scanRspData + extscanrsp_offset, advDataLen);
if (pAdvInfo->scanRspMaxLength == (extscanrsp_offset + advDataLen))
extscanrsp_offset = 0;
else
extscanrsp_offset += advDataLen;
}
void ll_hw_trx_settle_bb(uint8_t phyPktFmt, uint8_t delay)
{
if (phyPktFmt == PKT_FMT_BLE1M)
ll_hw_set_trx_settle(delay, pGlobal_config[LL_HW_AFE_DELAY], pGlobal_config[LL_HW_PLL_DELAY]);
else if (phyPktFmt == PKT_FMT_BLE1M)
ll_hw_set_trx_settle(delay, pGlobal_config[LL_HW_AFE_DELAY_2MPHY], pGlobal_config[LL_HW_PLL_DELAY_2MPHY]);
else if (phyPktFmt == PKT_FMT_BLR500K)
ll_hw_set_trx_settle(delay, pGlobal_config[LL_HW_AFE_DELAY_500KPHY], pGlobal_config[LL_HW_PLL_DELAY_500KPHY]);
else // (phyPktFmt == PKT_FMT_BLR500K)
ll_hw_set_trx_settle(delay, pGlobal_config[LL_HW_AFE_DELAY_125KPHY], pGlobal_config[LL_HW_PLL_DELAY_125KPHY]);
}
int8 ll_processExtAdvIRQ1(uint32_t irq_status)
{
uint8 mode;
extAdvInfo_t* pAdvInfo;
uint32_t T2, delay;
pAdvInfo = g_pAdvSchInfo[g_currentExtAdv].pAdvInfo;
if (pAdvInfo == NULL)
return FALSE;
HAL_ENTER_CRITICAL_SECTION();
mode = ll_hw_get_tr_mode();
if (ll_isLegacyAdv(pAdvInfo))
{
// process legacy Adv
uint8_t packet_len, pdu_type, txAdd;
uint8_t* peerAddr, *ownAddr;
uint8_t bWlRlCheckOk = TRUE;
uint16_t pktLen;
uint32_t pktFoot0, pktFoot1;
int calibra_time; // this parameter will be provided by global_config
ll_debug_output(DEBUG_LL_HW_TRX);
// read packet
packet_len = ll_hw_read_rfifo1((uint8_t*)(&(g_rx_adv_buf.rxheader)),
&pktLen,
&pktFoot0,
&pktFoot1);
if (ll_hw_get_rfifo_depth() > 0)
{
g_pmCounters.ll_rfifo_read_err++;
packet_len = 0;
pktLen = 0;
}
// check receive pdu type
pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK;
txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random
if ( (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM)
&& (pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) )
ownAddr = pAdvInfo->parameter.ownRandomAddress;
else
ownAddr = ownPublicAddr;
if ( (packet_len > 0) // any better checking rule for rx anything?
&& (pdu_type == ADV_SCAN_REQ)
&& ((pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_IND)
||(pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_SCAN_IND)) )
{
// 1. scan req
g_pmCounters.ll_recv_scan_req_cnt ++;
// check AdvA
if (g_rx_adv_buf.data[6] != ownAddr[0]
|| g_rx_adv_buf.data[7] != ownAddr[1]
|| g_rx_adv_buf.data[8] != ownAddr[2]
|| g_rx_adv_buf.data[9] != ownAddr[3]
|| g_rx_adv_buf.data[10] != ownAddr[4]
|| g_rx_adv_buf.data[11] != ownAddr[5])
{
}
else
{
uint8_t rpaListIndex;
peerAddr = &g_rx_adv_buf.data[0]; // ScanA
// Resolving list checking
if ( (g_llRlEnable == TRUE)
&& (txAdd == LL_DEV_ADDR_TYPE_RANDOM)
&& ((g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) )
{
rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]);
if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM)
{
peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0];
}
else
bWlRlCheckOk = FALSE;
}
// check white list
if ( (pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW)
&& ((adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ)
|| (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ))
&& (bWlRlCheckOk == TRUE) )
{
// check white list
bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr);
}
if (bWlRlCheckOk == FALSE) // if not in white list, do nothing
{
g_pmCounters.ll_filter_scan_req_cnt ++;
}
else
{
g_pmCounters.ll_rx_peer_cnt++;
uint8 retScanRspFilter = 1;
if(LL_PLUS_ScanRequestFilterCBack)
{
retScanRspFilter = 1; //LL_PLUS_ScanRequestFilterCBack();
}
if(retScanRspFilter)
{
// send scan rsp
ll_hw_set_stx(); // set LL HW as single Tx mode
g_same_rf_channel_flag = TRUE;
// calculate the delay
T2 = read_current_fine_time();
delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2);
calibra_time = pGlobal_config[SCAN_RSP_DELAY]; // consider rx_done to ISR time, SW delay after read_current_fine_time(), func read_current_fine_time() delay ...
delay = 118 - delay - calibra_time; // IFS = 150us, Tx tail -> Rx done time: about 32us
ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK
pGlobal_config[LL_HW_AFE_DELAY],
pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL
ll_hw_go();
llWaitingIrq = TRUE;
g_same_rf_channel_flag = FALSE;
// reset Rx/Tx FIFO
ll_hw_rst_rfifo();
ll_hw_rst_tfifo();
//write Tx FIFO
ll_hw_write_tfifo((uint8*)&(tx_scanRsp_desc.txheader),
((tx_scanRsp_desc.txheader & 0xff00) >> 8) + 2); // payload length + header length(2)
ll_debug_output(DEBUG_LL_HW_SET_STX);
g_pmCounters.ll_send_scan_rsp_cnt ++;
}
}
}
}
else if (pdu_type == ADV_CONN_REQ
&& (pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_IND
|| pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_LDC_ADV
|| pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_HDC_ADV))
{
// 2. connect req
g_pmCounters.ll_recv_conn_req_cnt ++;
// check AdvA
if (g_rx_adv_buf.data[6] != ownAddr[0]
|| g_rx_adv_buf.data[7] != ownAddr[1]
|| g_rx_adv_buf.data[8] != ownAddr[2]
|| g_rx_adv_buf.data[9] != ownAddr[3]
|| g_rx_adv_buf.data[10] != ownAddr[4]
|| g_rx_adv_buf.data[11] != ownAddr[5])
{
// nothing to do
}
else
{
uint8_t rpaListIndex;
peerAddr = &g_rx_adv_buf.data[0]; // initA
// Resolving list checking
if ( (g_llRlEnable == TRUE)
&& (txAdd == LL_DEV_ADDR_TYPE_RANDOM)
&& ((g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) )
{
rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]);
if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM)
{
peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0];
}
else
bWlRlCheckOk = FALSE;
}
// check white list
if ( (pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW)
&& (llState == LL_STATE_ADV_UNDIRECTED)
&& ((adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_CONNECT_REQ)
|| (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ))
&& (bWlRlCheckOk == TRUE) )
{
// check white list
bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr);
}
// fixed bug 2018-09-25, LL/CON/ADV/BV-04-C, for direct adv, initA should equal peer Addr
if (llState == LL_STATE_ADV_DIRECTED)
{
if ( (txAdd != peerInfo.peerAddrType)
|| (peerAddr[0] != peerInfo.peerAddr[0])
|| (peerAddr[1] != peerInfo.peerAddr[1])
|| (peerAddr[2] != peerInfo.peerAddr[2])
|| (peerAddr[3] != peerInfo.peerAddr[3])
|| (peerAddr[4] != peerInfo.peerAddr[4])
|| (peerAddr[5] != peerInfo.peerAddr[5]) )
{
// not match, check next
bWlRlCheckOk = FALSE;
}
}
if (bWlRlCheckOk == FALSE) // if not in white list, do nothing
{
g_pmCounters.ll_filter_conn_req_cnt ++;
}
else
{
// increment statistics counter
g_pmCounters.ll_rx_peer_cnt++;
// bug fixed 2018-01-23, peerAddrType should read TxAdd
peerInfo.peerAddrType = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random
osal_memcpy( peerInfo.peerAddr, g_rx_adv_buf.data, 6);
move_to_slave_function(); // move to slave role for connection state
// add 04-01, set adv inactive, and it will be remove from the scheduler when invoke ll_adv_scheduler()
pAdvInfo->active = FALSE;
LL_AdvSetTerminatedCback(LL_STATUS_SUCCESS,
pAdvInfo->advHandle,
adv_param.connId,
pAdvInfo->adv_event_counter);
}
}
}
}
else if (mode == LL_HW_MODE_TRX &&
(irq_status & LIRQ_COK))
{
// TRX mode, receives AUX_SCAN_REQ or AUX_CONNECT_REQ
uint8_t packet_len, pdu_type, txAdd;
uint8_t* peerAddr;
uint8_t bWlRlCheckOk = TRUE;
uint16_t pktLen;
uint32_t pktFoot0, pktFoot1;
int calibra_time; // this parameter will be provided by global_config
uint8* ownAddr;
ll_debug_output(DEBUG_LL_HW_TRX);
// read packet
packet_len = ll_hw_read_rfifo1((uint8_t*)(&(g_rx_adv_buf.rxheader)),
&pktLen,
&pktFoot0,
&pktFoot1);
if(ll_hw_get_rfifo_depth() > 0)
{
g_pmCounters.ll_rfifo_read_err++;
packet_len = 0;
pktLen = 0;
}
// check receive pdu type
pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK;
txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random
if ( (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM)
&& (pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) )
ownAddr = pAdvInfo->parameter.ownRandomAddress;
else if (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM)
ownAddr = g_currentLocalRpa;
else
ownAddr = ownPublicAddr;
if ( (packet_len > 0)
&& (pdu_type == ADV_AUX_SCAN_REQ)
&& ((pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK)
|| (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK)) )
{
// 1. scan req
g_pmCounters.ll_recv_scan_req_cnt ++;
// check AdvA
if ( (g_rx_adv_buf.data[6] != ownAddr[0])
|| (g_rx_adv_buf.data[7] != ownAddr[1])
|| (g_rx_adv_buf.data[8] != ownAddr[2])
|| (g_rx_adv_buf.data[9] != ownAddr[3])
|| (g_rx_adv_buf.data[10] != ownAddr[4])
|| (g_rx_adv_buf.data[11] != ownAddr[5]) )
{
}
else
{
uint8_t rpaListIndex;
peerAddr = &g_rx_adv_buf.data[0]; // ScanA
// Resolving list checking
if ( (g_llRlEnable == TRUE)
&& (txAdd == LL_DEV_ADDR_TYPE_RANDOM)
&& ((g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) )
{
rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]);
if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM)
{
peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0];
}
else
bWlRlCheckOk = FALSE;
}
// check white list
if ( (pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW)
&& ((adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ)
|| (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ))
&& (bWlRlCheckOk == TRUE) )
{
// check white list
bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr);
}
if (bWlRlCheckOk == FALSE) // if not in white list, do nothing
{
g_pmCounters.ll_filter_scan_req_cnt ++;
}
else
{
g_pmCounters.ll_rx_peer_cnt++;
llSetupAuxScanRspPDU(pAdvInfo);
// send scan rsp
ll_hw_set_stx(); // set LL HW as single Tx mode
g_same_rf_channel_flag = TRUE;
// calculate the delay
T2 = read_current_fine_time();
delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2);
if (g_rfPhyPktFmt == PKT_FMT_BLE1M)
{
calibra_time = pGlobal_config[EXT_ADV_AUXSCANRSP_DELAY_1MPHY];
delay = 118 - (delay + calibra_time); // IFS = 150us, Tx tail -> Rx done time: about 32us
}
else if (g_rfPhyPktFmt == PKT_FMT_BLE2M)
{
calibra_time = pGlobal_config[EXT_ADV_AUXSCANRSP_DELAY_2MPHY];
delay = 132 - (delay + calibra_time);
}
else
{ // PKT_FMT_BLR125K
calibra_time = pGlobal_config[EXT_ADV_AUXSCANRSP_DELAY_125KPHY];
delay = 118 - (delay + calibra_time);
}
ll_hw_trx_settle_bb(g_rfPhyPktFmt, delay);
ll_hw_go();
llWaitingIrq = TRUE;
g_same_rf_channel_flag = FALSE;
// reset Rx/Tx FIFO
ll_hw_rst_rfifo();
ll_hw_rst_tfifo();
//write Tx FIFO
// =================== TODO: change the buffer to ext adv set
ll_hw_write_tfifo((uint8*)&(g_tx_ext_adv_buf.txheader),
((g_tx_ext_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2)
ll_debug_output(DEBUG_LL_HW_SET_STX);
g_pmCounters.ll_send_scan_rsp_cnt ++;
}
}
}
else if ( (pdu_type == ADV_CONN_REQ)
&& (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK) )
{
// 2. connect req
// ??? g_auxconnreq_ISR_entry_time = ISR_entry_time;
g_pmCounters.ll_recv_conn_req_cnt ++;
// check AdvA
if (g_rx_adv_buf.data[6] != ownAddr[0]
|| g_rx_adv_buf.data[7] != ownAddr[1]
|| g_rx_adv_buf.data[8] != ownAddr[2]
|| g_rx_adv_buf.data[9] != ownAddr[3]
|| g_rx_adv_buf.data[10] != ownAddr[4]
|| g_rx_adv_buf.data[11] != ownAddr[5])
{
// nothing to do
}
else
{
uint8_t rpaListIndex;
peerAddr = &g_rx_adv_buf.data[0]; // ScanA
// Resolving list checking
if ( (g_llRlEnable == TRUE)
&& (txAdd == LL_DEV_ADDR_TYPE_RANDOM)
&& ((g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) )
{
rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]);
if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM)
{
peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0];
}
else
bWlRlCheckOk = FALSE;
}
// check white list
if ( (pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW)
&& ((adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ)
|| (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ))
&& (bWlRlCheckOk == TRUE) )
{
// check white list
bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr);
}
if (bWlRlCheckOk == FALSE) // if not in white list, do nothing
{
g_pmCounters.ll_filter_conn_req_cnt ++;
}
else
{
// increment statistics counter
g_pmCounters.ll_rx_peer_cnt++;
//==============
llSetupAuxConnectRspPDU(pAdvInfo);
if (llWaitingIrq == 0)
{
// send scan rsp
ll_hw_set_stx(); // set LL HW as single Tx mode
g_same_rf_channel_flag = TRUE;
// calculate the delay
T2 = read_current_fine_time();
delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2);
if (g_rfPhyPktFmt == PKT_FMT_BLE1M)
{
calibra_time = pGlobal_config[EXT_ADV_AUXCONNRSP_DELAY_1MPHY];
delay = 118 - (delay + calibra_time); // IFS = 150us, Tx tail -> Rx done time: about 32us
}
else if (g_rfPhyPktFmt == PKT_FMT_BLE2M)
{
calibra_time = pGlobal_config[EXT_ADV_AUXCONNRSP_DELAY_2MPHY];
delay = 132 - (delay + calibra_time);
}
else
{ // PKT_FMT_BLR125K
calibra_time = pGlobal_config[EXT_ADV_AUXCONNRSP_DELAY_125KPHY];
delay = 118 - (delay + calibra_time);
}
ll_hw_trx_settle_bb(g_rfPhyPktFmt, delay);
ll_hw_go();
llWaitingIrq = TRUE;
g_same_rf_channel_flag = FALSE;
// reset Rx/Tx FIFO
ll_hw_rst_rfifo();
ll_hw_rst_tfifo();
//write Tx FIFO
ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader),
((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2)
ll_debug_output(DEBUG_LL_HW_SET_STX);
g_pmCounters.ll_send_conn_rsp_cnt ++;
//==============
// bug fixed 2018-01-23, peerAddrType should read TxAdd
peerInfo.peerAddrType = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random
osal_memcpy( peerInfo.peerAddr, g_rx_adv_buf.data, 6);
move_to_slave_function3(); // move to slave role for connection state
// add 04-01, set adv inactive, and it will be remove from the scheduler when invoke ll_adv_scheduler()
pAdvInfo->active = FALSE;
LL_AdvSetTerminatedCback(LL_STATUS_SUCCESS,
pAdvInfo->advHandle,
adv_param.connId,
pAdvInfo->adv_event_counter);
}
}
}
}
}
else if (mode == LL_HW_MODE_STX )
{
}
// // update scheduler list
// ll_adv_scheduler();
if (!llWaitingIrq)
{
// update scheduler list // update 04-01, consider sending aux_scan_rsp/aux_conn_rsp case, will invoke scheduler after STX IRQ
ll_adv_scheduler();
ll_hw_clr_irq();
llTaskState = LL_TASK_OTHERS;
}
HAL_EXIT_CRITICAL_SECTION();
return TRUE;
}
void LL_IRQHandler2(void)
{
char ret;
uint irq_status;
ISR_entry_time = read_current_fine_time();
ll_debug_output(DEBUG_ISR_ENTRY);
irq_status = ll_hw_get_irq_status();
if ((irq_status & LIRQ_MD) == 0) { // only process IRQ of MODE DONE
ll_hw_clr_irq(); // clear irq status
return;
}
llWaitingIrq = FALSE;
if (llTaskState == LL_TASK_EXTENDED_ADV) {
ret = ll_processExtAdvIRQ1(irq_status);
} else if (llTaskState == LL_TASK_EXTENDED_SCAN) {
ret = ll_processExtScanIRQ(irq_status);
} else if (llTaskState == LL_TASK_EXTENDED_INIT) {
ret = ll_processExtInitIRQ(irq_status);
} else if (llTaskState == LL_TASK_PERIODIC_ADV) {
ret = ll_processPrdAdvIRQ(irq_status);
} else if (llTaskState == LL_TASK_PERIODIC_SCAN) {
ret = ll_processPrdScanIRQ(irq_status);
} else {
ll_processBasicIRQ(irq_status);
ret = FALSE;
}
if (ret != TRUE) {
// ================ Post ISR process: secondary pending state process
// conn-adv case 2: other ISR, there is pending secondary advertise event, make it happen
if (llSecondaryState == LL_SEC_STATE_ADV_PENDING)
{
if (llSecAdvAllow()) // for multi-connection case, it is possible still no enough time for adv
{
llSetupSecAdvEvt();
llSecondaryState = LL_SEC_STATE_ADV;
}
}
// there is pending scan event, make it happen, note that it may stay pending if there is no enough idle time
else if (llSecondaryState == LL_SEC_STATE_SCAN_PENDING)
{
// trigger scan
llSetupSecScan(scanInfo.nextScanChan);
}
// there is pending init event, make it happen, note that it may stay pending if there is no enough idle time
else if (llSecondaryState == LL_SEC_STATE_INIT_PENDING)
{
// trigger init
llSetupSecInit(initInfo.nextScanChan);
}
ll_debug_output(DEBUG_ISR_EXIT);
}
}
void TIM4_IRQHandler(void)
{
HAL_ENTER_CRITICAL_SECTION();
if (AP_TIM4->status & 0x1) {
g_timer4_irq_pending_time = AP_TIM4->CurrentCount - AP_TIM4->LoadCount;
clear_timer_int(AP_TIM4);
clear_timer(AP_TIM4);
if (g_currentTimerTask == LL_TASK_EXTENDED_ADV) {
LL_extAdvTimerExpProcess();
} else if (g_currentTimerTask == LL_TASK_PERIODIC_ADV) {
LL_prdAdvTimerExpProcess();
} else if (g_currentTimerTask == LL_TASK_EXTENDED_SCAN) {
LL_extScanTimerExpProcess();
} else if (g_currentTimerTask == LL_TASK_EXTENDED_INIT) {
llSetupExtInit();
} else if (g_currentTimerTask == LL_TASK_PERIODIC_SCAN) {
LL_prdScanTimerExpProcess();
}
}
HAL_EXIT_CRITICAL_SECTION();
}
void LL_IRQHandler3(void)
{
char ret;
uint irq_status;
ISR_entry_time = read_current_fine_time();
ll_debug_output(DEBUG_ISR_ENTRY);
irq_status = ll_hw_get_irq_status();
if ((irq_status & LIRQ_MD) == 0) {
ll_hw_clr_irq();
return;
}
llWaitingIrq = 0;
if (llTaskState == LL_TASK_EXTENDED_ADV) {
ret = ll_processExtAdvIRQ(irq_status);
} else if (llTaskState == LL_TASK_EXTENDED_SCAN) {
ret = ll_processExtScanIRQ1(irq_status);
} else if (llTaskState == LL_TASK_EXTENDED_INIT) {
ret = ll_processExtInitIRQ1(irq_status);
} else if (llTaskState == LL_TASK_PERIODIC_ADV) {
ret = ll_processPrdAdvIRQ(irq_status);
} else if (llTaskState == LL_TASK_PERIODIC_SCAN) {
ret = ll_processPrdScanIRQ(irq_status);
} else {
ll_processBasicIRQ(irq_status);
ret = FALSE;
}
if (ret != TRUE) {
if (llSecondaryState == LL_SEC_STATE_ADV_PENDING)
{
if (llSecAdvAllow())
{
llSetupSecAdvEvt();
llSecondaryState = LL_SEC_STATE_ADV;
}
}
else if (llSecondaryState == LL_SEC_STATE_SCAN_PENDING)
{
llSetupSecScan(scanInfo.nextScanChan);
} else if (llSecondaryState == LL_SEC_STATE_INIT_PENDING)
{
llSetupSecInit(initInfo.nextScanChan);
}
ll_debug_output(DEBUG_ISR_EXIT);
}
}
__ATTR_SECTION_XIP__
void init_extadv_config(void)
{
pGlobal_config = global_config;
// BB_IRQ_HANDLER
JUMP_FUNCTION(V4_IRQ_HANDLER) = (uint32_t) LL_IRQHandler2;
JUMP_FUNCTION(TIM4_IRQ_HANDLER) = (uint32_t) TIM4_IRQHandler;
JUMP_FUNCTION(LL_ADV_SCHEDULER) = (uint32_t) ll_adv_scheduler0;
JUMP_FUNCTION(LL_ADV_ADD_TASK) = (uint32_t) ll_add_adv_task0;
JUMP_FUNCTION(LL_ADV_DEL_TASK) = (uint32_t) ll_delete_adv_task0;
JUMP_FUNCTION(LL_SETUP_EXT_ADV_EVENT) = (uint32_t) llSetupExtAdvEvent0;
JUMP_FUNCTION(LL_SETUP_ADV_EXT_IND_PDU) = (uint32_t) llSetupAdvExtIndPDU0;
JUMP_FUNCTION(LL_SLAVE_CONN_EVENT) = (uint32_t) LL_slave_conn_event1;
JUMP_FUNCTION(LL_SETUP_AUX_ADV_IND_PDU) = (uint32_t) llSetupAuxAdvIndPDU1;
JUMP_FUNCTION(LL_SETUP_AUX_CHAIN_IND_PDU) = (uint32_t) llSetupAuxChainIndPDU1;
JUMP_FUNCTION(LL_SETUP_AUX_SCAN_RSP_PDU) = (uint32_t) llSetupAuxScanRspPDU1;
pGlobal_config[LL_SWITCH] = pGlobal_config[LL_SWITCH] | 0x80;
pGlobal_config[LL_EXT_ADV_TASK_DURATION] = 17000;
pGlobal_config[LL_PRD_ADV_TASK_DURATION] = 20000;
pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] = 1500;
pGlobal_config[LL_CONN_TASK_DURATION] = 5000;
pGlobal_config[LL_EXT_ADV_INTER_SEC_CHN_INT] = 2500;
pGlobal_config[LL_EXT_ADV_INTER_SEC_CHN_INT_2MPHY] = 1400;
pGlobal_config[LL_EXT_ADV_PRI_2_SEC_CHN_INT] = 1500;
pGlobal_config[LL_EXT_ADV_RSC_PERIOD] = 400000;
pGlobal_config[LL_EXT_ADV_RSC_SLOT_DURATION] = 10000;
pGlobal_config[LL_PRD_ADV_RSC_PERIOD] = 1000000;
pGlobal_config[LL_PRD_ADV_RSC_SLOT_DURATION] = 10000;
pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] = 150;
pGlobal_config[LL_PRD_ADV_PROCESS_TARGET] = 150;
if (g_system_clk == SYS_CLK_DLL_48M) {
pGlobal_config[EXT_ADV_AUXSCANRSP_DELAY_1MPHY] = 0xf;
pGlobal_config[EXT_ADV_AUXCONNRSP_DELAY_1MPHY] = 0xf;
pGlobal_config[EXT_ADV_AUXSCANRSP_DELAY_2MPHY] = 0xf;
pGlobal_config[EXT_ADV_AUXCONNRSP_DELAY_2MPHY] = 0xf;
pGlobal_config[EXT_ADV_AUXSCANRSP_DELAY_125KPHY] = 0x3f;
pGlobal_config[EXT_ADV_AUXCONNRSP_DELAY_125KPHY] = 0x3f;
}
}