• 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";

      配置权限,内容,描述。

      

     (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";
    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中已可以发现这两个特征值。

  • 相关阅读:
    递归遍历多维数组(树数据结构)的超级简单方式,并且可以递归超过200层,摘自<<PHP精粹:编写高效PHP代码>>
    http协议传输二进制数据以及对输入流(php://input)和http请求的理解
    一个非常简单的RPC服务
    php://input 打开的数据流只能读取一次,即读取一次之后读取的值为空
    soap的简单实现(PHP)
    使用PHP的curl扩展实现跨域post请求,以及file_get_contents()百度短网址例子
    jquery选取iframe
    算法之棋盘覆盖
    词法分析之实验报告
    简单的词法分析小程序
  • 原文地址:https://www.cnblogs.com/asam/p/6535374.html
Copyright © 2020-2023  润新知