干货|BLE入门谈:从空中数据收发理解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时,表示收到了一个数据包(地址匹配有效),然后可以访问CRCSTATUS寄存器判断CRC校验是否正确。若CRC有错,可能是数据包被干扰破坏,或者格式不正确。接收数据包的S0、LENGTH、S1、PAYLOAD字段存放到RAM中,稍有变化的是LENGTH和S1字段都被扩展成了字节存储。
我写了一个循环来持续接收数据包,进行37信道的监听。使用双缓冲区轮流存放收到的数据包,以便一边解析数据一边接收。
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第一个字节的低4位,可以判断数据包类型,然后识别余下数据。
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数据的包,可以将地址、数据记录下来,待收集一段时间后进行统计。
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));