blob: 003e8fb0b0b2e76d6600a4c19fc38fbcf8982f65 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "rmad/utils/accelerometer_calibration_utils_impl.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/synchronization/lock.h>
#include "rmad/utils/iio_ec_sensor_utils_impl.h"
#include "rmad/utils/vpd_utils_impl.h"
namespace {
constexpr int kSamples = 100;
constexpr double kGravity = 9.80665;
// The calibbias data is converted to 1/1024G unit,
// and the sensor reading unit is m/s^2.
constexpr double kCalibbiasDataScale = kGravity / 1024.0;
// Both thresholds are used in m/s^2 units.
// The offset is indicating the tolerance in m/s^2 for
// the digital output of sensors under 0 and 1G.
constexpr double kOffsetThreshold = 2.0;
// The variance of capture data can not be larger than the threshold.
constexpr double kVarianceThreshold = 5.0;
constexpr double kProgressComplete = 1.0;
constexpr double kProgressFailed = -1.0;
constexpr double kProgressInit = 0.0;
constexpr double kProgressSensorReset = 0.15;
constexpr double kProgressSensorDataReceived = 0.6;
constexpr double kProgressBiasCalculated = 0.65;
constexpr double kProgressBiasWritten = 0.85;
constexpr double kProgressBiasSet = kProgressComplete;
constexpr char kCalibbiasPrefix[] = "in_";
constexpr char kCalibbiasPostfix[] = "_calibbias";
const std::vector<std::string> kAccelerometerCalibbias = {
"in_accel_x_calibbias", "in_accel_y_calibbias", "in_accel_z_calibbias"};
const std::vector<std::string> kAccelerometerChannels = {"accel_x", "accel_y",
"accel_z"};
const std::vector<double> kAccelerometerIdealValues = {0, 0, kGravity};
} // namespace
namespace rmad {
AccelerometerCalibrationUtilsImpl::AccelerometerCalibrationUtilsImpl(
scoped_refptr<VpdUtilsImplThreadSafe> vpd_utils_impl_thread_safe,
const std::string& location,
const std::string& name)
: SensorCalibrationUtils(location, name),
vpd_utils_impl_thread_safe_(vpd_utils_impl_thread_safe),
progress_(kProgressInit) {
iio_ec_sensor_utils_ = std::make_unique<IioEcSensorUtilsImpl>(location, name);
}
bool AccelerometerCalibrationUtilsImpl::Calibrate() {
std::vector<double> avg_data;
std::vector<double> variance_data;
std::vector<int> scaled_data;
std::map<std::string, int> scaled_calibbias;
SetProgress(kProgressInit);
// Before starting the calibration, we clear the sensor state by writing 0 to
// sysfs.
if (!iio_ec_sensor_utils_->SetSysValues(kAccelerometerCalibbias, {0, 0, 0})) {
SetProgress(kProgressFailed);
return false;
}
SetProgress(kProgressSensorReset);
// Due to the uncertainty of the sensor value, we use the average value to
// calibrate it.
if (!iio_ec_sensor_utils_->GetAvgData(kAccelerometerChannels, kSamples,
&avg_data, &variance_data)) {
LOG(ERROR) << location_ << ":" << name_ << ": Failed to accumulate data.";
SetProgress(kProgressFailed);
return false;
}
SetProgress(kProgressSensorDataReceived);
if (avg_data.size() != kAccelerometerIdealValues.size()) {
LOG(ERROR) << location_ << ":" << name_ << ": Get wrong data size "
<< avg_data.size();
SetProgress(kProgressFailed);
return false;
}
if (variance_data.size() != kAccelerometerIdealValues.size()) {
LOG(ERROR) << location_ << ":" << name_ << ": Get wrong variance data size "
<< variance_data.size();
SetProgress(kProgressFailed);
return false;
}
for (int i = 0; i < variance_data.size(); i++) {
double var = variance_data[i];
if (var > kVarianceThreshold) {
LOG(ERROR) << location_ << ":" << name_ << ": Data variance=" << var
<< " too high in channel " << kAccelerometerChannels[i]
<< ". Expected to be less than " << kVarianceThreshold;
SetProgress(kProgressFailed);
return false;
}
}
// For each axis, we calculate the difference between the ideal values.
scaled_data.resize(kAccelerometerIdealValues.size());
for (int i = 0; i < avg_data.size(); i++) {
double offset = kAccelerometerIdealValues[i] - avg_data[i];
if (std::fabs(offset) > kOffsetThreshold) {
LOG(ERROR) << location_ << ":" << name_
<< ": Data is out of range, the accelerometer may be damaged "
"or the device setup is incorrect.";
SetProgress(kProgressFailed);
return false;
}
scaled_data[i] = offset / kCalibbiasDataScale;
std::string entry = kCalibbiasPrefix + kAccelerometerChannels[i] + "_" +
location_ + kCalibbiasPostfix;
scaled_calibbias[entry] = scaled_data[i];
}
SetProgress(kProgressBiasCalculated);
// We first write the calibbias data to vpd, and then update the sensor via
// sysfs accordingly.
if (!vpd_utils_impl_thread_safe_->SetCalibbias(scaled_calibbias)) {
SetProgress(kProgressFailed);
return false;
}
SetProgress(kProgressBiasWritten);
if (!iio_ec_sensor_utils_->SetSysValues(kAccelerometerCalibbias,
scaled_data)) {
SetProgress(kProgressFailed);
return false;
}
SetProgress(kProgressBiasSet);
return true;
}
bool AccelerometerCalibrationUtilsImpl::GetProgress(double* progress) const {
CHECK(progress);
base::AutoLock lock_scope(progress_lock_);
*progress = progress_;
return true;
}
void AccelerometerCalibrationUtilsImpl::SetProgress(double progress) {
base::AutoLock lock_scope(progress_lock_);
progress_ = progress;
}
} // namespace rmad