blob: 7d76e934d87a2b1af9e094fda877e1be3e5526b1 [file] [log] [blame]
// Copyright 2019 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 "diagnostics/routines/battery/battery.h"
#include <utility>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
namespace diagnostics {
namespace {
// When the battery routine's low_mah and high_mah parameters are not set, we
// default to low_mah = 1000 and high_mah = 10000.
constexpr int kDefaultLowmAh = 1000;
constexpr int kDefaultHighmAh = 10000;
// Conversion factor from uAh to mAh.
constexpr int kuAhTomAhDivisor = 1000;
int CalculateProgressPercent(grpc_api::DiagnosticRoutineStatus status) {
// Since the battery test cannot be paused or cancelled, the progress
// percent can only be 0 or 100.
if (status == grpc_api::ROUTINE_STATUS_PASSED ||
status == grpc_api::ROUTINE_STATUS_FAILED)
return 100;
return 0;
}
} // namespace
const char kBatteryChargeFullDesignPath[] =
"sys/class/power_supply/BAT0/charge_full_design";
const char kBatteryRoutineParametersInvalidMessage[] =
"Invalid BatteryRoutineParameters.";
const char kBatteryNoChargeFullDesignMessage[] =
"charge_full_design does not exist.";
const char kBatteryFailedReadingChargeFullDesignMessage[] =
"Failed to read charge_full_design.";
const char kBatteryFailedParsingChargeFullDesignMessage[] =
"Failed to parse charge_full_design.";
const char kBatteryRoutineSucceededMessage[] =
"Battery design capacity within given limits.";
const char kBatteryRoutineFailedMessage[] =
"Battery design capacity not within given limits.";
BatteryRoutine::BatteryRoutine(
const grpc_api::BatteryRoutineParameters& parameters)
: status_(grpc_api::ROUTINE_STATUS_READY), parameters_(parameters) {}
BatteryRoutine::~BatteryRoutine() = default;
void BatteryRoutine::Start() {
DCHECK_EQ(status_, grpc_api::ROUTINE_STATUS_READY);
status_ = RunBatteryRoutine();
if (status_ != grpc_api::ROUTINE_STATUS_PASSED)
LOG(ERROR) << "Routine failed: " << status_message_;
}
// The battery test can only be started.
void BatteryRoutine::Pause() {}
void BatteryRoutine::Resume() {}
void BatteryRoutine::Cancel() {}
void BatteryRoutine::PopulateStatusUpdate(
grpc_api::GetRoutineUpdateResponse* response, bool include_output) {
// Because the battery routine is non-interactive, we will never include a
// user message.
response->set_status(status_);
response->set_progress_percent(CalculateProgressPercent(status_));
response->set_status_message(status_message_);
}
grpc_api::DiagnosticRoutineStatus BatteryRoutine::GetStatus() {
return status_;
}
void BatteryRoutine::set_root_dir_for_testing(const base::FilePath& root_dir) {
root_dir_ = root_dir;
}
grpc_api::DiagnosticRoutineStatus BatteryRoutine::RunBatteryRoutine() {
int low_mah = parameters_.low_mah() ? parameters_.low_mah() : kDefaultLowmAh;
int high_mah =
parameters_.high_mah() ? parameters_.high_mah() : kDefaultHighmAh;
if (low_mah > high_mah) {
status_message_ = kBatteryRoutineParametersInvalidMessage;
return grpc_api::ROUTINE_STATUS_ERROR;
}
base::FilePath charge_full_design_path(
root_dir_.AppendASCII(kBatteryChargeFullDesignPath));
if (!base::PathExists(charge_full_design_path)) {
status_message_ = kBatteryNoChargeFullDesignMessage;
return grpc_api::ROUTINE_STATUS_ERROR;
}
std::string charge_full_design_contents;
if (!base::ReadFileToString(charge_full_design_path,
&charge_full_design_contents)) {
status_message_ = kBatteryFailedReadingChargeFullDesignMessage;
return grpc_api::ROUTINE_STATUS_ERROR;
}
base::TrimWhitespaceASCII(charge_full_design_contents, base::TRIM_TRAILING,
&charge_full_design_contents);
int charge_full_design_uah;
if (!base::StringToInt(charge_full_design_contents,
&charge_full_design_uah)) {
status_message_ = kBatteryFailedParsingChargeFullDesignMessage;
return grpc_api::ROUTINE_STATUS_ERROR;
}
// Conversion is necessary because the inputs are given in mAh, whereas the
// design capacity is reported in uAh.
int charge_full_design_mah = charge_full_design_uah / kuAhTomAhDivisor;
if (!(charge_full_design_mah >= low_mah) ||
!(charge_full_design_mah <= high_mah)) {
status_message_ = kBatteryRoutineFailedMessage;
return grpc_api::ROUTINE_STATUS_FAILED;
}
status_message_ = kBatteryRoutineSucceededMessage;
return grpc_api::ROUTINE_STATUS_PASSED;
}
} // namespace diagnostics