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
5     0,                                        //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为例)

 

1 static  uint8 TEMProfileChar2Prop = GATT_PROP_READ ;
2 // TEM Profile char2 Value
3 static  uint8 TEMProfileChar2[TEMPROFILE_CHAR2_LEN] = {0};
4 // TEM Profile char2 Description
5 static  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)填写属性表

 1 static gattAttribute_t  TEMProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED]=
 2 {
 3   //TEMProfile Service
 4   {
 5     {ATT_BT_UUID_SIZE,primaryServiceUUID},   //type
 6     GATT_PERMIT_READ,                        //permissions
 7     0,                                       //handle
 8     (uint8*)&TEMProfileService              //pValue
 9   },
10
11   //char 1 Declaration
12   {
13     {ATT_BT_UUID_SIZE,characterUUID},
14     GATT_PERMIT_READ,
15     0,
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,
23     0,
24     &TEMProfileChar1
25   },
26
27   //char 1 Description
28    {
29     {ATT_BT_UUID_SIZE,charUserDescUUID},
30     GATT_PERMIT_READ,
31     0,
32     TEMProfileChar1Desp
33   },
34
35   //char 2 Declaration
36   {
37     {ATT_BT_UUID_SIZE,characterUUID},
38     GATT_PERMIT_READ,
39     0,
40     &TEMProfileChar2Prop
41   },
42
43   //char 2 Value
44   {
45     {ATT_BT_UUID_SIZE,TEMProfilechar2UUID},   // !! Attribue Value UUID need definition
46     GATT_PERMIT_READ,
47     0,
48     TEMProfileChar2
49   },
50
51   //char 2 Description
52     {
53     {ATT_BT_UUID_SIZE,charUserDescUUID},
54     GATT_PERMIT_READ,
55     0,
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;
 4   switch  ( param )
 5   {
 6     case TEMPROFILE_CHAR1 :
 7       if( len == sizeof(uint8)  )
 8       {
 9         TEMProfileChar1 = *((uint8*)value);
10       }
11       else
12       {
13         ret = bleInvalidRange;
14       }
15       break;
16
17     case TEMPROFILE_CHAR2 :
18       if( len == TEMPROFILE_CHAR2_LEN )
19       {
20          VOID osal_memcpy( TEMProfileChar2, value, TEMPROFILE_CHAR2_LEN );
21       }
22       else
23       {
24         ret = bleInvalidRange;
25       }
26       break;
27
28     default  :
29       ret = INVALIDPARAMETER;
30       break;
31   }
32
33   return 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;
 4   switch  ( param )
 5   {
 6   case TEMPROFILE_CHAR1 :
 7     *((uint8*)value)  = TEMProfileChar1;
 8     break;
 9
10   case TEMPROFILE_CHAR2 :
11     VOID osal_memcpy( value, TEMProfileChar2, TEMPROFILE_CHAR2_LEN );
12     break;
13
14   default:
15     ret = INVALIDPARAMETER;
16     break;
17   }
18
19   return  (ret);
20 }

然后是TEMProfile_WriteAttrCB()函数

 1 static  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
 7    if  ( gattPermitAuthorWrite( pAttr->permissions ) )
 8    {
 9       return ( ATT_ERR_INSUFFICIENT_AUTHOR );
10    }
11
12    if ( pAttr->type.len == ATT_BT_UUID_SIZE )
13    {
14       uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
15       switch  (uuid)
16       {
17          case TEMPROFILE_CHAR1_UUID:
18
19            if( offset  ==  0 )
20            {
21                if( len !=  1 )
22                {
23                   status = ATT_ERR_INVALID_VALUE_SIZE;
24                }
25            }
26            else
27            {
28              status = ATT_ERR_ATTR_NOT_LONG;
29            }
30
31
32             if ( status == SUCCESS )
33             {
34               uint8 *pCurValue = (uint8 *)pAttr->pValue;
35               *pCurValue = pValue[0];
36               notifyApp = TEMPROFILE_CHAR1;
37             }
38
39          break;
40
41          default:
42             status = ATT_ERR_ATTR_NOT_FOUND;
43          break;
44        }
45     }
46     else
47     {
48       status = ATT_ERR_INVALID_HANDLE;
49     }
50
51   if ( (notifyApp != 0xFF ) && TEMProfile_AppCBs && TEMProfile_AppCBs->pfnTEMProfileChange )
52   {
53     TEMProfile_AppCBs->pfnTEMProfileChange( notifyApp );
54   }
55
56   return ( status );
57 }

以及ReadAttrCb函数

 1 static  uint8 TEMProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
 2                                     uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
 3 {
 4   bStatus_t status  = SUCCESS;
 5
 6   if( gattPermitAuthorRead( pAttr->permissions))
 7   {
 8     return  (ATT_ERR_INSUFFICIENT_AUTHOR);
 9   }
10
11   if( offset  > 0)
12   {
13     return  (ATT_ERR_ATTR_NOT_LONG);
14   }
15
16   if ( pAttr->type.len == ATT_BT_UUID_SIZE )
17   {
18     uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
19     switch( uuid )
20     {
21       //must have read permisson
22     case TEMPROFILE_CHAR1_UUID:
23         *pLen =1;
24         pValue[0] = *pAttr->pValue;
25         break;
26
27     case TEMPROFILE_CHAR2_UUID:
28         *pLen = TEMPROFILE_CHAR2_LEN;
29         VOID osal_memcpy( pValue, pAttr->pValue, TEMPROFILE_CHAR2_LEN );
30         break;
31
32     default:
33         *pLen = 0;
34         status=ATT_ERR_ATTR_NOT_FOUND;
35         break;
36     }
37   }
38   else
39   {
40     *pLen = 0;
41     status=ATT_ERR_INVALID_HANDLE;
42   }
43
44     return  (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上的数据也会随之改变。

 1 static void simpleProfileChangeCB( uint8 paramID )
 2 {
 3   uint8 newValue;
 4
 5   switch( paramID )
 6   {
 7     case 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
14       break;
15
16     case 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
23       break;
24
25     default:
26       // should not reach here!
27       break;
28   }
29 }

至此,特征值的新增即完成了。

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

时间: 2024-07-30 08:58:29

BLE4.0之新增特征值(CC2541)的相关文章

BLE4.0之自定义服务(CC2541)

1.什么是服务 蓝牙通信中,我们就是需要对各个服务中的特征值进行交流,现在尝试自定义一个服务. 2.创建TEMProfile.c.TEMProfile.h 这是服务的主体文件. 其里面大致无非是定义特征值,创建读写值的函数,注册函数,增添服务函数,以及包装一些回调函数. 具体如下. (1)所有定义的变量其实都是和特征值相关的,具体详见上篇文章:http://www.cnblogs.com/asam/p/6535374.html (2)创建函数 需要创建的函数如下: 全局函数: extern bS

IOS BLE4.0蓝牙和外设连接和收发数据的流程

前言: 苹果在IOS 6系统之后开始支持BLE 4.0,iPhone4s,iPod 5,iPad 3等之后的机型开始内嵌BLE4.0硬件,因此在开发前请先确认你的开发环境符合上述要求,并且苹果在BLE4.0之后,对外部的连接设备已经不在需要MFI认证了,当然你的外设肯定得要有蓝牙4.0模块了 综述: 开发BLE4.0的App,你需要在你的项目里面导入框架: CoreBluetooth.framework 在需要使用到蓝牙的文件里面你需要导入头文件: #import <CoreBluetooth/

Android BLE与终端通信(五)——Google API BLE4.0低功耗蓝牙文档解读之案例初探

Android BLE与终端通信(五)--Google API BLE4.0低功耗蓝牙文档解读之案例初探 算下来很久没有写BLE的博文了,上家的技术都快忘记了,所以赶紧读了一遍Google的API顺便写下这篇博客心得 Google API:http://developer.android.com/guide/topics/connectivity/bluetooth-le.html#terms 其实大家要学习Android的技术,Google的API就是最详细的指导书了,而且通俗易懂,就算看不懂

ble4.0 app后台运行、报警、通知实现

先把收集到有用资料整理一下,等项目完成再写篇文章 app在后台播放报警音:https://developer.apple.com/library/ios/qa/qa1668/_index.html 后台运行设置:http://blog.shiqichan.com/ios-ble-background-central-scanning/ http://blog.csdn.net/monsterguaishou/article/details/36013659 蓝牙app后台运行接收数据.通知设定:

RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版新增系统参数管理

欲了解V3.0版本的相关内容可查看下面的链接地址. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版本发布 在V3.0版本的Web(Mvc.WebForm)与WinForm中我们新增了“系统参数管理”模块.系统参数管理的功能就非常广了,可以发挥我们的想象把所有可能的东西放在这儿定义,比如:系统的分页大小.系统的数据库类型.用户的访问限制等等一切可能的东西都可以在这儿定义,定义后通过框架提供的接口来使用即可.当然“系统参数”管理界面中有一些数据是系统生成的默认数据

RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版本新增序列管理

欲了解V3.0版本的相关内容可查看下面的链接地址. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版本发布 在V3.0版本的Web(Mvc.WebForm)与WinForm中我们新增了“序列管理”模块.序列管理是对定义框架的序列或叫“排序码”进行管理,在很多界面中我们可以看到有排序按钮,这儿的定义就是针对排序按钮的,当然这儿不般不需要人工来维护,系统都是自动管理的,特殊情况下可能需要人工来维护,比如:我们想把某个表的序列以指定值开始递增,在这个界面我们就可以进行

RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版新增查询引擎管理

欲了解V3.0版本的相关内容可查看下面的链接地址. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版本发布 RDIFramework.NET — 基于.NET的快速信息化系统开发框架 — 系列目录 在V3.0版本的Web(Mvc.WebForm)与WinForm中我们新增了“查询引擎管理”模块.主要分为两部分”查询引擎管理“与”查询引定义“.”查询引擎管理“主要是对整个系统的查询引擎定义进行分类管理,用户可以对整个系统所要用到的查询定义在这儿进行合理分类.在查询

ASP.Net4.0中新增23项功能

这篇文章介绍Visual Studio 2010 (ASP.Net 4.0)的新功能. 1.代码片段(Code Snippets): 代码段是预先开发的代码模板,可以节省我们对有关语法思考的时间.在VS 2005和VS 2008中,已经有建立了很多代码段.不过,这些只适用于隐藏代码(code behind).在VS 2010中代码片段支持JScript,HTML以及asp.net标记.在下面画面,展示了JScript和HTML片段的快捷菜单. 在JS中: 在Html中 : 2.New Profi

BLE4.0 学历笔记1之串口体验

PS:这篇文章记录笔者TI ble协议栈的学习串口的笔记. 前些日子CC2540模块没到,就捣鼓CC2530.深深的感受到,ZigBee就是个坑啊.然后果断玩BLE了.BLE,TI的栈给的文档,project这回看起来好点,然后找了其他一些资料.这里介绍<蓝牙4.0BLE开发完全手册-物联网开发技术实战>.看起来还行吧.不过我照着他的串口例子做,没看到效果(可能是协议栈版本问题).于是,一怒之下,自己啃. 最后再说一下,CC2530和CC2540除了RF不同外,51内核是一样的.因为栈中使用的