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中已可以發現這兩個特征值。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM