Esempio n. 1
0
/*********************************************************************
 * @fn      Thermometer_sendStoredMeas
 *
 * @brief   Prepare and send a stored Meas Indication.
 *
 * @param   none
 *
 * @return  none
 */
static void Thermometer_sendStoredMeas(void)
{ 
  // If previously connected to this peer send any stored measurements.
  if (thStoreStartIndex != thStoreIndex)
  {
    bStatus_t status = FAILURE;
    attHandleValueInd_t *pStoreInd = &thStoreMeas[thStoreStartIndex];
  
    if (pStoreInd->handle == THERMOMETER_TEMP_VALUE_POS)
    {
      // Send Measurement.
      status  = Thermometer_TempIndicate(thermometer_connHandle, 
                                         pStoreInd, ICall_getEntityId());
    }
    else if (pStoreInd->handle == THERMOMETER_INTERVAL_VALUE_POS)
    {
      // Send Interval.
      status = Thermometer_IntervalIndicate(thermometer_connHandle, 
                                            pStoreInd, ICall_getEntityId());
    }
    
    if (status == SUCCESS)
    {
      thStoreStartIndex = thStoreStartIndex + 1;
      
      // Wrap around buffer.
      if(thStoreStartIndex > TH_STORE_MAX)
      {
        thStoreStartIndex = 0;
      }
      
      // Clear out this Meas indication.
      memset(pStoreInd, 0, sizeof(attHandleValueInd_t));
    }
  }
}
/*********************************************************************
 * @fn      Time_configNext()
 *
 * @brief   Perform the characteristic configuration read or
 *          write procedure.
 *
 * @param   state - Configuration state.
 *
 * @return  New configuration state.
 */
uint8_t Time_configNext(uint8_t state)
{
  bool read;

  // Find next non-zero cached handle of interest
  while (state < TIME_CONFIG_MAX &&
          Time_handleCache[Time_configList[state]] == 0)
  {
    state++;
  }

  // Return if reached end of list
  if (state >= TIME_CONFIG_MAX)
  {
    return TIME_CONFIG_CMPL;
  }

  // Determine what to do with characteristic
  switch (Time_configList[state])
  {
    // Read these characteristics
    case HDL_CURR_TIME_CT_TIME_START:
      read = TRUE;
      break;

    // Set notification for these characteristics
    case HDL_CURR_TIME_CT_TIME_CCCD:
      read = FALSE;
      break;

    default:
      return state;
  }

  if(Time_configDone==TRUE)
  {
    return state;
  }
  
  // Do a GATT read or write
  if (read)
  {
    attReadReq_t  readReq;
      
    readReq.handle = Time_handleCache[Time_configList[state]];
    
    // Send the read request
    GATT_ReadCharValue(Time_connHandle, &readReq, ICall_getEntityId());
    
    // Only reading time right now
    Time_configDone = TRUE;
  }
  else
  {
    attWriteReq_t writeReq;
    
    writeReq.pValue = GATT_bm_alloc(Time_connHandle, ATT_WRITE_REQ, 2, NULL);
    if (writeReq.pValue != NULL)
    {
      writeReq.len = 2;
      writeReq.pValue[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
      writeReq.pValue[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
      writeReq.sig = 0;
      writeReq.cmd = 0;

      writeReq.handle = Time_handleCache[Time_configList[state]];
      
      // Send the read request
      if (GATT_WriteCharValue(Time_connHandle, &writeReq, 
                              ICall_getEntityId()) != SUCCESS)
      {
        GATT_bm_free((gattMsg_t *)&writeReq, ATT_WRITE_REQ);
      }
    }
  }

  return state;
}
/*********************************************************************
 * @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;
}
Esempio n. 5
0
/*********************************************************************
 * @fn      Thermometer_handleKeys
 *
 * @brief   Handles all key events for this device.
 *
 * @param   shift - true if in shift/alt.
 * @param   keys - bit field for key events.
 *
 * @return  none
 */
static void Thermometer_handleKeys(uint8_t shift, uint8_t keys)
{
  bStatus_t status; 
  uint8_t notify_interval;
  
  if (keys & KEY_UP)
  {
    // Set simulated measurement flag index.
    thermometerFlagsIdx+=1;
    
    if (thermometerFlagsIdx == FLAGS_IDX_MAX)
    {
      thermometerFlagsIdx = 0;
    }
  }
  
  // Read stored interval value.
  Thermometer_GetParameter(THERMOMETER_INTERVAL, &notify_interval); 

  if(notify_interval == 0)
  {
    thMeasTimerRunning = FALSE;
  }
  
  if (keys & KEY_RIGHT)
  {
    // If device is not in a connection, pressing the right key should toggle
    // advertising on and off. If timer is running, then will adv when meas is 
    // ready.
    if((gapProfileState != GAPROLE_CONNECTED) && (thMeasTimerRunning == FALSE))
    {
      uint8_t current_adv_enabled_status;
      uint8_t new_adv_enabled_status;
      
      // Find the current GAP advertisement status.
      GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED, &current_adv_enabled_status);
      
      if(current_adv_enabled_status == FALSE)
      {
        new_adv_enabled_status = TRUE;
      }
      else
      {
        new_adv_enabled_status = FALSE;
      }
      
      // Change the GAP advertisement status to opposite of current status.
      GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                           &new_adv_enabled_status);   
    }
    // Timer is running, so allow simulated changes.
    else
    {
      // Change temperature, remove single precision.
      if((thermometerCelcius) < 0x000175)
      {
        thermometerCelcius += 1;
      }
      else
      {
        uint16_t thInterval = 30;
        
        thermometerCelcius = 0x000173;

        // Simulate interval change.
        Thermometer_SetParameter(THERMOMETER_INTERVAL, THERMOMETER_INTERVAL_LEN,
                                 &thInterval);
        
        if(temperatureIntervalConfig == true) 
        {
          attHandleValueInd_t intervalInd;
          
          intervalInd.pValue = GATT_bm_alloc(thermometer_connHandle, 
                                             ATT_HANDLE_VALUE_IND, 
                                             THERMOMETER_INTERVAL_LEN, NULL);
          if (intervalInd.pValue != NULL)
          {
            intervalInd.len = THERMOMETER_INTERVAL_LEN;
            intervalInd.pValue[0] = LO_UINT16(thInterval);
            intervalInd.pValue[1] = HI_UINT16(thInterval);
            intervalInd.handle = THERMOMETER_INTERVAL_VALUE_POS;
        
            status = Thermometer_IntervalIndicate(thermometer_connHandle, 
                                                  &intervalInd,
                                                  ICall_getEntityId());
            // We can fail if there was pending meas or not connected.
            if (status != SUCCESS)
            {
              // Queue indication.
              Thermometer_storeIndications(&intervalInd);
            }
          }
        }
      }
    }
  }
}