1.目的
学习nrf51822主机和从机通信
2.分析
2个设备,一个做主机一个做从机,相互通信
3.平台:
协议栈版本:SDK10.0.0
编译软件:keil 5.12
硬件平台:nrf51822最小系统
例子: SDK10.0\examples\ble_peripheral\ble_app_hrs\pca10028\s110\arm4 从机例子
SDK10.0\examples\ble_central\ble_app_hrs_c\pca10028\s120 做主机
4.代码分析
上一篇文章是串口(nrf51822 --- 主从通信)主机的大概分析,上面只有一个服务以及一个服务下面有2个特征值。假如事件应用中有多个服务怎么办呢?接下来来分析,如何发现多个特征值的。以心率例子为例 SDK10.0\examples\ble_peripheral\ble_app_hrs\pca10028\s110\arm4
主函数了里面,红色方框,是初始化心率和电池的控制初始化。
hrs_c_init();主要完成收集回调函数,以及心率UUID类型初始化和以及发现回调函数的初始化过程
bas_c_init();主要完成收集回调函数,以及电池UUID类型初始化和以及发现回调函数的初始化过程
注意:这里都是在已知,从机已知特定服务,以及特征值的情况下的连接情况
这里注意m_num_of_handlers_reg这里是定义主服务控制的个数,DB_DISCOVERY_MAX_USERS红定义限制定义服务数
static uint32_t registered_handler_set(const ble_uuid_t * const p_srv_uuid, ble_db_discovery_evt_handler_t p_evt_handler) { if (m_num_of_handlers_reg < DB_DISCOVERY_MAX_USERS) { m_registered_handlers[m_num_of_handlers_reg].srv_uuid = *p_srv_uuid; m_registered_handlers[m_num_of_handlers_reg].evt_handler = p_evt_handler; m_num_of_handlers_reg++; return NRF_SUCCESS; } else { return NRF_ERROR_NO_MEM; } }
扫描的国产和(nrf51822 --- 主从通信)差不多,唯一不一样的是心率代码有绑定过程,开始找服务的函数在
发现服务后会产生case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:事件--->on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt)); -->err_code = characteristics_discover(p_db_discovery);发现特征值-->case BLE_GATTC_EVT_CHAR_DISC_RSP:-->on_characteristic_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));-->判断是否特征值已经全部发现或者特征值超过了预定义的个数
---> err_code = characteristics_discover(p_db_discovery);(开始扫描描述符)-->case BLE_GATTC_EVT_DESC_DISC_RSP:事件--> on_descriptor_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));(继续发现描述符,并且判断特征值已经全部发现或者特征值超过了预定义的个数)-->判断是否发现完毕①
if (raise_discov_complete)
{
DB_LOG("[DB]: Discovery of service with UUID 0x%x completed with success for Connection"
"handle %d\r\n", p_srv_being_discovered->srv_uuid.uuid,
p_db_discovery->conn_handle);
discovery_complete_evt_trigger(p_db_discovery, true);
on_srv_disc_completion(p_db_discovery);
}
这个发现完毕会产生对应的控制回调函数 discovery_complete_evt_trigger(p_db_discovery, true);,然后执行 on_srv_disc_completion(p_db_discovery);
这里面m_num_of_handlers_reg是刚才是注册时候的定义主服务控制的个数registered_handler_set();函数,一开始定义了心率和电池电量的服务控制2个,所以当第一次扫描完成的时候,if(true) 所以,sd_ble_gattc_primary_services_discover()函数继续 找服务。找完之后又会到这里,但是这里if(false)表示完成,发现服务完毕,如果没有完全发现完服务需要把把一些参数初始化。
注意:但是假如在不知道服务个数的情况怎么办呢?是不是m_num_of_handlers_reg要变大?
以及一次最多能发现多少个特征值呢?
static void on_srv_disc_completion(ble_db_discovery_t * p_db_discovery) { p_db_discovery->discoveries_count++; // Check if more services need to be discovered. if (p_db_discovery->discoveries_count < m_num_of_handlers_reg) { //重新发现服务以及特征值,需要把一些参数初始化, // Reset the current characteristic index since a new service discovery is about to start. p_db_discovery->curr_char_ind = 0; // Initiate discovery of the next service. p_db_discovery->curr_srv_ind++; //下一个服务的位置。也就是地址累加 ble_gatt_db_srv_t * p_srv_being_discovered; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind].srv_uuid; // Reset the characteristic count in the current service to zero since a new service // discovery is about to start. p_srv_being_discovered->char_count = 0; //特征值个数要清掉,重新发现 DB_LOG("[DB]: Starting discovery of service with UUID 0x%x for Connection handle %d\r\n", p_srv_being_discovered->srv_uuid.uuid, p_db_discovery->conn_handle); uint32_t err_code; err_code = sd_ble_gattc_primary_services_discover ( p_db_discovery->conn_handle, SRV_DISC_START_HANDLE, &(p_srv_being_discovered->srv_uuid) ); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; //SEGGER_RTT_printf(0,"error\r\n"); // Error with discovering the service. // Indicate the error to the registered user application. discovery_error_evt_trigger(p_db_discovery, err_code); return; } } else { // No more service discovery is needed. p_db_discovery->discovery_in_progress = false; } }
看下面回调函数,扫描完成了,可以得到服务特征值的个数,然后找到和BLE_UUID_HEART_RATE_MEASUREMENT_CHAR相当的位子,把CCCD和handle保存下来,因为值为BLE_UUID_HEART_RATE_MEASUREMENT_CHAR特征值具有notify的属性,需要主机使能notify,所以需要知道CCCD和handle(handle可以理解为扫描发现服务的地址,然后主机可以通过地址使能通道)
但是在实际应用中假如未知从机属性怎么办?可以通过UUID的属性值来保存Handle,如下:
if (p_evt->params.discovered_db.charateristics[i].characteristic.char_props.notify == 1)
{
//保存cccd和handle
// Found Heart Rate characteristic. Store CCCD handle and break.
mp_ble_hrs_c->hrm_cccd_handle =
p_evt->params.discovered_db.charateristics[i].cccd_handle;
mp_ble_hrs_c->hrm_handle =
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
}
假如,要知道wirte的属性的handle也可以通过上面的方法。。
static void db_discover_evt_handler(ble_db_discovery_evt_t * p_evt) { // Check if the Heart Rate Service was discovered. if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE && p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_HEART_RATE_SERVICE && p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE) { mp_ble_hrs_c->conn_handle = p_evt->conn_handle; // Find the CCCD Handle of the Heart Rate Measurement characteristic. uint32_t i; // for (i = 0; i < p_evt->params.discovered_db.char_count; i++) { //扫描到的特征值和定义的特征值相等的位子,然后把CCCD和handle保存下来, if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid == BLE_UUID_HEART_RATE_MEASUREMENT_CHAR) { // Found Heart Rate characteristic. Store CCCD handle and break. mp_ble_hrs_c->hrm_cccd_handle = p_evt->params.discovered_db.charateristics[i].cccd_handle; mp_ble_hrs_c->hrm_handle = p_evt->params.discovered_db.charateristics[i].characteristic.handle_value; break; } } LOG("[HRS_C]: Heart Rate Service discovered at peer.\r\n"); ble_hrs_c_evt_t evt; evt.evt_type = BLE_HRS_C_EVT_DISCOVERY_COMPLETE; mp_ble_hrs_c->evt_handler(mp_ble_hrs_c, &evt); } }