欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

BLE协议栈入门三(Server端读写属性表)

程序员文章站 2022-07-13 17:20:31
...

以TI BLE协议栈为例,Server端对自己的属性表进行读写操作的函数Simple Profile Service Callbacks如下,下面两个回调是有GATT层的Lib调用:

Server端读属性表的回调函数

/*********************************************************************
 * @fn          simpleProfile_ReadAttrCB
 *
 * @brief       Read an attribute.
 *
 * @param       connHandle - connection message was received on
 * @param       pAttr - pointer to attribute
 * @param       pValue - pointer to data to be read
 * @param       pLen - length of data to be read
 * @param       offset - offset of the first octet to be read
 * @param       maxLen - maximum length of data to be read
 *
 * @return      Success or Failure
 */
static uint8 simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                            uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen )
{
  bStatus_t status = SUCCESS;

  // If attribute permissions require authorization to read, return error
  if ( gattPermitAuthorRead( pAttr->permissions ) )
  {
    // Insufficient authorization
    return ( ATT_ERR_INSUFFICIENT_AUTHOR );
  }

  // Make sure it's not a blob operation (no attributes in the profile are long)
  if ( offset > 0 )
  {
    return ( ATT_ERR_ATTR_NOT_LONG );
  }

  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 )
    {
      // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases;
      // gattserverapp handles those reads

      // characteristics 1 and 2 have read permissions
      // characteritisc 3 does not have read permissions; therefore it is not
      //   included here
      // characteristic 4 does not have read permissions, but because it
      //   can be sent as a notification, it is included here
      case SIMPLEPROFILE_CHAR1_UUID:
        *pLen = 1;
        pValue[0] = *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;
    }
  }
  else
  {
    // 128-bit UUID
    *pLen = 0;
    status = ATT_ERR_INVALID_HANDLE;
  }

  return ( status );
}

Server端写属性表的回调函数

/*********************************************************************
* @fn      simpleProfile_WriteAttrCB
*
* @brief   Validate attribute data prior to a write operation
*
* @param   connHandle - connection message was received on
* @param   pAttr - pointer to attribute
* @param   pValue - pointer to data to be written
* @param   len - length of data
* @param   offset - offset of the first octet to be written
*
* @return  Success or Failure
*/
static bStatus_t simpleProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                uint8 *pValue, uint8 len, uint16 offset )
{
 bStatus_t status = SUCCESS;
 uint8 notifyApp = 0xFF;

 // If attribute permissions require authorization to write, return error
 if ( gattPermitAuthorWrite( pAttr->permissions ) )
 {
   // Insufficient authorization
   return ( ATT_ERR_INSUFFICIENT_AUTHOR );
 }

 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_CHAR1_UUID:
       //Validate the value
       // Make sure it's not a blob oper
       if ( offset ==0 )
       {
         if ( len != 1 )
         {
           status = ATT_ERR_INVALID_VALUE_SIZE;
         }
       }
       else
       {
         status = ATT_ERR_ATTR_NOT_LONG;
       }

       //Write the value
       if ( status == SUCCESS )
       {
         uint8 *pCurValue = (uint8 *)pAttr->pValue;
         *pCurValue = pValue[0];

         if( pAttr->pValue == &simpleProfileChar1 )
         {
           notifyApp = SIMPLEPROFILE_CHAR1;
         }
       }

       break;

     case GATT_CLIENT_CHAR_CFG_UUID:
     	//处理给定客户端的客户端特性配置写入请求
       status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                                offset, GATT_CLIENT_CFG_NOTIFY );
       break;

     default:
       // Should never get here! (characteristics 2 and 4 do not have write permissions)
       status = ATT_ERR_ATTR_NOT_FOUND;
       break;
   }
 }
 else
 {
   // 128-bit UUID
   status = ATT_ERR_INVALID_HANDLE;
 }

 // If a charactersitic value changed then callback function to notify application of change
 // 写了属性表之后,调用simpleProfile的应用层回调函数,通知应用层
 if ( (notifyApp != 0xFF ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange )
 {
   simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp );
 }

 return ( status );
}

应用层写特征值变量的函数

/*********************************************************************
* @fn      SimpleProfile_SetParameter
*
* @brief   Set a Simple Profile parameter.
*
* @param   param - Profile parameter ID
* @param   len - length of data to right
* @param   value - pointer to data to write.  This is dependent on
*          the parameter ID and WILL be cast to the appropriate
*          data type (example: data type of uint16 will be cast to
*          uint16 pointer).
*
* @return  bStatus_t
*/
bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void *value )
{
 bStatus_t ret = SUCCESS;
 switch ( param )
 {
   case SIMPLEPROFILE_CHAR1:
     if ( len == sizeof ( uint8 ) )
     {
       simpleProfileChar1 = *((uint8*)value);
     }
     else
     {
       ret = bleInvalidRange;
     }
     break;

   case SIMPLEPROFILE_CHAR4:
     if ( len == sizeof ( uint8 ) )
     {
       simpleProfileChar4 = *((uint8*)value);

       // See if Notification has been enabled
       // 通常,默认情况下不会启用特征通知。客户端可以写入客户端特征配置描述符(CCCD)以启用/禁用通知。该调用(GATT_writeReq)被转换为服务器端的GATTServApp_ProcessCharCfg,以更改通知设置。
       GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE,
                                   simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                   INVALID_TASK_ID );
     }
     else
     {
       ret = bleInvalidRange;
     }
     break;

   case SIMPLEPROFILE_CHAR5:
     if ( len == SIMPLEPROFILE_CHAR5_LEN )
     {
       VOID osal_memcpy( simpleProfileChar5, value, SIMPLEPROFILE_CHAR5_LEN );
     }
     else
     {
       ret = bleInvalidRange;
     }
     break;

   default:
     ret = INVALIDPARAMETER;
     break;
 }

 return ( ret );
}

应用层读特征值变量的函数

/*********************************************************************
* @fn      SimpleProfile_GetParameter
*
* @brief   Get a Simple Profile parameter.
*
* @param   param - Profile parameter ID
* @param   value - pointer to data to put.  This is dependent on
*          the parameter ID and WILL be cast to the appropriate
*          data type (example: data type of uint16 will be cast to
*          uint16 pointer).
*
* @return  bStatus_t
*/
bStatus_t SimpleProfile_GetParameter( uint8 param, void *value )
{
bStatus_t ret = SUCCESS;
switch ( param )
{
  case SIMPLEPROFILE_CHAR1:
    *((uint8*)value) = simpleProfileChar1;
    break;

  case SIMPLEPROFILE_CHAR2:
    *((uint8*)value) = simpleProfileChar2;
    break;

  case SIMPLEPROFILE_CHAR3:
    *((uint8*)value) = simpleProfileChar3;
    break;

  case SIMPLEPROFILE_CHAR4:
    *((uint8*)value) = simpleProfileChar4;
    break;

  case SIMPLEPROFILE_CHAR5:
    VOID osal_memcpy( value, simpleProfileChar5, SIMPLEPROFILE_CHAR5_LEN );
    break;

  case SIMPLEPROFILE_CHAR6:
    VOID osal_memcpy( value, simpleProfileChar6, SIMPLEPROFILE_CHAR6_LEN );
    break;

  default:
    ret = INVALIDPARAMETER;
    break;
}

return ( ret );
}