int DfMpu9250Wrapper::_publish(struct imu_sensor_data &data)
{
	/* Check if calibration values are still up-to-date. */
	bool updated;
	orb_check(_param_update_sub, &updated);

	if (updated) {
		parameter_update_s parameter_update;
		orb_copy(ORB_ID(parameter_update), _param_update_sub, &parameter_update);

		_update_accel_calibration();
		_update_gyro_calibration();
		_update_mag_calibration();
	}

	math::Vector<3> vec_integrated_unused;
	uint64_t integral_dt_unused;

	math::Vector<3> accel_val((data.accel_m_s2_x - _accel_calibration.x_offset) * _accel_calibration.x_scale,
				  (data.accel_m_s2_y - _accel_calibration.y_offset) * _accel_calibration.y_scale,
				  (data.accel_m_s2_z - _accel_calibration.z_offset) * _accel_calibration.z_scale);

	// apply sensor rotation on the accel measurement
	accel_val = _rotation_matrix * accel_val;

	_accel_int.put_with_interval(data.fifo_sample_interval_us,
				     accel_val,
				     vec_integrated_unused,
				     integral_dt_unused);

	math::Vector<3> gyro_val(data.gyro_rad_s_x,
				 data.gyro_rad_s_y,
				 data.gyro_rad_s_z);

	// apply sensor rotation on the gyro measurement
	gyro_val = _rotation_matrix * gyro_val;

	// Apply calibration after rotation.
	gyro_val(0) = (gyro_val(0) - _gyro_calibration.x_offset) * _gyro_calibration.x_scale;
	gyro_val(1) = (gyro_val(1) - _gyro_calibration.y_offset) * _gyro_calibration.y_scale;
	gyro_val(2) = (gyro_val(2) - _gyro_calibration.z_offset) * _gyro_calibration.z_scale;

	_gyro_int.put_with_interval(data.fifo_sample_interval_us,
				    gyro_val,
				    vec_integrated_unused,
				    integral_dt_unused);

	// If we are not receiving the last sample from the FIFO buffer yet, let's stop here
	// and wait for more packets.
	if (!data.is_last_fifo_sample) {
		return 0;
	}

	// The driver empties the FIFO buffer at 1kHz, however we only need to publish at 250Hz.
	// Therefore, only publish every forth time.
	++_publish_count;

	if (_publish_count < 4) {
		return 0;
	}

	_publish_count = 0;

	// Update all the counters.
	perf_set_count(_read_counter, data.read_counter);
	perf_set_count(_error_counter, data.error_counter);
	perf_set_count(_fifo_overflow_counter, data.fifo_overflow_counter);
	perf_set_count(_fifo_corruption_counter, data.fifo_overflow_counter);
	perf_set_count(_gyro_range_hit_counter, data.gyro_range_hit_counter);
	perf_set_count(_accel_range_hit_counter, data.accel_range_hit_counter);

	if (_mag_enabled) {
		perf_set_count(_mag_fifo_overflow_counter, data.mag_fifo_overflow_counter);
	}

	perf_begin(_publish_perf);

	accel_report accel_report = {};
	gyro_report gyro_report = {};
	mag_report mag_report = {};

	accel_report.timestamp = gyro_report.timestamp = hrt_absolute_time();

	if (_mag_enabled) {
		mag_report.timestamp = accel_report.timestamp;
	}

	// TODO: get these right
	gyro_report.scaling = -1.0f;
	gyro_report.range_rad_s = -1.0f;
	gyro_report.device_id = m_id.dev_id;

	accel_report.scaling = -1.0f;
	accel_report.range_m_s2 = -1.0f;
	accel_report.device_id = m_id.dev_id;

	if (_mag_enabled) {
		mag_report.scaling = -1.0f;
		mag_report.range_ga = -1.0f;
		mag_report.device_id = m_id.dev_id;
	}

	// TODO: remove these (or get the values)
	gyro_report.x_raw = NAN;
	gyro_report.y_raw = NAN;
	gyro_report.z_raw = NAN;

	accel_report.x_raw = NAN;
	accel_report.y_raw = NAN;
	accel_report.z_raw = NAN;

	if (_mag_enabled) {
		mag_report.x_raw = NAN;
		mag_report.y_raw = NAN;
		mag_report.z_raw = NAN;
	}

	math::Vector<3> gyro_val_filt;
	math::Vector<3> accel_val_filt;

	// Read and reset.
	math::Vector<3> gyro_val_integ = _gyro_int.get_and_filtered(true, gyro_report.integral_dt, gyro_val_filt);
	math::Vector<3> accel_val_integ = _accel_int.get_and_filtered(true, accel_report.integral_dt, accel_val_filt);

	// Use the filtered (by integration) values to get smoother / less noisy data.
	gyro_report.x = gyro_val_filt(0);
	gyro_report.y = gyro_val_filt(1);
	gyro_report.z = gyro_val_filt(2);

	accel_report.x = accel_val_filt(0);
	accel_report.y = accel_val_filt(1);
	accel_report.z = accel_val_filt(2);

	if (_mag_enabled) {

		math::Vector<3> mag_val((data.mag_ga_x - _mag_calibration.x_offset) * _mag_calibration.x_scale,
					(data.mag_ga_y - _mag_calibration.y_offset) * _mag_calibration.y_scale,
					(data.mag_ga_z - _mag_calibration.z_offset) * _mag_calibration.z_scale);

		mag_val = _rotation_matrix * mag_val;

		mag_report.x = mag_val(0);
		mag_report.y = mag_val(1);
		mag_report.z = mag_val(2);
	}

	gyro_report.x_integral = gyro_val_integ(0);
	gyro_report.y_integral = gyro_val_integ(1);
	gyro_report.z_integral = gyro_val_integ(2);

	accel_report.x_integral = accel_val_integ(0);
	accel_report.y_integral = accel_val_integ(1);
	accel_report.z_integral = accel_val_integ(2);

	// TODO: when is this ever blocked?
	if (!(m_pub_blocked)) {

		if (_gyro_topic != nullptr) {
			orb_publish(ORB_ID(sensor_gyro), _gyro_topic, &gyro_report);
		}

		if (_accel_topic != nullptr) {
			orb_publish(ORB_ID(sensor_accel), _accel_topic, &accel_report);
		}

		if (_mag_enabled) {

			if (_mag_topic == nullptr) {
				_mag_topic = orb_advertise_multi(ORB_ID(sensor_mag), &mag_report,
								 &_mag_orb_class_instance, ORB_PRIO_LOW);

			} else {
				orb_publish(ORB_ID(sensor_mag), _mag_topic, &mag_report);
			}
		}

		/* Notify anyone waiting for data. */
		DevMgr::updateNotify(*this);

		// Report if there are high vibrations, every 10 times it happens.
		const bool threshold_reached = (data.accel_range_hit_counter - _last_accel_range_hit_count > 10);

		// Report every 5s.
		const bool due_to_report = (hrt_elapsed_time(&_last_accel_range_hit_time) > 5000000);

		if (threshold_reached && due_to_report) {
			mavlink_log_critical(&_mavlink_log_pub,
					     "High accelerations, range exceeded %llu times",
					     data.accel_range_hit_counter);

			_last_accel_range_hit_time = hrt_absolute_time();
			_last_accel_range_hit_count = data.accel_range_hit_counter;
		}
	}

	perf_end(_publish_perf);

	// TODO: check the return codes of this function
	return 0;
};
int DfLsm9ds1Wrapper::_publish(struct imu_sensor_data &data)
{
	/* Check if calibration values are still up-to-date. */
	bool updated;
	orb_check(_param_update_sub, &updated);

	if (updated) {
		parameter_update_s parameter_update;
		orb_copy(ORB_ID(parameter_update), _param_update_sub, &parameter_update);

		_update_accel_calibration();
		_update_gyro_calibration();
	}

	matrix::Vector3f vec_integrated_unused;
	uint32_t integral_dt_unused;
	matrix::Vector3f accel_val(data.accel_m_s2_x,
				   data.accel_m_s2_y,
				   data.accel_m_s2_z);
	// apply sensor rotation on the accel measurement
	accel_val = _rotation_matrix * accel_val;
	// Apply calibration after rotation
	accel_val(0) = (accel_val(0) - _accel_calibration.x_offset) * _accel_calibration.x_scale;
	accel_val(1) = (accel_val(1) - _accel_calibration.y_offset) * _accel_calibration.y_scale;
	accel_val(2) = (accel_val(2) - _accel_calibration.z_offset) * _accel_calibration.z_scale;
	_accel_int.put_with_interval(data.fifo_sample_interval_us,
				     accel_val,
				     vec_integrated_unused,
				     integral_dt_unused);
	matrix::Vector3f gyro_val(data.gyro_rad_s_x,
				  data.gyro_rad_s_y,
				  data.gyro_rad_s_z);
	// apply sensor rotation on the gyro measurement
	gyro_val = _rotation_matrix * gyro_val;
	// Apply calibration after rotation
	gyro_val(0) = (gyro_val(0) - _gyro_calibration.x_offset) * _gyro_calibration.x_scale;
	gyro_val(1) = (gyro_val(1) - _gyro_calibration.y_offset) * _gyro_calibration.y_scale;
	gyro_val(2) = (gyro_val(2) - _gyro_calibration.z_offset) * _gyro_calibration.z_scale;
	_gyro_int.put_with_interval(data.fifo_sample_interval_us,
				    gyro_val,
				    vec_integrated_unused,
				    integral_dt_unused);

	// The driver empties the FIFO buffer at 1kHz, however we only need to publish at 250Hz.
	// Therefore, only publish every forth time.
	++_publish_count;

	if (_publish_count < 4) {
		return 0;
	}

	_publish_count = 0;

	// Update all the counters.
	perf_set_count(_read_counter, data.read_counter);
	perf_set_count(_error_counter, data.error_counter);
	perf_set_count(_fifo_overflow_counter, data.fifo_overflow_counter);
	perf_set_count(_fifo_corruption_counter, data.fifo_overflow_counter);
	perf_set_count(_gyro_range_hit_counter, data.gyro_range_hit_counter);
	perf_set_count(_accel_range_hit_counter, data.accel_range_hit_counter);

	perf_begin(_publish_perf);

	sensor_accel_s accel_report = {};
	sensor_gyro_s gyro_report = {};
	mag_report mag_report = {};

	accel_report.timestamp = gyro_report.timestamp = hrt_absolute_time();
	mag_report.timestamp = accel_report.timestamp;
	mag_report.is_external = false;

	// TODO: get these right
	gyro_report.scaling = -1.0f;
	gyro_report.device_id = m_id.dev_id;

	accel_report.scaling = -1.0f;
	accel_report.device_id = m_id.dev_id;

	if (_mag_enabled) {
		mag_report.scaling = -1.0f;
		mag_report.device_id = m_id.dev_id;
	}

	// TODO: remove these (or get the values)
	gyro_report.x_raw = 0;
	gyro_report.y_raw = 0;
	gyro_report.z_raw = 0;

	accel_report.x_raw = 0;
	accel_report.y_raw = 0;
	accel_report.z_raw = 0;

	if (_mag_enabled) {
		mag_report.x_raw = 0;
		mag_report.y_raw = 0;
		mag_report.z_raw = 0;
	}

	matrix::Vector3f gyro_val_filt;
	matrix::Vector3f accel_val_filt;

	// Read and reset.
	matrix::Vector3f gyro_val_integ = _gyro_int.get_and_filtered(true, gyro_report.integral_dt, gyro_val_filt);
	matrix::Vector3f accel_val_integ = _accel_int.get_and_filtered(true, accel_report.integral_dt, accel_val_filt);

	// Use the filtered (by integration) values to get smoother / less noisy data.
	gyro_report.x = gyro_val_filt(0);
	gyro_report.y = gyro_val_filt(1);
	gyro_report.z = gyro_val_filt(2);

	accel_report.x = accel_val_filt(0);
	accel_report.y = accel_val_filt(1);
	accel_report.z = accel_val_filt(2);

	if (_mag_enabled) {
		matrix::Vector3f mag_val(data.mag_ga_x,
					 data.mag_ga_y,
					 data.mag_ga_z);
		mag_val = _rotation_matrix * mag_val;
		mag_val(0) = (mag_val(0) - _mag_calibration.x_offset) * _mag_calibration.x_scale;
		mag_val(1) = (mag_val(1) - _mag_calibration.y_offset) * _mag_calibration.y_scale;
		mag_val(2) = (mag_val(2) - _mag_calibration.z_offset) * _mag_calibration.z_scale;

		mag_report.x = mag_val(0);
		mag_report.y = mag_val(1);
		mag_report.z = mag_val(2);
	}

	gyro_report.x_integral = gyro_val_integ(0);
	gyro_report.y_integral = gyro_val_integ(1);
	gyro_report.z_integral = gyro_val_integ(2);

	accel_report.x_integral = accel_val_integ(0);
	accel_report.y_integral = accel_val_integ(1);
	accel_report.z_integral = accel_val_integ(2);

	// TODO: when is this ever blocked?
	if (!(m_pub_blocked)) {


		if (_gyro_topic != nullptr) {
			orb_publish(ORB_ID(sensor_gyro), _gyro_topic, &gyro_report);
		}

		if (_accel_topic != nullptr) {
			orb_publish(ORB_ID(sensor_accel), _accel_topic, &accel_report);
		}

		if (_mag_topic != nullptr) {
			orb_publish(ORB_ID(sensor_mag), _mag_topic, &mag_report);
		}

		// Report if there are high vibrations, every 10 times it happens.
		const bool threshold_reached = (data.accel_range_hit_counter - _last_accel_range_hit_count > 10);

		// Report every 5s.
		const bool due_to_report = (hrt_elapsed_time(&_last_accel_range_hit_time) > 5000000);

		if (threshold_reached && due_to_report) {
			mavlink_log_critical(&_mavlink_log_pub,
					     "High accelerations, range exceeded %llu times",
					     data.accel_range_hit_counter);

			_last_accel_range_hit_time = hrt_absolute_time();
			_last_accel_range_hit_count = data.accel_range_hit_counter;
		}
	}

	perf_end(_publish_perf);

	// TODO: check the return codes of this function
	return 0;
};