ble csdn用什么函数 接收设备发送的 notify-CSDN论坛

今天写的东西就深入一点了,是一个昆天科的定制协议的理解,即QPPS profile。这个profile用于手机与模块的透传,非常的实用,因为我们在BLE上使用最多的就是透传。
首先烧录程序,完成后用light blue查看服务。
在profile中只有一个服务,UUID为128位的UUID,但是可以转换为16位UUID:FEE9,在这个服务下包含有8个特征,其中第一个特征UUID为9600结尾的一个128位UUID,是用于接收APP发送的数据的特征,在APP端显示为可写的一个特征值。后面是7个用于发送数据到APP的特征值,特征值UUID后四位由9601递增至9607,一共有七个特征值。这个特征值的数目实际是可以修改的,可以改为1~7,在usr_config.h中有如下定义,更改QPPS_NOTIFY_NUM的数值就可以改变发送特征值的数目。
///Quintic private profile Role
#define CFG_PRF_QPPS
#define QPPS_NOTIFY_NUM
//#define CFG_TASK_QPPS
app向第一个特征值中写入数据,发送,则系统会调用到gatt_write_cmd_ind_handler函数处理APP端的操作命令。
static int gatt_write_cmd_ind_handler(ke_msg_id_t const msgid,
struct gatt_write_cmd_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
uint8_t status = PRF_ERR_OK;
if (param-&conhdl == qpps_env.conhdl)
// Client Char. Configuration
uint8_t char_index = param-&handle - (qpps_env.shdl + QPPS_IDX_VAL_NTF_CFG);
if ((param-&handle & (qpps_env.shdl + QPPS_IDX_VAL_CHAR)) && ((char_index % 3) == 0))
uint16_t value = 0x0000;
//Extract value before check
memcpy(&value, &(param-&value), sizeof(uint16_t));
if ((value == PRF_CLI_STOP_NTFIND) || (value == PRF_CLI_START_NTF))
if (value == PRF_CLI_STOP_NTFIND)
qpps_env.features &= ~(QPPS_VALUE_NTF_CFG && (char_index / 3));
else //PRF_CLI_START_NTF
qpps_env.features |= QPPS_VALUE_NTF_CFG && (char_index / 3);
status = PRF_APP_ERROR;
if (status == PRF_ERR_OK)
uint8_t *old_
atts_size_
attsdb_att_get_value(param-&handle, &length, &old_value);
if (value != co_read16p(old_value))
//Update the attribute value
attsdb_att_set_value(param-&handle, sizeof(uint16_t), (uint8_t *)&value);
if(param-&last)
//Inform APP of configuration change
struct qpps_cfg_indntf_ind * ind = KE_MSG_ALLOC(QPPS_CFG_INDNTF_IND,
qpps_env.appid, TASK_QPPS,
qpps_cfg_indntf_ind);
ind-&char_index = (char_index / 3);
memcpy(&ind-&cfg_val, &value, sizeof(uint16_t));
ke_msg_send(ind);
else if (param-&handle == (qpps_env.shdl + QPPS_IDX_RX_DATA_VAL))
if (param-&length &= QPP_DATA_MAX_LEN)
//inform APP of configuration change
struct qpps_data_val_ind * ind = KE_MSG_ALLOC_DYN(QPPS_DAVA_VAL_IND,
qpps_env.appid,
TASK_QPPS,
qpps_data_val_ind, param-&length);
memcpy(&ind-&conhdl, &(qpps_env.conhdl), sizeof(uint16_t));
//Send received data to app value
ind-&length = param-&
memcpy(ind-&data, param-&value, param-&length);
ke_msg_send(ind);
status = QPPS_ERR_RX_DATA_EXCEED_MAX_LENGTH;
status = QPPS_ERR_INVALID_PARAM;
if (param-&response)
//Send write response
atts_write_rsp_send(qpps_env.conhdl, param-&handle, status);
return (KE_MSG_CONSUMED);
由于app对特征&#的写入操作实际上是对特征中QPPS_IDX_RX_DATA_VAL一值进行了写入操作,所以函数中以下代码就是经过了一系列的接收操作后,我们能在程序中看到的第一入口。程序中构建了一条标识为QPPS_DAVA_VAL_IND的消息,在信息中填入了从app处获取到的写入内容。
if (param-&handle == (qpps_env.shdl + QPPS_IDX_RX_DATA_VAL))
if (param-&length &= QPP_DATA_MAX_LEN)
//inform APP of configuration change
struct qpps_data_val_ind * ind = KE_MSG_ALLOC_DYN(QPPS_DAVA_VAL_IND,
qpps_env.appid,
TASK_QPPS,
qpps_data_val_ind, param-&length);
memcpy(&ind-&conhdl, &(qpps_env.conhdl), sizeof(uint16_t));
//Send received data to app value
ind-&length = param-&
memcpy(ind-&data, param-&value, param-&length);
ke_msg_send(ind);
status = QPPS_ERR_RX_DATA_EXCEED_MAX_LENGTH;
status = QPPS_ERR_INVALID_PARAM;
通过查看QPPS_DAVA_VAL_IND,得知该消息处理函数为app_qpps_data_ind_handler。根据函数描述,app发送数据到开发板后,会在串口中输出数据,打开串口,设置好波特率(9600),可以看到app端发送数据的字节长度和第一个数据的16进制。如果需要取出完整数据,根据param-&length把param-&data数组的数据都取出来,就是完整的数据了。
int app_qpps_data_ind_handler(ke_msg_id_t const msgid,
struct qpps_data_val_ind *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
if (param-&length & 0)
QPRINTF(&len=%d, I%02X&, param-&length, param-&data[0]);
QPRINTF(&\r\n&);
return (KE_MSG_CONSUMED);
对于发送数据,昆天科做了一个很有意思的算法,让app在配置完所有的notify后持续发送递增数据到每一个发送特征值中,所以开启这个发送的办法在与打开所有的notify。我们看一下打开notify的操作,这个操作会触发gatt_write_cmd_ind_handler处理函数,代码片如下:
uint8_t char_index = param-&handle - (qpps_env.shdl + QPPS_IDX_VAL_NTF_CFG);
if ((param-&handle & (qpps_env.shdl + QPPS_IDX_VAL_CHAR)) && ((char_index % 3) == 0))
uint16_t value = 0x0000;
//Extract value before check
memcpy(&value, &(param-&value), sizeof(uint16_t));
if ((value == PRF_CLI_STOP_NTFIND) || (value == PRF_CLI_START_NTF))
if (value == PRF_CLI_STOP_NTFIND)
qpps_env.features &= ~(QPPS_VALUE_NTF_CFG && (char_index / 3));
else //PRF_CLI_START_NTF
qpps_env.features |= QPPS_VALUE_NTF_CFG && (char_index / 3);
status = PRF_APP_ERROR;
if (status == PRF_ERR_OK)
uint8_t *old_
atts_size_
attsdb_att_get_value(param-&handle, &length, &old_value);
if (value != co_read16p(old_value))
//Update the attribute value
attsdb_att_set_value(param-&handle, sizeof(uint16_t), (uint8_t *)&value);
if(param-&last)
//Inform APP of configuration change
struct qpps_cfg_indntf_ind * ind = KE_MSG_ALLOC(QPPS_CFG_INDNTF_IND,
qpps_env.appid, TASK_QPPS,
qpps_cfg_indntf_ind);
ind-&char_index = (char_index / 3);
memcpy(&ind-&cfg_val, &value, sizeof(uint16_t));
ke_msg_send(ind);
当app开启notify的时候,会带来一个value,value代表着是开启还是关闭notify,所以首先要进行判断是哪一个特征中开启或者关闭了notify,然后判断是否需要进行开启和关闭操作(检查之前状态是否与当前操作冲突),如果需要开启或者关闭,则会发出一个标识为QPPS_CFG_INDNTF_IND的消息,消息中填入了操作的特征序号和值。
消息QPPS_CFG_INDNTF_IND的处理函数为app_qpps_cfg_indntf_ind_handler,此消息为指示性消息,notify已经在刚才 的处理中开启,所以本函数主要任务是指示了哪一个消息被开启或关闭,在判断所有的notify被开启后,函数调用了另一个函数app_test_send_data(app_qpps_env-&tx_char_num - 1);,发送数据到七个特征值去。
int app_qpps_cfg_indntf_ind_handler(ke_msg_id_t const msgid,
struct qpps_cfg_indntf_ind *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
if (app_qpps_env-&conhdl == param-&conhdl)
if (param-&cfg_val == PRF_CLI_START_NTF)
QPRINTF(&param-&char_index %d\r\n&,param-&char_index);
app_qpps_env-&features |= (QPPS_VALUE_NTF_CFG && param-&char_index);
// App send data if all of characteristic have been configured
QPRINTF(&app_qpps_env-&features 0x%X : 0x%X \r\n&,app_qpps_env-&features,app_qpps_env-&tx_char_num);
if (get_bit_num(app_qpps_env-&features) == app_qpps_env-&tx_char_num)
app_qpps_env-&char_status = app_qpps_env-&
app_test_send_data(app_qpps_env-&tx_char_num - 1);
app_qpps_env-&features &= ~(QPPS_VALUE_NTF_CFG && param-&char_index);
app_qpps_env-&char_status &= ~(QPPS_VALUE_NTF_CFG && param-&char_index);
return (KE_MSG_CONSUMED);
函数通过对cnt计数和一些条件判断,对特征值依次发送数据。
static void app_test_send_data(uint8_t max)
for (cnt = 0; (max != 0) && cnt & app_qpps_env-&tx_char_ cnt++)
if ((app_qpps_env-&char_status && cnt) & QPPS_VALUE_NTF_CFG)
static uint8_t val[] = {0, '0', '1', '2','3','4','5','6','7','8','9','8','7','6','5','4','3','2','1','0'};
// Increment the first byte for test
// Allow next notify until confirmation received in this characteristic
app_qpps_env-&char_status &= ~(QPPS_VALUE_NTF_CFG && cnt);
app_qpps_data_send(app_qpps_env-&conhdl, cnt, sizeof(val), val);
QPRINTF(&send to cnt:%d,max %d\r\n&,cnt,max);
QPRINTF(&app_qpps_env-&char_status: %X\r\n&,app_qpps_env-&char_status);
发送数据完成,系统会发出QPPS_DATA_SEND_CFM消息作为响应,于是在消息对应的处理函数app_qpps_data_send_cfm_handler中,再次发起消息发送。
int app_qpps_data_send_cfm_handler(ke_msg_id_t const msgid,
struct qpps_data_send_cfm *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
if (app_qpps_env-&conhdl == param-&conhdl && param-&status == PRF_ERR_OK)
// Allow new notify
app_qpps_env-&char_status |= (1 && param-&char_index);
QPRINTF(&app_qpps_env-&char_status %X\r\n&,app_qpps_env-&char_status);
// Send next group data until current data have been sent
if (get_bit_num(app_qpps_env-&char_status) == (app_qpps_env-&tx_char_num - 1))
QPRINTF(&t:app_qpps_env-&char_status %X\r\n&,app_qpps_env-&char_status);
app_test_send_data(app_qpps_env-&tx_char_num - 1);
QPRINTF(&QPPS send error %d.\r\n&, param-&status);
return (KE_MSG_CONSUMED);
探讨:如果仔细观察,可以发现,从第一次发送的数据分别是以01、02、03、...、06开头的,而07却再次回到了9601,接下来08、09、...、0c,0c发送在9607的特征上,9606并没有观察到发送的数据。也就是第一次循环的时候9607没有参与到发送循环中,而第二次发送时,9606没有参与到循环中,如此重复。这是为什么呢?
版权声明:本文为博主原创文章,未经博主允许不得转载。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:568次
排名:千里之外模态对话框如何发送消息到父窗口,WM_PARENTNOTIFY可以用么
[问题点数:40分,无满意结帖,结帖人ZhanYan4S]
模态对话框如何发送消息到父窗口,WM_PARENTNOTIFY可以用么
[问题点数:40分,无满意结帖,结帖人ZhanYan4S]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。&&& 代码实例:Board/pca s110/experimental/ble_app_uart。
&&& 实现的功能是从uart口发送数据至另一个蓝牙串口,或是从蓝牙读取数据通过uart打印出数据。
int main(void)
// Initialize
leds_init();
timers_init();
buttons_init();
uart_init();
ble_stack_init();
gap_params_init();
services_init();
advertising_init();
conn_params_init();
sec_params_init();
simple_uart_putstring(START_STRING);
advertising_start();
// Enter main loop
power_manage();
uart_init初始化uart的硬件。
当uart有数据时会进入uart中断处理:
Function for handling UART interrupts.
* @details This function will receive a single character from the UART and append it to a string.
The string will be be sent over BLE when the last character received was a 'new line'
i.e '\n' (hex 0x0D) or if the string has reached a length of @ref NUS_MAX_DATA_LENGTH.
void UART0_IRQHandler(void)
static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
static uint8_t index = 0;
uint32_t err_
/**@snippet [Handling the data received over UART] */
data_array[index] = simple_uart_get();
if ((data_array[index - 1] == '\n') || (index &= (BLE_NUS_MAX_DATA_LEN - 1)))
err_code = ble_nus_send_string(&m_nus, data_array, index + 1);
if (err_code != NRF_ERROR_INVALID_STATE)
APP_ERROR_CHECK(err_code);
index = 0;
/**@snippet [Handling the data received over UART] */
data_array是数据缓冲区,当一个接收到换行符时认为是输入结束,或是达到缓冲区的最大字节数。
ble_nus_send_string函数即是把uart输入的数据通过蓝牙发送。
此实例中建立了一个服务:
/**@brief Function for initializing services that will be used by the application.
static void services_init(void)
ble_nus_init_t
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code);
uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
ble_uuid_t
ble_uuid128_t
nus_base_uuid = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0,
0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E};
if ((p_nus == NULL) || (p_nus_init == NULL))
return NRF_ERROR_NULL;
// Initialize service structure.
p_nus-&conn_handle
= BLE_CONN_HANDLE_INVALID;
p_nus-&data_handler
= p_nus_init-&data_
p_nus-&is_notification_enabled
/**@snippet [Adding proprietary Service to S110 SoftDevice] */
// Add custom base UUID.
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus-&uuid_type);
if (err_code != NRF_SUCCESS)
return err_
ble_uuid.type = p_nus-&uuid_
ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
// Add service.
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_nus-&service_handle);
/**@snippet [Adding proprietary Service to S110 SoftDevice] */
if (err_code != NRF_SUCCESS)
return err_
// Add RX Characteristic.
err_code = rx_char_add(p_nus, p_nus_init);
if (err_code != NRF_SUCCESS)
return err_
// Add TX Characteristic.
err_code = tx_char_add(p_nus, p_nus_init);
if (err_code != NRF_SUCCESS)
return err_
return NRF_SUCCESS;
rx_char_add()添加了接收特性,tx_char_add()添加了发送特性。
当从蓝牙接收到数据时,通过串口将数据打印出来:
Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
* @param[in] p_dfu
Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt-&evt.gatts_evt.params.
(p_evt_write-&handle == p_nus-&rx_handles.cccd_handle)
(p_evt_write-&len == 2)
if (ble_srv_is_notification_enabled(p_evt_write-&data))
p_nus-&is_notification_enabled =
p_nus-&is_notification_enabled =
(p_evt_write-&handle == p_nus-&tx_handles.value_handle)
(p_nus-&data_handler != NULL)
p_nus-&data_handler(p_nus, p_evt_write-&data, p_evt_write-&len);
// Do Nothing. This event is not relevant to this service.
版权声明:本文为博主原创文章,未经博主允许不得转载。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:634671次
积分:8479
积分:8479
排名:第998名
原创:173篇
转载:105篇
评论:206条
(7)(4)(5)(3)(1)(4)(4)(4)(3)(2)(4)(2)(7)(4)(23)(11)(5)(2)(8)(1)(3)(1)(4)(3)(1)(13)(35)(20)(5)(2)(1)(2)(1)(1)(4)(1)(3)(4)(10)(17)(1)(1)(3)(3)(1)(7)(2)(6)(1)(1)(10)(7)(2)(1)(2)(3)(2)(1)(2)(6)(3)(3)(1)(1)(2)(5)(1)(2)BLE 用什么函数 接收设备发送的 notify
[问题点数:40分,无满意结帖,结帖人dengchonglin]
BLE 用什么函数 接收设备发送的 notify
[问题点数:40分,无满意结帖,结帖人dengchonglin]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。关于用nexus 4 开发BLE应用过程,有时候会出现连接蓝牙设备时连不上,除非在设置里把蓝牙关调再重新打开蓝牙,然后再连设备才能连接,这是什么问题?
[问题点数:40分]
关于用nexus 4 开发BLE应用过程,有时候会出现连接蓝牙设备时连不上,除非在设置里把蓝牙关调再重新打开蓝牙,然后再连设备才能连接,这是什么问题?
[问题点数:40分]
只显示楼主
取消只显示楼主
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。

我要回帖

更多关于 ble接收数据 的文章

 

随机推荐