fr8016 sdk协议栈开发-gatt

一、gatt协议

  通用属性配置文件协议(GATT)是在属性协议(ATT)之上构建的为传输的数据建立共同的操作规范,数据以ATT协议的形式存储。
  Gatt定义了两个角色:服务器和客户。 Gatt角色不一定与特定的角色有关,而是可以通过较高的profile指定。gatt和att不特定用于BR/EDR和LE的传输,但是,因为Gatt和ATT用于发现服务,在LE中是必须的。
  GATT server存储通过ATT协议传输的数据,以及接受来自的ATT协议的请求、命令和来自client的确认。GATT server发送对请求的响应,当被配置时,向client发送指示和异步通知。
  GATT Profile定义了数据传输的数据结构,如server(服务)、characteristic(特征),如下如所示,一个GATT Profile由一个或者多个server组成,每个server由一个或者多个characteristic组成,由于GATT是基于ATT协议的,组成数据的最基本单位是attribute,在attribute之上封装得到server和characteristic,我们读写的对象就是这些attribute。可以说,gatt编程,是对attribute的读写。
  gatt的server和attribute通过uuid唯一标识,SIG制定了不同行业应用的uuid标准,开发相应应用时,需满足这些标准,如心率检测的uuid是0x2A37。
fr8016 sdk协议栈开发-gatt_第1张图片

二、gatt server开发

  在ble应用中,角色分为中心设备和外设,中心设备一般是手机、笔记本电脑,连接中心设备的外围设备是外设(如键盘、鼠标、传感器),在gatt的角色划分中,外设一般作为server,中心设备作为client通过ATT协议访问外设的属性。
  fr8016的协议栈为用户提供了gatt_add_service用于注册服务,用户向协议栈注册属性表gatt_attribute_t和属性操作回调gatt_msg_handler_t,当对端设备发起读写请求时,协议栈会回调gatt_msg_handler,由用户处理对端的读写请求。

typedef struct
{
    const gatt_attribute_t  *p_att_tb;          //!< Service's attributes table to add to system attribute database. 
    uint8_t                 att_nb;             //!< Service's attributes number. 
    gatt_msg_handler_t      gatt_msg_handler;   //!< Read request callback function. 
} gatt_service_t;

  用户填充gatt_service_t结构体,调用gatt_add_service完成服务的注册,不需要关心协议的实现,只需要关心业务的处理。

三、ble应用-心率检测

进入components/ble/profile文件夹,可以看到很多profile的实现,现在以心率检测为例。

3.1 创建gatt server

调用gatt_add_service注册心率检测服务。

void hr_gatt_add_service(void)
{
	static gatt_service_t service;
	service.p_att_tb = heart_rate_att_table;
	service.att_nb = HEART_RATE_NB;
	service.gatt_msg_handler = hr_gatt_msg_handler;
	hr_svc_id = gatt_add_service(&service);
}

3.2 心率检测业务的服务、特征、属性

3.2.1 服务

示例profile提供了对BODY_SENSOR_LOCATION_VAL属性的读请求响应,向请求端返回位置数据,如下所示。

static void hr_gatt_read_cb(uint8_t* p_read,uint16_t * len,uint16_t att_idx)
{
	switch(att_idx)
	{
		case BODY_SENSOR_LOCATION_VAL:
			for(int i= 0;i < HR_SERVICE_DATA_VAL_LEN;i++)
				hr_bodysensor_vlaue[i] = hr_bodysensor_vlaue[0] + i + 1;
			memcpy(p_read,hr_bodysensor_vlaue,HR_SERVICE_DATA_VAL_LEN);
			*len = HR_SERVICE_DATA_VAL_LEN;
		default:
			break;
			
	}
}

示例profile提供了对HEARTRATE_CONTROL_POINT_VAL属性的写请求响应,接收client的控制信息,如下所示。

static void hr_gatt_write_cb(uint8_t *write_buf,uint16_t len,uint16_t att_idx)
{
	for(int i = 0; i < len; i++)
	{   
		co_printf(" HR Write request: len: %d, 0x%x \r\n", len, write_buf[i]);
	}
	if(att_idx == HEARTRATE_CONTROL_POINT_VAL)
			memcpy(hr_control_val,write_buf,len);
    
    uint16_t uuid = BUILD_UINT16(heart_rate_att_table[att_idx].uuid.p_uuid[0],heart_rate_att_table[att_idx].uuid.p_uuid[1]);
	if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
	{
		hr_measurement_buf[1] = write_buf[1];
	}
}

上面介绍了心率检测服务的读写请求,如下函数则是用户向协议栈注册的服务处理函数。

static uint16_t hr_gatt_msg_handler(gatt_msg_t *p_msg)
{
	switch(p_msg->msg_evt)
	{
		case GATTC_MSG_READ_REQ:
			hr_gatt_read_cb((uint8_t*)(p_msg->param.msg.p_msg_data ),&(p_msg->param.msg.msg_len),p_msg->att_idx);
			break;
		case GATTC_MSG_WRITE_REQ:
			hr_gatt_write_cb((uint8_t*)(p_msg->param.msg.p_msg_data),(p_msg->param.msg.msg_len),p_msg->att_idx);
			break;
		
		default:
			break;
	}
	
	return p_msg->param.msg.msg_len;
	
}

3.2.1 特征

HEART_RATE_SERVICE有三个characteristic:

  • HEART_RATE_MEASUREMENT:心率测量
  • BODY_SENSOR_LOCATION:位置
  • HEARTRATE_CONTROL_POINT:传感器控制

3.2.1 属性

属性表定义了心率检测服务提供给对端操作的属性,如下所示。

const gatt_attribute_t heart_rate_att_table[HEART_RATE_NB] = {
	//Simple gatt Service Declaration
	[HEART_RATE_SERVICE] = {
							{UUID_SIZE_2, UUID16_ARR(GATT_PRIMARY_SERVICE_UUID)},
							GATT_PROP_READ,
							UUID_SIZE_2,
							(uint8_t*)HtRt_svc_uuid,
							},
	//Characteristic 1 Declaration
	[HEART_RATE_MEASUREMENT_CHAR] = {
										{UUID_SIZE_2,UUID16_ARR(GATT_CHARACTER_UUID)},
										GATT_PROP_READ,
										0,
										NULL,
										},
	//Characteristic 1 value
	[HEART_RATE_MEASUREMENT_VAL]  = {
										{UUID_SIZE_2,UUID16_ARR(HEARTRATE_MEAS_UUID)},
										GATT_PROP_NOTI,
										HR_SERVICE_DATA_VAL_LEN,
										NULL,
										},
	//Characteristic 1 client configration
	[HEART_RATE_MENSUREMENT_CFG] =  {
										{UUID_SIZE_2,UUID16_ARR(GATT_CLIENT_CHAR_CFG_UUID)},
										GATT_PROP_READ | GATT_PROP_WRITE,
										0x02,
										NULL,
										},
	//Characteristic 1 Description
	[HEART_RATE_MENSUREMENT_DESC] = {
									    {UUID_SIZE_2,UUID16_ARR(GATT_CHAR_USER_DESC_UUID)},
										GATT_PROP_READ,
										HR_SERVICE_DATA_DESC_LEN,
										(uint8_t*)HEART_RATE_MENSUREMENT,
										},
										
	//Characteristic 2 Declaration
	[BODY_SENSOR_LOCATION_CHAR] = {
									{UUID_SIZE_2,UUID16_ARR(GATT_CHARACTER_UUID)},
									GATT_PROP_READ,
									0,
									NULL,
									},
	//Characteristic 2 value
	[BODY_SENSOR_LOCATION_VAL]  = {
									{UUID_SIZE_2,UUID16_ARR(BODY_SENSOR_LOC_UUID)},
									GATT_PROP_READ,
									HR_SERVICE_DATA_VAL_LEN,
									NULL,
									},
	//Characteristic 2 Desciption
	[BODY_SENSOR_LOCATION_DESC] = {
									{UUID_SIZE_2,UUID16_ARR(GATT_CHAR_USER_DESC_UUID)},
									GATT_PROP_READ,
									HR_SERVICE_DATA_DESC_LEN,
									(uint8_t*)BODY_SENSOR_LOCATION,
									},
	
	//Characteristic 3 Declation
	[HEARTRATE_CONTROL_POINT_CHAR] = {
										{UUID_SIZE_2,UUID16_ARR(GATT_CHARACTER_UUID)},
										GATT_PROP_READ,
										0,
										NULL,
										},
	//Characteristic 3 value
	[HEARTRATE_CONTROL_POINT_VAL] = {
										{UUID_SIZE_2,UUID16_ARR(HEARTRATE_CTRL_PT_UUID)},
										GATT_PROP_WRITE,
										HR_SERVICE_DATA_VAL_LEN,
										NULL,
										},
	//Characteristic 3 Description 
	[HEARTRATE_CONTROL_POINT_DESC] = {
										{UUID_SIZE_2,UUID16_ARR(GATT_CHAR_USER_DESC_UUID)},
										GATT_PROP_READ,
										HR_SERVICE_DATA_DESC_LEN,
										(uint8_t*)HEARTRATE_CONTROL_POINT,
										},
	
};

你可能感兴趣的:(蓝牙,单片机)