一步步教您如何在DA14580 cust profile基础上实现大量notify的发送.docx
《一步步教您如何在DA14580 cust profile基础上实现大量notify的发送.docx》由会员分享,可在线阅读,更多相关《一步步教您如何在DA14580 cust profile基础上实现大量notify的发送.docx(22页珍藏版)》请在冰豆网上搜索。
一步步教您如何在DA14580custprofile基础上实现大量notify的发送
BDF001-一步步教您如何在DA14580custprofile基础上实现大量notify的发送
文档版本:
v0.0.1
本文主要介绍如何在DA14580SDK5.0.3的prox_reporter例子基础上添加custprofile,并最终利用notify给手机发送大量数据。
主要的内容分三个部分:
1.custprofile的添加;
2.connparamupdate代码添加;
3.大量Notify数据发送丢包严重问题缓解。
需要准备的工具:
1.DA14580开发板,或者其他可以运行代码的DA14580板子;
2.基本的软件开发环境,如Keil等;
3.支持BLE的手机或者其他平台。
以上工具是DA14580开发必备,如果没有,请自行XX相关资料解决。
准备工作完毕后,我们就可以开始了:
一、custprofile的添加。
首先我们来看看custprofile添加完毕后的结果,用lightblue搜索并与芯片建立连接后,会出现以下服务:
首先,我们打开prox_reporter工程,然后,添加custservice服务所必须文件到我们的工程中:
这几个文件分别在以下位置:
sdk\ble_stack\profiles\custom\custs\custs1.c
sdk\ble_stack\profiles\custom\custs\custs1_task.c
sdk\ble_stack\profiles\custom\custom_common.c
sdk\ble_stack\host\att\attm\attm_db_128.c
然后我们在prox_reporter\src\config文件夹中建立一个新文件user_custs_config.h并加入到工程中:
完毕后,我们在工程属性中加入一个宏定义,以便后续方便查找我们本次修改的代码,当然,你也可以不加此宏定义:
好了,现在开始我们添加代码。
首先打开user_proxr.c文件,并加入以下代码:
其中char_value我们用作存放read和write数据的地方,notify_timer作为发送notify的定时器。
在user_proxr.c文件的最后面,加入以下4个函数:
其中,user_app_on_connection用来定义连接建立后需要添加的代码;user_app_on_disconnect为连接断开后需要做的工作;user_on_db_init_complete为database初始化完毕后的接口函数;user_catch_rest_hndl我们用来处理由主机(可以是手机)往下发送的msg,这里我们用来处理CUSTS1_VAL_WRITE_IND请求。
我们来一步步添加每一个函数体:
Default_app_on_connection为系统默认的connection处理函数,我们保留它的所有功能,接下去我们开启notify_timer,利用的是app_easy_timer,这个函数是SDK5里面新的设置定时器的函数,如果用老的SDK,是没有这个函数的,可以利用其它的方法实现;函数的第一个参数1000,我们设置了定时器触发的时间为1000*10ms也就是10s,第二个参数notify_charactertistic_update为触发时调用的函数,一旦定时器到达10s,则会直接跳转到notify_charactertistic_update函数。
按照字面理解,此函数为disconnect处理函数,同样的道理,我们保留default_app_on_disconnect的所有功能,然后我们关闭之前开启的timer,因为连接端口后,再发送notify是没有任何意义的。
此函数只在database完成初始化后调用一次,这里我们设置了之前定义的char_value值到数据库中,以便主机发起read请求后能够得到有效数据。
此函数处理主机发送的消息,这里只处理CUSTS1_VAL_WRITE_IND,我们将得到的数据写入char_value,并用attmdb_att_set_value函数将数据更新到底层。
然后在user_app_on_connection上面添加timer回调函数:
此函数里面暂时只做一件事情:
开启一个10ms的定时器,回调函数是它自己,也就是说每10ms调用一次此函数。
后续我们会利用此函数来发送Notify,现在暂时留空。
好了,user_proxr.c文件的工作暂时结束,然后在user_proxr.h中添加函数声明:
接下去在user_profiles_config.h中添加代码:
修改user_config.h中的广播数据:
这个修改并不是必须的,没有这个系统也能正常工作,只是广播数据中少了custprofile信息,为了避免表里不一,还是建议修改一下吧。
刚才我们在user_proxr.c添加了user_app_on_connection、user_app_on_disconnect、user_on_db_init_complete和user_catch_rest_hndl,我们必须告诉系统我们要调用这些函数,而不是默认,所以我们需要修改user_callback_config.h:
添加头文件:
修改以下callback函数:
修改以下定义:
staticvoid(*constapp_process_catch_rest_cb)(ke_msg_id_tconstmsgid,voidconst*param,ke_task_id_tconstdest_id,ke_task_id_tconstsrc_id)=NULL;
为
staticvoid(*constapp_process_catch_rest_cb)(ke_msg_id_tconstmsgid,voidconst*param,ke_task_id_tconstdest_id,ke_task_id_tconstsrc_id)=(catch_rest_event_func_t)user_catch_rest_hndl;
修改完毕后我们需要编辑user_custs_config.h文件,这里代码有点多,我直接贴出来:
#ifndef_USER_CUSTS_CONFIG_H_
#define_USER_CUSTS_CONFIG_H_
#include
#include"prf_types.h"
#include"attm_db_128.h"
#include"app_prf_types.h"
#include"app_customs.h"
#defineDEF_CUST_SVC_UUID_128{0x2F,0x2A,0x93,0xA6,0xBD,0xD8,0x41,0x52,0xAC,0x0B,0x10,0x99,0x2E,0xC6,0xFE,0xED}
#defineDEF_CUST_WRITE_CHAR_UUID_128{0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F}
#defineDEF_CUST_READ_CHAR_UUID_128{0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F}
#defineDEF_CUST_NOTIFY_CHAR_UUID_128{0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F}
#defineDEF_CUST_CHAR_LEN20
#defineCUST_CHAR_USER_DESC"Custom"
///CUSTOMServiceDataBaseCharacteristicenum
enum
{
CUST_IDX_SVC=0,
CUST_IDX_WRITE_CHAR,
CUST_IDX_WRITE_CHAR_VAL,
CUST_IDX_READ_CHAR,
CUST_IDX_READ_CHAR_VAL,
CUST_IDX_NOTIFY_CHAR,
CUST_IDX_NOTIFY_CHAR_VAL,
CUST_IDX_NB,
};
staticconstuint8_tcustoms_att_max_size[CUST_IDX_NB]=
{
[CUST_IDX_SVC]=0,
[CUST_IDX_WRITE_CHAR]=0,
[CUST_IDX_WRITE_CHAR_VAL]=DEF_CUST_CHAR_LEN,
[CUST_IDX_READ_CHAR]=0,
[CUST_IDX_READ_CHAR_VAL]=DEF_CUST_CHAR_LEN,
[CUST_IDX_NOTIFY_CHAR]=0,
[CUST_IDX_NOTIFY_CHAR_VAL]=DEF_CUST_CHAR_LEN,
};
staticconstatt_svc_desc128_tcustom_svc=DEF_CUST_SVC_UUID_128;
staticuint8_tCUST_WRITE_CHAR_UUID_128[ATT_UUID_128_LEN]=DEF_CUST_WRITE_CHAR_UUID_128;
staticuint8_tCUST_READ_CHAR_UUID_128[ATT_UUID_128_LEN]=DEF_CUST_READ_CHAR_UUID_128;
staticuint8_tCUST_NOTIFY_CHAR_UUID_128[ATT_UUID_128_LEN]=DEF_CUST_NOTIFY_CHAR_UUID_128;
staticconststructatt_char128_desccustom_write_char={ATT_CHAR_PROP_WR,
{0,0},
DEF_CUST_WRITE_CHAR_UUID_128};
staticconststructatt_char128_desccustom_read_char={ATT_CHAR_PROP_RD,
{0,0},
DEF_CUST_READ_CHAR_UUID_128};
staticconststructatt_char128_desccustom_notify_char={ATT_CHAR_PROP_NTF|ATT_CHAR_PROP_RD,
{0,0},
DEF_CUST_NOTIFY_CHAR_UUID_128};
staticconstuint16_tatt_decl_svc=ATT_DECL_PRIMARY_SERVICE;
staticconstuint16_tatt_decl_char=ATT_DECL_CHARACTERISTIC;
staticconstuint16_tatt_decl_cfg=ATT_DESC_CLIENT_CHAR_CFG;
staticconstuint16_tatt_decl_user_desc=ATT_DESC_CHAR_USER_DESCRIPTION;
staticconststructattm_desc_128custs1_att_db[CUST_IDX_NB]=
{
//CUSTOMServiceDeclaration
[CUST_IDX_SVC]={(uint8_t*)&att_decl_svc,ATT_UUID_16_LEN,PERM(RD,ENABLE),
sizeof(custom_svc),sizeof(custom_svc),(uint8_t*)&custom_svc},
//CustomWriteCharacteristicDeclaration
[CUST_IDX_WRITE_CHAR]={(uint8_t*)&att_decl_char,ATT_UUID_16_LEN,PERM(RD,ENABLE),
sizeof(custom_write_char),sizeof(custom_write_char),(uint8_t*)&custom_write_char},
//CustomWriteCharacteristicValue
[CUST_IDX_WRITE_CHAR_VAL]={CUST_WRITE_CHAR_UUID_128,ATT_UUID_128_LEN,PERM(WR,ENABLE),
DEF_CUST_CHAR_LEN,0,NULL},
//CustomReadCharacteristicDeclaration
[CUST_IDX_READ_CHAR]={(uint8_t*)&att_decl_char,ATT_UUID_16_LEN,PERM(RD,ENABLE),
sizeof(custom_read_char),sizeof(custom_read_char),(uint8_t*)&custom_read_char},
//CustomReadCharacteristicValue
[CUST_IDX_READ_CHAR_VAL]={CUST_READ_CHAR_UUID_128,ATT_UUID_128_LEN,PERM(RD,ENABLE),
DEF_CUST_CHAR_LEN,0,NULL},
//CustomReadCharacteristicDeclaration
[CUST_IDX_NOTIFY_CHAR]={(uint8_t*)&att_decl_char,ATT_UUID_16_LEN,PERM(RD,ENABLE),
sizeof(custom_notify_char),sizeof(custom_notify_char),(uint8_t*)&custom_notify_char},
//CustomCharacteristicValue
[CUST_IDX_NOTIFY_CHAR_VAL]={CUST_NOTIFY_CHAR_UUID_128,ATT_UUID_128_LEN,PERM(RD,ENABLE)|PERM(NTF,ENABLE),
DEF_CUST_CHAR_LEN,0,NULL},
};
/*
*LOCALVARIABLES
****************************************************************************************
*/
///Custom1/2serverfunctioncallbacktable
staticconststructcust_prf_func_callbackscust_prf_funcs[]=
{
#if(BLE_CUSTOM1_SERVER)
{TASK_CUSTS1,
custs1_att_db,
CUST_IDX_NB,
#if(BLE_APP_PRESENT)
app_custs1_create_db,app_custs1_enable,
#else
NULL,NULL,
#endif
custs1_init,NULL
},
#endif
#if(BLE_CUSTOM2_SERVER)
{TASK_CUSTS2,
NULL,
0,
#if(BLE_APP_PRESENT)
app_custs2_create_db,app_custs2_enable,
#else
NULL,NULL,
#endif
custs2_init,NULL
},
#endif
{TASK_NONE,NULL,0,NULL,NULL,NULL,NULL},//DONOTMOVE.Mustalwaysbelast
};
///@}USER_CONFIG
#endif//_USER_CUSTS_CONFIG_H_
以上代码主要添加了CUST_IDX_WRITE_CHAR、CUST_IDX_READ_CHAR、CUST_IDX_NOTIFY_CHAR等属性,如果需要增加其他属性如Indication,则可以按照它的样子添加即可:
可以在上图中的CUST_IDX_NOTIFY_CHAR_VAL后面添加相关定义,这里就不展开说明了。
当然,不仅仅是上图的一个地方要添加,其他相关地方也需要。
全部添加完毕后,编译并烧录到芯片运行,应该就能实现一开始所描述的功能。
二、connparamupdate代码添加
由于本次测试需要将conninterval设置为最快7.5ms,所以,增加连接参数同步代码比较重要,本次修改都在user_proxr.c中进行:
首先在头部添加以下代码:
其中红框中的部分为连接参数,此参数IOS会毫无疑问拒绝同步,如果你测试的是ISO手机,则请修改为IOS支持的连接参数规则。
然后在文件最后加上以下代码:
最后在user_app_on_connection函数中添加timer启动函数,以便在每次连接建立后APP_PARAM_UPDT_TIMEOUT时间内发起参数同步请求:
到此,同步参数代码添加完成。
接下去我们来添加Notify发送代码,来测试Notify发送。
我们在user_proxr.c中定义以下两个变量:
data_buff为发送数据,p_data为发送指针,我们的目的是将data_buff[400]这个数据包通过20个notify发送出去,每个notify的长度为20.
我们在前面写的notify_charactertistic_update函数中添加以下发送代码:
该代码的意思是当p_data小于20时会往底层写入发送数据,大于20就停止写入,也就是分了20包将数据发送出去。
最后,我们为了能重复测试,在CUSTS1_VAL_WRITE_IND中加入p_data清零代码,以实现当手机给DA14580做任何写入操作时,会重新发送20个Notify,此代码仅仅是为了方便测试。
最后,增加宏定义:
好了,编译,运行,让我们看看效果。
从抓包的结果来看,很明显,丢了地14号的包。
看来这样直接发是不可靠的,那么问题来了,如何让Notify更可靠呢?
三、大量Notify数据发送丢包严重问题缓解
这一部分是本文的重点,像前面的直接用attmdb_att_set_value和prf_server_send_event两个函数往底层写入notify数据包的方法,在对付小量的数据时是可以的,但是,如果遇到大量的数据,则这样做很容易丢包(前面我们才发了20个包就发现了,那么发200个呢,2000个呢)。
现在我们来修改代码解决此问题:
这里我们要用到cust1profile中的一个函数进行发送--custs1_val_ntf_req_handler,它在custs1_task.c中。
我们通过调用此函数来发送我们的Notify数据,我们删除刚刚在notify_charactertistic_update添加的代码并增加以下代码:
这里我们看到两个新函数,cust1_ntf_send_not_complete和app_custs1_val_ntf_upd_chars。
cust1_ntf_send_not_complete是我们自定义的,当底层还未完全接受上一个notify包的时候,他会返回一个ture,当底层已经接受了所有的notify,则会返回一个false;app_custs1_val_ntf_upd_chars是我们新写的发送函数,在user_proxr.c中来添加它的函数体:
这个函数会给系统发送一个req,系统收到后会调用我们前面提到的custs1_val_ntf_req_handler。
接下去,我们要对SDK中的文件做一些修改,按照以下位置一步步修改:
代码添加完毕后,记得添加宏定义:
这里强调一下,强烈建议加上TK_CUST_TEST这个宏定义,因为以上修改的代码都是在SDK中公共部分修改的,这里改掉了,其他工程也会被修改掉,所以为了不让其他工程崩溃,还是建议加上!
全部添加完毕后,编译运行,丢包的现象应该会消失或者缓解,因为notify这个东西是没有反馈的,成功与否取决于很多因素。
为了方便大家调试,我会将此代码放在我的个人网站上(),用户可以去下载,如遇到访问密码,请尝试:
bdf0001snowywind
版本修改记录:
时间
版本
内容
修改者
2016.08.25
V0.0.1
文件创建