コード例 #1
0
ファイル: nRF51GattServer.cpp プロジェクト: kliboon/mbed
ble_error_t nRF51GattServer::updateValue(uint16_t charHandle, uint8_t buffer[], uint16_t len, bool localOnly)
{
    if (localOnly)
    {
        /* Only update locally regardless of notify/indicate */
        ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(nrfCharacteristicHandles[charHandle].value_handle, 0, &len, buffer), BLE_ERROR_PARAM_OUT_OF_RANGE );
    }
    if ((p_characteristics[charHandle]->properties & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)) &&
            (m_connectionHandle != BLE_CONN_HANDLE_INVALID) )
    {
        /* HVX update for the characteristic value */
        ble_gatts_hvx_params_t hvx_params;

        hvx_params.handle = nrfCharacteristicHandles[charHandle].value_handle;
        hvx_params.type   = (p_characteristics[charHandle]->properties & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)  ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
        hvx_params.offset = 0;
        hvx_params.p_data = buffer;
        hvx_params.p_len  = &len;

        error_t error = (error_t) sd_ble_gatts_hvx(m_connectionHandle, &hvx_params);

        /* ERROR_INVALID_STATE, ERROR_BUSY, ERROR_GATTS_SYS_ATTR_MISSING and ERROR_NO_TX_BUFFERS the ATT table has been updated. */
        if ( (error != ERROR_NONE                      ) && (error != ERROR_INVALID_STATE) &&
                (error != ERROR_BLE_NO_TX_BUFFERS         ) && (error != ERROR_BUSY         ) &&
                (error != ERROR_BLEGATTS_SYS_ATTR_MISSING ) )
        {
            ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(nrfCharacteristicHandles[charHandle].value_handle, 0, &len, buffer), BLE_ERROR_PARAM_OUT_OF_RANGE );
        }
    } else
    {
        ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(nrfCharacteristicHandles[charHandle].value_handle, 0, &len, buffer), BLE_ERROR_PARAM_OUT_OF_RANGE );
    }

    return BLE_ERROR_NONE;
}
コード例 #2
0
/**@brief Function for handling the Connect event.
 *
 * @param[in]   p_hids      HID Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static void on_connect(ble_hids_t * p_hids, ble_evt_t * p_ble_evt)
{
    uint32_t          err_code;
    uint8_t           default_protocol_mode;
    ble_gatts_value_t gatts_value;

    p_hids->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;

    if (p_hids->protocol_mode_handles.value_handle)
    {
        // Set Protocol Mode characteristic value to default value
        default_protocol_mode = DEFAULT_PROTOCOL_MODE;
    
        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));
    
        gatts_value.len     = sizeof(uint8_t);
        gatts_value.offset  = 0;
        gatts_value.p_value = &default_protocol_mode;
    
        err_code = sd_ble_gatts_value_set(p_hids->conn_handle,
                                          p_hids->protocol_mode_handles.value_handle,
                                          &gatts_value);
        if ((err_code != NRF_SUCCESS) && (p_hids->error_handler != NULL))
        {
            p_hids->error_handler(err_code);
        }
    }
}
コード例 #3
0
uint32_t sd_ble_gatts_value_set(uint16_t handle, uint16_t offset, uint16_t* const p_len, uint8_t const * const p_value) {
  ble_gatts_value_t val;

  val.len = *p_len;
  val.offset = offset;
  val.p_value = (uint8_t*)p_value;
  sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID, handle, &val);
}
コード例 #4
0
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location)
{
    #if 0
    uint16_t len = sizeof(uint8_t);
    return sd_ble_gatts_value_set(p_hrs->bsl_handles.value_handle, 0, &len, &body_sensor_location);
    #else
    return 0;
    #endif
}
コード例 #5
0
ファイル: ble_bas.c プロジェクト: etx/Espruino
uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level)
{
    if (p_bas == NULL)
    {
        return NRF_ERROR_NULL;
    }

    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;

    if (battery_level != p_bas->battery_level_last)
    {
        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));

        gatts_value.len     = sizeof(uint8_t);
        gatts_value.offset  = 0;
        gatts_value.p_value = &battery_level;

        // Update database.
        err_code = sd_ble_gatts_value_set(p_bas->conn_handle,
                                          p_bas->battery_level_handles.value_handle,
                                          &gatts_value);
        if (err_code == NRF_SUCCESS)
        {
            // Save new battery value.
            p_bas->battery_level_last = battery_level;
        }
        else
        {
            return err_code;
        }

        // Send value if connected and notifying.
        if ((p_bas->conn_handle != BLE_CONN_HANDLE_INVALID) && p_bas->is_notification_supported)
        {
            ble_gatts_hvx_params_t hvx_params;

            memset(&hvx_params, 0, sizeof(hvx_params));

            hvx_params.handle = p_bas->battery_level_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = gatts_value.offset;
            hvx_params.p_len  = &gatts_value.len;
            hvx_params.p_data = gatts_value.p_value;

            err_code = sd_ble_gatts_hvx(p_bas->conn_handle, &hvx_params);
        }
        else
        {
            err_code = NRF_ERROR_INVALID_STATE;
        }
    }

    return err_code;
}
コード例 #6
0
ファイル: ble_tps.c プロジェクト: 1072258106/duband
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level)
{
    uint16_t len = sizeof(int8_t);
    
    // Update database
    return sd_ble_gatts_value_set(p_tps->tx_power_level_handles.value_handle, 
                                  0, 
                                  &len, 
                                  (uint8_t*)&tx_power_level);
}
コード例 #7
0
/**@brief Function for decoding a command packet with RPC_SD_BLE_GATTS_VALUE_SET opcode.
 *
 * This function will decode the command, call the BLE Stack API, and also send command response
 * to the peer through the the transport layer.
 *
 * @param[in] p_command         The encoded structure that needs to be decoded and passed on
 *                              to the BLE Stack API.
 * @param[in] command_len       The length of the encoded command read from transport layer.
 *
 * @retval NRF_SUCCESS               If the decoding of the command was successful, the SoftDevice
 *                                   API was called, and the command response was sent to peer,
 *                                   otherwise an error code.
 * @retval NRF_ERROR_INVALID_LENGTH  If the content length of the packet is not conforming to the
 *                                   codec specification.
 */
static uint32_t gatts_value_set_handle(uint8_t const * const p_command, uint32_t command_len)
{
    uint16_t handle;
    uint16_t offset;
    uint32_t err_code;

    uint32_t        index    = 0;
    uint16_t        length   = 0;
    uint16_t *      p_length = NULL;
    const uint8_t * p_value  = NULL;

    handle  = uint16_decode(&p_command[index]);
    index  += sizeof(uint16_t);
    RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_VALUE_SET);

    offset  = uint16_decode(&p_command[index]);
    index  += sizeof(uint16_t);
    RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_VALUE_SET);

    // Value length present.
    if (p_command[index++] == RPC_BLE_FIELD_PRESENT)
    {
        length    = uint16_decode(&p_command[index]);
        p_length  = &length;
        index    += sizeof(uint16_t);
    }

    RPC_DECODER_LENGTH_CHECK(command_len, (index + length), SD_BLE_GATTS_VALUE_SET);

    // Value present.
    if (p_command[index++] == RPC_BLE_FIELD_PRESENT)
    {
        p_value = &p_command[index];
    }

    RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_VALUE_SET);

    err_code = sd_ble_gatts_value_set(handle, offset, p_length, p_value);

    if (err_code == NRF_SUCCESS)
    {
        uint8_t resp_data[sizeof(uint16_t)];
        UNUSED_VARIABLE(uint16_encode(*p_length, resp_data));

        return ble_rpc_cmd_resp_data_send(SD_BLE_GATTS_VALUE_SET,
                                          err_code,
                                          resp_data,
                                          sizeof(resp_data));
    }
    else
    {
        return ble_rpc_cmd_resp_send(SD_BLE_GATTS_VALUE_SET, err_code);
    }
}
コード例 #8
0
bool nRF51822::updateCharacteristicValue(BLECharacteristic& characteristic) {
  bool success = true;

  for (int i = 0; i < this->_numLocalCharacteristics; i++) {
    struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i];

    if (localCharacteristicInfo->characteristic == &characteristic) {
      if (&characteristic == this->_broadcastCharacteristic) {
        this->broadcastCharacteristic(characteristic);
      }

      uint16_t valueLength = characteristic.valueLength();

      sd_ble_gatts_value_set(localCharacteristicInfo->handles.value_handle, 0, &valueLength, characteristic.value());

      ble_gatts_hvx_params_t hvxParams;

      memset(&hvxParams, 0, sizeof(hvxParams));

      hvxParams.handle = localCharacteristicInfo->handles.value_handle;
      hvxParams.offset = 0;
      hvxParams.p_data = NULL;
      hvxParams.p_len  = &valueLength;

      if (localCharacteristicInfo->notifySubscribed) {
        if (this->_txBufferCount > 0) {
          this->_txBufferCount--;

          hvxParams.type = BLE_GATT_HVX_NOTIFICATION;

          sd_ble_gatts_hvx(this->_connectionHandle, &hvxParams);
        } else {
          success = false;
        }
      }

      if (localCharacteristicInfo->indicateSubscribed) {
        if (this->_txBufferCount > 0) {
          this->_txBufferCount--;

          hvxParams.type = BLE_GATT_HVX_INDICATION;

          sd_ble_gatts_hvx(this->_connectionHandle, &hvxParams);
        } else {
          success = false;
        }
      }
    }
  }

  return success;
}
コード例 #9
0
ファイル: ble_hrs.c プロジェクト: etx/Espruino
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location)
{
    ble_gatts_value_t gatts_value;

    // Initialize value struct.
    memset(&gatts_value, 0, sizeof(gatts_value));

    gatts_value.len     = sizeof(uint8_t);
    gatts_value.offset  = 0;
    gatts_value.p_value = &body_sensor_location;

    return sd_ble_gatts_value_set(p_hrs->conn_handle, p_hrs->bsl_handles.value_handle, &gatts_value);
}
コード例 #10
0
ファイル: nrf_ble_cgms.c プロジェクト: AaltoNEPPI/nRF52_dev
ret_code_t nrf_ble_cgms_update_status(nrf_ble_cgms_t * p_cgms, nrf_ble_cgm_status_t * p_status)
{
    uint8_t           encoded_status[NRF_BLE_CGMS_STATUS_LEN];
    ble_gatts_value_t status_val;

    memset(&status_val, 0, sizeof(status_val));
    p_cgms->sensor_status = *p_status;
    status_val.len        = encode_status(encoded_status, p_cgms);
    status_val.p_value    = encoded_status;
    status_val.offset     = 0;

    return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.status.value_handle,
                                   &status_val));
}
コード例 #11
0
/**@brief Function for setting the Record. */
uint32_t ble_display_service_record_set(ble_display_service_t * p_display_service, ble_display_service_record_t * p_record)
{
	ble_gatts_value_t gatts_value;
	uint8_t encoded_value[MAX_RECORD_LEN];

	    // Initialize value struct.
	memset(&gatts_value, 0, sizeof(gatts_value));

	gatts_value.len     = record_encode(p_record, encoded_value);
	gatts_value.offset  = 0;
	gatts_value.p_value = encoded_value;

	return sd_ble_gatts_value_set(p_display_service->conn_handle, p_display_service->record_handles.value_handle, &gatts_value);
}
コード例 #12
0
ファイル: ble_ambient.c プロジェクト: leokho/SETEC-Pandlets
/**@brief Function for updating the Ambient Service service values.
 *
 * @param[in]   p_amb             Ambient Service Service structure.
 * @param[in]   values            Buffer with new values.
 * @param[in]   number_of_bytes   Size of the buffer.
 * @param[in]   type              Type of the value.
 *
 * @return      NRF_SUCCESS on success, otherwise an error code.
 * @return 		BLE_ERROR_GATTS_SYS_ATTR_MISSING if notifications disabled
 */
uint32_t ble_ambient_sensor_update(ble_ambient_t * p_amb, uint8_t * values, uint8_t number_of_bytes,
				ble_ambient_sensor_type type){
	
    uint32_t err_code = NRF_SUCCESS;
    
	int i, t;
	
	for(i = 0; i < AMB_NUMBER_OF_SENSORS; i++){
		if(type_to_handle[i].type == type){

			uint16_t len = (uint16_t)number_of_bytes;

			// Save new axis value
			for(t = 0; t < number_of_bytes; t++) type_to_handle[i].value[t] = values[t];

			// Update database
			err_code = sd_ble_gatts_value_set((*(type_to_handle[i].handle)).value_handle,
											  0,
											  &len,
											  values);
			if (err_code != NRF_SUCCESS)
				return err_code;

			// Send value if connected and notifying
			if ((p_amb->conn_handle != BLE_CONN_HANDLE_INVALID) && p_amb->is_notification_supported){
				ble_gatts_hvx_params_t hvx_params;

				memset(&hvx_params, 0, sizeof(hvx_params));

				hvx_params.handle = (*(type_to_handle[i].handle)).value_handle;
				hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
				hvx_params.offset = 0;
				hvx_params.p_len  = &len;
				hvx_params.p_data = values;

				err_code = sd_ble_gatts_hvx(p_amb->conn_handle, &hvx_params);
			}
			else
				err_code = NRF_ERROR_INVALID_STATE; //no-one is connected!

			return err_code;			
		}	
	}
	
	//type doesn't exist
	err_code = NRF_ERROR_NOT_FOUND;
	return err_code;
}
コード例 #13
0
ファイル: nrf_ble_cgms.c プロジェクト: AaltoNEPPI/nRF52_dev
ret_code_t nrf_ble_cgms_srt_set(nrf_ble_cgms_t * p_cgms, uint16_t run_time)
{
    ble_gatts_value_t srt_val;
    uint8_t           encoded_session_run_time[NRF_BLE_CGMS_SRT_LEN];
    uint8_t           gatts_value_set_len = 0;

    gatts_value_set_len = uint16_encode(run_time, encoded_session_run_time); // (p_sst, encoded_start_session_time);

    memset(&srt_val, 0, sizeof(ble_gatts_value_t));
    srt_val.len     = gatts_value_set_len;
    srt_val.p_value = encoded_session_run_time;
    srt_val.offset  = 0;

    return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.srt.value_handle,
                                   &srt_val));
}
コード例 #14
0
ファイル: ble_tps.c プロジェクト: AaltoNEPPI/nRF52_dev
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level)
{
    ble_gatts_value_t gatts_value;

    // Initialize value struct.
    memset(&gatts_value, 0, sizeof(gatts_value));

    gatts_value.len     = sizeof(uint8_t);
    gatts_value.offset  = 0;
    gatts_value.p_value = (uint8_t*)&tx_power_level;

    // Update database
    return sd_ble_gatts_value_set(p_tps->conn_handle,
                                  p_tps->tx_power_level_handles.value_handle,
                                  &gatts_value);
}
コード例 #15
0
uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level)
{
    uint32_t err_code = NRF_SUCCESS;

    if (battery_level != p_bas->battery_level_last)
    {
        uint16_t len = sizeof(uint8_t);

        // Save new battery value
        p_bas->battery_level_last = battery_level;

        // Update database
				SERV_LOG("[SERV][bas]: sd_ble_gatts_value_set\r\n");			
        err_code = sd_ble_gatts_value_set(p_bas->battery_level_handles.value_handle,
                                          0,
                                          &len,
                                          &battery_level);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }

        // Send value if connected and notifying
        if ((p_bas->conn_handle != BLE_CONN_HANDLE_INVALID) && p_bas->is_notification_supported)
        {
            ble_gatts_hvx_params_t hvx_params;

            memset(&hvx_params, 0, sizeof(hvx_params));
            len = sizeof(uint8_t);

            hvx_params.handle = p_bas->battery_level_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = 0;
            hvx_params.p_len  = &len;
            hvx_params.p_data = &battery_level;

						SERV_LOG("[SERV][bas]: sd_ble_gatts_hvx(BLE_GATT_HVX_NOTIFICATION, %d)\r\n", battery_level);			
            err_code = sd_ble_gatts_hvx(p_bas->conn_handle, &hvx_params);
        }
        else
        {
            err_code = NRF_ERROR_INVALID_STATE;
        }
    }

    return err_code;
}
コード例 #16
0
ファイル: ble_accel_svc.c プロジェクト: AveryLouie/flashware
uint32_t ble_acc_accel_level_update(ble_acc_t * p_acc, uint16_t accel_level)
{
    uint32_t err_code = NRF_SUCCESS;

    if (accel_level != p_acc->accel_level_last)
    {
        uint16_t len = sizeof(uint16_t);

        // Save new accel value
        p_acc->accel_level_last = accel_level;

        // Update database
        err_code = sd_ble_gatts_value_set(p_acc->accel_level_handles.value_handle,
                                          0,
                                          &len,
                                          (uint8_t*)&accel_level);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }

        // Send value if connected and notifying
        if ((p_acc->conn_handle != BLE_CONN_HANDLE_INVALID) && p_acc->is_notification_supported)
        {
            ble_gatts_hvx_params_t hvx_params;

            memset(&hvx_params, 0, sizeof(hvx_params));
            len = sizeof(uint8_t);

            hvx_params.handle = p_acc->accel_level_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = 0;
            hvx_params.p_len  = &len;
            hvx_params.p_data = (uint8_t*)&accel_level;

            err_code = sd_ble_gatts_hvx(p_acc->conn_handle, &hvx_params);
        }
        else
        {
            err_code = NRF_ERROR_INVALID_STATE;
        }
    }

    return err_code;
}
コード例 #17
0
ファイル: cgms_sst.c プロジェクト: CWBudde/Espruino
ret_code_t cgms_sst_set(nrf_ble_cgms_t * p_cgms, ble_cgms_sst_t * p_sst)
{
    uint16_t          conn_handle;
    uint16_t          value_handle;
    ble_gatts_value_t sst_val;
    uint8_t           encoded_start_session_time[NRF_BLE_CGMS_SST_LEN];
    uint8_t           gatts_value_set_len = 0;

    gatts_value_set_len = sst_encode(p_sst, encoded_start_session_time);
    conn_handle         = p_cgms->conn_handle;
    value_handle        = p_cgms->char_handles.sst.value_handle;
    memset(&sst_val, 0, sizeof(ble_gatts_value_t));
    sst_val.len     = gatts_value_set_len;
    sst_val.p_value = encoded_start_session_time;
    sst_val.offset  = 0;

    return (sd_ble_gatts_value_set(conn_handle, value_handle, &sst_val));
}
コード例 #18
0
ファイル: ble_dp.c プロジェクト: claesmathias/ble_app_hrs
/** NOT used at this moment, OTP update routine **/
uint32_t ble_otp_update(ble_dp_t * p_dp, uint8_t dp_otp)
{
    uint32_t err_code = NRF_SUCCESS;

    if (dp_otp != p_dp->otp_last)
    {
        uint16_t len = sizeof(uint8_t);
        
        // Save new OTP value
        p_dp->otp_last = dp_otp;
        
        // Update database
        err_code = sd_ble_gatts_value_set(p_dp->dp_otp_handles.value_handle,
                                          0,
                                          &len,
                                          &dp_otp);
		}

    return err_code;
}
コード例 #19
0
ファイル: ble_hids.c プロジェクト: 1072258106/duband
/**@brief Function for handling the Connect event.
 *
 * @param[in]   p_hids      HID Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static void on_connect(ble_hids_t * p_hids, ble_evt_t * p_ble_evt)
{
    uint32_t err_code;
    uint16_t len;
    uint8_t  default_protocol_mode;
    
    p_hids->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;

    // Set Protocol Mode characteristic value to default value
    len                   = sizeof(uint8_t);
    default_protocol_mode = DEFAULT_PROTOCOL_MODE;

    err_code = sd_ble_gatts_value_set(p_hids->protocol_mode_handles.value_handle, 
                                      0, 
                                      &len,
                                      &default_protocol_mode);
    if ((err_code != NRF_SUCCESS) && (p_hids->error_handler != NULL))
    {
        p_hids->error_handler(err_code);
    }
}
コード例 #20
0
ファイル: ble_step.c プロジェクト: hlmpost/code_backup
//---------------------------------------------------------------------------------
uint32_t ble_wechat_target_update(ble_step_t * p_step, uint8_t* target)
{
	 if (p_step == NULL)
    {
        return NRF_ERROR_NULL;
    }
    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;
    { 
        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));

        gatts_value.len     =4;// sizeof(uint8_t);
        gatts_value.offset  = 0;
        gatts_value.p_value =target;// &step_count;
        // Update database.
        err_code = sd_ble_gatts_value_set(p_step->conn_handle,
                                          target_handles.value_handle,
                                          &gatts_value);
       
        // Send value if connected and notifying.
        {
            ble_gatts_hvx_params_t hvx_params;

            memset(&hvx_params, 0, sizeof(hvx_params));

            hvx_params.handle = target_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_INDICATION;
            hvx_params.offset = gatts_value.offset;
            hvx_params.p_len  = &gatts_value.len;
            hvx_params.p_data = gatts_value.p_value;

            err_code = sd_ble_gatts_hvx(p_step->conn_handle, &hvx_params);
        }
    }
			//SEGGER_RTT_printf(0,"0x%x,0x%x\r\n",target[0],target[1]);

    return err_code;
}
コード例 #21
0
ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
{
    ble_error_t returnValue = BLE_ERROR_NONE;

    ble_gatts_value_t value = {
        /* .len     = */ len,
        /* .offset  = */ 0,
        /* .p_value = */ const_cast<uint8_t *>(buffer),
    };

    if (localOnly) {
        /* Only update locally regardless of notify/indicate */
        ASSERT_INT( ERROR_NONE,
                    sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
                    BLE_ERROR_PARAM_OUT_OF_RANGE );
        return BLE_ERROR_NONE;
    }

    int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
    if ((characteristicIndex != -1) &&
        (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
        /* HVX update for the characteristic value */
        ble_gatts_hvx_params_t hvx_params;

        hvx_params.handle = attributeHandle;
        hvx_params.type   =
            (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
        hvx_params.offset = 0;
        hvx_params.p_data = const_cast<uint8_t *>(buffer);
        hvx_params.p_len  = &len;

        if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */
            nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
            connectionHandle = gap.getConnectionHandle();
        }

        bool updatesEnabled = false;
        if (connectionHandle != BLE_CONN_HANDLE_INVALID) {
            ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled);

            // FIXME: The softdevice allocates and populates CCCD when the client
            // interract with them. Checking for updates may return an out of
            // range error in such case.
            if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) {
                return err;
            }
        }

        bool updates_permitted = false;
        ble_gap_conn_sec_t connection_security;
        uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security);
        if (!err &&
            (connection_security.sec_mode.sm == 1) &&
            (connection_security.sec_mode.lv >=  p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) {
            updates_permitted = true;
        }

        if (updatesEnabled && updates_permitted) {
            error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
            if (error != ERROR_NONE) {
                switch (error) {
                    case ERROR_BLE_NO_TX_BUFFERS: /*  Notifications consume application buffers. The return value can be used for resending notifications. */
                    case ERROR_BUSY:
                        returnValue = BLE_STACK_BUSY;
                        break;

                    case ERROR_INVALID_STATE:
                    case ERROR_BLEGATTS_SYS_ATTR_MISSING:
                        returnValue = BLE_ERROR_INVALID_STATE;
                        break;

                    default :
                        ASSERT_INT( ERROR_NONE,
                                    sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
                                    BLE_ERROR_PARAM_OUT_OF_RANGE );

                        /* Notifications consume application buffers. The return value can
                        * be used for resending notifications. */
                        returnValue = BLE_STACK_BUSY;
                        break;
                }
            }
        } else {
            returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
        }
    } else {
        returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
    }

    return returnValue;
}
コード例 #22
0
void nRF51822::begin(unsigned char advertisementDataType,
                      unsigned char advertisementDataLength,
                      const unsigned char* advertisementData,
                      unsigned char scanDataType,
                      unsigned char scanDataLength,
                      const unsigned char* scanData,
                      BLELocalAttribute** localAttributes,
                      unsigned char numLocalAttributes,
                      BLERemoteAttribute** remoteAttributes,
                      unsigned char numRemoteAttributes)
{

#ifdef __RFduino__
  sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_SYNTH_250_PPM, NULL);
#else
  sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL); // sd_nvic_EnableIRQ(SWI2_IRQn);
#endif

#ifdef NRF51_S130
  ble_enable_params_t enableParams = {
      .gatts_enable_params = {
          .service_changed = true
      }
  };

  sd_ble_enable(&enableParams);
#endif

#ifdef NRF_51822_DEBUG
  ble_version_t version;

  sd_ble_version_get(&version);

  Serial.print(F("version = "));
  Serial.print(version.version_number);
  Serial.print(F(" "));
  Serial.print(version.company_id);
  Serial.print(F(" "));
  Serial.print(version.subversion_number);
  Serial.println();
#endif

  ble_gap_conn_params_t gap_conn_params;

  gap_conn_params.min_conn_interval = 40;  // in 1.25ms units
  gap_conn_params.max_conn_interval = 80;  // in 1.25ms unit
  gap_conn_params.slave_latency     = 0;
  gap_conn_params.conn_sup_timeout  = 4000 / 10; // in 10ms unit

  sd_ble_gap_ppcp_set(&gap_conn_params);
  sd_ble_gap_tx_power_set(0);

  unsigned char srData[31];
  unsigned char srDataLen = 0;

  this->_advDataLen = 0;

  // flags
  this->_advData[this->_advDataLen + 0] = 2;
  this->_advData[this->_advDataLen + 1] = 0x01;
  this->_advData[this->_advDataLen + 2] = 0x06;

  this->_advDataLen += 3;

  if (advertisementDataType && advertisementDataLength && advertisementData) {
    this->_advData[this->_advDataLen + 0] = advertisementDataLength + 1;
    this->_advData[this->_advDataLen + 1] = advertisementDataType;
    this->_advDataLen += 2;

    memcpy(&this->_advData[this->_advDataLen], advertisementData, advertisementDataLength);

    this->_advDataLen += advertisementDataLength;
  }

  if (scanDataType && scanDataLength && scanData) {
    srData[0] = scanDataLength + 1;
    srData[1] = scanDataType;
    memcpy(&srData[2], scanData, scanDataLength);

    srDataLen = 2 + scanDataLength;
  }

  sd_ble_gap_adv_data_set(this->_advData, this->_advDataLen, srData, srDataLen);
  sd_ble_gap_appearance_set(0);

  for (int i = 0; i < numLocalAttributes; i++) {
    BLELocalAttribute *localAttribute = localAttributes[i];

    if (localAttribute->type() == BLETypeCharacteristic) {
      this->_numLocalCharacteristics++;
    }
  }

  this->_numLocalCharacteristics -= 3; // 0x2a00, 0x2a01, 0x2a05

  this->_localCharacteristicInfo = (struct localCharacteristicInfo*)malloc(sizeof(struct localCharacteristicInfo) * this->_numLocalCharacteristics);

  unsigned char localCharacteristicIndex = 0;

  uint16_t handle = 0;
  BLEService *lastService = NULL;

  for (int i = 0; i < numLocalAttributes; i++) {
    BLELocalAttribute *localAttribute = localAttributes[i];
    BLEUuid uuid = BLEUuid(localAttribute->uuid());
    const unsigned char* uuidData = uuid.data();
    unsigned char value[255];

    ble_uuid_t nordicUUID;

    if (uuid.length() == 2) {
      nordicUUID.uuid = (uuidData[1] << 8) | uuidData[0];
      nordicUUID.type = BLE_UUID_TYPE_BLE;
    } else {
      unsigned char uuidDataTemp[16];

      memcpy(&uuidDataTemp, uuidData, sizeof(uuidDataTemp));

      nordicUUID.uuid = (uuidData[13] << 8) | uuidData[12];

      uuidDataTemp[13] = 0;
      uuidDataTemp[12] = 0;

      sd_ble_uuid_vs_add((ble_uuid128_t*)&uuidDataTemp, &nordicUUID.type);
    }

    if (localAttribute->type() == BLETypeService) {
      BLEService *service = (BLEService *)localAttribute;

      if (strcmp(service->uuid(), "1800") == 0 || strcmp(service->uuid(), "1801") == 0) {
        continue; // skip
      }

      sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &nordicUUID, &handle);

      lastService = service;
    } else if (localAttribute->type() == BLETypeCharacteristic) {
      BLECharacteristic *characteristic = (BLECharacteristic *)localAttribute;

      if (strcmp(characteristic->uuid(), "2a00") == 0) {
        ble_gap_conn_sec_mode_t secMode;
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&secMode); // no security is needed

        sd_ble_gap_device_name_set(&secMode, characteristic->value(), characteristic->valueLength());
      } else if (strcmp(characteristic->uuid(), "2a01") == 0) {
        const uint16_t *appearance = (const uint16_t*)characteristic->value();

        sd_ble_gap_appearance_set(*appearance);
      } else if (strcmp(characteristic->uuid(), "2a05") == 0) {
        // do nothing
      } else {
        uint8_t properties = characteristic->properties() & 0xfe;
        uint16_t valueLength = characteristic->valueLength();

        this->_localCharacteristicInfo[localCharacteristicIndex].characteristic = characteristic;
        this->_localCharacteristicInfo[localCharacteristicIndex].notifySubscribed = false;
        this->_localCharacteristicInfo[localCharacteristicIndex].indicateSubscribed = false;
        this->_localCharacteristicInfo[localCharacteristicIndex].service = lastService;

        ble_gatts_char_md_t characteristicMetaData;
        ble_gatts_attr_md_t clientCharacteristicConfigurationMetaData;
        ble_gatts_attr_t    characteristicValueAttribute;
        ble_gatts_attr_md_t characteristicValueAttributeMetaData;

        memset(&characteristicMetaData, 0, sizeof(characteristicMetaData));

        memcpy(&characteristicMetaData.char_props, &properties, 1);

        characteristicMetaData.p_char_user_desc  = NULL;
        characteristicMetaData.p_char_pf         = NULL;
        characteristicMetaData.p_user_desc_md    = NULL;
        characteristicMetaData.p_cccd_md         = NULL;
        characteristicMetaData.p_sccd_md         = NULL;

        if (properties & (BLENotify | BLEIndicate)) {
          memset(&clientCharacteristicConfigurationMetaData, 0, sizeof(clientCharacteristicConfigurationMetaData));

          BLE_GAP_CONN_SEC_MODE_SET_OPEN(&clientCharacteristicConfigurationMetaData.read_perm);
          BLE_GAP_CONN_SEC_MODE_SET_OPEN(&clientCharacteristicConfigurationMetaData.write_perm);

          clientCharacteristicConfigurationMetaData.vloc = BLE_GATTS_VLOC_STACK;

          characteristicMetaData.p_cccd_md = &clientCharacteristicConfigurationMetaData;
        }

        memset(&characteristicValueAttributeMetaData, 0, sizeof(characteristicValueAttributeMetaData));

        if (properties & (BLERead | BLENotify | BLEIndicate)) {
          if (this->_bondStore) {
            BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&characteristicValueAttributeMetaData.read_perm);
          } else {
            BLE_GAP_CONN_SEC_MODE_SET_OPEN(&characteristicValueAttributeMetaData.read_perm);
          }
        }

        if (properties & (BLEWriteWithoutResponse | BLEWrite)) {
          if (this->_bondStore) {
            BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&characteristicValueAttributeMetaData.write_perm);
          } else {
            BLE_GAP_CONN_SEC_MODE_SET_OPEN(&characteristicValueAttributeMetaData.write_perm);
          }
        }

        characteristicValueAttributeMetaData.vloc       = BLE_GATTS_VLOC_STACK;
        characteristicValueAttributeMetaData.rd_auth    = 0;
        characteristicValueAttributeMetaData.wr_auth    = 0;
        characteristicValueAttributeMetaData.vlen       = !characteristic->fixedLength();

        for (int j = (i + 1); j < numLocalAttributes; j++) {
          localAttribute = localAttributes[j];

          if (localAttribute->type() != BLETypeDescriptor) {
            break;
          }

          BLEDescriptor *descriptor = (BLEDescriptor *)localAttribute;

          if (strcmp(descriptor->uuid(), "2901") == 0) {
            characteristicMetaData.p_char_user_desc        = (uint8_t*)descriptor->value();
            characteristicMetaData.char_user_desc_max_size = descriptor->valueLength();
            characteristicMetaData.char_user_desc_size     = descriptor->valueLength();
          } else if (strcmp(descriptor->uuid(), "2904") == 0) {
            characteristicMetaData.p_char_pf = (ble_gatts_char_pf_t *)descriptor->value();
          }
        }

        memset(&characteristicValueAttribute, 0, sizeof(characteristicValueAttribute));

        characteristicValueAttribute.p_uuid       = &nordicUUID;
        characteristicValueAttribute.p_attr_md    = &characteristicValueAttributeMetaData;
        characteristicValueAttribute.init_len     = valueLength;
        characteristicValueAttribute.init_offs    = 0;
        characteristicValueAttribute.max_len      = characteristic->valueSize();
        characteristicValueAttribute.p_value      = NULL;

        sd_ble_gatts_characteristic_add(BLE_GATT_HANDLE_INVALID, &characteristicMetaData, &characteristicValueAttribute, &this->_localCharacteristicInfo[localCharacteristicIndex].handles);

        if (valueLength) {
          for (int j = 0; j < valueLength; j++) {
            value[j] = (*characteristic)[j];
          }

          sd_ble_gatts_value_set(this->_localCharacteristicInfo[localCharacteristicIndex].handles.value_handle, 0, &valueLength, value);
        }

        localCharacteristicIndex++;
      }
    } else if (localAttribute->type() == BLETypeDescriptor) {
      BLEDescriptor *descriptor = (BLEDescriptor *)localAttribute;

      if (strcmp(descriptor->uuid(), "2901") == 0 ||
          strcmp(descriptor->uuid(), "2902") == 0 ||
          strcmp(descriptor->uuid(), "2903") == 0 ||
          strcmp(descriptor->uuid(), "2904") == 0) {
        continue; // skip
      }

      uint16_t valueLength = descriptor->valueLength();

      ble_gatts_attr_t descriptorAttribute;
      ble_gatts_attr_md_t descriptorMetaData;

      memset(&descriptorAttribute, 0, sizeof(descriptorAttribute));
      memset(&descriptorMetaData, 0, sizeof(descriptorMetaData));

      descriptorMetaData.vloc = BLE_GATTS_VLOC_STACK;
      descriptorMetaData.vlen = (valueLength == descriptor->valueLength()) ? 0 : 1;

      if (this->_bondStore) {
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&descriptorMetaData.read_perm);
      } else {
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&descriptorMetaData.read_perm);
      }

      descriptorAttribute.p_uuid    = &nordicUUID;
      descriptorAttribute.p_attr_md = &descriptorMetaData;
      descriptorAttribute.init_len  = valueLength;
      descriptorAttribute.max_len   = descriptor->valueLength();
      descriptorAttribute.p_value   = NULL;

      sd_ble_gatts_descriptor_add(BLE_GATT_HANDLE_INVALID, &descriptorAttribute, &handle);

      if (valueLength) {
        for (int j = 0; j < valueLength; j++) {
          value[j] = (*descriptor)[j];
        }

        sd_ble_gatts_value_set(handle, 0, &valueLength, value);
      }
    }
  }

  if ( numRemoteAttributes > 0) {
    numRemoteAttributes -= 2; // 0x1801, 0x2a05
  }

  for (int i = 0; i < numRemoteAttributes; i++) {
    BLERemoteAttribute *remoteAttribute = remoteAttributes[i];

    if (remoteAttribute->type() == BLETypeService) {
      this->_numRemoteServices++;
    } else if (remoteAttribute->type() == BLETypeCharacteristic) {
      this->_numRemoteCharacteristics++;
    }
  }

  this->_remoteServiceInfo = (struct remoteServiceInfo*)malloc(sizeof(struct remoteServiceInfo) * this->_numRemoteServices);
  this->_remoteCharacteristicInfo = (struct remoteCharacteristicInfo*)malloc(sizeof(struct remoteCharacteristicInfo) * this->_numRemoteCharacteristics);

  BLERemoteService *lastRemoteService = NULL;
  unsigned char remoteServiceIndex = 0;
  unsigned char remoteCharacteristicIndex = 0;

  for (int i = 0; i < numRemoteAttributes; i++) {
    BLERemoteAttribute *remoteAttribute = remoteAttributes[i];
    BLEUuid uuid = BLEUuid(remoteAttribute->uuid());
    const unsigned char* uuidData = uuid.data();

    ble_uuid_t nordicUUID;

    if (uuid.length() == 2) {
      nordicUUID.uuid = (uuidData[1] << 8) | uuidData[0];
      nordicUUID.type = BLE_UUID_TYPE_BLE;
    } else {
      unsigned char uuidDataTemp[16];

      memcpy(&uuidDataTemp, uuidData, sizeof(uuidDataTemp));

      nordicUUID.uuid = (uuidData[13] << 8) | uuidData[12];

      uuidDataTemp[13] = 0;
      uuidDataTemp[12] = 0;

      sd_ble_uuid_vs_add((ble_uuid128_t*)&uuidDataTemp, &nordicUUID.type);
    }

    if (remoteAttribute->type() == BLETypeService) {
      this->_remoteServiceInfo[remoteServiceIndex].service = lastRemoteService = (BLERemoteService *)remoteAttribute;
      this->_remoteServiceInfo[remoteServiceIndex].uuid = nordicUUID;

      memset(&this->_remoteServiceInfo[remoteServiceIndex].handlesRange, 0, sizeof(this->_remoteServiceInfo[remoteServiceIndex].handlesRange));

      remoteServiceIndex++;
    } else if (remoteAttribute->type() == BLETypeCharacteristic) {
      this->_remoteCharacteristicInfo[remoteCharacteristicIndex].characteristic = (BLERemoteCharacteristic *)remoteAttribute;
      this->_remoteCharacteristicInfo[remoteCharacteristicIndex].service = lastRemoteService;
      this->_remoteCharacteristicInfo[remoteCharacteristicIndex].uuid = nordicUUID;

      memset(&this->_remoteCharacteristicInfo[remoteCharacteristicIndex].properties, 0, sizeof(this->_remoteCharacteristicInfo[remoteCharacteristicIndex].properties));
      this->_remoteCharacteristicInfo[remoteCharacteristicIndex].valueHandle = 0;

      remoteCharacteristicIndex++;
    }
  }

  if (this->_bondStore && this->_bondStore->hasData()) {
#ifdef NRF_51822_DEBUG
    Serial.println(F("Restoring bond data"));
#endif
#ifdef NRF51_S130
    this->_bondStore->getData(this->_bondData, 0, sizeof(this->_bondData));
#else
    this->_bondStore->getData(this->_authStatusBuffer, 0, sizeof(this->_authStatusBuffer));
#endif
  }

  this->startAdvertising();

#ifdef __RFduino__
  RFduinoBLE_enabled = 1;
#endif
}
コード例 #23
0
ファイル: conn_mw_ble_gatts.c プロジェクト: IOIOI/nRF51
uint32_t conn_mw_ble_gatts_value_set(uint8_t const * const p_rx_buf,
                                     uint32_t              rx_buf_len,
                                     uint8_t * const       p_tx_buf,
                                     uint32_t * const      p_tx_buf_len)
{
    SER_ASSERT_NOT_NULL(p_rx_buf);
    SER_ASSERT_NOT_NULL(p_tx_buf);
    SER_ASSERT_NOT_NULL(p_tx_buf_len);

    uint16_t          conn_handle;
    uint16_t          handle;
    uint8_t           attr_val_table[BLE_GATTS_VAR_ATTR_LEN_MAX];
    ble_gatts_value_t attr_val = 
    {
        .len = sizeof (attr_val_table),
        .offset = 0,
        .p_value = attr_val_table
    };
    ble_gatts_value_t * p_attr_val = &attr_val; 

    uint32_t err_code = NRF_SUCCESS;
    uint32_t sd_err_code;

    err_code = ble_gatts_value_set_req_dec(p_rx_buf, rx_buf_len, &conn_handle, &handle, &p_attr_val);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);
    
    sd_err_code = sd_ble_gatts_value_set(conn_handle, handle, p_attr_val);

    err_code = ble_gatts_value_set_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len, p_attr_val);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    return err_code;
}

uint32_t conn_mw_ble_gatts_value_get(uint8_t const * const p_rx_buf,
                                     uint32_t              rx_buf_len,
                                     uint8_t * const       p_tx_buf,
                                     uint32_t * const      p_tx_buf_len)
{
    SER_ASSERT_NOT_NULL(p_rx_buf);
    SER_ASSERT_NOT_NULL(p_tx_buf);
    SER_ASSERT_NOT_NULL(p_tx_buf_len);

    uint16_t   conn_handle;
    uint16_t   handle;
    uint8_t    val[BLE_GATTS_VAR_ATTR_LEN_MAX];
    ble_gatts_value_t attr_value;
    ble_gatts_value_t * p_attr_value = &attr_value;

    attr_value.p_value = val;

    uint32_t err_code = NRF_SUCCESS;
    uint32_t sd_err_code;

    err_code = ble_gatts_value_get_req_dec(p_rx_buf, rx_buf_len, &conn_handle, &handle, &p_attr_value);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    sd_err_code = sd_ble_gatts_value_get(conn_handle, handle, p_attr_value);

    err_code = ble_gatts_value_get_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len, p_attr_value);
    SER_ASSERT(err_code == NRF_SUCCESS, err_code);

    return err_code;
}
コード例 #24
0
ファイル: ble_si7021.c プロジェクト: pcbreflux/nordic
/**@brief Function for handling the Disconnect event.
 *
 * @param[in] p_si7021  si7021 Service structure.
 * @param[in]   hum  Relative Humidity Raw 16-Bit.
 * @param[in]   temp Temperature Raw 16-Bit.
 */
uint32_t ble_si7021_sensor_update(ble_si7021_t * p_si7021, uint16_t hum, uint16_t temp) {
	uint8_t encoded_data[BLE_si7021_VALUE_MAX_LEN];
	//uint8_t len;

    if (p_si7021 == NULL) {
        return NRF_ERROR_NULL;
    }

    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;

    if ((hum != p_si7021->last_humraw && hum != 0) || (temp != p_si7021->last_tempraw && temp != 0)) {
    	NRF_LOG_DEBUG("ble_si7021_sensor_update %x,%x\n\r",hum,temp);

	    uint16_encode(hum,&encoded_data[0]);
	    uint16_encode(temp,&encoded_data[2]);

        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));

        gatts_value.len     = BLE_si7021_VALUE_MAX_LEN;
        gatts_value.offset  = 0;
        gatts_value.p_value = &encoded_data[0];

    	NRF_LOG_DEBUG("sd_ble_gatts_value_set %x,%x\n\r",p_si7021->conn_handle,p_si7021->value_char_handles.value_handle);
        // Update database. Set the value of a given attribute
        err_code = sd_ble_gatts_value_set(p_si7021->conn_handle,
        		                          p_si7021->value_char_handles.value_handle,
                                          &gatts_value);
    	NRF_LOG_DEBUG("sd_ble_gatts_value_set =%d\n\r",err_code);
        if (err_code == NRF_SUCCESS) {
            // save new temperature value.
        	p_si7021->last_humraw = hum;
        	p_si7021->last_tempraw = temp;
        } else {
            return err_code;
        }

        // Send value if connected and notifying.
        if (p_si7021->conn_handle != BLE_CONN_HANDLE_INVALID) {
            ble_gatts_hvx_params_t hvx_params;

            memset(&hvx_params, 0, sizeof(hvx_params));

            hvx_params.handle = p_si7021->value_char_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = gatts_value.offset;
            hvx_params.p_len  = &gatts_value.len;
            hvx_params.p_data = gatts_value.p_value;

        	NRF_LOG_DEBUG("sd_ble_gatts_hvx\n\r");
            // Notify or Indicate an attribute value
            err_code = sd_ble_gatts_hvx(p_si7021->conn_handle, &hvx_params);
        	NRF_LOG_DEBUG("sd_ble_gatts_hvx =%d\n\r",err_code);
        } else {
            err_code = NRF_ERROR_INVALID_STATE;
        }
    }

    return err_code;
}
コード例 #25
0
ファイル: ble_sc_ctrlpt.c プロジェクト: kiibohd/controller
/**@brief Handle a write event to the Speed and Cadence Control Point.
 *
 * @param[in]   p_sc_ctrlpt      SC Ctrlpt structure.
 * @param[in]   p_evt_write      WRITE event to be handled.
 */
static void on_ctrlpt_write(ble_sc_ctrlpt_t             * p_sc_ctrlpt,
                            ble_gatts_evt_write_t const * p_evt_write)
{
    ble_sc_ctrlpt_val_t                   rcvd_ctrlpt =
    { BLE_SCPT_RESPONSE_CODE , 0, BLE_SENSOR_LOCATION_OTHER };

    ble_sc_ctrlpt_rsp_t                   rsp;
    uint32_t                              err_code;
    ble_gatts_rw_authorize_reply_params_t auth_reply;
    ble_sc_ctrlpt_evt_t                   evt;

    auth_reply.type                     = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
    auth_reply.params.write.offset      = 0;
    auth_reply.params.write.len         = 0;
    auth_reply.params.write.p_data      = NULL;
    auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
    auth_reply.params.write.update      = 1;

    if (is_cccd_configured(p_sc_ctrlpt))
    {
        if (p_sc_ctrlpt->procedure_status == BLE_SCPT_NO_PROC_IN_PROGRESS)
        {
            auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
        }
        else
        {
            auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS;
        }
    }
    else
    {
        auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED;
    }

    err_code = sd_ble_gatts_rw_authorize_reply(p_sc_ctrlpt->conn_handle, &auth_reply);
    if (err_code != NRF_SUCCESS)
    {
        // Report error to application.
        if (p_sc_ctrlpt->error_handler != NULL)
        {
            p_sc_ctrlpt->error_handler(err_code);
        }
    }

    if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
    {
        return;
    }

    p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
    rsp.status                    = BLE_SCPT_OP_CODE_NOT_SUPPORTED;

    err_code = sc_ctrlpt_decode(p_evt_write->data, p_evt_write->len, &rcvd_ctrlpt);
    if (err_code != NRF_SUCCESS)
    {
        rsp.opcode = rcvd_ctrlpt.opcode;
        rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
    }
    else
    {
        rsp.opcode = rcvd_ctrlpt.opcode;

        switch (rcvd_ctrlpt.opcode)
        {
            case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
                if ((p_sc_ctrlpt->supported_functions &
                     BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
                     BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
                {
                    rsp.status = BLE_SCPT_SUCCESS;
                }
                else
                {
                    rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
                }
                break;

            case BLE_SCPT_UPDATE_SENSOR_LOCATION:
                if ((p_sc_ctrlpt->supported_functions &
                     BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
                     BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
                {
                    if (is_location_supported(p_sc_ctrlpt, rcvd_ctrlpt.location))
                    {
                        ble_gatts_value_t gatts_value;
                        uint8_t  rcvd_location = (uint8_t)rcvd_ctrlpt.location;
                        rsp.status = BLE_SCPT_SUCCESS;

                        // Initialize value struct.
                        memset(&gatts_value, 0, sizeof(gatts_value));

                        gatts_value.len     = sizeof(uint8_t);
                        gatts_value.offset  = 0;
                        gatts_value.p_value = &rcvd_location;

                        evt.evt_type               = BLE_SC_CTRLPT_EVT_UPDATE_LOCATION;
                        evt.params.update_location = rcvd_ctrlpt.location;
                        if (p_sc_ctrlpt->evt_handler != NULL)
                        {
                            rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
                        }
                        if (rsp.status == BLE_SCPT_SUCCESS)
                        {
                            err_code = sd_ble_gatts_value_set(p_sc_ctrlpt->conn_handle,
                                                              p_sc_ctrlpt->sensor_location_handle,
                                                              &gatts_value);
                            if (err_code != NRF_SUCCESS)
                            {
                                // Report error to application
                                if (p_sc_ctrlpt->error_handler != NULL)
                                {
                                    p_sc_ctrlpt->error_handler(err_code);
                                }
                                rsp.status = BLE_SCPT_OPERATION_FAILED;
                            }
                        }
                    }
                    else
                    {
                        rsp.status = BLE_SCPT_INVALID_PARAMETER;
                    }
                }
                else
                {
                    rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
                }
                break;

            case BLE_SCPT_SET_CUMULATIVE_VALUE:
                if ((p_sc_ctrlpt->supported_functions &
                     BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) ==
                     BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED)
                {
                    rsp.status = BLE_SCPT_SUCCESS;

                    evt.evt_type                = BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE;
                    evt.params.cumulative_value = rcvd_ctrlpt.cumulative_value;
                    if (p_sc_ctrlpt->evt_handler != NULL)
                    {
                        rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
                    }
                }
                else
                {
                    rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
                }
                break;

            case BLE_SCPT_START_AUTOMATIC_CALIBRATION:
                if ((p_sc_ctrlpt->supported_functions &
                     BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) ==
                     BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED)
                {
                    p_sc_ctrlpt->procedure_status = BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS;
                    evt.evt_type                  = BLE_SC_CTRLPT_EVT_START_CALIBRATION;
                    if (p_sc_ctrlpt->evt_handler != NULL)
                    {
                        rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
                        if (rsp.status != BLE_SCPT_SUCCESS)
                        {
                            // If the application returns an error, the response is to be sent
                            // right away and the calibration is considered as not started.
                            p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
                        }
                    }
                }
                else
                {
                    rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
                }
                break;

            default:
                rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
                break;
        }

    }

    p_sc_ctrlpt->response.len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp,
                                                  p_sc_ctrlpt->response.encoded_ctrl_rsp);


    if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
    {
        sc_ctrlpt_resp_send(p_sc_ctrlpt);
    }
}
コード例 #26
0
uint32_t mesh_srv_char_val_set(uint8_t index, uint8_t* data, uint16_t len, bool update_sender)
{
    if (!is_initialized)
    {
        return NRF_ERROR_INVALID_STATE;
    }
    
    if (index > g_mesh_service.value_count || index == 0)
    {
        return NRF_ERROR_INVALID_ADDR;
    }
    
    if (len > MAX_VALUE_LENGTH)
    {
        return NRF_ERROR_INVALID_LENGTH;
    }
    uint32_t error_code = 0;
    
    mesh_char_metadata_t* ch_md = &g_mesh_service.char_metadata[index - 1];
    
    /* this is now a new version of this data, signal to the rest of the mesh */
    ++ch_md->version_number;
    
    bool first_time = 
        (ch_md->flags & 
        (1 << MESH_MD_FLAGS_USED_POS)) == 0;
    
    if (first_time)
    {
        ch_md->flags |= 
            (1 << MESH_MD_FLAGS_INITIALIZED_POS) |
            (1 << MESH_MD_FLAGS_USED_POS);
        trickle_init(&ch_md->trickle);
    }
    else
    {
        trickle_rx_inconsistent(&ch_md->trickle);
    }
    
    if (update_sender || first_time)
    {
        ble_gap_addr_t my_addr;
        sd_ble_gap_address_get(&my_addr);
        memcpy(&ch_md->last_sender_addr, &my_addr, sizeof(ble_gap_addr_t));
        ch_md->flags |= (1 << MESH_MD_FLAGS_IS_ORIGIN_POS);
    }
        
    /* notify the connected central node, if any */
    if (g_active_conn_handle != CONN_HANDLE_INVALID)
    {
        ble_gatts_hvx_params_t notify_params;
        notify_params.handle = ch_md->char_value_handle;
        notify_params.offset = 0;
        notify_params.p_data = data;
        notify_params.p_len = &len;
        notify_params.type = BLE_GATT_HVX_NOTIFICATION;
        error_code = sd_ble_gatts_hvx(g_active_conn_handle, &notify_params);
        if (error_code != NRF_SUCCESS)
        {
            if (error_code == BLE_ERROR_INVALID_CONN_HANDLE)
            {
                g_active_conn_handle = CONN_HANDLE_INVALID;
            }
            else if (error_code == BLE_GATTS_EVT_SYS_ATTR_MISSING)
            {
                sd_ble_gatts_sys_attr_set(g_active_conn_handle, NULL, 0);
            }
            else
            {
                return NRF_ERROR_INTERNAL;
            }
        }
    }
    else
    {
        error_code = sd_ble_gatts_value_set(
            ch_md->char_value_handle, 
            0, &len, data);
        
        if (error_code != NRF_SUCCESS)
        {
            return NRF_ERROR_INTERNAL;
        }
    }
    
    return NRF_SUCCESS;
}
コード例 #27
0
ファイル: ble_ambient.c プロジェクト: leokho/SETEC-Pandlets
/**@brief Function for updating the Ambient Service config values.
 * 
 * @param[in]   p_amb                  Ambient Service Service structure.
 * @param[in]   sensor_configuration   New sensor configuration.
 *
 * @return      NRF_SUCCESS on success, otherwise an error code.
 */
uint32_t ble_ambient_config_update(ble_ambient_t * p_amb, uint8_t sensor_configuration, ble_ambient_sensor_type type){
	//new data!
#if TEMP_ENABLED || PR_ENABLED || HUM_ENABLED || LUM_ENABLED || HUMSOLO_ENABLED 
	uint16_t len = 1;
#endif
	uint32_t err_code = NRF_SUCCESS;
	
	switch(type){
		#if TEMP_ENABLED
		case BLE_AMBIENT_TEMP:
		// Save new configuration value
		p_amb->temp_configuration = sensor_configuration;
		
		// Update database
		err_code = sd_ble_gatts_value_set(p_amb->temp_configuration_handles.value_handle,
										  0,
										  &len,
										  &sensor_configuration);
		break;
		#endif
		
		#if PR_ENABLED
		case BLE_AMBIENT_PR:
		// Save new configuration value
		p_amb->pr_configuration = sensor_configuration;

		// Update database
		err_code = sd_ble_gatts_value_set(p_amb->pr_configuration_handles.value_handle,
										  0,
										  &len,
										  &sensor_configuration);
		break;
		#endif

		#if HUM_ENABLED
		case BLE_AMBIENT_HUM:
		// Save new configuration value
		p_amb->hum_configuration = sensor_configuration;

		// Update database
		err_code = sd_ble_gatts_value_set(p_amb->hum_configuration_handles.value_handle,
										  0,
										  &len,
										  &sensor_configuration);
		break;
		#endif

		#if HUMSOLO_ENABLED
		case BLE_AMBIENT_HUMSOLO:
		// Save new configuration value
		p_amb->humsolo_configuration = sensor_configuration;

		// Update database
		err_code = sd_ble_gatts_value_set(p_amb->humsolo_configuration_handles.value_handle,
										  0,
										  &len,
										  &sensor_configuration);
		break;
		#endif


		#if LUM_ENABLED
		case BLE_AMBIENT_LUM:
		// Save new configuration value
		p_amb->lum_configuration = sensor_configuration;

		// Update database
		err_code = sd_ble_gatts_value_set(p_amb->lum_configuration_handles.value_handle,
										  0,
										  &len,
										  &sensor_configuration);
		break;
		#endif
		
		default:
		break;
	}
	
	return err_code;
}
コード例 #28
0
void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt)
{
    GattAttribute::Handle_t        handle_value;
    GattServerEvents::gattEvent_t  eventType;
    const ble_gatts_evt_t         *gattsEventP = &p_ble_evt->evt.gatts_evt;

    switch (p_ble_evt->header.evt_id) {
        case BLE_GATTS_EVT_WRITE: {
                /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */

                /* 1.) Handle CCCD changes */
                handle_value = gattsEventP->params.write.handle;
                int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value);
                if ((characteristicIndex != -1) &&
                    (p_characteristics[characteristicIndex]->getProperties() &
                        (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {

                    uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */

                    if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) ||
                        ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) {
                        eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED;
                    } else {
                        eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED;
                    }

                    handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle());
                    return;
                }

                /* 2.) Changes to the characteristic value will be handled with other events below */
                eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN;
            }
            break;

        case BLE_GATTS_EVT_HVC:
            /* Indication confirmation received */
            eventType    = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED;
            handle_value = gattsEventP->params.hvc.handle;
            break;
        
#if  NRF_SD_BLE_API_VERSION >= 4 // This event has been renamed in API V4+
        case BLE_GATTS_EVT_HVN_TX_COMPLETE: {
            handleDataSentEvent(p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count);
            return;
        }
#else
        case BLE_EVT_TX_COMPLETE: {
            handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count);
            return;
        }
#endif

        case BLE_GATTS_EVT_SYS_ATTR_MISSING:
            sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0);
            return;

        case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            switch (gattsEventP->params.authorize_request.type) {
                case BLE_GATTS_AUTHORIZE_TYPE_READ:
                    eventType    = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ;
                    handle_value = gattsEventP->params.authorize_request.request.read.handle;
                    break;
                case BLE_GATTS_AUTHORIZE_TYPE_WRITE:
                    eventType    = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ;
                    handle_value = gattsEventP->params.authorize_request.request.write.handle;
                    break;
                default:
                    return;
            }
            break;

        case BLE_EVT_USER_MEM_REQUEST: {
            uint16_t conn_handle = p_ble_evt->evt.common_evt.conn_handle;

            // allocate a new long request for this connection
            // NOTE: we don't care about the result at this stage,
            // it is not possible to cancel the operation anyway.
            // If the request was not allocated then it will gracefully failled
            // at subsequent stages.
            allocateLongWriteRequest(conn_handle);
            sd_ble_user_mem_reply(conn_handle, NULL);
            return;
        }

        default:
            return;
    }

    int characteristicIndex = resolveValueHandleToCharIndex(handle_value);
    if (characteristicIndex == -1) {
        // filter out the case were the request is a long one,
        // and there is no attribute handle provided
        uint8_t write_op = gattsEventP->params.authorize_request.request.write.op;
        if (eventType != GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ ||
            (write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW &&
             write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) {
            return;
        }
    }

    /* Find index (charHandle) in the pool */
    switch (eventType) {
        case GattServerEvents::GATT_EVENT_DATA_WRITTEN: {
            GattWriteCallbackParams cbParams = {
                /* .connHandle = */ gattsEventP->conn_handle,
                /* .handle     = */ handle_value,
                /* .writeOp    = */ static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op),
                /* .offset     = */ gattsEventP->params.write.offset,
                /* .len        = */ gattsEventP->params.write.len,
                /* .data       = */ gattsEventP->params.write.data
            };
            handleDataWrittenEvent(&cbParams);
            break;
        }
        case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: {
            uint16_t conn_handle = gattsEventP->conn_handle;
            const ble_gatts_evt_write_t& input_req = gattsEventP->params.authorize_request.request.write;
            const uint16_t max_size = getBiggestCharacteristicSize();

            // this is a long write request, handle it here.
            switch (input_req.op) {
                case BLE_GATTS_OP_PREP_WRITE_REQ: {
                    // verify that the request is not outside of the possible range
                    if ((input_req.offset + input_req.len) > max_size) {
                        sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply);
                        releaseLongWriteRequest(conn_handle);
                        return;
                    }

                    // find the write request
                    long_write_request_t* req = findLongWriteRequest(conn_handle);
                    if (!req)  {
                        sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply);
                        return;
                    }

                    // initialize the first request by setting the offset
                    if (req->length == 0) {
                        req->attr_handle = input_req.handle;
                        req->offset = input_req.offset;
                    } else {
                        // it should be the subsequent write
                        if ((req->offset + req->length) != input_req.offset) {
                            sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply);
                            releaseLongWriteRequest(conn_handle);
                            return;
                        }

                        // it is not allowed to write multiple characteristic with the same request
                        if (input_req.handle != req->attr_handle) {
                            sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply);
                            releaseLongWriteRequest(conn_handle);
                            return;
                        }
                    }

                    // start the copy of what is in input
                    memcpy(req->data + req->length, input_req.data, input_req.len);

                    // update the lenght of the data written
                    req->length = req->length + input_req.len;

                    // success, signal it to the softdevice
                    ble_gatts_rw_authorize_reply_params_t reply = {
                        /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
                        /* .params = */ {
                            /* .write = */ {
                                /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS,
                                /* .update = */ 1,
                                /* .offset = */ input_req.offset,
                                /* .len = */ input_req.len,
                                /* .p_data = */ input_req.data
                            }
                        }
                    };

                    sd_ble_gatts_rw_authorize_reply(conn_handle, &reply);
                }   return;

                case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL: {
                    releaseLongWriteRequest(conn_handle);
                    sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply);
                }   return;

                case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW: {
                    long_write_request_t* req = findLongWriteRequest(conn_handle);
                    if (!req) {
                        sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply);
                        return;
                    }

                    GattWriteAuthCallbackParams cbParams = {
                        /* .connHandle = */ conn_handle,
                        /* .handle     = */ req->attr_handle,
                        /* .offset     = */ req->offset,
                        /* .len        = */ req->length,
                        /* .data       = */ req->data,
                        /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
                                                                           * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
                                                                           * request is to proceed. */
                    };
                    uint16_t write_authorization = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams);

                    // the user code didn't provide the write authorization,
                    // just leave here.
                    if (write_authorization != AUTH_CALLBACK_REPLY_SUCCESS) {
                        // report the status of the operation in any cases
                        sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply);
                        releaseLongWriteRequest(conn_handle);
                        return;
                    }

                    // FIXME can't use ::write here, this function doesn't take the offset into account ...
                    ble_gatts_value_t value = {
                        /* .len     = */ req->length,
                        /* .offset  = */ req->offset,
                        /* .p_value = */ req->data
                    };
                    uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value);
                    if (update_err) {
                        sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply);
                        releaseLongWriteRequest(conn_handle);
                        return;
                    }

                    sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply);

                    GattWriteCallbackParams writeParams = {
                        /* .connHandle = */ conn_handle,
                        /* .handle     = */ req->attr_handle,
                        /* .writeOp    = */ static_cast<GattWriteCallbackParams::WriteOp_t>(input_req.op),
                        /* .offset     = */ req->offset,
                        /* .len        = */ req->length,
                        /* .data       = */ req->data,
                    };
                    handleDataWrittenEvent(&writeParams);
                    releaseLongWriteRequest(conn_handle);
                }   return;
            }

            GattWriteAuthCallbackParams cbParams = {
                /* .connHandle = */ gattsEventP->conn_handle,
                /* .handle     = */ handle_value,
                /* .offset     = */ gattsEventP->params.authorize_request.request.write.offset,
                /* .len        = */ gattsEventP->params.authorize_request.request.write.len,
                /* .data       = */ gattsEventP->params.authorize_request.request.write.data,
                /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
                                                                   * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
                                                                   * request is to proceed. */
            };

            ble_gatts_rw_authorize_reply_params_t reply = {
                /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE,
                /* .params = */ {
                    /* .write = */ {
                        /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeWrite(&cbParams),
                        /* .update = */ 1,
                        /* .offset = */ cbParams.offset,
                        /* .len = */ cbParams.len,
                        /* .p_data = */ cbParams.data
                    }
                }
            };

            if (reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
            {
                reply.params.write.update = 0;
            }

            sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);

            /*
             * If write-authorization is enabled for a characteristic,
             * AUTHORIZATION_REQ event (if replied with true) is *not*
             * followed by another DATA_WRITTEN event; so we still need
             * to invoke handleDataWritten(), much the same as we would
             * have done if write-authorization had not been enabled.
             */
            if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) {
                GattWriteCallbackParams cbParams = {
                    /* .connHandle = */ gattsEventP->conn_handle,
                    /* .handle     = */ handle_value,
                    /* .writeOp    = */ static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op),
                    /* .offset     = */ gattsEventP->params.authorize_request.request.write.offset,
                    /* .len        = */ gattsEventP->params.authorize_request.request.write.len,
                    /* .data       = */ gattsEventP->params.authorize_request.request.write.data,
                };
                handleDataWrittenEvent(&cbParams);
            }
            break;
        }
        case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
            GattReadAuthCallbackParams cbParams = {
                /* .connHandle         = */ gattsEventP->conn_handle,
                /* .handle             = */ handle_value,
                /* .offset             = */ gattsEventP->params.authorize_request.request.read.offset,
                /* .len                = */ 0,
                /* .data               = */ NULL,
                /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
                                                                   * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
                                                                   * request is to proceed. */
            };

            ble_gatts_rw_authorize_reply_params_t reply = {
                /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_READ,
                /* .params = */ {
                    /* .read = */ {
                        /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
                    }
                }
            };

            if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) {
                if (cbParams.data != NULL) {
                    reply.params.read.update = 1;
                    reply.params.read.offset = cbParams.offset;
                    reply.params.read.len    = cbParams.len;
                    reply.params.read.p_data = cbParams.data;
                }
            }

            sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
            break;
        }

        default:
            handleEvent(eventType, handle_value);
            break;
    }
}