blob: 48a019382bc51b4021a9013fb0b254d95ea394af [file] [log] [blame]
/* Copyright 2014 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Test thermal engine.
*/
#include "common.h"
#include "console.h"
#include "fan.h"
#include "hooks.h"
#include "host_command.h"
#include "temp_sensor.h"
#include "test_util.h"
#include "thermal.h"
#include "timer.h"
#include "util.h"
#define FAN_RPM(fan) fans[fan].rpm
/*****************************************************************************/
/* Tests */
void set_thermal_control_enabled(int fan, int enable);
static int test_fan(void)
{
/* "actual" fan speed from board/host/fan.c */
extern int mock_rpm;
sleep(2);
/* Fans initialize disabled. */
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
set_thermal_control_enabled(0, 1);
/*
* fan_set_percent_needed() is normally called once a second by the
* thermal task, but we're not using a thermal test in this test so
* we can dink around with the fans without having to wait. The host
* implementation just sets mock_rpm to whatever it's asked for.
*/
/* Off */
fan_set_percent_needed(0, 0);
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
fan_set_percent_needed(0, 0);
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
/* On, but just barely */
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_start);
/* fan is above min speed now, so should be set to min */
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_min);
/* Full speed */
fan_set_percent_needed(0, 100);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_max);
fan_set_percent_needed(0, 100);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_max);
/* Slow again */
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_min);
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_min);
/* Off */
fan_set_percent_needed(0, 0);
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
fan_set_percent_needed(0, 0);
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
/* On, but just barely */
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_start);
/* Force the mock_rpm to be slow, to simulate dragging */
mock_rpm = FAN_RPM(0)->rpm_min - 105;
/* It should keep trying for the start speed */
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_start);
/* But we have to keep forcing the mock_rpm back down */
mock_rpm = FAN_RPM(0)->rpm_min - 105;
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_start);
/* Now let it turn just under rpm_min. Should be okay there. */
mock_rpm = FAN_RPM(0)->rpm_min - 10;
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_min);
/* Let it go a little faster, still okay */
mock_rpm = FAN_RPM(0)->rpm_min + 10;
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_min);
/* But if it drops too low, it should go back to the start speed */
mock_rpm = FAN_RPM(0)->rpm_min - 105;
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_start);
/* And then relax */
fan_set_percent_needed(0, 1);
TEST_ASSERT(fan_get_rpm_actual(0) == FAN_RPM(0)->rpm_min);
return EC_SUCCESS;
}
/* Provide a test driver to make test easier to read. */
int temp_to_rpm(int temperature_c)
{
const int temp_fan_off = C_TO_K(35);
const int temp_fan_max = C_TO_K(55);
const struct fan_step_1_1 fan_table[] = {
{ .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(35),
.increasing_temp_ratio_threshold = TEMP_TO_RATIO(41),
.rpm = 2500 },
{ .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(37),
.increasing_temp_ratio_threshold = TEMP_TO_RATIO(43),
.rpm = 3200 },
{ .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(42),
.increasing_temp_ratio_threshold = TEMP_TO_RATIO(45),
.rpm = 3500 },
{ .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(44),
.increasing_temp_ratio_threshold = TEMP_TO_RATIO(47),
.rpm = 3900 },
{ .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(46),
.increasing_temp_ratio_threshold = TEMP_TO_RATIO(49),
.rpm = 4500 },
{ .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(48),
.increasing_temp_ratio_threshold = TEMP_TO_RATIO(52),
.rpm = 5100 },
{ .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(51),
.increasing_temp_ratio_threshold = TEMP_TO_RATIO(55),
.rpm = 5400 },
};
const int num_fan_levels = ARRAY_SIZE(fan_table);
int temp_ratio = TEMP_TO_RATIO(temperature_c);
int rpm = temp_ratio_to_rpm_hysteresis(fan_table, num_fan_levels, 0,
temp_ratio, NULL);
fan_set_rpm_target(FAN_CH(0), rpm);
return rpm;
}
static int test_temp_ratio_to_rpm_hysteresis(void)
{
const int ZERO = 0;
/* set initial value to be different so that a log message appears */
fan_set_rpm_target(FAN_CH(0), 5400);
/* initial turn-on behavior, ramp up. @ represents fan speed; + temp */
TEST_ASSERT(temp_to_rpm(30) == ZERO); /* @+. . 40 . 50 .60 */
TEST_ASSERT(temp_to_rpm(30) == ZERO); /* @+. . . . . . */
TEST_ASSERT(temp_to_rpm(35) == ZERO); /* @ + . . . . */
TEST_ASSERT(temp_to_rpm(37) == ZERO); /* @ . + . . . . */
TEST_ASSERT(temp_to_rpm(39) == ZERO); /* @ . +. . . . */
TEST_ASSERT(temp_to_rpm(40) == ZERO); /* @ . + . . . */
TEST_ASSERT(temp_to_rpm(41) == 2500); /* @. .+ . . . */
TEST_ASSERT(temp_to_rpm(36) == 2500); /* @.+ . . . . */
TEST_ASSERT(temp_to_rpm(42) == 2500); /* @. . + . . . */
TEST_ASSERT(temp_to_rpm(43) == 3200); /* @ . + . . . */
TEST_ASSERT(temp_to_rpm(38) == 3200); /* @ + . . . . */
TEST_ASSERT(temp_to_rpm(44) == 3200); /* @ . +. . . */
TEST_ASSERT(temp_to_rpm(45) == 3500); /* .@ . + . . */
TEST_ASSERT(temp_to_rpm(43) == 3500); /* .@ . + . . . */
TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
TEST_ASSERT(temp_to_rpm(47) == 3900); /* . @ . . + . . */
TEST_ASSERT(temp_to_rpm(45) == 3900); /* . @ . + . . */
TEST_ASSERT(temp_to_rpm(48) == 3900); /* . @ . . + . . */
TEST_ASSERT(temp_to_rpm(49) == 4500); /* . @ . . +. . */
TEST_ASSERT(temp_to_rpm(47) == 4500); /* . @ . . + . . */
TEST_ASSERT(temp_to_rpm(51) == 4500); /* . @ . . .+ . */
TEST_ASSERT(temp_to_rpm(52) == 5100); /* . @. . . + . */
TEST_ASSERT(temp_to_rpm(49) == 5100); /* . @. . +. . */
TEST_ASSERT(temp_to_rpm(54) == 5100); /* . @. . . +. */
TEST_ASSERT(temp_to_rpm(55) == 5400); /* . @ . . + */
TEST_ASSERT(temp_to_rpm(52) == 5400); /* . @ . . + . */
TEST_ASSERT(temp_to_rpm(60) == 5400); /* . @ . 50 ..+ */
/* cool-down */
TEST_ASSERT(temp_to_rpm(55) == 5400); /* . @ . . + */
TEST_ASSERT(temp_to_rpm(52) == 5400); /* . @ . . + . */
TEST_ASSERT(temp_to_rpm(51) == 5100); /* . @. . .+ . */
TEST_ASSERT(temp_to_rpm(54) == 5100); /* . @. . . +. */
TEST_ASSERT(temp_to_rpm(49) == 5100); /* . @. . +. . */
TEST_ASSERT(temp_to_rpm(48) == 4500); /* . @ . . + . . */
TEST_ASSERT(temp_to_rpm(51) == 4500); /* . @ . . .+ . */
TEST_ASSERT(temp_to_rpm(47) == 4500); /* . @ . . + . . */
TEST_ASSERT(temp_to_rpm(46) == 3900); /* . @ . .+ . . */
TEST_ASSERT(temp_to_rpm(48) == 3900); /* . @ . . + . . */
TEST_ASSERT(temp_to_rpm(45) == 3900); /* . @ . + . . */
TEST_ASSERT(temp_to_rpm(44) == 3500); /* .@ . +. . . */
TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
TEST_ASSERT(temp_to_rpm(43) == 3500); /* .@ . + . . . */
TEST_ASSERT(temp_to_rpm(42) == 3200); /* @ . + . . . */
TEST_ASSERT(temp_to_rpm(44) == 3200); /* @ . +. . . */
TEST_ASSERT(temp_to_rpm(38) == 3200); /* @ + . . . . */
TEST_ASSERT(temp_to_rpm(37) == 2500); /* @. + . . . . */
TEST_ASSERT(temp_to_rpm(42) == 2500); /* @. . + . . . */
TEST_ASSERT(temp_to_rpm(36) == 2500); /* @.+ . . . . */
TEST_ASSERT(temp_to_rpm(35) == ZERO); /* @ + 40 . 50 . */
/* warm up again */
TEST_ASSERT(temp_to_rpm(38) == ZERO); /* @ . + . . . . */
/* jumping */
TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
TEST_ASSERT(temp_to_rpm(36) == 2500); /* @.+ . . . . */
TEST_ASSERT(temp_to_rpm(35) == ZERO); /* @ + . . . . */
TEST_ASSERT(temp_to_rpm(37) == ZERO); /* @ . + . . . . */
TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
TEST_ASSERT(temp_to_rpm(54) == 5100); /* . @. . . +. */
TEST_ASSERT(temp_to_rpm(55) == 5400); /* . @ . . + */
TEST_ASSERT(temp_to_rpm(60) == 5400); /* . @ . . ..+ */
TEST_ASSERT(temp_to_rpm(53) == 5400); /* . @ . . + . */
TEST_ASSERT(temp_to_rpm(46) == 3900); /* . @ . .+ . . */
TEST_ASSERT(temp_to_rpm(30) == ZERO); /* @+. . 40 . 50 . */
return EC_SUCCESS;
}
void run_test(int argc, const char **argv)
{
RUN_TEST(test_fan);
RUN_TEST(test_temp_ratio_to_rpm_hysteresis);
test_print_result();
}
/* Doesn't do anything, but it makes this test stop intermittently covering
* some code in core/host/task.c:fast_forward().
*/
void interrupt_generator(void)
{
}