/********************************************************************* * @fn scanParamWriteAttrCB * * @brief Validate attribute data prior to a write operation * * @param connHandle - connection message was received on * @param pAttr - pointer to attribute * @param pValue - pointer to data to be written * @param len - length of data * @param offset - offset of the first octet to be written * @param complete - whether this is the last packet * @param oper - whether to validate and/or write attribute value * * @return Success or Failure */ static bStatus_t scanParamWriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint8 len, uint16 offset ) { bStatus_t status = SUCCESS; // Make sure it's not a blob operation (no attributes in the profile are long) if ( offset > 0 ) { return ( ATT_ERR_ATTR_NOT_LONG ); } uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); // Only one writeable attribute if ( uuid == SCAN_INTERVAL_WINDOW_UUID ) { // require encryption if ( linkDB_Encrypted( connHandle ) == FALSE ) { return ( ATT_ERR_INSUFFICIENT_ENCRYPT ); } if ( len == SCAN_INTERVAL_WINDOW_CHAR_LEN ) { uint16 interval = BUILD_UINT16( pValue[0], pValue[1] ); uint16 window = BUILD_UINT16( pValue[0], pValue[1] ); // Validate values if ( window <= interval ) { osal_memcpy( pAttr->pValue, pValue, len ); (*scanParamServiceCB)( SCAN_INTERVAL_WINDOW_SET ); } else { status = ATT_ERR_INVALID_VALUE; } } else { status = ATT_ERR_INVALID_VALUE_SIZE; } } else if ( uuid == GATT_CLIENT_CHAR_CFG_UUID ) { status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY ); } else { status = ATT_ERR_ATTR_NOT_FOUND; } return ( status ); }
/********************************************************************* * @fn glucose_ReadAttrCB * * @brief Read an attribute. * * @param connHandle - connection message was received on * @param pAttr - pointer to attribute * @param pValue - pointer to data to be read * @param pLen - length of data to be read * @param offset - offset of the first octet to be read * @param maxLen - maximum length of data to be read * * @return Success or Failure */ static uint8 glucose_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen ) { bStatus_t status = SUCCESS; // Require security for all characteristics if ( linkDB_Encrypted( connHandle ) == FALSE ) { return ATT_ERR_INSUFFICIENT_ENCRYPT; } // Make sure it's not a blob operation (no attributes in the profile are long) if ( offset > 0 ) { return ( ATT_ERR_ATTR_NOT_LONG ); } if ( pAttr->type.len == ATT_BT_UUID_SIZE ) { // 16-bit UUID uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); switch ( uuid ) { // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases; // gattserverapp handles those types for reads case GLUCOSE_FEATURE_UUID: *pLen = 2; pValue[0] = LO_UINT16( glucoseFeature ); pValue[1] = HI_UINT16( glucoseFeature ); break; default: // Should never get here! (characteristics 3 and 4 do not have read permissions) *pLen = 0; status = ATT_ERR_ATTR_NOT_FOUND; break; } } return ( status ); }
/********************************************************************* * @fn glucose_WriteAttrCB * * @brief Validate attribute data prior to a write operation * * @param connHandle - connection message was received on * @param pAttr - pointer to attribute * @param pValue - pointer to data to be written * @param len - length of data * @param offset - offset of the first octet to be written * * @return Success or Failure */ static bStatus_t glucose_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint8 len, uint16 offset ) { bStatus_t status = SUCCESS; // Require security for all characteristics if ( linkDB_Encrypted( connHandle ) == FALSE ) { return ATT_ERR_INSUFFICIENT_ENCRYPT; } // Make sure it's not a blob operation (no attributes in the profile are long) if ( offset > 0 ) { return ( ATT_ERR_ATTR_NOT_LONG ); } uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); switch ( uuid ) { case GATT_CLIENT_CHAR_CFG_UUID: // Glucose Notifications if ((pAttr->handle == glucoseAttrTbl[GLUCOSE_MEAS_CONFIG_POS].handle || pAttr->handle == glucoseAttrTbl[GLUCOSE_CONTEXT_CONFIG_POS].handle)) { status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY ); if ( status == SUCCESS ) { uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); if(pAttr->handle == glucoseAttrTbl[GLUCOSE_MEAS_CONFIG_POS].handle) { (*glucoseServiceCB)((charCfg == 0) ? GLUCOSE_MEAS_NTF_DISABLED : GLUCOSE_MEAS_NTF_ENABLED, NULL, NULL); } else { (*glucoseServiceCB)((charCfg == 0) ? GLUCOSE_CONTEXT_NTF_DISABLED : GLUCOSE_CONTEXT_NTF_ENABLED, NULL, NULL); } } } // Glucose Indications else if ( pAttr->handle == glucoseAttrTbl[GLUCOSE_CTL_PNT_CONFIG_POS].handle ) { status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_INDICATE ); if ( status == SUCCESS ) { uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); (*glucoseServiceCB)((charCfg == 0) ? GLUCOSE_CTL_PNT_IND_DISABLED : GLUCOSE_CTL_PNT_IND_ENABLED, NULL, NULL); } } else { status = ATT_ERR_INVALID_VALUE; } break; case RECORD_CONTROL_POINT_UUID: if(len >= GLUCOSE_CTL_PNT_MIN_SIZE && len <= GLUCOSE_CTL_PNT_MAX_SIZE) { uint8 opcode = pValue[0]; // if transfer in progress if (opcode != CTL_PNT_OP_ABORT && glucoseSendAllRecords) { status = GLUCOSE_ERR_IN_PROGRESS; } // if CCC not configured for glucose measurement else if ( opcode == CTL_PNT_OP_REQ && !( GATTServApp_ReadCharCfg( connHandle, glucoseMeasConfig ) & GATT_CLIENT_CFG_NOTIFY ) ) { status = GLUCOSE_ERR_CCC_CONFIG; } else { (*glucoseServiceCB)(GLUCOSE_CTL_PNT_CMD, pValue, len); } } else { status = ATT_ERR_INVALID_VALUE_SIZE; } break; default: status = ATT_ERR_ATTR_NOT_FOUND; break; } return ( status ); }