 BLE添加(jia)特(te)征(zheng)值
							時間:2018-08-16      來源:未知(zhi)
							BLE添加(jia)特(te)征(zheng)值
							時間:2018-08-16      來源:未知(zhi) 
							一、 什么是特征值
特征值(zhi)就是(shi)BLE協(xie)議(yi)棧(zhan)向外提供的一個(ge)數(shu)據接(jie)口,藍牙之間的數(shu)據傳輸(shu)終落實在特征值(zhi)上。在BLE協(xie)議(yi)棧(zhan)的GATT層(ceng)中封裝(zhuang)了若(ruo)干服務(wu)(service),而(er)在每一個(ge)服務(wu)中又有(you)若(ruo)干特征值(zhi)(characters),特征值(zhi)可以是(shi)任意類(lei)型的數(shu)據。藍牙之間的數(shu)據傳輸(shu)靠協(xie)議(yi)棧(zhan)提供的write和read函(han)數(shu),而(er)這兩個(ge)函(han)數(shu)就是(shi)在操作特征值(zhi)
二、UUID
UUID就是通(tong)用唯(wei)(wei)一(yi)識別碼。在(zai)藍牙協議(yi)棧中可(ke)能會有(you)多個(ge)服務(wu),每個(ge)服務(wu)會有(you)多個(ge)特(te)征值,而這些服務(wu)或者特(te)征值都有(you)一(yi)個(ge)唯(wei)(wei)一(yi)的ID,這樣(yang)就可(ke)以(yi)區(qu)分了。這個(ge)UUID是其(qi)他設(she)備設(she)置藍牙服務(wu)和特(te)征值的唯(wei)(wei)一(yi)方法。
三、增加特征值(zhi)
在(zai)BLE協議棧中(zhong),GATT層(ceng)定義(yi)了特征(zheng)值和服務。下面就以(yi)SimpleBLEPeripheral為例,增加一個(ge)特征(zheng)值。在(zai)simpleGATTprofile.c中(zhong),已經(jing)有定義(yi)好的(de)(de)特征(zheng)值,參考已有的(de)(de)特征(zheng)值就可以(yi)順利添加自己的(de)(de)特征(zheng)值
1) 修改頭文件simpleGATTprofile.h
頭(tou)文件中定義(yi)了特征值的UUID,以及長度和默認值
//特征值UUID
#define SIMPLEPROFILE_CHAR5_UUID     0xFFF5
//特征值長(chang)度
#define SIMPLEPROFILE_CHAR5_LEN   5
2)添加特征值(zhi)相關變量
包括特征值(zhi)的讀寫(xie)權限、變量(liang)名、展現給用(yong)戶的名字(zi)
//特(te)征值初始化
// 特征值(zhi)屬性,讀或(huo)者(zhe)寫
static uint8 simpleProfileChar6Props = GATT_PROP_READ | GATT_PROP_WRITE;
// 值,可(ke)以(yi)(yi)向(xiang)其寫入數(shu)據(ju),也可(ke)以(yi)(yi)讀出(chu)數(shu)據(ju)。這里是(shi)一(yi)個字符數(shu)組
static uint8 simpleProfileChar6[SIMPLEPROFILE_CHAR6_LEN] = {0};
// 用戶(hu)描述,展現給用戶(hu)的名字
static uint8 simpleProfileChar6UserDesp[17] = "Characteristic 6\0";
//提取(qu)uuid,uuid定義在頭文件(jian)中
CONST uint8 simpleProfilechar5UUID[ATT_BT_UUID_SIZE] =
{
LO_UINT16(SIMPLEPROFILE_CHAR5_UUID), HI_UINT16(SIMPLEPROFILE_CHAR5_UUID)
};
3)將特征(zheng)值加入屬性表
特(te)征(zheng)(zheng)值(zhi)由(you)服務(wu)統一(yi)(yi)管理(li),所有的特(te)征(zheng)(zheng)值(zhi)都會在一(yi)(yi)個(ge)服務(wu)的屬性表中(zhong)呈現出來,每增加(jia)(jia)一(yi)(yi)個(ge)特(te)征(zheng)(zheng)值(zhi),它的相關變量就要(yao)在添加(jia)(jia)到屬性表中(zhong)
//特征值初始化
static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] =
{
// Simple Profile Service
{
{ ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
GATT_PERMIT_READ,   /* permissions */
0,   /* handle */
(uint8 *)&simpleProfileService /* pValue */
},
// Characteristic 1 Declaration
{
{ ATT_BT_UUID_SIZE, characterUUID },
GATT_PERMIT_READ,
0,
&simpleProfileChar1Props
},
// Characteristic Value 1
{
{ ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
GATT_PERMIT_AUTHEN_READ | GATT_PERMIT_AUTHEN_WRITE,
0,
&simpleProfileChar1
},
  // Characteristic 1 User Description
{
    { ATT_BT_UUID_SIZE, charUserDescUUID },
  GATT_PERMIT_READ,
0,
    simpleProfileChar1UserDesp
},
。。。。。
// Characteristic 5 Declaration
{
  { ATT_BT_UUID_SIZE, characterUUID },
GATT_PERMIT_READ,
0,
  &simpleProfileChar5Props
},
// Characteristic Value 5
{
{ ATT_BT_UUID_SIZE, simpleProfilechar5UUID },
GATT_PERMIT_AUTHEN_READ| GATT_PERMIT_AUTHEN_WRITE, 
0,
simpleProfileChar5
},
  // Characteristic 5 User Description
{
{ ATT_BT_UUID_SIZE, charUserDescUUID },
GATT_PERMIT_READ,
0,
simpleProfileChar5UserDesp
},
4)修改(gai)屬性表的長度(du)
每增加(jia)一(yi)個(ge)特(te)征值,屬(shu)(shu)性(xing)表的長(chang)度也會(hui)增加(jia),因此要(yao)修(xiu)改屬(shu)(shu)性(xing)表的長(chang)度。在(zai)文件的一(yi)開(kai)始就聲明了屬(shu)(shu)性(xing)表的長(chang)度
#define SERVAPP_NUM_ATTR_SUPPORTED   24
5)修改SimpleProfile_SetParamete和(he)SimpleProfile_GetParamete函數
這是操(cao)作(zuo)特(te)(te)征值的(de)(de)兩(liang)個函(han)數(shu)(shu),set函(han)數(shu)(shu)可以用(yong)來初始(shi)化特(te)(te)征值,get函(han)數(shu)(shu)可以用(yong)來提取(qu)特(te)(te)征值。一般我們(men)定義的(de)(de)特(te)(te)征值都是uint8類型的(de)(de)數(shu)(shu)組,因此(ci)無論set還是get,都可以使用(yong)copy函(han)數(shu)(shu)來完成(cheng),同時要注意實(shi)際的(de)(de)長(chang)度
bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void *value )
{
bStatus_t ret = SUCCESS;
switch ( param )
{
。。。。。。。
case SIMPLEPROFILE_CHAR5:
if ( len <= SIMPLEPROFILE_CHAR5_LEN )
{
//將value值(zhi)復制到特(te)征(zheng)值(zhi)5,同時(shi)注意長度
VOID osal_memcpy( simpleProfileChar5, value, len );
}
else
{
ret = bleInvalidRange;
}
break;  
default:
  ret = INVALIDPARAMETER;
break;
}
return ( ret );
}
bStatus_t SimpleProfile_GetParameter( uint8 param, void *value )
{
bStatus_t ret = SUCCESS;
switch ( param )
{
。。。。。。
case SIMPLEPROFILE_CHAR5:
//將(jiang)特征(zheng)值5復制到value
VOID osal_memcpy( value, simpleProfileChar5, osal_strlen(simpleProfileChar5));
break;
default:
    ret = INVALIDPARAMETER;
break;
}
return ( ret );
}
6)修改simpleProfile_ReadAttrCB和simpleProfile_WriteAttrCB函數(shu)
上面已經有了set和(he)get函數,可以實現對(dui)特(te)征值(zhi)(zhi)的(de)讀(du)寫(xie),那么這里(li)為何(he)又來了一(yi)(yi)對(dui)read和(he)write呢???set和(he)get是(shi)用(yong)來本地讀(du)寫(xie)特(te)征值(zhi)(zhi)的(de),而(er)read和(he)write則是(shi)網絡上的(de)讀(du)寫(xie)。什(shen)么意思呢,當(dang)藍牙網絡的(de)另一(yi)(yi)端想要讀(du)取特(te)征值(zhi)(zhi)的(de)時(shi)候,協議棧就會自動回調這個read函數,然(ran)后(hou)將讀(du)取的(de)結(jie)果傳輸(shu)的(de)網絡的(de)另一(yi)(yi)端。當(dang)然(ran),寫(xie)操作(zuo)也是(shi)一(yi)(yi)樣的(de)。
static uint8 simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
{
bStatus_t status = SUCCESS;
if ( pAttr->type.len == ATT_BT_UUID_SIZE )
{
// 16-bit UUID
uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
switch ( uuid )
{
。。。。。。
 
case SIMPLEPROFILE_CHAR5_UUID:
  *pLen = osal_strlen(pAttr->pValue);
VOID osal_memcpy( pValue, pAttr->pValue, osal_strlen(pAttr->pValue) );
  break;  
default:
// Should never get here! (characteristics 3 and 4 do not have read permissions)
    *pLen = 0;
status = ATT_ERR_ATTR_NOT_FOUND;
  break;
}
}
return ( status );
}
static bStatus_t simpleProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
uint8 *pValue, uint8 len, uint16 offset )
{
bStatus_t status = SUCCESS;
uint8 notifyApp = 0xFF;
if ( pAttr->type.len == ATT_BT_UUID_SIZE )
{
// 16-bit UUID
uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
switch ( uuid )
{
。。。。。。
  case SIMPLEPROFILE_CHAR5_UUID:
//Validate the value 檢測輸入數據是(shi)否合法
// Make sure it's not a blob oper
  if ( offset == 0 ) //是(shi)第(di)一字(zi)節
{
if ( len >= SIMPLEPROFILE_CHAR6_LEN )
{
  status = ATT_ERR_INVALID_VALUE_SIZE;
  } //若(ruo)輸入(ru)長度不對,status為
}
  else
{
status = ATT_ERR_ATTR_NOT_LONG;//不(bu)是第一字節
}
   
  if ( status == SUCCESS )
  {
//清空緩(huan)沖區
osal_memset(pAttr->pValue, '\0', SIMPLEPROFILE_CHAR6_LEN) ;
//復(fu)制(zhi)
  VOID osal_memcpy( pAttr->pValue, pValue, len);
  notifyApp = SIMPLEPROFILE_CHAR6;
}  
break;
 
default:
// Should never get here! (characteristics 2 and 4 do not have write permissions)
status = ATT_ERR_ATTR_NOT_FOUND;
  break;
}
}
7)修改simpleBLEPeripheral.c
A、在SimpleBLEPeripheral_Init函數(shu)中可以使用set方法對特征值做初始化(hua)操作(zuo)
SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR5, 5, charValue5 );
B、修改simpleProfileChangeCB
當特(te)征(zheng)值被網絡的(de)另一端(duan)修(xiu)改之后,協議棧會回調這個(ge)函數,通知當前(qian)特(te)征(zheng)值發生變化
static void simpleProfileChangeCB( uint8 paramID )
{
uint8 newValue;
uint8 *val;
switch( paramID )
{
。。。。。。
case SIMPLEPROFILE_CHAR5:
  val = osal_msg_allocate(15);
//提取特征值,注意(yi)這里使用(yong)的是(shi)get方式(shi)
  SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR5, val );
break;
default:
// should not reach here!
break;
}
SerialPrint(val);
}
四、測試
如何驗證特(te)(te)征值已(yi)經被成(cheng)功的(de)(de)添加(jia)呢,基于上(shang)面的(de)(de)例(li)子,我們需要(yao)一(yi)個BLE主機設備來(lai)讀取特(te)(te)征值。建議使用手機來(lai)完(wan)成(cheng)測(ce)試,因為你(ni)很難確保你(ni)的(de)(de)主機代碼是正確的(de)(de)。從(cong)網絡上(shang)下載(zai)BLE調試軟件(jian),可以輕(qing)松(song)的(de)(de)操作特(te)(te)征值。
 