/*********************************************************************
 * @fn      SimpleServiceDiscovery_discoverService
 *
 * @brief   Perform discovery of the given simpleService_t structure.
 *          This function is to be called inside the GATT discovery event
 *          callback to process the service discovery.
 *
 * @param   connHandle    - connection handle
 *          entity        - ICall entity of the calling task
 *          *service      - pointer to the service struct
 *          *pMsg         - pointer to the received gattMsgEvent_t
 *
 * @return  SIMPLE_DISCOVERY_SUCCESSFUL, SIMPLE_DISCOVERY_FINDING_SERVICE,
 *          SIMPLE_DISCOVERY_FINDING_CHAR or SIMPLE_DISCOVERY_UNSUCCESSFUL.
 */
uint32_t SimpleServiceDiscovery_discoverService(uint16_t connHandle, ICall_EntityID entity,
                                                simpleService_t *service, gattMsgEvent_t *pMsg)
{
    uint32_t retVal = 0;

    switch (discoveryState) {
    case BLE_DISC_STATE_IDLE:
    {
        discoveryState = BLE_DISC_STATE_SVC;

        // Discovery the service
        GATT_DiscPrimaryServiceByUUID(connHandle, service->uuid.uuid, service->uuid.len,
                                      entity);

        retVal = SIMPLE_DISCOVERY_FINDING_SERVICE;
        break;
    }
    case BLE_DISC_STATE_SVC:
    {
        // Service found, store handles
        if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
            pMsg->msg.findByTypeValueRsp.numInfo > 0)
        {
          service->startHandle = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
          service->endHandle = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
        }

        // If procedure complete
        if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) &&
             (pMsg->hdr.status == bleProcedureComplete))  ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          if (service->startHandle != 0)
          {
            discoveryState = BLE_DISC_STATE_CHAR;
            GATT_DiscAllCharDescs(connHandle, service->startHandle, service->endHandle, entity);
            retVal = SIMPLE_DISCOVERY_FINDING_CHAR;
          }
          else
          {
            discoveryState = BLE_DISC_STATE_IDLE;
            retVal = SIMPLE_DISCOVERY_UNSUCCESSFUL;
          }
        }
        break;
    }
    case BLE_DISC_STATE_CHAR:
    {
        // Characteristic found, store handle
        if (pMsg->method == ATT_FIND_INFO_RSP)
        {

            if (pMsg->msg.findInfoRsp.numInfo > 0)
            {
              SimpleServiceDiscovery_processFindInfoRsp(pMsg->msg.findInfoRsp, service);
            }

            if (pMsg->hdr.status == bleProcedureComplete)
            {
              discoveryState = BLE_DISC_STATE_IDLE;
              retVal = SIMPLE_DISCOVERY_SUCCESSFUL;
            }
        }
        break;
    }
    default:
        break;
    }

    return retVal;
}
示例#2
0
/*********************************************************************
 * @fn      GlucoseDevInfoDisc
 *
 * @brief   Current glucose service and characteristic discovery. 
 *
 * @param   state - Discovery state.
 * @param   pMsg - GATT message.
 *
 * @return  New discovery state.
 */
static uint8_t GlucoseDevInfoDisc(uint8_t state, gattMsgEvent_t *pMsg)
{
  uint8_t newState = state;
  
  switch (state)
  {
    case DISC_DEVINFO_START:  
      {
        uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(DEVINFO_SERV_UUID),
                                           HI_UINT16(DEVINFO_SERV_UUID) };

        // Initialize service discovery variables
        glucoseSvcStartHdl = glucoseSvcEndHdl = 0;
        glucoseEndHdlIdx = 0;
        
        // Discover service by UUID
        GATT_DiscPrimaryServiceByUUID(glucCollConnHandle, uuid,
                                      ATT_BT_UUID_SIZE, glucCollTaskId);      

        newState = DISC_DEVINFO_SVC;
      } 
      break;

    case DISC_DEVINFO_SVC:
      // Service found, store handles
      if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
          pMsg->msg.findByTypeValueRsp.numInfo > 0)
      {
        glucoseSvcStartHdl = 
          ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
        glucoseSvcEndHdl = 
          ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
      }
      
      // If procedure complete
      if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP  && 
           pMsg->hdr.status == bleProcedureComplete) ||
          (pMsg->method == ATT_ERROR_RSP))
      {
        // If service found
        if (glucoseSvcStartHdl != 0)
        {
          // Discover all characteristics
          GATT_DiscAllChars(glucCollConnHandle, glucoseSvcStartHdl,
                            glucoseSvcEndHdl, glucCollTaskId);
          
          newState = DISC_DEVINFO_CHAR;
        }
        else
        {
          // Service not found
          newState = DISC_FAILED;
        }
      }    
      break;

    case DISC_DEVINFO_CHAR:
      {
        uint8_t   i;
        uint8_t   *p;
        uint16_t  handle;
        uint16_t  uuid;
        
        // Characteristics found
        if (pMsg->method == ATT_READ_BY_TYPE_RSP &&
            pMsg->msg.readByTypeRsp.numPairs > 0 && 
            pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN)
        {
          // For each characteristic declaration
          p = pMsg->msg.readByTypeRsp.pDataList;
          
          for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--)
          {
            // Parse characteristic declaration
            handle = BUILD_UINT16(p[3], p[4]);
            uuid = BUILD_UINT16(p[5], p[6]);
                   
            // If UUID is of interest, store handle
            switch (uuid)
            {
              case MANUFACTURER_NAME_UUID:
                glucoseHdlCache[HDL_DEVINFO_MANUFACTURER_NAME] = handle;
                break;                
                
              case SYSTEM_ID_UUID:
                glucoseHdlCache[HDL_DEVINFO_SYSTEM_ID] = handle;
                break;
                
              case MODEL_NUMBER_UUID:
                glucoseHdlCache[HDL_DEVINFO_MODEL_NUM] = handle;
                break;
                
              default:
                break;
            }
            
            p += CHAR_DESC_HDL_UUID16_LEN;
          }
        }
          
        // If procedure complete
        if ((pMsg->method == ATT_READ_BY_TYPE_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          // If didn't find required device info
          if (glucoseHdlCache[HDL_DEVINFO_MANUFACTURER_NAME] == 0 ||
              glucoseHdlCache[HDL_DEVINFO_SYSTEM_ID] == 0 ||
              glucoseHdlCache[HDL_DEVINFO_MODEL_NUM] == 0)
          {
            newState = DISC_FAILED;
          }
          else
          {
            newState = DISC_IDLE;
          }
        }
      }      
      break;
      
    default:
      break;
  }
  
  return newState;
}
示例#3
0
/*********************************************************************
 * @fn      simpleTopology_processGATTDiscEvent
 *
 * @brief   Process GATT discovery event
 *
 * @return  none
 */
static void simpleTopology_processGATTDiscEvent(gattMsgEvent_t *pMsg)
{ 
  if (pMsg->method == ATT_MTU_UPDATED_EVENT)
  {   
    // MTU size updated
    LCD_WRITE_STRING_VALUE("MTU Size:", pMsg->msg.mtuEvt.MTU, 10, LCD_PAGE4);
  }
  else if (discState == BLE_DISC_STATE_MTU)
  {
    // MTU size response received, discover simple BLE service
    if (pMsg->method == ATT_EXCHANGE_MTU_RSP)
    {
      uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(SIMPLEPROFILE_SERV_UUID),
                                         HI_UINT16(SIMPLEPROFILE_SERV_UUID) };        
      discState = BLE_DISC_STATE_SVC;

      // Discovery simple BLE service
      VOID GATT_DiscPrimaryServiceByUUID(connHandle, uuid, ATT_BT_UUID_SIZE,
                                         selfEntity);
    }
  }
  else if (discState == BLE_DISC_STATE_SVC)
  {
    // Service found, store handles
    if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
        pMsg->msg.findByTypeValueRsp.numInfo > 0)
    {
      svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
      svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
    }
    
    // If procedure complete
    if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) && 
         (pMsg->hdr.status == bleProcedureComplete))  ||
        (pMsg->method == ATT_ERROR_RSP))
    {
      if (svcStartHdl != 0)
      {
        attReadByTypeReq_t req;
          
        // Discover characteristic
        discState = BLE_DISC_STATE_CHAR;
        
        req.startHandle = svcStartHdl;
        req.endHandle = svcEndHdl;
        req.type.len = ATT_BT_UUID_SIZE;
        req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
        req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);

        VOID GATT_ReadUsingCharUUID(connHandle, &req, selfEntity);
      }
    }
  }
  else if (discState == BLE_DISC_STATE_CHAR)
  {
    // Characteristic found, store handle
    if ((pMsg->method == ATT_READ_BY_TYPE_RSP) && 
        (pMsg->msg.readByTypeRsp.numPairs > 0))
    {
      //find index to store handle
      uint8_t connIndex = gapRoleInfo_Find(connHandle);
      charHdl[connIndex] = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
                             pMsg->msg.readByTypeRsp.pDataList[1]);
      
      LCD_WRITE_STRING("Simple Svc Found", LCD_PAGE6);
    }
    
    discState = BLE_DISC_STATE_IDLE;
  }    
}
示例#4
0
/*********************************************************************
 * @fn      GlucoseDisc
 *
 * @brief   Current glucose service and characteristic discovery. 
 *
 * @param   state - Discovery state.
 * @param   pMsg - GATT message.
 *
 * @return  New discovery state.
 */
static uint8_t GlucoseDisc(uint8_t state, gattMsgEvent_t *pMsg)
{
  uint8_t newState = state;
  
  switch (state)
  {
    case DISC_GLUCOSE_START:  
      {
        uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(GLUCOSE_SERV_UUID),
                                           HI_UINT16(GLUCOSE_SERV_UUID) };

        // Initialize service discovery variables
        glucoseSvcStartHdl = glucoseSvcEndHdl = 0;
        glucoseEndHdlIdx = 0;
        
        // Discover service by UUID
        GATT_DiscPrimaryServiceByUUID(glucCollConnHandle, uuid,
                                      ATT_BT_UUID_SIZE, glucCollTaskId);      

        newState = DISC_GLUCOSE_SVC;
      } 
      break;

    case DISC_GLUCOSE_SVC:
      // Service found, store handles
      if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
          pMsg->msg.findByTypeValueRsp.numInfo > 0)
      {
        glucoseSvcStartHdl = 
          ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
        glucoseSvcEndHdl = 
          ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
      }
      
      // If procedure complete
      if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP  && 
           pMsg->hdr.status == bleProcedureComplete) ||
          (pMsg->method == ATT_ERROR_RSP))
      {
        // If service found
        if (glucoseSvcStartHdl != 0)
        {
          // Discover all characteristics
          GATT_DiscAllChars(glucCollConnHandle, glucoseSvcStartHdl,
                            glucoseSvcEndHdl, glucCollTaskId);
          
          newState = DISC_GLUCOSE_CHAR;
        }
        else
        {
          // Service not found
          newState = DISC_FAILED;
        }
      }
      break;

    case DISC_GLUCOSE_CHAR:
      {
        uint8_t   i;
        uint8_t   *p;
        uint16_t  handle;
        uint16_t  uuid;

        // Characteristics found
        if (pMsg->method == ATT_READ_BY_TYPE_RSP &&
            pMsg->msg.readByTypeRsp.numPairs > 0 && 
            pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN)
        {
          // For each characteristic declaration
          p = pMsg->msg.readByTypeRsp.pDataList;

          for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--)
          {
            // Parse characteristic declaration
            handle = BUILD_UINT16(p[3], p[4]);
            uuid = BUILD_UINT16(p[5], p[6]);

            // If looking for end handle
            if (glucoseEndHdlIdx != 0)
            {
              // End handle is one less than handle of characteristic declaration
              glucoseHdlCache[glucoseEndHdlIdx] = BUILD_UINT16(p[0], p[1]) - 1;
              glucoseEndHdlIdx = 0;
            }

            // If UUID is of interest, store handle
            switch (uuid)
            {
              case GLUCOSE_MEAS_UUID:
                glucoseHdlCache[HDL_GLUCOSE_START] = handle;
                glucoseEndHdlIdx = HDL_GLUCOSE_END;
                break;

              case GLUCOSE_CONTEXT_UUID:
                glucoseHdlCache[HDL_GLUCOSE_CONTEXT_START] = handle;
                glucoseEndHdlIdx = HDL_GLUCOSE_CONTEXT_END;
                break;

              case RECORD_CTRL_PT_UUID:
                glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_START] = handle;
                glucoseEndHdlIdx = HDL_GLUCOSE_CTL_PNT_END;
                break;                
                
              case GLUCOSE_FEATURE_UUID:
                glucoseHdlCache[HDL_GLUCOSE_FEATURE] = handle;
                break;
                
              default:
                break;
            }
            
            p += CHAR_DESC_HDL_UUID16_LEN;
          }         
        }
          
        // If procedure complete
        if ((pMsg->method == ATT_READ_BY_TYPE_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          // Special case of end handle at end of service
          if (glucoseEndHdlIdx != 0)
          {
            glucoseHdlCache[glucoseEndHdlIdx] = glucoseSvcEndHdl;
            glucoseEndHdlIdx = 0;
          }
          
          // If didn't find glucose characteristic
          if (glucoseHdlCache[HDL_GLUCOSE_START] == 0)
          {
            newState = DISC_FAILED;
          }
          else if (glucoseHdlCache[HDL_GLUCOSE_START] <
                   glucoseHdlCache[HDL_GLUCOSE_END])
          {
            // Discover characteristic descriptors
            GATT_DiscAllCharDescs(glucCollConnHandle,
                                  glucoseHdlCache[HDL_GLUCOSE_START] + 1,
                                  glucoseHdlCache[HDL_GLUCOSE_END],
                                  glucCollTaskId);
                                        
            newState = DISC_GLUCOSE_CCCD;
          }
          else
          {
            newState = DISC_IDLE;
          }
        }
      }      
      break;

    case DISC_GLUCOSE_CCCD:
      {
        uint8_t i;
        
        // Characteristic descriptors found
        if (pMsg->method == ATT_FIND_INFO_RSP &&
            pMsg->msg.findInfoRsp.numInfo > 0 && 
            pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE)
        {
          attFindInfoRsp_t *pRsp = &(pMsg->msg.findInfoRsp);
                      
          // For each handle/uuid pair
          for (i = 0; i < pRsp->numInfo; i++)
          {           
            // Look for CCCD
            if ( ATT_BT_PAIR_UUID( pRsp->pInfo, i ) == GATT_CLIENT_CHAR_CFG_UUID )
            {
              // CCCD found
              glucoseHdlCache[HDL_GLUCOSE_MEAS_CCCD] = 
                ATT_BT_PAIR_HANDLE( pRsp->pInfo, i );
              
              break;
            }
          }
        }
        
        // If procedure complete
        if ((pMsg->method == ATT_FIND_INFO_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          // If CCCD found
          if (glucoseHdlCache[HDL_GLUCOSE_MEAS_CCCD] != 0)
          {
            // Should we look for unread category status CCCD
            if (glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_START] <
                glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_END])
            {
              // Discover unread category status characteristic descriptors
              GATT_DiscAllCharDescs(glucCollConnHandle,
                                    glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_START] + 1,
                                    glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_END],
                                    glucCollTaskId);
                                          
              newState = DISC_GLUCOSE_CTL_PNT_CCCD;
            }
            else
            {
              // Missing required characteristic
              newState = DISC_FAILED;
            }
          }
          else
          {
            // Missing required characteristic descriptor
            glucoseHdlCache[HDL_GLUCOSE_MEAS_CCCD] = 0;
            newState = DISC_FAILED;
          }          
        }
      }
      break;
         
   case DISC_GLUCOSE_CTL_PNT_CCCD:
      {
        uint8_t i;
        
        // Characteristic descriptors found
        if (pMsg->method == ATT_FIND_INFO_RSP &&
            pMsg->msg.findInfoRsp.numInfo > 0 && 
            pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE)
        {
          attFindInfoRsp_t *pRsp = &(pMsg->msg.findInfoRsp);
          
          // For each handle/uuid pair
          for (i = 0; i < pRsp->numInfo; i++)
          {
            // Look for CCCD
            if ( ATT_BT_PAIR_UUID( pRsp->pInfo, i ) == GATT_CLIENT_CHAR_CFG_UUID )
            {
              // CCCD found
              glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_CCCD] =
                ATT_BT_PAIR_HANDLE( pRsp->pInfo, i );
              
              break;
            }
          }
        }
        
        // If procedure complete
        if ((pMsg->method == ATT_FIND_INFO_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          // If CCCD found
          if (glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_CCCD] != 0)
          {
            // Should we look for unread category status CCCD
            if (glucoseHdlCache[HDL_GLUCOSE_CONTEXT_START] <
                glucoseHdlCache[HDL_GLUCOSE_CONTEXT_END])
            {
              // Discover unread category status characteristic descriptors
              GATT_DiscAllCharDescs(glucCollConnHandle,
                                    glucoseHdlCache[HDL_GLUCOSE_CONTEXT_START] + 1,
                                    glucoseHdlCache[HDL_GLUCOSE_CONTEXT_END],
                                    glucCollTaskId);
                                          
              newState = DISC_GLUCOSE_CONTEXT_CCCD;
            }
            else
            {
              // Done
              newState = DISC_IDLE;
            }
          }
          else
          {
            // Missing required characteristic descriptor
            glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_CCCD] = 0;
            newState = DISC_FAILED;
          }          
        }
      }
      break;

   case DISC_GLUCOSE_CONTEXT_CCCD:
      {
        uint8_t i;
        
        // Characteristic descriptors found
        if (pMsg->method == ATT_FIND_INFO_RSP &&
            pMsg->msg.findInfoRsp.numInfo > 0 && 
            pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE)
        {
          attFindInfoRsp_t *pRsp = &(pMsg->msg.findInfoRsp);
          
          // For each handle/uuid pair
          for (i = 0; i < pRsp->numInfo; i++)
          {
            // Look for CCCD
            if ( ATT_BT_PAIR_UUID( pRsp->pInfo, i ) == GATT_CLIENT_CHAR_CFG_UUID )
            {
              // CCCD found
              glucoseHdlCache[HDL_GLUCOSE_CONTEXT_CCCD] =
                ATT_BT_PAIR_HANDLE( pRsp->pInfo, i );
              
              break;
            }
          }
        }
        
        // If procedure complete
        if ((pMsg->method == ATT_FIND_INFO_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          newState = DISC_IDLE;
        }
      }
      break;
      
    default:
      break;
  }
  
  return newState;
}
示例#5
0
/*********************************************************************
 * @fn      TimeAppDiscCurrTime()
 *
 * @brief   Current time service and characteristic discovery. 
 *
 * @param   state - Discovery state.
 * @param   pMsg - GATT message.
 *
 * @return  New discovery state.
 */
static uint8 TimeAppDiscCurrTime( uint8 state, gattMsgEvent_t *pMsg )
{
  uint8 newState = state;
  
  switch ( state )
  {
    case DISC_CURR_TIME_START:  
      {
        uint8 uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(CURRENT_TIME_SERV_UUID),
                                         HI_UINT16(CURRENT_TIME_SERV_UUID) };

        // Initialize service discovery variables
        timeAppSvcStartHdl = timeAppSvcEndHdl = 0;
        timeAppEndHdlIdx = 0;
        
        // Discover service by UUID
        GATT_DiscPrimaryServiceByUUID( gapConnHandle, uuid,
                                       ATT_BT_UUID_SIZE, thermometerTaskId );      

        newState = DISC_CURR_TIME_SVC;
      } 
      break;

    case DISC_CURR_TIME_SVC:
      // Service found, store handles
      if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
           pMsg->msg.findByTypeValueRsp.numInfo > 0 )
      {
        timeAppSvcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
        timeAppSvcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
      }
      
      // If procedure complete
      if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP  && 
             pMsg->hdr.status == bleProcedureComplete ) ||
           ( pMsg->method == ATT_ERROR_RSP ) )
      {
        // If service found
        if ( timeAppSvcStartHdl != 0 )
        {
          // Discover all characteristics
          GATT_DiscAllChars( gapConnHandle, timeAppSvcStartHdl,
                             timeAppSvcEndHdl, thermometerTaskId );
          
          newState = DISC_CURR_TIME_CHAR;
        }
        else
        {
          // Service not found
          newState = DISC_FAILED;
        }
      }    
      break;

    case DISC_CURR_TIME_CHAR:
      {
         // Characteristics found
        if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
             pMsg->msg.readByTypeRsp.numPairs > 0 && 
             pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN)
        {
          uint8   i;
          uint8   *p;
          uint16  handle;
          uint16  uuid;          
          // For each characteristic declaration
          p = pMsg->msg.readByTypeRsp.pDataList;
          for ( i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i-- )
          {
            // Parse characteristic declaration
            handle = BUILD_UINT16(p[3], p[4]);
            uuid = BUILD_UINT16(p[5], p[6]);
                   
            // If looking for end handle
            if ( timeAppEndHdlIdx != 0 )
            {
              // End handle is one less than handle of characteristic declaration
              timeAppHdlCache[timeAppEndHdlIdx] = BUILD_UINT16(p[0], p[1]) - 1;
              
              timeAppEndHdlIdx = 0;
            }

            // If UUID is of interest, store handle
            switch ( uuid )
            {
              case CT_TIME_UUID:
                timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] = handle;
                timeAppEndHdlIdx = HDL_CURR_TIME_CT_TIME_END;
                break;

              default:
                break;
            }
            
            p += CHAR_DESC_HDL_UUID16_LEN;
          }
          
        }
          
        // If procedure complete
        if ( ( pMsg->method == ATT_READ_BY_TYPE_RSP  && 
               pMsg->hdr.status == bleProcedureComplete ) ||
             ( pMsg->method == ATT_ERROR_RSP ) )
        {
          // Special case of end handle at end of service
          if ( timeAppEndHdlIdx != 0 )
          {
            timeAppHdlCache[timeAppEndHdlIdx] = timeAppSvcEndHdl;
            timeAppEndHdlIdx = 0;
          }

          // If didn't find time characteristic
          if ( timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] == 0 )
          {
            newState = DISC_FAILED;
          }

          else if ( timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] <timeAppHdlCache[HDL_CURR_TIME_CT_TIME_END] )
          {
            // Discover characteristic descriptors
            GATT_DiscAllCharDescs( gapConnHandle,
                                   timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] + 1,
                                   timeAppHdlCache[HDL_CURR_TIME_CT_TIME_END],
                                   thermometerTaskId );
                                        
            newState = DISC_CURR_TIME_CT_TIME_CCCD;
          }
          else
          {
            newState = DISC_IDLE;
          }
        }
      }      
      break;

    case DISC_CURR_TIME_CT_TIME_CCCD:
      {
        // Characteristic descriptors found
        if ( pMsg->method == ATT_FIND_INFO_RSP &&
             pMsg->msg.findInfoRsp.numInfo > 0 && 
             pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE )
        {
          uint8 i;
          
          // For each handle/uuid pair
          for ( i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++ )
          {
            // Look for CCCD
            if ( ATT_BT_PAIR_UUID(pMsg->msg.findInfoRsp.pInfo, i) ==
                                                     GATT_CLIENT_CHAR_CFG_UUID )
            {
              // CCCD found
              timeAppHdlCache[HDL_CURR_TIME_CT_TIME_CCCD] =
                             ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
              break;
            }
          }
        }
        
        // If procedure complete
        if ( ( pMsg->method == ATT_FIND_INFO_RSP  && 
               pMsg->hdr.status == bleProcedureComplete ) ||
             ( pMsg->method == ATT_ERROR_RSP ) )
        {
          newState = DISC_IDLE;
        }
      }
      break;

    default:
      break;
  }
  
  return newState;
}
/*********************************************************************
 * @fn      Time_discAlertNtf()
 *
 * @brief   Alert notification service and characteristic discovery. 
 *
 * @param   state - Discovery state.
 * @param   pMsg  - GATT message.
 *
 * @return  New discovery state.
 */
static uint8_t Time_discAlertNtf(uint8_t state, gattMsgEvent_t *pMsg)
{
  uint8_t newState = state;
  
  switch (state)
  {
    case DISC_ALERT_NTF_START:  
      {
        uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(ALERT_NOTIF_SERV_UUID),
                                           HI_UINT16(ALERT_NOTIF_SERV_UUID) };

        // Initialize service discovery variables
        Time_svcStartHdl = Time_svcEndHdl = 0;
        Time_endHdlIdx = 0;
        
        // Discover service by UUID
        GATT_DiscPrimaryServiceByUUID(Time_connHandle, uuid,
                                      ATT_BT_UUID_SIZE, ICall_getEntityId());      

        newState = DISC_ALERT_NTF_SVC;
      }
      break;

    case DISC_ALERT_NTF_SVC:
      // Service found, store handles
      if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
          pMsg->msg.findByTypeValueRsp.numInfo > 0)
      {
        Time_svcStartHdl = 
          ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
        Time_svcEndHdl = 
          ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
      }
      
      // If procedure complete
      if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP  && 
           pMsg->hdr.status == bleProcedureComplete) ||
          (pMsg->method == ATT_ERROR_RSP))
      {
        // If service found
        if (Time_svcStartHdl != 0)
        {
          // Discover all characteristics
          GATT_DiscAllChars(Time_connHandle, Time_svcStartHdl,
                            Time_svcEndHdl, ICall_getEntityId());
          
          newState = DISC_ALERT_NTF_CHAR;
        }
        else
        {
          // Service not found
          newState = DISC_FAILED;
        }
      }    
      break;

    case DISC_ALERT_NTF_CHAR:
      {
        // Characteristics found
        if (pMsg->method == ATT_READ_BY_TYPE_RSP &&
            pMsg->msg.readByTypeRsp.numPairs > 0 && 
            pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN)
        {
          uint8_t   i;
          uint8_t   *p;
          uint16_t  handle;
          uint16_t  uuid;
          
          p = pMsg->msg.readByTypeRsp.pDataList;
          
          // For each characteristic declaration
          for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--)
          {
            // Parse characteristic declaration
            handle = BUILD_UINT16(p[3], p[4]);
            uuid = BUILD_UINT16(p[5], p[6]);
                   
            // If looking for end handle
            if (Time_endHdlIdx != 0)
            {
              // End handle is one less than handle of characteristic declaration
              Time_handleCache[Time_endHdlIdx] = BUILD_UINT16(p[0], p[1]) - 1;
              
              Time_endHdlIdx = 0;
            }

            // If UUID is of interest, store handle
            switch (uuid)
            {
              case ALERT_NOTIF_CTRL_PT_UUID:
                Time_handleCache[HDL_ALERT_NTF_CTRL] = handle;
                break;

              case UNREAD_ALERT_STATUS_UUID:
                Time_handleCache[HDL_ALERT_NTF_UNREAD_START] = handle;
                Time_endHdlIdx = HDL_ALERT_NTF_UNREAD_END;
                break;

              case NEW_ALERT_UUID:
                Time_handleCache[HDL_ALERT_NTF_NEW_START] = handle;
                Time_endHdlIdx = HDL_ALERT_NTF_NEW_END;
                break;

              case SUP_NEW_ALERT_CAT_UUID:
                Time_handleCache[HDL_ALERT_NTF_NEW_CAT] = handle;
                break;

              case SUP_UNREAD_ALERT_CAT_UUID:
                Time_handleCache[HDL_ALERT_NTF_UNREAD_CAT] = handle;
                break;

              default:
                break;
            }
            
            p += CHAR_DESC_HDL_UUID16_LEN;
          }
        }
          
        // If procedure complete
        if ((pMsg->method == ATT_READ_BY_TYPE_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          // Special case of end handle at end of service
          if (Time_endHdlIdx != 0)
          {
            Time_handleCache[Time_endHdlIdx] = Time_svcEndHdl;
            Time_endHdlIdx = 0;
          }
          
          // If didn't find new alert characteristic
          if (Time_handleCache[HDL_ALERT_NTF_NEW_START] == 0)
          {
            newState = DISC_FAILED;
          }
          else if (Time_handleCache[HDL_ALERT_NTF_NEW_START] <
                   Time_handleCache[HDL_ALERT_NTF_NEW_END])
          {
            // Discover incoming alert characteristic descriptors
            GATT_DiscAllCharDescs(Time_connHandle,
                                  Time_handleCache[HDL_ALERT_NTF_NEW_START] + 1,
                                  Time_handleCache[HDL_ALERT_NTF_NEW_END],
                                  ICall_getEntityId());
                                        
            newState = DISC_ALERT_NTF_NEW_CCCD;
          }
          else
          {
            // Missing required characteristic descriptor
            Time_handleCache[HDL_ALERT_NTF_NEW_START] = 0;
            newState = DISC_FAILED;
          }
        }
      }      
      break;

    case DISC_ALERT_NTF_NEW_CCCD:
      {
        // Characteristic descriptors found
        if (pMsg->method == ATT_FIND_INFO_RSP &&
            pMsg->msg.findInfoRsp.numInfo > 0 && 
            pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE)
        {
          uint8_t i;
          
          // For each handle/uuid pair
          for (i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++)
          {
            // Look for CCCD
            if (ATT_BT_PAIR_UUID(pMsg->msg.findInfoRsp.pInfo, i) ==
                GATT_CLIENT_CHAR_CFG_UUID)
            {
              // CCCD found
              Time_handleCache[HDL_ALERT_NTF_NEW_CCCD] =
                ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
              
              break;
            }
          }
        }
        
        // If procedure complete
        if ((pMsg->method == ATT_FIND_INFO_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          // If CCCD found
          if (Time_handleCache[HDL_ALERT_NTF_NEW_CCCD] != 0)
          {
            // Should we look for unread category status CCCD
            if (Time_handleCache[HDL_ALERT_NTF_UNREAD_START] <
                Time_handleCache[HDL_ALERT_NTF_UNREAD_END])
            {
              // Discover unread category status characteristic descriptors
              GATT_DiscAllCharDescs(Time_connHandle,
                                    Time_handleCache[HDL_ALERT_NTF_UNREAD_START] + 1,
                                    Time_handleCache[HDL_ALERT_NTF_UNREAD_END],
                                    ICall_getEntityId());
                                          
              newState = DISC_ALERT_NTF_UNREAD_CCCD;
            }
            else
            {
              // Done
              newState = DISC_IDLE;
            }
          }
          else
          {
            // Missing required characteristic descriptor
            Time_handleCache[HDL_ALERT_NTF_NEW_START] = 0;
            newState = DISC_FAILED;
          }          
        }
      }
      break;

    case DISC_ALERT_NTF_UNREAD_CCCD:
      {
        // Characteristic descriptors found
        if (pMsg->method == ATT_FIND_INFO_RSP &&
            pMsg->msg.findInfoRsp.numInfo > 0 && 
            pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE)
        {
          uint8_t i;
          
          // For each handle/uuid pair
          for (i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++)
          {
            // Look for CCCD
            if (ATT_BT_PAIR_UUID(pMsg->msg.findInfoRsp.pInfo, i) ==
                GATT_CLIENT_CHAR_CFG_UUID)
            {
              // CCCD found
              Time_handleCache[HDL_ALERT_NTF_UNREAD_CCCD] =
                ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
              
              break;
            }
          }
        }
        
        // If procedure complete
        if ((pMsg->method == ATT_FIND_INFO_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          newState = DISC_IDLE;
        }
      }
      break;

    default:
      break;
  }
  
  return newState;
}
/*********************************************************************
 * @fn      Time_discRefTime()
 *
 * @brief   Reference time service and characteristic discovery. 
 *
 * @param   state - Discovery state.
 * @param   pMsg  - GATT message.
 *
 * @return  New discovery state.
 */
static uint8_t Time_discRefTime(uint8_t state, gattMsgEvent_t *pMsg)
{
  uint8_t newState = state;
  
  switch (state)
  {
    case DISC_REF_TIME_START:  
      {
        uint8_t uuid[ATT_BT_UUID_SIZE] = 
          { LO_UINT16(REF_TIME_UPDATE_SERV_UUID),
            HI_UINT16(REF_TIME_UPDATE_SERV_UUID) };

        // Initialize service discovery variables
        Time_svcStartHdl = Time_svcEndHdl = 0;
        Time_endHdlIdx = 0;
        
        // Discover service by UUID
        GATT_DiscPrimaryServiceByUUID(Time_connHandle, uuid,
                                      ATT_BT_UUID_SIZE, ICall_getEntityId());

        newState = DISC_REF_TIME_SVC;
      }
      break;

    case DISC_REF_TIME_SVC:
      // Service found, store handles
      if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
          pMsg->msg.findByTypeValueRsp.numInfo > 0)
      {
        Time_svcStartHdl = 
          ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
        Time_svcEndHdl = 
          ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
      }
      
      // If procedure complete
      if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP  && 
           pMsg->hdr.status == bleProcedureComplete) ||
          (pMsg->method == ATT_ERROR_RSP))
      {
        // If service found
        if (Time_svcStartHdl != 0)
        {
          // Discover all characteristics
          GATT_DiscAllChars(Time_connHandle, Time_svcStartHdl,
                            Time_svcEndHdl, ICall_getEntityId());
          
          newState = DISC_REF_TIME_CHAR;
        }
        else
        {
          // Service not found
          newState = DISC_FAILED;
        }
      }    
      break;

    case DISC_REF_TIME_CHAR:
      {
        // Characteristics found
        if (pMsg->method == ATT_READ_BY_TYPE_RSP &&
             pMsg->msg.readByTypeRsp.numPairs > 0 && 
             pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN)
        {
          uint8_t   i;
          uint8_t   *p;
          uint16_t  handle;
          uint16_t  uuid;
          
          p = pMsg->msg.readByTypeRsp.pDataList;
          
          // For each characteristic declaration
          for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--)
          {
            // Parse characteristic declaration
            handle = BUILD_UINT16(p[3], p[4]);
            uuid = BUILD_UINT16(p[5], p[6]);
                   
            // If UUID is of interest, store handle
            switch (uuid)
            {
              case TIME_UPDATE_CTRL_PT_UUID:
                Time_handleCache[HDL_REF_TIME_UPD_CTRL] = handle;
                break;
                
              case TIME_UPDATE_STATE_UUID:
                Time_handleCache[HDL_REF_TIME_UPD_STATE] = handle;
                break;
                
              default:
                break;
            }
            
            p += CHAR_DESC_HDL_UUID16_LEN;
          }
        }
          
        // If procedure complete
        if ((pMsg->method == ATT_READ_BY_TYPE_RSP  && 
             pMsg->hdr.status == bleProcedureComplete) ||
            (pMsg->method == ATT_ERROR_RSP))
        {
          // If didn't find mandatory characteristics
          if (Time_handleCache[HDL_REF_TIME_UPD_CTRL] == 0 ||
              Time_handleCache[HDL_REF_TIME_UPD_STATE] == 0)
          {
            newState = DISC_FAILED;
          }
          else
          {
            newState = DISC_IDLE;
          }
        }
      }      
      break;

    default:
      break;
  }

  return newState;
}
示例#8
0
static void hidappProcessGATTMsg( gattMsgEvent_t *pPkt )
{
  // Build the message first
  switch ( pPkt->method )
  {
    case ATT_HANDLE_VALUE_NOTI:
      // First try to send out pending HID report
      if ( reportRetries > 0 )
      {
        hidappSendInReport( &lastInReport );
        
        // Free last report's payload
        GATT_bm_free( (gattMsg_t *)&lastInReport, ATT_HANDLE_VALUE_NOTI );
        
        // Zero out all fields of last report
        VOID osal_memset( &lastInReport, 0, sizeof( attHandleValueNoti_t ) );
      
        reportRetries = 0;
        osal_stop_timerEx( hidappTaskId, HIDAPP_EVT_REPORT_RETRY );
      }

      // Send incoming HID report
      if ( hidappSendInReport( &(pPkt->msg.handleValueNoti) ) == FALSE )
      {
        // Save report for retries later
        osal_memcpy( &lastInReport, &(pPkt->msg.handleValueNoti), sizeof( attHandleValueNoti_t ) );

        // Report's payload is part of lastInReport now so no need to free it yet
        pPkt->msg.handleValueNoti.pValue = NULL;
        
        reportRetries = 1;
        osal_start_timerEx( hidappTaskId, HIDAPP_EVT_REPORT_RETRY, HIDAPP_INPUT_RETRY_TIMEOUT );
      }
      break;

    case ATT_FIND_BY_TYPE_VALUE_RSP:
      // Response from GATT_DiscPrimaryServiceByUUID
      // Service found, store handles
      if ( pPkt->msg.findByTypeValueRsp.numInfo > 0 )
      {
        serviceStartHandle = 
          ATT_ATTR_HANDLE(pPkt->msg.findByTypeValueRsp.pHandlesInfo, 0);
        serviceEndHandle = 
          ATT_GRP_END_HANDLE(pPkt->msg.findByTypeValueRsp.pHandlesInfo, 0);
      }
      // If procedure complete
      else if ( pPkt->hdr.status == bleProcedureComplete )
      {
        if ( serviceStartHandle != 0 )
        {
          if ( serviceToDiscover == GATT_SERVICE_UUID )
          {
            // Begin the search for characteristic handle of the service
            readReq.startHandle = serviceStartHandle;
            readReq.endHandle = serviceEndHandle;
            readReqType.len = 2;
            readReqType.uuid[0] = LO_UINT16(SERVICE_CHANGED_UUID);
            readReqType.uuid[1] = HI_UINT16(SERVICE_CHANGED_UUID);
            readReq.type = readReqType;

            GATT_DiscCharsByUUID(connHandle, &readReq, hidappTaskId );
          }
          else if ( serviceToDiscover == HID_SERV_UUID )
          {
            // Discover all characteristics
            GATT_DiscAllChars( connHandle, serviceStartHandle, serviceEndHandle, hidappTaskId );
          }
        }
      }
      break;

    case ATT_READ_BY_TYPE_RSP:
      // Response from Discover all Characteristics.
      // Success indicates packet with characteristic discoveries.
      if ( pPkt->hdr.status == SUCCESS )
      {
        attReadByTypeRsp_t *pRsp = &pPkt->msg.readByTypeRsp;
        uint8 idx = 0;

        if ( serviceToDiscover == GATT_SERVICE_UUID )
        {
          // We have discovered the GATT Service Characteristic handle
          serviceChangeHandle = BUILD_UINT16( pRsp->pDataList[3],
                                              pRsp->pDataList[4] );
          
          // Break to skip next part, it doesn't apply here
          break;
        }

        // Search characteristics for those with notification permissions.
        while( idx < ((pRsp->numPairs * pRsp->len) - 1) )
        {
          // Check permissions of characteristic for notification permission
          if ( (pRsp->pDataList[idx+2] & GATT_PROP_NOTIFY ) )
          {
            uint16* pHandle = (mouseCharHandle == GATT_INVALID_HANDLE) ? &mouseCharHandle : &keyCharHandle ;

            if ( pHandle == &keyCharHandle && consumerCtrlCharHandle == GATT_INVALID_HANDLE )
            {
              pHandle = ( keyCharHandle == GATT_INVALID_HANDLE ) ? &keyCharHandle : &consumerCtrlCharHandle;
            }

            if ( *pHandle == GATT_INVALID_HANDLE )
            {
              *pHandle = BUILD_UINT16( pRsp->pDataList[idx+3], pRsp->pDataList[idx+4] );
            }
          }

          idx += pRsp->len;
        }
      }
      // This indicates that there is no more characteristic data
      // to be discovered within the given handle range.
      else if ( pPkt->hdr.status == bleProcedureComplete )
      {
        if ( serviceToDiscover == GATT_SERVICE_UUID )
        {
          // Begin Service Discovery of HID Service
          serviceToDiscover = HID_SERV_UUID;
          hidappDiscoverService( connHandle, HID_SERV_UUID );
          // Break to skip next part, it doesn't apply yet.
          break;
        }

        if ( enableCCCDs == TRUE )
        {
          mouseCCCHandle = mouseCharHandle + 1;

          // Begin configuring the characteristics for notifications
          hidappEnableNotification( connHandle, mouseCCCHandle );
        }
        else
        {
          serviceDiscComplete = TRUE;
        }
      }
      break;

    case ATT_WRITE_RSP:
      if ( pPkt->hdr.status == SUCCESS && !serviceDiscComplete )
      {
        uint16 handle = ( keyCCCHandle == GATT_INVALID_HANDLE ) ?
                        ( keyCCCHandle = keyCharHandle + 1 ) :
                        ( consumerCtrlCCCHandle = consumerCtrlCharHandle + 1 );

        hidappEnableNotification( connHandle, handle );

        if ( consumerCtrlCCCHandle != GATT_INVALID_HANDLE)
        {
          serviceDiscComplete = TRUE;
        }
      }
      break;

    // Service Change indication
    case ATT_HANDLE_VALUE_IND:
      // Note: this logic assumes that the only indications that will be sent
      //       will come from that GATT Service Changed Characteristic
      if ( pPkt->hdr.status == SUCCESS )
      {
        serviceChange = CHANGE_OCCURED;

        // Acknowledge receipt of indication
        ATT_HandleValueCfm( pPkt->connHandle );

        // Handles in server have changed while devices are connected
        if ( ( gapBondMgrState == PAIRED_BONDED_STATE ) &&
            ( serviceChangeHandle == pPkt->msg.handleValueInd.handle ) )
        {
          // Begin Service Discovery of HID Service
          serviceToDiscover = HID_SERV_UUID;
          hidappDiscoverService( connHandle, HID_SERV_UUID );

          serviceChange = NO_CHANGE;
        }
      }
      break;

    default:
      // Unknown event
      break;
  }
  
  GATT_bm_free( &pPkt->msg, pPkt->method );
}