因为以前做的IAP2协议主要是用USB或者uart来实现,自己本身对USB协议比较熟悉,但是对蓝牙协议完全不懂,也没接触过,蓝牙相比较USB就复杂很多了,我试着在蓝牙平台下也一点一点摸索也实现了IAP2协议的传输。
为什么要用蓝牙实现IAP2协议?
首先我想到了有以写几点,除过以下几点还有更多其他功能有待摸索。
- 通过IAP2协议可以提升蓝牙传输速率,因为苹果IOS与外部配件如果想实现透传,只能用BLE,但是BLE速率太慢,有些场景是无法满足的,比如打印机,这个时候就可以通过IAP2协议认证后,利用IAP2的EA传输,这个时候传输包长度可以到了680字节以上,而且可以直接透传,我实测速率可以达到1Mbit/s.
- 通过IAP2协议后可以自启动app,里面IAP2协议里面的app launch功能可以不用手动操作打开APP,这个也是国外某些产品有这种需求,比如蓝牙音响,回到家手机自动连接蓝牙音响后自动会打开spotify(类似QQ音乐播放器)播放音乐。
- 盲文显示器,通过IAP2协议后,可以传输盲文给外设。
以下我就记录一下我开发的全过程,除了IAP2源代码不会开放,其他任何环节都可以不保留的开放。
1. 环境平台
芯片:炬芯ATS285X
嵌入式系统:Zephyr OS
编译环境:window
SDK要求:必须有SPP的发送和接收接口可以正常使用。
2. 根据文档修改UUID
根据文档说明修改SDK的SPP部分的UUID。
下面展示一些 `内联代码片`。
/* SPP */
/* UUID: "00001101-0000-1000-8000-00805F9B34FB" */
//static const u8_t sppble_ota_spp_uuid[16] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00};
//static const u8_t sppble_ota_spp_uuid[16] = {0x00, 0x00, 0x00, 0x00, 0xde, 0xca, 0xfa, 0xde, 0xde, 0xca, 0xde, 0xaf, 0xde, 0xca, 0xca, 0xff};
static const u8_t sppble_ota_spp_uuid[16] = {0xff, 0xca, 0xca, 0xde, 0xaf, 0xde, 0xca, 0xde, 0xde, 0xfa, 0xca, 0xde, 0x00, 0x00, 0x00, 0x00};
接下来要实现接收函数,此函数主要作用是接收到数据后送入IAP2代码中进行解析并回复相应操作。
static u8_t read_buf[1024];
static void test_run_delaywork(os_work *work)
{
int ret;
//int i;
//static u8_t needacknext=0;
//static u8_t seqnum=0;
//static u8_t acknum=0;
//static u16_t PayloadLen;
//SYS_LOG_INF("test_run_delaywork*****************************\n");
if (sppble_stream && sppble_stream_opened) {
ret = stream_read(sppble_stream, read_buf, 1024);
if (ret > 6) {
SYS_LOG_INF("#######sppble_stream rx: %d sessionid %d\n", ret, read_buf[7]);
if(read_buf[0]==0xff&&read_buf[1]==0x5a&&read_buf[7]!=0x02){
// SYS_LOG_INF("DataReceive_process in\n");
DataReceive_process(read_buf,ret);
}else{
//SYS_LOG_INF("iAP2_Link_EA_SendACK in\n");
if(read_buf[0]==0xff&&read_buf[1]==0x5a){
iAP2_Link_EA_SendACK(read_buf[6], read_buf[5], read_buf[7]);
}
#if 0
if(needacknext){
SYS_LOG_INF("send ack2222\n");
iAP2_Link_EA_SendACK(seqnum, acknum, 2);
needacknext=0;
}
for(i=0;i<(ret-6);i++){
if(read_buf[i]==0xff&&read_buf[1+i]==0x5a){
PayloadLen = (UINT16)((read_buf[i+2] << 8) & 0xFF00);
PayloadLen |= (UINT16)(read_buf[i+3] & 0x00FF);
SYS_LOG_INF("send ack111 i=%d PayloadLen=%d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", i, PayloadLen, read_buf[i], read_buf[i+1], read_buf[i+2], read_buf[i+3], read_buf[i+4], read_buf[i+5]);
if((i+PayloadLen)<(ret+1)){
SYS_LOG_INF("send ack0000\n");
iAP2_Link_EA_SendACK(read_buf[6+i], read_buf[5+i], read_buf[7+i]);
}else{
needacknext=1;
seqnum = read_buf[6+i];
acknum = read_buf[5+i];
}
}
}
#endif
}
}else{
SYS_LOG_INF("DataReceive_process in\n");
DataReceive_process(read_buf,ret);
}
//SYS_LOG_INF("sppble_run_delaywork sssssss %d\n", ret);
//os_delayed_work_submit(&sppble_run_delaywork, 0);
os_delayed_work_submit_to_queue(&test_sppble_q, &sppble_run_delaywork, 0);
}
}
下面是发送数据的函数,在IAP2协议里面会调用此函数发送数据给ios.
下面展示一些 内联代码片
。
int iap_send(u8_t *buf, u32_t len)
{
printk("iap send data\n");
//print_buffer(buf, 1, len, 16, -1);
if (sppble_stream && sppble_stream_opened) {
printk("iap send data act\n");
stream_write(sppble_stream, buf, len);
}
return 0;
}
3. 测试通讯
在上面修改完成后,就要测试简单的数据通讯,其实原理上跟USB类似,首先要先测试收发数据正常,如果调这类功能多了后也就会有自己的调试流程,这个时候可以借助于PC工具,网上有很多PC工具可以测试这个功能,我找到的工具无法修改UUID,当时因为这个折腾了很久,后来原厂提供了一个他们自己工具就可以测试,其实就是外设通过SPP发送数据电脑可以收到,电脑发送数据,外设spp可以收到就达到目的了。
上图中都是根据sdk和上位机通讯测试结果简单展示,这一步通讯尤其重要,如果这一步不正常,是无法往下进行的。
4. 移植IAP2协议
有了上面的通讯接口,就可以移植我们的IAP2协议了,移植过程也比较轻松,因为类似USB的通讯一样。移植完成后,下面就是ATS抓数据,抓出来的数据全部蓝色没有飘红,还是很开心的。
5. 打通IAP2后
打通IAP2协议后可以做很多事情,我下面两个视频简单展示了一个传输速率和app自启动,盲文显示器功能正在研究中。
MFI蓝牙SPP传输IAP2协议和EA数据
MFI蓝牙SPP传输IAP2协议app launch自启动