blob: 8acc2acafbaef5b093fe8dd8a53b90de4a37b53a [file] [log] [blame]
// Copyright 2015 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 "thermald/temperature_sensor_monitor.h"
#include <string>
#include "base/callback.h"
#include "base/check.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
using std::string;
namespace thermald {
static const int kNoTemperature = -273150;
TemperatureSensorMonitor::TemperatureSensorMonitor(
TemperatureSensorInterface *sensor, base::TimeDelta sample_period)
: sensor_(sensor),
sample_period_(sample_period),
weak_ptr_factory_(this),
timer_(new base::RepeatingTimer()) {
DCHECK(sensor);
DVLOG(3) << "[" << sensor_->name() << "] Constructor";
subscribers_.set_removal_callback(
base::Bind(&TemperatureSensorMonitor::OnSubscriberRemoved,
weak_ptr_factory_.GetWeakPtr()));
}
TemperatureSensorMonitor::~TemperatureSensorMonitor() {
DVLOG(3) << "[" << sensor_->name() << "] Destructor";
// Sampling only needs to be stopped when there is at least one subscriber.
// Otherwise either the sampling never started or it has been stopped
// earlier when the last active subscriber canceled its subscription.
if (!subscribers_.empty()) {
StopSampling();
}
}
string TemperatureSensorMonitor::name() const {
return sensor_->name();
}
void TemperatureSensorMonitor::ReadAndReportTemperature() {
if (!sensor_->IsOperational()) {
if (sensor_was_operational_) {
LOG(WARNING) << "[" << sensor_->name() << "] Sensor is not operational";
sensor_was_operational_ = false;
}
return;
} else if (!sensor_was_operational_) {
LOG(INFO) << "[" << sensor_->name() << "] Sensor became operational";
sensor_was_operational_ = true;
}
int temperature;
if (!sensor_->ReadTemperature(&temperature)) {
LOG(WARNING) << "[" << sensor_->name() << "] Failed to read temperature";
return;
}
if (temperature != prev_temperature_) {
DVLOG(1) << "[" << sensor_->name() << "] Temperature changed: "
<< temperature;
subscribers_.Notify(temperature);
prev_temperature_ = temperature;
}
}
void TemperatureSensorMonitor::ReportInitialTemperature(
const TemperatureMonitorCallback &cb, int temperature) {
// Don't report the initial temperature if an updated reading has already
// been reported from the regular polling.
if (temperature == prev_temperature_) {
cb.Run(temperature);
}
}
#if BASE_VER < 860220
std::unique_ptr<TemperatureMonitorInterface::Subscription>
#else
base::CallbackListSubscription
#endif
TemperatureSensorMonitor::Subscribe(const TemperatureMonitorCallback &cb) {
if (subscribers_.empty()) {
StartSampling();
} else {
if (prev_temperature_ != kNoTemperature) {
// Schedule task to report initial temperature.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&TemperatureSensorMonitor::ReportInitialTemperature,
weak_ptr_factory_.GetWeakPtr(), cb, prev_temperature_));
}
}
return subscribers_.Add(cb);
}
void TemperatureSensorMonitor::OnSubscriberRemoved() {
if (subscribers_.empty()) {
StopSampling();
}
}
void TemperatureSensorMonitor::StartSampling() {
DVLOG(1) << "[" << sensor_->name() << "] Start sampling";
prev_temperature_ = kNoTemperature;
sensor_was_operational_ = true;
// Take first temperature reading immediately.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&TemperatureSensorMonitor::ReadAndReportTemperature,
weak_ptr_factory_.GetWeakPtr()));
timer_->Start(FROM_HERE, sample_period_,
base::Bind(&TemperatureSensorMonitor::ReadAndReportTemperature,
weak_ptr_factory_.GetWeakPtr()));
}
void TemperatureSensorMonitor::StopSampling() {
DVLOG(1) << "[" << sensor_->name() << "] Stop sampling";
timer_->Stop();
}
} // namespace thermald