BLE4.0教程四新增特征值(CC2541)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

BLE4.0教程四新增特征值(CC2541)
注:(本⽂基于我⾃⼰定义的⼀个服务TEMProfile,但适⽤其他服务)
1.特征值是什么
⼀个蓝⽛协议栈中,包含了多个服务,⼀个服务⾥⼜包含了多个特征值,每个特征值都有其相关的⼀些信息。

我们与蓝⽛进⾏通信的时候,就是通过读写这些特征值,来获得数据。

2.特征值的属性
⼀个特征值⾥⾯基本需要的变量是——
1.UUID码
2.权限属性:基本就是可读、可写、可通知这些了。

(通知是表⽰允许数据主动发送)
3.内容
4.描述:这个特征值的名称
3.属性表
⼀个服务⾥,所有的特征值中的每个变量都有相应的属性,所有的属性都放在⼀个数组中,这个数组称之为属性表。


⼀个变量的属性表包含四个内容,
1.type
2.permission
3.handle
4.pValue
属性表其实就是定义了⼀个 gattAttribute_t类型的数组。

需要注意的是,属性表中,除了特征值的属性,第⼀个还要添加服务的属性
1//TEMProfile Service
2 {
3 {ATT_BT_UUID_SIZE,primaryServiceUUID}, //type
4 GATT_PERMIT_READ, //permissions
50, //handle
6 (uint8*)&TEMProfileService //pValue
7 },
4.增添⼀个新的特征值
(1)Define出配置属性的数值,⽤以填写配置属性。

1// Profile Parameters
2#define TEMPROFILE_CHAR1 0
3#define TEMPROFILE_CHAR2 1
4
5// Simple Profile Service UUID
6#define TEMPROFILE_SERV_UUID 0xFF00
7
8// Key Pressed UUID
9#define TEMPROFILE_CHAR1_UUID 0xFF01
10#define TEMPROFILE_CHAR2_UUID 0xFF02
11
12// Simple Keys Profile Services bit fields
13#define TEMPROFILE_SERVICE 0x00000001
14
15// Length of Characteristic 2 in bytes
16#define TEMPROFILE_CHAR2_LEN 12
其中UUID号有特定的范围,应避免与其他服务UUID冲突。

这⾥增添了两个特征值,特征值2是数组型的,所以需要定义⼀个长度TEMPROFILE_CHAR2_LEN。


 (2)定义每个特征值的属性变量(以特征值2为例)
1static uint8 TEMProfileChar2Prop = GATT_PROP_READ ;
2// TEM Profile char2 Value
3static uint8 TEMProfileChar2[TEMPROFILE_CHAR2_LEN] = {0};
4// TEM Profile char2 Description
5static uint8 TEMProfileChar2Desp[6]="Data\0";
配置权限,内容,描述。

 (3)由于属性表中的Value属性⽐较特殊,需要将其UUID号定义出来。

具体原因暂时不是很理解。

1 CONST uint8 TEMProfilechar2UUID[ATT_BT_UUID_SIZE]=
2 {
3 LO_UINT16(TEMPROFILE_CHAR2_UUID),HI_UINT16(TEMPROFILE_CHAR2_UUID)
4 };
 (4)填写属性表
1static gattAttribute_t TEMProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED]=
2 {
3//TEMProfile Service
4 {
5 {ATT_BT_UUID_SIZE,primaryServiceUUID}, //type
6 GATT_PERMIT_READ, //permissions
70, //handle
8 (uint8*)&TEMProfileService //pValue
9 },
10
11//char 1 Declaration
12 {
13 {ATT_BT_UUID_SIZE,characterUUID},
14 GATT_PERMIT_READ,
150,
16 &TEMProfileChar1Prop
17 },
18
19//char 1 Value
20 {
21 {ATT_BT_UUID_SIZE,TEMProfilechar1UUID}, // !! Attribue Value UUID need definition
22 GATT_PERMIT_READ | GATT_PERMIT_WRITE,
230,
24 &TEMProfileChar1
25 },
26
27//char 1 Description
28 {
29 {ATT_BT_UUID_SIZE,charUserDescUUID},
30 GATT_PERMIT_READ,
310,
32 TEMProfileChar1Desp
33 },
34
35//char 2 Declaration
36 {
37 {ATT_BT_UUID_SIZE,characterUUID},
38 GATT_PERMIT_READ,
390,
40 &TEMProfileChar2Prop
41 },
42
43//char 2 Value
44 {
45 {ATT_BT_UUID_SIZE,TEMProfilechar2UUID}, // !! Attribue Value UUID need definition
46 GATT_PERMIT_READ,
470,
48 TEMProfileChar2
49 },
50
51//char 2 Description
52 {
53 {ATT_BT_UUID_SIZE,charUserDescUUID},
54 GATT_PERMIT_READ,
550,
56 TEMProfileChar2Desp
57 },
58
59 };
注意: 这⾥每个属性都有⼀个权限属性(如GATT_PERMIT_READ),之前定义特征值时也有⼀个权限变量(如
GATT_PROP_WRITE) 两者作⽤对象不⼀样。

可以这样理解,每个特征值都是⼀个⼤宝箱,⾥⾯还有许多个⼩宝箱,要打开他们需要不同的钥匙。

⾄此,⼀个特征值的基本定义和声明就已经做完了。

但我们需要使⽤这个特征值,所以要在调⽤到特征值的函数中,添加上它。

(5)修改Get_Parameter函数和Set_Parameter函数、ReadAttrCB函数、WriteAttrCB函数
在服务中,基本是通过这四个函数对特征值进⾏读写。

后两个是回调函数。

在TEMProfile_SetParameter()函数中,新增⼀个case。

1 bStatus_t TEMProfile_SetParameter( uint8 param, uint8 len, void *value)
2 {
3 bStatus_t ret = SUCCESS;
4switch ( param )
5 {
6case TEMPROFILE_CHAR1 :
7if( len == sizeof(uint8) )
8 {
9 TEMProfileChar1 = *((uint8*)value);
10 }
11else
12 {
13 ret = bleInvalidRange;
14 }
15break;
16
17case TEMPROFILE_CHAR2 :
18if( len == TEMPROFILE_CHAR2_LEN )
19 {
20 VOID osal_memcpy( TEMProfileChar2, value, TEMPROFILE_CHAR2_LEN );
21 }
22else
23 {
24 ret = bleInvalidRange;
25 }
26break;
27
28default :
29 ret = INVALIDPARAMETER;
30break;
31 }
32
33return ret;
34
35 }
这是⼀个设置特征值内容的函数,参数param是特征值,len是内容的长度,value是新内容的地址。

以特征值2为例,先判断新内容的长度是否符合原先特征值定义的内容长度。

如果⼀致,则将新内容填写进⼊特征值的内容TEMProfileChar2。

TEMProfile_GetParameter()函数同理
1 bStatus_t TEMProfile_GetParameter( uint8 param, void *value)
2 {
3 bStatus_t ret = SUCCESS;
4switch ( param )
5 {
6case TEMPROFILE_CHAR1 :
7 *((uint8*)value) = TEMProfileChar1;
8break;
9
10case TEMPROFILE_CHAR2 :
11 VOID osal_memcpy( value, TEMProfileChar2, TEMPROFILE_CHAR2_LEN );
12break;
13
14default:
15 ret = INVALIDPARAMETER;
16break;
17 }
18
19return (ret);
20 }
然后是TEMProfile_WriteAttrCB()函数
1static bStatus_t TEMProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
2 uint8 *pValue, uint8 len, uint16 offset )
3 {
4 bStatus_t status = SUCCESS;
5 uint8 notifyApp = 0xFF;
6
7if ( gattPermitAuthorWrite( pAttr->permissions ) )
8 {
9return ( ATT_ERR_INSUFFICIENT_AUTHOR );
10 }
11
12if ( pAttr->type.len == ATT_BT_UUID_SIZE )
13 {
14 uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
15switch (uuid)
16 {
17case TEMPROFILE_CHAR1_UUID:
18
19if( offset == 0 )
20 {
21if( len != 1 )
22 {
23 status = ATT_ERR_INVALID_VALUE_SIZE;
24 }
25 }
26else
27 {
28 status = ATT_ERR_ATTR_NOT_LONG;
29 }
30
31
32if ( status == SUCCESS )
33 {
34 uint8 *pCurValue = (uint8 *)pAttr->pValue;
35 *pCurValue = pValue[0];
36 notifyApp = TEMPROFILE_CHAR1;
37 }
38
39break;
40
41default:
42 status = ATT_ERR_ATTR_NOT_FOUND;
43break;
44 }
45 }
46else
47 {
48 status = ATT_ERR_INVALID_HANDLE;
49 }
50
51if ( (notifyApp != 0xFF ) && TEMProfile_AppCBs && TEMProfile_AppCBs->pfnTEMProfileChange )
52 {
53 TEMProfile_AppCBs->pfnTEMProfileChange( notifyApp );
54 }
55
56return ( status );
57 }
以及ReadAttrCb函数
1static uint8 TEMProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
2 uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
3 {
4 bStatus_t status = SUCCESS;
5
6if( gattPermitAuthorRead( pAttr->permissions))
7 {
8return (ATT_ERR_INSUFFICIENT_AUTHOR);
9 }
10
11if( offset > 0)
12 {
13return (ATT_ERR_ATTR_NOT_LONG);
14 }
15
16if ( pAttr->type.len == ATT_BT_UUID_SIZE )
17 {
18 uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
19switch( uuid )
20 {
21//must have read permisson
22case TEMPROFILE_CHAR1_UUID:
23 *pLen =1;
24 pValue[0] = *pAttr->pValue;
25break;
26
27case TEMPROFILE_CHAR2_UUID:
28 *pLen = TEMPROFILE_CHAR2_LEN;
29 VOID osal_memcpy( pValue, pAttr->pValue, TEMPROFILE_CHAR2_LEN );
30break;
31
32default:
33 *pLen = 0;
34 status=ATT_ERR_ATTR_NOT_FOUND;
35break;
36 }
37 }
38else
39 {
40 *pLen = 0;
41 status=ATT_ERR_INVALID_HANDLE;
42 }
43
44return (status);
45
46 }
⾄此服务的特征值已经修改完,接下来需要去应⽤层进⾏设置。

(6)在SimpleBLEPeripheral_Init()函数中,初始化特征值。

1 uint8 TEMProfile_Char1Vaule=1;
2 uint8 TEMProfile_Char2Value[TEMPROFILE_CHAR2_LEN]="2017.03.11\0";
3 TEMProfile_SetParameter( TEMPROFILE_CHAR1, sizeof(uint8), &TEMProfile_Char1Vaule );
4 TEMProfile_SetParameter( TEMPROFILE_CHAR2, TEMPROFILE_CHAR2_LEN, TEMProfile_Char2Value );
(7)回调函数simpleProfileChangeCB( )中增添特征值。

该函数是当特征值改变时,即会被调⽤。

本例中,当特征值改变时,LCD上的数据也会随之改变。

1static void simpleProfileChangeCB( uint8 paramID )
2 {
3 uint8 newValue;
4
5switch( paramID )
6 {
7case SIMPLEPROFILE_CHAR1:
8 SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR1, &newValue );
9
10#if (defined HAL_LCD) && (HAL_LCD == TRUE)
11 HalLcdWriteStringValue( "Char 1:", (uint16)(newValue), 10, HAL_LCD_LINE_3 );
12#endif// (defined HAL_LCD) && (HAL_LCD == TRUE)
13
14break;
15
16case SIMPLEPROFILE_CHAR3:
17 SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR3, &newValue );
18
19#if (defined HAL_LCD) && (HAL_LCD == TRUE)
20 HalLcdWriteStringValue( "Char 3:", (uint16)(newValue), 10, HAL_LCD_LINE_3 );
21#endif// (defined HAL_LCD) && (HAL_LCD == TRUE)
22
23break;
24
25default:
26// should not reach here!
27break;
28 }
29 }
⾄此,特征值的新增即完成了。

APP中已可以发现这两个特征值。

相关文档
最新文档