干货|BLE入门谈:从空中数据收发理解BLE(下)



NRF_RADIO->RXADDRESSES = 1; // enable address 0NRF_RADIO->FREQUENCY = 2; // 2402MHz, CH37NRF_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=2bitNRF_RADIO->PCNF0 = 0x00020106;// STATLEN=6, MAXLEN=37, BALEN=3, ENDIAN=0 (little), WHITEEN=1NRF_RADIO->PCNF1 = 0x02030025;NRF_RADIO->CRCCNF = 0x103; // only PDU, 3 octetsNRF_RADIO->CRCINIT = 0x555555; // for advertising packetNRF_RADIO->CRCPOLY = 0x100065b;// set receive bufferNRF_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);elseuart_wstr(".");if(NRF_RADIO->EVENTS_END)uart_wstr("!");while(! NRF_RADIO->EVENTS_END){}crcok1=NRF_RADIO->CRCSTATUS;NRF_RADIO->CRCINIT = 0x555555;// for advertising packetNRF_RADIO->PACKETPTR = (uint32_t)pkt_buf2;NRF_RADIO->EVENTS_END = 0;NRF_RADIO->TASKS_START = 1;if(crcok1)show_pkt(pkt_buf1);elseuart_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_INDuart_wstr("s");add_log(buf);break;case 0: // ADV_INDuart_wstr("A");add_log(buf);break;case 2: // ADV_NONCONN_INDuart_wstr("n");add_log(buf);break;case 4: // SCAN_RESPuart_wstr("R");break;case 1: // ADV_DIRECT_INDuart_wstr("i");break;case 3: // SCAN_REQuart_wstr("+");break;case 5: // CONN_REQuart_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 statetxpkt[0]=0x42;// private TX address, non-connectableif(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,// flags15,0x09,'A','D','V','_','D','e','m','o',' ','5','1','8','2','2'};radio_adv_tx(dummy_adv,sizeof(dummy_adv));

