#include #include #include #include #include #include #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 = 550; // minimum display brightness in percent float min_brightness_percent = 0.05; // returns the luminance value in percentage between 0 and 1 int get_luminance_raw (void) { freopen(NULL, "r", luminance_fp); const char *x = fgets(STR_BUFFER, sizeof(STR_BUFFER), luminance_fp); if (x == NULL) { return -1; } int luminance = strtol(STR_BUFFER, NULL, 10); return luminance; } // read a string from a file and convert it to int, should only be used for // positive numbers since negative numbers mean an error int read_int(FILE *fp) { freopen(NULL, "r", 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; } return r; } float bezier(float t) { const float B = 0.66; const float D = 0.28; return 3*B*t+(3*D-6*B)*t*t+(1+3*B-3*D)*t*t*t; } // TODO: add some command line options like: // -v: verbose/logging // -c file; specify a config file 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(); if (x < 0) { fprintf(stderr, "Could not read luminance value: %s\n", strerror(errno)); } 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; x = get_luminance_raw(); if (x >= 0) luminance_samples[idx] = x; idx = (idx + 1) % MEDIAN_SAMPLES; luminance = 0; for (int i = 0; i < MEDIAN_SAMPLES; i++) { luminance += luminance_samples[i] / MEDIAN_SAMPLES; } luminance_percent = bezier(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); // TODO: put this in write_int() function 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)); actual_brightness = brightness_adjusted; } off = actual_brightness - brightness_target; if (brightness_target != max_brightness || off < 0){ user_offset = off; } // TODO: option to turn off logging printf("brightness target: %d; user offset: %d; brightness adjusted: %d\n", brightness_target, user_offset, brightness_adjusted); } return 0; }