干貨|BLE入門談:從空中數(shù)據(jù)收發(fā)理解BLE(下)
NRF_RADIO->RXADDRESSES = 1; // enable address 0
NRF_RADIO->FREQUENCY = 2; // 2402MHz, CH37
NRF_RADIO->DATAWHITEIV = 37;
NRF_RADIO->MODE = (RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos);
NRF_RADIO->PREFIX0 = 0x8E;
NRF_RADIO->BASE0 = 0x89BED600;
// LFLEN=6 bits, S0LEN=1Byte, S1LEN=2bit
NRF_RADIO->PCNF0 = 0x00020106;
// STATLEN=6, MAXLEN=37, BALEN=3, ENDIAN=0 (little), WHITEEN=1
NRF_RADIO->PCNF1 = 0x02030025;
NRF_RADIO->CRCCNF = 0x103; // only PDU, 3 octets
NRF_RADIO->CRCINIT = 0x555555; // for advertising packet
NRF_RADIO->CRCPOLY = 0x100065b;
// set receive buffer
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf;
當收到END event時,表示收到了一個數(shù)據(jù)包(地址匹配有效),然后可以訪問CRCSTATUS寄存器判斷CRC校驗是否正確。若CRC有錯,可能是數(shù)據(jù)包被干擾破壞,或者格式不正確。接收數(shù)據(jù)包的S0、LENGTH、S1、PAYLOAD字段存放到RAM中,稍有變化的是LENGTH和S1字段都被擴展成了字節(jié)存儲。
我寫了一個循環(huán)來持續(xù)接收數(shù)據(jù)包,進行37信道的監(jiān)聽。使用雙緩沖區(qū)輪流存放收到的數(shù)據(jù)包,以便一邊解析數(shù)據(jù)一邊接收。
for(;;)
{
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf1;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->TASKS_START = 1;
if(crcok2)
show_pkt(pkt_buf2);
else
uart_wstr(".");
if(NRF_RADIO->EVENTS_END)
uart_wstr("!");
while(! NRF_RADIO->EVENTS_END)
{}
crcok1=NRF_RADIO->CRCSTATUS;
NRF_RADIO->CRCINIT = 0x555555; // for advertising packet
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf2;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->TASKS_START = 1;
if(crcok1)
show_pkt(pkt_buf1);
else
uart_wstr(".");
if(NRF_RADIO->EVENTS_END)
uart_wstr("!");
while(! NRF_RADIO->EVENTS_END)
{}
crcok2=NRF_RADIO->CRCSTATUS;
}
通過對PDU第一個字節(jié)的低4位,可以判斷數(shù)據(jù)包類型,然后識別余下數(shù)據(jù)。
static inline void show_pkt(volatile uint8_t *buf)
{
switch(buf[0]&0xF)
{
case 6: // ADV_SCAN_IND
uart_wstr("s");
add_log(buf);
break;
case 0: // ADV_IND
uart_wstr("A");
add_log(buf);
break;
case 2: // ADV_NONCONN_IND
uart_wstr("n");
add_log(buf);
break;
case 4: // SCAN_RESP
uart_wstr("R");
break;
case 1: // ADV_DIRECT_IND
uart_wstr("i");
break;
case 3: // SCAN_REQ
uart_wstr("+");
break;
case 5: // CONN_REQ
uart_wstr("C");
break;
default:
uart_wstr("?");
break;
}
}
如果是包含advertising數(shù)據(jù)的包,可以將地址、數(shù)據(jù)記錄下來,待收集一段時間后進行統(tǒng)計。
void add_log(uint8_t *buf)
{
int i;
for(i=0;i<32;i++)
{
if(adv_log.count) // not blank
{
if(memcmp(adv_log.addr, buf+3, 6)==0 && adv_log.type==buf[0]) // match
{
adv_log.count++;
return;
}
}
else // add entry
{
memcpy(adv_log.addr, buf+3, 6);
adv_log.type = buf[0];
adv_log.len = buf[1]-6;
memcpy(adv_log.payload, buf+9, adv_log.len);
adv_log.count=1;
return;
}
}
}
void radio_adv_tx(uint8_t *pdu, uint8_t len)
{
uint8_t txpkt[40];
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->TASKS_TXEN = 1;
while (NRF_RADIO->EVENTS_READY == 0);
// now in TXIDLE state
txpkt[0]=0x42; // private TX address, non-connectable
if(len>31)
len=31;
txpkt[1]=len+6;
txpkt[2]=0;
txpkt[3]=0x37; txpkt[4]=0x5A; txpkt[5]=0x29;
txpkt[6]=0xC6; txpkt[7]=0x8B; txpkt[8]=0x04;
memcpy(txpkt+9, pdu, len);
NRF_RADIO->PACKETPTR = (uint32_t)txpkt;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->TASKS_START = 1;
while(! NRF_RADIO->EVENTS_END)
{}
}
const uint8_t dummy_adv[]={0x02,0x01,0x06, // flags
15,0x09,'A','D','V','_','D','e','m','o',' ','5','1','8','2','2'};
radio_adv_tx(dummy_adv,sizeof(dummy_adv));
工程師必備
- 項目客服
- 培訓客服
- 平臺客服
TOP




















