蓝牙----蓝牙消息传输_从机(GATT Server)与主机(GATT Cilent)

本文详细解释了蓝牙设备通信中,GATTServer如何发送通知和接收消息,以及GATTClient如何发送指示和接收数据,包括使用GATTServApp函数和不同类型的通信事件如通知/指示和读写操作。
摘要由CSDN通过智能技术生成


1.从机(GATT_Server)发送消息(通知)

GATT服务器的抽象
在这里插入图片描述
1.APP调用profile函数

    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),&charValue4);

2.profile调用GATTServAPP层函数

GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE,
                                    simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                    INVALID_TASK_ID, simpleProfile_ReadAttrCB );

3.GATTServApp_ProcessCharCfg调用GATT层函数
  通过特征值Value地址找到特征值对应的属性
   发送ATT通知/指示

      pAttr = GATTServApp_FindAttr( attrTbl, numAttrs, pValue );
      if ( pAttr != NULL )
      {
        if ( pItem->value & GATT_CLIENT_CFG_NOTIFY )
        {
        //    发送ATT通知/指示
           status |= gattServApp_SendNotiInd( pItem->connHandle, GATT_CLIENT_CFG_NOTIFY,
                                              authenticated, pAttr, taskId, pfnReadAttrCB );
        }

        if ( pItem->value & GATT_CLIENT_CFG_INDICATE )
        {
           status |= gattServApp_SendNotiInd( pItem->connHandle, GATT_CLIENT_CFG_INDICATE,
                                              authenticated, pAttr, taskId, pfnReadAttrCB );
        }
      }

4.Readback回调将APP中缓存的要发送的信息(charValue4),同步到协议栈发送(noti.pValue)

	status = (*pfnReadAttrCB)( connHandle, pAttr, noti.pValue, &noti.len,
                               0, len, GATT_LOCAL_READ );
    if ( status == SUCCESS )
    {
      noti.handle = pAttr->handle;

      if ( cccValue & GATT_CLIENT_CFG_NOTIFY )
      {
        status = GATT_Notification( connHandle, &noti, authenticated );
      }
      else // GATT_CLIENT_CFG_INDICATE
      {
        status = GATT_Indication( connHandle, (attHandleValueInd_t *)&noti,
                                  authenticated, taskId );
      }
    }

5.GATT_Notification/GATT_Indication完成发送,这两个区别时 indicate 需要主机回应后才能继续发送,而 Notify 不需要。

2.从机(GATT_Server)接收消息

从机的消息接收是,通过回调实现的。
1.将APP的回调函数注册到Profiles层

  SimpleProfile_RegisterAppCBs(&SimplePeripheral_simpleProfileCBs);

回调函数函数的作用是,发送SP_CHAR_CHANGE_EVT队列消息

static void SimplePeripheral_charValueChangeCB(uint8_t paramId)
{
  uint8_t *pValue = ICall_malloc(sizeof(uint8_t));

  if (pValue)
  {
    *pValue = paramId;

    if (SimplePeripheral_enqueueMsg(SP_CHAR_CHANGE_EVT, pValue) != SUCCESS)
    {
      ICall_free(pValue);
    }
  }
}

2.将Profiles层的回调函数注册到 GATT Server App层

    status = GATTServApp_RegisterService( simpleProfileAttrTbl,
                                          GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                          GATT_MAX_ENCRYPT_KEY_SIZE,
                                          &simpleProfileCBs );

simpleProfile_WriteAttrCB回调函数的作用是1.将协议栈获得的信息,同步到APP层,2.通知APP层接收到消息

static bStatus_t simpleProfile_WriteAttrCB(uint16_t connHandle,
                                           gattAttribute_t *pAttr,
                                           uint8_t *pValue, uint16_t len,
                                           uint16_t offset, uint8_t method)
{
  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 )
    {
        // 改变特征值
        if ( status == SUCCESS )
        {
          uint8 *pCurValue = (uint8 *)pAttr->pValue;
          *pCurValue = pValue[0];
          // 判断是哪个特征值
          if( pAttr->pValue == &simpleProfileChar1 )
          {
            notifyApp = SIMPLEPROFILE_CHAR1;
          }
          else
          {
            notifyApp = SIMPLEPROFILE_CHAR3;
          }
        }

        break;

      case GATT_CLIENT_CHAR_CFG_UUID:
      //处理客户端的客户端特征配置ccc写请求
        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;
    }
  }
  // 将事件发送给APP层
  if ( (notifyApp != 0xFF ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange )
  {
    simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp );
  }
}

在这其中的将事件发送给APP层的回调函数pfnSimpleProfileChange就是SimplePeripheral_charValueChangeCB。
3.当从机(GATT服务器)收到消息是,协议栈回调GATT_Server_App层的回调函数simpleProfile_WriteAttrCB,simpleProfile_WriteAttrCB再回调APP层的函数SimplePeripheral_charValueChangeCB,在APP层SP_CHAR_CHANGE_EVT事件处理中,完成对消息的处理。

static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId)
{
  uint8_t newValue;

  switch(paramId)
  {
    case SIMPLEPROFILE_CHAR1:
      SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);
      Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 1: %d", (uint16_t)newValue);
      break;

    case SIMPLEPROFILE_CHAR3:
      SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue);
      Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "Char 3: %d", (uint16_t)newValue);
      break;

    default:
      // should not reach here!
      break;
  }
}

3.主机(GATT_Cilent)发送消息(ATT指示)

GATT客户端的抽象
在这里插入图片描述
GATT客户端通过 GATT_WriteCharValue()完成发送
GATT_WriteCharValue调用成功,在主机(GATT客户端)返回GATT层消息ATT_WRITE_RSP。

static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg)
{
  if (linkDB_Up(pMsg->connHandle))
  {
     //ATT写响应  或  ATT写请求出错
    //GATT_WriteCharValue中使用ATT_WriteReq,GATT_WriteCharValue成功则返回ATT_WRITE_RSP
    //GATT_WriteCharValue向协议栈发送ATT_WriteReq请求,写成功后协议栈向APP层返回ATT_WRITE_RSP响应
    else if ((pMsg->method == ATT_WRITE_RSP)  ||
             ((pMsg->method == ATT_ERROR_RSP) &&
              (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ)))
    {
      if (pMsg->method == ATT_ERROR_RSP)
      {
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Write Error %d", pMsg->msg.errorRsp.errCode);
      }
      else
      {
        // After a successful write, display the value that was written and
        // increment value
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Write sent: 0x%02x", charVal);
      }

      tbm_goTo(&scMenuPerConn);
    }
  }
 }

4.主机(GATT_Cilent)接收消息

当收到消息时,协议栈告诉GATT Cilent,有通知到达
1SimpleCentral_task阻塞,直到事件发生
2.判断为GATT协议栈事件

static void SimpleCentral_taskFxn(uintptr_t a0, uintptr_t a1)
{
		  ......
          if (pEvt->signature != 0xffff)
          {
            // Process inter-task message
            safeToDealloc = SimpleCentral_processStackMsg((ICall_Hdr *)pMsg);
          }
		  ......
}

3.处理接收消息事件

static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg)
{
  if (linkDB_Up(pMsg->connHandle))
  {
    ......
    //Cilent接收方式1:ATT读响应  或  ATT读请求出错
    //GATT_ReadCharValue()函数成功返回ATT_READ_RSP
    //对应从机 SimpleProfile_SetParameter()修改特征值的值
    else if ((pMsg->method == ATT_READ_RSP)   ||
             ((pMsg->method == ATT_ERROR_RSP) &&
              (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
    {
      if (pMsg->method == ATT_ERROR_RSP)
      {
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Read Error %d", pMsg->msg.errorRsp.errCode);
      }
      else
      {
        // After a successful read, display the read value
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Read rsp: 0x%02x", pMsg->msg.readRsp.pValue[0]);
      }
    }

      //Cilent接收方式2.通知
      //对应从机的 GATT_Notification()函数
     else if ( ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) ) 
    {
    }

  // Needed only for ATT Protocol messages
  GATT_bm_free(&pMsg->msg, pMsg->method);
  }
}

因为SimpleProfile_SetParameter()内部也是调用GATT_Notification。
所以主机(GATT_Cilent)接收消息可以分为两种:
1.SimpleProfile_SetParameter可以使用GATT_ReadCharValue(),进而在ATT_READ_RSP消息处理,也可以在直接ATT_HANDLE_VALUE_NOTI 中使用。
2.GATT_Notification在ATT_HANDLE_VALUE_NOTI 中处理

从机GATT服务器发送:GATT_Notification,对应主机GATT客户端的ATT_HANDLE_VALUE_NOTI事件
主机CATT客户端发送:GATT_WriteCharValue,对应从机GATT服务器的SBP_EVEVT_CHANGE_EVENT事件

当特征值具有读、写属性时,GATT_Cilent可以通过 GATT_ReadCharValue、GATT_WriteCharValue 进行读、写 GATT_Server端的特征。
当特征具有CCC通知属性时,GATT_Server端可以主动将特征的值通知给 GATT_Cilent。

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值