这里实现的BLE广播包是基于上一章介绍的,我要通过2.4G来发出这个广播包
发包:获取到比特流后->加密->CRC->白化->发到空中
收包:空中数据->反白化->CRC校验->获取到比特流
BLE的广播是不用加密的,所以我们可以省略这一步
BLE广播包如下,这里并没有把前导码和接入地址实现到2.4G包中,道理是一样,大家可以自己实现。
所以,这里实现的包结构应该是这样,包最大为42个字节。
最终包结构是
代码1
/*[ 包头|总长度 |MAC1|2|3|4|5|6| 长度|类型|广播类型| 长度|类型|名字| |||||||||||||||]*/
static uint8_t _packet[42];
/*长度索引*/
static uint8_t _length = 0;
static uint8_t _dataFieldStartPoint = 0;
代码2
void setPhone(uint8_t phone_type) {
_packet[0] = phone_type;
}
setPhone(0x40);
代码3
void setMAC(uint8_t* address, uint8_t len) {
_length = 2;
_packet[_length++] = address[0];
_packet[_length++] = address[1];
_packet[_length++] = address[2];
_packet[_length++] = address[3];
_packet[_length++] = address[4];
_packet[_length++] = address[5];
_packet[_length++] = 2; //flag length
_packet[_length++] = 0x01; //data type
_packet[_length++] = 0x06; //actual flag
}
uint8_t address[] = { 0x4f,0x21,0xc1,0x41,0x26,0x50 };
setMAC(address,6);
代码4,这里用了点C++,问题不大,相信大家能懂。
还记得CRC的介绍吗? CRC 的移位寄存器一定需要初值的, 对于广播通道的 CRC 移位
寄存器的初始值为 0x55555。 而对于数据通道下的 CRC 初始值则是由主机发送连接请求时将 CRC 移位寄存器的初始值发送给从机,之后就一直使用这个值作为连接状态下的 CRC 移位寄存器的初始值。所以这里先设置CRC为0x555555。
void setData(const void* data, uint8_t dataLen) {
/*定位*/
_dataFieldStartPoint = _dataFieldStartPoint == 0 ? _length : _dataFieldStartPoint;
_length = _dataFieldStartPoint;
const uint8_t* current = reinterpret_cast(data);
/*长度*/
_packet[_length++] = dataLen + 1;
/*类型*/
_packet[_length++] = 0xFF;
/*复制进来*/
for (uint8_t i = 0; i < dataLen; i++) {
_packet[_length++] = *(current);
current++;
}
/*最后的CRC先补0x555555*/
_packet[_length++] = 0x55;
_packet[_length++] = 0x55;
_packet[_length++] = 0x55;
}
char data[] = {0x4c,0x00,0x10,0x02,0x07,0x08};
setData(data, 6);
这里,我们实现了2.4G的广播包,我们对比一下。
/*填充总长度 3个CRC 2个包头,所以减5*/
_packet[1] = _length - 5;
大家要记得,BLE是CRC24,生成项是
PS:我是每学习一次CRC就忘一次,我记不牢。代码如下,拿走不谢,现在我就忘了为什么这样写了
代码5
/*进行CRC,以LFSR的方式进行CRC*/
void BLEcrc(const uint8_t* data, uint8_t dataLen, uint8_t* outputCRC) {
// calculating the CRC based on a LFSR
uint8_t i, temp, tempData;
while (dataLen--) {
tempData = *data++;
for (i = 0; i < 8; i++, tempData >>= 1) {
temp = outputCRC[0] >> 7;
outputCRC[0] <<= 1;
if (outputCRC[1] & 0x80) { outputCRC[0] |= 1; }
outputCRC[1] <<= 1;
if (outputCRC[2] & 0x80) { outputCRC[1] |= 1; }
outputCRC[2] <<= 1;
if (temp != (tempData & 1)) {
outputCRC[2] ^= 0x5B;
outputCRC[1] ^= 0x06;
}
}
}
}
/*去掉CRC位*/
uint8_t i, dataLen = _length- 3;
BLEcrc(_packet, dataLen, packet + dataLen);
到目前为止,我们组的包都是小端模式的,可是CRC可是大端的噢
代码6
uint8_t reverseBits(uint8_t input) {
uint8_t temp = 0;
if (input & 0x80) temp |= 0x01;
if (input & 0x40) temp |= 0x02;
if (input & 0x20) temp |= 0x04;
if (input & 0x10) temp |= 0x08;
if (input & 0x08) temp |= 0x10;
if (input & 0x04) temp |= 0x20;
if (input & 0x02) temp |= 0x40;
if (input & 0x01) temp |= 0x80;
return temp;
}
//CRC大小端转换
for (i = 0; i < 3; i++, dataLen++)
_packet[dataLen] = reverseBits(_packet[dataLen]);
这里注意白化是不分广播状态或者是连接状态,它的移位寄存器的初始值为信道通道号,并且最高位一定置 1,也就是初始值的第7bit位一定是1。例如,广播通道 channel是37(0x25), 那么初始值就是 37。
代码7
uint8_t bleWhitenStart(uint8_t chan) {
//use left shifted one
//最高位一定要是1
return reverseBits(chan) | 2;
}
/*白化,LFSR的方式进行白化*/
void bleWhiten(uint8_t* data, uint8_t len, uint8_t whitenCoeff) {
// Implementing whitening with LFSR
uint8_t m;
while (len--) {
for (m = 1; m; m <<= 1) {
if (whitenCoeff & 0x80) {
whitenCoeff ^= 0x11;
(*data) ^= m;
}
whitenCoeff <<= 1;
}
data++;
}
}
bleWhiten(_packet, _length, bleWhitenStart(37));
比如现在是0xd6,11010110B;现在就要变为01101011
代码8
for (i = 0; i < len; i++)
packet[i] = reverseBits(packet[i]);
空中的包是先发_packet[0],再发_packet[1]
先发_packet[0]的bit8,再发bit7。
什么?你问我要源代码?嘻嘻不给。我要留着去赚积分