ambientd/ambientd.c

165 lines
4.8 KiB
C
Raw Normal View History

2024-10-09 17:35:05 +02:00
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define MEDIAN_SAMPLES 4
const char *LUMINANCE_DEV = "/sys/bus/iio/devices/iio:device0/in_illuminance_raw";
const char *MAX_BRIGHTNESS_DEV = "/sys/class/backlight/intel_backlight/max_brightness";
const char *BRIGHTNESS_DEV = "/sys/class/backlight/intel_backlight/brightness";
const char *ACTUAL_BRIGHTNESS_DEV = "/sys/class/backlight/intel_backlight/actual_brightness";
char STR_BUFFER[128] = {0};
// file pointer to the luminance device
FILE *luminance_fp = NULL;
// max luminance that the display can output
int max_luminance = 400;
// minimum display brightness in percent
float min_brightness_percent = 0.05;
2024-10-10 23:07:29 +02:00
// returns the luminance value in percentage between 0 and 1
2024-10-09 17:35:05 +02:00
int get_luminance_raw (void)
{
const char *x = fgets(STR_BUFFER, sizeof(STR_BUFFER), luminance_fp);
if (x == NULL) {
fprintf(stderr, "Could not read luminance value: %s\n", strerror(errno));
2024-10-10 23:07:29 +02:00
return -1;
2024-10-09 17:35:05 +02:00
}
int luminance = strtol(STR_BUFFER, NULL, 10);
rewind(luminance_fp);
return luminance;
}
int read_int(FILE *fp)
{
fflush(fp);
const char *p = fgets(STR_BUFFER, sizeof(STR_BUFFER), fp);
if (p == NULL) {
return -1;
}
long r = strtol(STR_BUFFER, NULL, 10);
if (r == LONG_MIN || r == LONG_MAX) {
return -1;
}
rewind(fp);
return r;
}
int main (void)
{
// open the luminance device
luminance_fp = fopen(LUMINANCE_DEV, "r");
if (luminance_fp == NULL) {
fprintf(stderr, "Could not open luminance device '%s': %s\n",
LUMINANCE_DEV, strerror(errno));
return 1;
}
// get max and min brightness
FILE *fp = fopen(MAX_BRIGHTNESS_DEV, "r");
if (fp == NULL) {
fprintf(stderr, "Could not open max_brightness file '%s': %s\n",
MAX_BRIGHTNESS_DEV, strerror(errno));
return 1;
}
int max_brightness = read_int(fp);
if (max_brightness < 0) {
fprintf(stderr, "Could not read max brightness value: %s\n", strerror(errno));
return 1;
}
int min_brightness = max_brightness * min_brightness_percent;
fclose(fp);
// open brightness device
FILE *brightness_fp = fopen(BRIGHTNESS_DEV, "w");
if (brightness_fp == NULL) {
fprintf(stderr, "Could not open brightness device '%s': %s\n",
BRIGHTNESS_DEV, strerror(errno));
return 1;
}
// open actual brightness device
FILE *actual_brightness_fp = fopen(ACTUAL_BRIGHTNESS_DEV, "r");
if (brightness_fp == NULL) {
fprintf(stderr, "Could not open actual brightness device '%s': %s\n",
ACTUAL_BRIGHTNESS_DEV, strerror(errno));
return 1;
}
int x = get_luminance_raw();
int luminance_samples[MEDIAN_SAMPLES] = {x, x, x, x};
int idx = 0;
int user_offset = 0;
int brightness_target = min_brightness;
int brightness_old = min_brightness;
int brightness_adjusted = min_brightness;
int brightness_delta = 0;
while (1) {
static float luminance;
static float luminance_percent;
2024-10-10 23:07:29 +02:00
x = get_luminance_raw();
if (x >= 0) luminance_samples[idx] = x;
2024-10-09 17:35:05 +02:00
idx = (idx + 1) % MEDIAN_SAMPLES;
luminance = 0;
for (int i = 0; i < MEDIAN_SAMPLES; i++) {
luminance += luminance_samples[i] / MEDIAN_SAMPLES;
}
luminance_percent = MIN(luminance/max_luminance, 1.0);
brightness_old = brightness_target;
brightness_target = MAX((int)(luminance_percent * max_brightness), min_brightness);
brightness_delta = ABS((float)(brightness_target - brightness_old)/brightness_old);
// if the brightness changes by more than 10% reduce the user offset, scaling
// with the delta, this accounts for large changes in brightness no longer
// corresponding to the adjustments that the user made to the brightness
if (brightness_delta > 0.1) {
user_offset = user_offset * MAX(MIN(1-(brightness_delta*1.2), 1), 0);
}
brightness_adjusted = MIN(MAX(brightness_target + user_offset, min_brightness), max_brightness);
x = snprintf(STR_BUFFER, sizeof(STR_BUFFER), "%d", brightness_adjusted);
if (x <= 0) {
fprintf(stderr, "Error in snprintf(): %s\n", strerror(errno));
}
if (fputs(STR_BUFFER, brightness_fp) == EOF) {
fprintf(stderr, "error writing brightness: %s\n", strerror(errno));
}
rewind(brightness_fp);
sleep(3);
// read actual brightness to get the user offset
int actual_brightness = 0;
int off = 0;
actual_brightness = read_int(actual_brightness_fp);
if (actual_brightness < 0) {
fprintf(stderr, "error reading actual brightness: %s\n", strerror(errno));
2024-10-10 23:07:29 +02:00
actual_brightness = brightness_adjusted;
2024-10-09 17:35:05 +02:00
}
off = actual_brightness - brightness_target;
if (brightness_target != max_brightness || off < 0){
user_offset = off;
}
2024-10-10 23:07:29 +02:00
printf("brightness target: %d; user offset: %d; brightness adjusted: %d\n", brightness_target, user_offset, brightness_adjusted);
2024-10-09 17:35:05 +02:00
}
return 0;
}