예제 #1
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;
}
예제 #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
파일: hidapp.c 프로젝트: AubrCool/BLE
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 );

        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 ) );

        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 = pPkt->msg.findByTypeValueRsp.handlesInfo[0].handle;
        serviceEndHandle   = pPkt->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
      }
      // 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_SERVICE_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 rsp = pPkt->msg.readByTypeRsp;
        uint8 idx = 0;

        if ( serviceToDiscover ==  GATT_SERVICE_UUID )
        {
          // We have discovered the GATT Service Characteristic handle
          uint8 low = LO_UINT16(pPkt->msg.readByTypeRsp.dataList[3]);
          uint8 high = HI_UINT16(pPkt->msg.readByTypeRsp.dataList[4]);
          serviceChangeHandle = BUILD_UINT16(low, high);
          // Break to skip next part, it doesn't apply here
          break;
        }

        // Search characteristics for those with notification permissions.
        while( idx < ((rsp.numPairs * rsp.len ) - 1))
        {
          // Check permissions of characteristic for notification permission
          if ( (rsp.dataList[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( rsp.dataList[idx+3], rsp.dataList[idx+4] );
            }
          }

          idx += rsp.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_SERVICE_UUID;
          hidappDiscoverService( connHandle, HID_SERVICE_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_SERVICE_UUID;
          hidappDiscoverService( connHandle, HID_SERVICE_UUID );

          serviceChange = NO_CHANGE;
        }
      }
      break;

    default:
      // Unknown event
      break;
  }
}
예제 #4
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_SVC_UUID),
                                         HI_UINT16(CURRENT_TIME_SVC_UUID) };

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

        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 = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
        timeAppSvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
      }
      
      // 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, bloodPressureTaskId );
          
          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.dataList;
          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],
                                   bloodPressureTaskId );
                                        
            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 ( (pMsg->msg.findInfoRsp.info.btPair[i].uuid[0] ==
                  LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID)) &&
                 (pMsg->msg.findInfoRsp.info.btPair[i].uuid[1] ==
                  HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID)) )
            {
              // CCCD found
              timeAppHdlCache[HDL_CURR_TIME_CT_TIME_CCCD] =
                pMsg->msg.findInfoRsp.info.btPair[i].handle;
              
              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      softCmdDiscGenCtrl()
 *
 * @brief   Generic control service and characteristic discovery. 
 *
 * @param   state - Discovery state.
 * @param   pMsg - GATT message.
 *
 * @return  New discovery state.
 */
static uint8 softCmdDiscGenCtrl( uint8 state, gattMsgEvent_t *pMsg )
{
  uint8 newState = state;
  
  switch ( state )
  {
    case DISC_GEN_CTRL_START:  
      {
        uint8 uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(GEN_CTRL_SERVICE_UUID),
                                         HI_UINT16(GEN_CTRL_SERVICE_UUID) };

        // Initialize service discovery variables
        softCmdSvcStartHdl = softCmdSvcEndHdl = 0;
        
        // Discover service by UUID
        GATT_DiscPrimaryServiceByUUID( softCmdConnHandle, uuid,
                                       ATT_BT_UUID_SIZE, softCmdTaskId );      

        newState = DISC_GEN_CTRL_SVC;
      } 
      break;

    case DISC_GEN_CTRL_SVC:
      // Service found, store handles
      if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
           pMsg->msg.findByTypeValueRsp.numInfo > 0 )
      {
        softCmdSvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
        softCmdSvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
      }
      
      // 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 ( softCmdSvcStartHdl != 0 )
        {
          // Discover all characteristics
          GATT_DiscAllChars( softCmdConnHandle, softCmdSvcStartHdl,
                             softCmdSvcEndHdl, softCmdTaskId );
          
          newState = DISC_GEN_CTRL_CHAR;
        }
        else
        {
          // Service not found
          newState = DISC_FAILED;
        }
      }    
      break;

    case DISC_GEN_CTRL_CHAR:
      {
        uint8   i;
        uint8   *p;
        uint16  handle;
        uint16  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.dataList;
          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 GEN_CMD_UUID:
                softCmdHdlCache[HDL_GEN_CTRL_GEN_CMD] = handle;
                break;

              case CMD_ENUM_UUID:
                softCmdHdlCache[HDL_GEN_CTRL_CMD_ENUM] = 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 Generic Command then fail
          if ( softCmdHdlCache[HDL_GEN_CTRL_GEN_CMD] == 0 )
          {
            newState = DISC_FAILED;
          }
          // If found Command Enumeration read it
          else if ( softCmdHdlCache[HDL_GEN_CTRL_CMD_ENUM] != 0 )
          {
            attReadReq_t  readReq;

            readReq.handle = softCmdHdlCache[HDL_GEN_CTRL_CMD_ENUM];
            GATT_ReadCharValue( softCmdConnHandle, &readReq, softCmdTaskId );
            
            newState = DISC_GEN_CTRL_READ_ENUM;
          }
          else
          {
            newState = DISC_IDLE;
          }
        }
      }      
      break;

    case DISC_GEN_CTRL_READ_ENUM:
      // Currently nothing is done when this characteristic is read
      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;
}