send函数 获得已发送数据长度_蓝牙BLE开发1--起因与回调函数

6fbfea83664c1822c23d07af96109875.png

1 起因

笔者在开发蓝牙芯片CC2540,试图取实现大量数据的BLE透传功能,在认真学习了蓝牙4.0协议标准以及TI提供的SDK说明,我总结了两个发送函数,以及两个接收函数的位置。

两个发送函数包括

1 当我的设备处于主机角色的时候,发送数据给从机的函数,此时采用写特征值的方法。

void CC2541_send_as_central(uint8 * buf , uint16 len);

2 当我的设备处于从机角色的时候,发送数据采用notify方法

void CC2541_send_as_periph(uint8 * buf , uint16 len);

理所当然的可以将两个发送函数合并为

CC2541_send(role_t role , uint8* buf , uint16 len);

阅读TI提供的蓝牙协议栈函数,各种机制,函数回调非常复杂,但是通过网上其他人的文章我找到了插入位置。

两个接收的位置

1 做从机的时候,接收数据事件发生在profile里的特征值被修改后发生。

static void TRANSFERProfileChangeCB(uint8 paramID) {
 uint8 bBuf[20] = { 0 };        
uint8 rltByteNum=0;
//...省略部分
TRANSFERProfile_GetParameter(TRANSFERPROFILE_CHAR1, bBuf,&rltByteNum);
//通过get函数获得值修改后的特征值,存放在bBuf数组里
//在这里得知了获取的数据bBuf 以及长度 rltByteNum
}

2 做主机的时候,接收数据事件发生在GATT的MESSAGE事件中,因为作主机的时候,获得数据实际上就是得到了从机的notify。(从机给主机发数据采用notify,类似中断一样,强行告诉主机,我有数据发给你,主机还有一个read方法可以访问从机的数据,但是不是从机主动发起的)。

static void simpleBLECentralProcessGATTMsg(gattMsgEvent_t *pMsg) {
 //...函数里面包含了各种GATT的消息,通过判断pMsg->method来判断这是哪一种消息类型,很明显simpleBLECentralProcessGATTMsg函数是一个系统的回调函数,下文分享笔者对回调的理解,为文章简洁,仅复制相关代码
 
 else if ((pMsg->method == ATT_HANDLE_VALUE_NOTI)) {
 //检查profile Handle号,由BTools获得
  if (pMsg->msg.handleValueNoti.handle == 0x0025)  {
//获得的数据 pMsg->msg.handleValueNoti.value
//获得数据的长度是 pMsg->msg.handleValueNoti.len
  }
 }
 
}

笔者想实现的功能是 主从一体的蓝牙透传模块,数据由外部经过UART传入蓝牙芯片,蓝牙芯片通过调制蓝牙信号发送给另一个蓝牙芯片,另一个蓝牙芯片经过UART传给终端设备。

因此,笔者还得研究关于TI提供的UART工具。找到了一个发送函数,以及一个在回调函数中的接收位置。

发送函数

void NPI_WriteTransport(uint8* buffer , uint16 len);

接收位置

static void simpleBLE_NpiSerialCallback(uint8 port, uint8 events) {
 if (events & (HAL_UART_RX_TIMEOUT | HAL_UART_RX_FULL)){
  uint8 numBytes = 0;
  numBytes = NPI_RxBufLen();           //读出串口缓冲区有多少字节
  if (numBytes == 0) {
   return;
  } else{
   uint8 *buffer = osal_mem_alloc(numBytes);
   if (buffer){
                //数据指针是 buffer 长度是 numBytes
    osal_mem_free(buffer);
}
}
 }
}

回调函数的理解

如果你自己也经常使用函数指针,那么对回调应该很容易理解。

例如我自己是一个非常崇尚代码完美主义的人,我的main函数是这样写的,写的很漂亮。

int main(void){
mySystem_init();
Loop:
mySystem_handle();
User_handle();
goto Loop;
}

注意这里mySystem_handle 和 mySystem_init是我写的代码,User_handle是我预留给用户去写的!

这个main函数的结构就是由三块构成的,mySystem_init 和 mySystem_handle 以及User_handle ,类比蓝牙协议栈,mySystem_init和mySystem_handle实现了蓝牙协议栈的基本功能,我想绝大多数人是不愿意修改这部分代码的,因此不能动这部分代码。

TI的作者工程师也不希望你修改这段代码的代码结构!于是作者们会给你提供User_handle的入口给你。

例如 User_handle会这样写

typedef void * function_pointer(void);// 定义函数指针类型
function_pointer User_app;
void User_handle(){
User_app();
}
void register_user_app(function_pointer ){
User_app = function_pointer ;
}

这样一来,你可以使用register_user_app函数来修改主函数的执行内容,转到你配置的程序流中,但是不修改原有的工程运行结构。

BLE的协议栈很复杂,一般人不应当轻易的改变他的工程结构,所以TI的工程师们选择把回调函数放给开发者。

上文中的simpleBLECentralProcessGATTMsg等函数都是回调函数。

回调函数怎么传值?

还是以app_handle为例

typedef void * function_pointer(int);// 定义函数指针类型
function_pointer User_app;
void User_handle(){
User_app(100);
}
void register_user_app(function_pointer ){
User_app = function_pointer ;
}
void test_task(int a){
  printf(“得到的数 %d ”,a);
} 
//在主函数中注册
register_user_app(test_task);

运行原有工程结构后,test_task就获得了100这个值。

在BLE的SDK中大部分都是依靠这样的回调来进行传值,包括我之前总结的几个接收数据的位置!

现在遇到的问题是:

1 在回调函数中得到的数据不完整,举个例子来说,外部通过UART传进来的数据,不止一次的进入回调函数,每次进入回调函数获得的数据长度都不同,但是系统能保证的是不会少数据,但是每次进入的次数都不一样,这给最终的数据处理带来麻烦,因为最终数据处理肯定得是一个完整的包。

2 蓝牙发送速度与串口接受速度不一致,有快有慢,会出现数据覆盖的现象。

笔者采用两种方法解决这个问题,

1 通过超时判断

2 通过循环队列缓存

后面慢慢写自己解决问题的过程,分享解决的过程给大家

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值