Browse Source

Add debouncing logic to fan curve selection

Modify fan curve selection so that it only occurrs if
the same curve point is selected for 20+ sensor readings.

This prevents erroneous readings from ramping up the fans
for a short period
master
Shawn Anastasio 2 years ago
parent
commit
0e0a9364d6
  1. 2
      include/fan-daemon.h
  2. 61
      src/control.c
  3. 6
      src/fan-daemon.c

2
include/fan-daemon.h

@ -104,6 +104,8 @@ struct zone_data {
const struct fan_curve_point *curve;
size_t curve_size;
size_t curve_pos;
size_t next_curve_pos;
size_t next_curve_count;
};
// Program state

61
src/control.c

@ -36,6 +36,9 @@
#include "curve.h"
#include "util.h"
// Number of consecutive times a curve needs to be selected for it to take effect
#define NEXT_CURVE_COUNT_MIN 20
void print_zones(struct controller_state *state) {
printf("CPU0: ");
for (size_t i=0; i<state->zones[ZONE_CPU0].sensors.count; i++) {
@ -82,10 +85,31 @@ bool read_temp(int sensor_fd, uint32_t *temp_out) {
/**
* Scan for the most appropriate curve point for the given temperature
*/
uint32_t find_new_curve_point(const struct fan_curve_point *curve, size_t curve_size, uint32_t temp) {
uint32_t new = curve_size - 1;
for (size_t i=0; i<curve_size; i++) {
if (temp >= curve[i].temp)
uint32_t find_new_curve_point(const struct zone_data *zone, uint32_t temp) {
// Check for raise
if (zone->curve_pos != zone->curve_size - 1) {
const struct fan_curve_point *next = &zone->curve[zone->curve_pos + 1];
// Check if temperature is high enough to go to next point
if (temp > next->temp)
goto find_new;
}
// Check for drop
if (zone->curve_pos != 0) {
const struct fan_curve_point *cur = &zone->curve[zone->curve_pos];
// Check if temperature dropped below cur - hysteresis
if (temp < cur->temp - cur->hysteresis)
goto find_new;
}
// No change
return zone->curve_pos;
find_new: ;
// Pick new point
uint32_t new = zone->curve_size - 1;
for (size_t i=0; i<zone->curve_size; i++) {
if (temp >= zone->curve[i].temp)
new = i;
}
return new;
@ -107,6 +131,34 @@ bool update_zone(struct controller_state *state, enum zone z) {
max_temp = temp;
}
uint32_t new_point = find_new_curve_point(zone, max_temp);
if (new_point == zone->curve_pos)
return true; // no update
// Check if the new curve point matches the previous new curve point
if (new_point != zone->next_curve_pos) {
// Didn't match, reset counter
if (zone->next_curve_count != NEXT_CURVE_COUNT_MIN)
dbg_printf("[Zone %u] flushed staging curve (was going to %u)!\n", z,
zone->curve[zone->next_curve_pos].speed);
zone->next_curve_pos = new_point;
zone->next_curve_count = 1;
return true;
} else
// Matched, increment counter
zone->next_curve_count++;
// If counter isn't high enough, skip update
if (zone->next_curve_count < NEXT_CURVE_COUNT_MIN)
return true;
// Curve point has been selected for enough cycles, write it
dbg_printf("Zone %u temperature changed to %u, setting speed to %u\n", z, max_temp,
zone->curve[zone->next_curve_pos].speed);
pwm_provider->set_zone_speed(z, zone->curve[zone->next_curve_pos].speed);
zone->curve_pos = zone->next_curve_pos;
#if 0
// Check for raise
if (zone->curve_pos != zone->curve_size - 1) {
const struct fan_curve_point *next = &zone->curve[zone->curve_pos + 1];
@ -136,6 +188,7 @@ bool update_zone(struct controller_state *state, enum zone z) {
return true;
}
}
#endif
return true;
}

6
src/fan-daemon.c

@ -227,14 +227,20 @@ struct controller_state *controller_init(void) {
state->zones[ZONE_CPU0].curve = zone_cpu0_curve;
state->zones[ZONE_CPU0].curve_size = ARRAY_SIZE(zone_cpu0_curve);
state->zones[ZONE_CPU0].curve_pos = ARRAY_SIZE(zone_cpu0_curve) - 1;
state->zones[ZONE_CPU0].next_curve_pos = 0;
state->zones[ZONE_CPU0].next_curve_count = 0;
state->zones[ZONE_CPU1].curve = zone_cpu1_curve;
state->zones[ZONE_CPU1].curve_size = ARRAY_SIZE(zone_cpu1_curve);
state->zones[ZONE_CPU1].curve_pos = ARRAY_SIZE(zone_cpu1_curve) - 1;
state->zones[ZONE_CPU1].next_curve_pos = 0;
state->zones[ZONE_CPU1].next_curve_count = 0;
state->zones[ZONE_CHASSIS].curve = zone_chassis_curve;
state->zones[ZONE_CHASSIS].curve_size = ARRAY_SIZE(zone_chassis_curve);
state->zones[ZONE_CHASSIS].curve_pos = ARRAY_SIZE(zone_chassis_curve) - 1;
state->zones[ZONE_CHASSIS].next_curve_pos = 0;
state->zones[ZONE_CHASSIS].next_curve_count = 0;
// Open sensor groups
if (!open_sensor_group(cpu0_sensors_path, &state->occ0)) {

Loading…
Cancel
Save