/* redshift.c */ /* Copyright (c) 2009, Jon Lund Steffensen */ #include #include #include #include #include #include #include #include "solar.h" #include "colortemp.h" /* Bounds for parameters. */ #define MIN_LAT -90.0 #define MAX_LAT 90.0 #define MIN_LON -180.0 #define MAX_LON 180.0 #define MIN_TEMP 1000 #define MAX_TEMP 10000 #define MIN_GAMMA 0.1 #define MAX_GAMMA 10.0 /* Default values for parameters. */ #define DEFAULT_DAY_TEMP 5500 #define DEFAULT_NIGHT_TEMP 3700 #define DEFAULT_GAMMA 1.0 /* Angular elevation of the sun at which the color temperature transition period starts and ends. */ #define TRANSITION_LOW SOLAR_CIVIL_TWILIGHT_ELEV #define TRANSITION_HIGH 6.0 #define USAGE \ "Usage: %s -l LAT:LON -t DAY:NIGHT [OPTIONS...]\n" #define HELP \ USAGE \ " Set color temperature of display according to time of day.\n" \ " -g GAMMA\tAdditional gamma correction to apply\n" \ " -h\t\tDisplay this help message\n" \ " -l LAT:LON\tYour current location\n" \ " -t DAY:NIGHT\tColor temperature to set at night/day\n" \ " -v\t\tVerbose output\n" /* DEGREE SIGN is Unicode U+00b0 */ #define DEG_CHAR 0xb0 int main(int argc, char *argv[]) { /* Check extensions needed for color temperature adjustment. */ int r = colortemp_check_extension(); if (r < 0) { fprintf(stderr, "Unable to set color temperature:" " Needed extension is missing.\n"); exit(EXIT_FAILURE); } /* Init locale for degree symbol. */ char *loc = setlocale(LC_CTYPE, ""); if (loc == NULL) { fprintf(stderr, "Unable to set locale.\n"); exit(EXIT_FAILURE); } /* Parse arguments. */ float lat = NAN; float lon = NAN; int temp_day = DEFAULT_DAY_TEMP; int temp_night = DEFAULT_NIGHT_TEMP; float gamma = DEFAULT_GAMMA; int verbose = 0; char *s; int opt; while ((opt = getopt(argc, argv, "g:hl:t:v")) != -1) { switch (opt) { case 'g': gamma = atof(optarg); break; case 'h': printf(HELP, argv[0]); exit(EXIT_SUCCESS); break; case 'l': s = strchr(optarg, ':'); if (s == NULL) { fprintf(stderr, USAGE, argv[0]); exit(EXIT_FAILURE); } *(s++) = '\0'; lat = atof(optarg); lon = atof(s); break; case 't': s = strchr(optarg, ':'); if (s == NULL) { fprintf(stderr, USAGE, argv[0]); exit(EXIT_FAILURE); } *(s++) = '\0'; temp_day = atoi(optarg); temp_night = atoi(s); break; case 'v': verbose = 1; break; default: fprintf(stderr, USAGE, argv[0]); exit(EXIT_FAILURE); } } /* Latitude and longitude must be set */ if (isnan(lat) || isnan(lon)) { fprintf(stderr, USAGE, argv[0]); fprintf(stderr, "Latitude and longitude must be set.\n"); exit(EXIT_FAILURE); } if (verbose) { printf("Location: %f%lc, %f%lc\n", lat, DEG_CHAR, lon, DEG_CHAR); } /* Latitude */ if (lat < MIN_LAT || lat > MAX_LAT) { fprintf(stderr, "Latitude must be between %.1f%lc and %.1f%lc.\n", MIN_LAT, DEG_CHAR, MAX_LAT, DEG_CHAR); exit(EXIT_FAILURE); } /* Longitude */ if (lon < MIN_LON || lon > MAX_LON) { fprintf(stderr, "Longitude must be between %.1f%lc and %.1f%lc.\n", MIN_LON, DEG_CHAR, MAX_LON, DEG_CHAR); exit(EXIT_FAILURE); } /* Color temperature at daytime */ if (temp_day < MIN_TEMP || temp_day >= MAX_TEMP) { fprintf(stderr, "Temperature must be between %uK and %uK.\n", MIN_TEMP, MAX_TEMP); exit(EXIT_FAILURE); } /* Color temperature at night */ if (temp_night < MIN_TEMP || temp_night >= MAX_TEMP) { fprintf(stderr, "Temperature must be between %uK and %uK.\n", MIN_TEMP, MAX_TEMP); exit(EXIT_FAILURE); } /* Gamma */ if (gamma < MIN_GAMMA || gamma > MAX_GAMMA) { fprintf(stderr, "Gamma value must be between %.1f and %.1f.\n", MIN_GAMMA, MAX_GAMMA); exit(EXIT_FAILURE); } /* Current angular elevation of the sun */ time_t now = time(NULL); double elevation = solar_elevation(now, lat, lon); if (verbose) { printf("Solar elevation: %f%lc\n", elevation, DEG_CHAR); } /* Use elevation of sun to set color temperature */ int temp = 0; if (elevation < TRANSITION_LOW) { temp = temp_night; if (verbose) printf("Period: Night\n"); } else if (elevation < TRANSITION_HIGH) { /* Transition period: interpolate */ float a = (TRANSITION_LOW - elevation) / (TRANSITION_LOW - TRANSITION_HIGH); temp = (1.0-a)*temp_night + a*temp_day; if (verbose) { printf("Period: Transition (%.2f%% day)\n", a*100); } } else { temp = temp_day; if (verbose) printf("Period: Daytime\n"); } if (verbose) { printf("Color temperature: %uK\n", temp); } /* Set color temperature */ r = colortemp_set_temperature(temp, gamma); if (r < 0) { fprintf(stderr, "Unable to set color temperature.\n"); exit(EXIT_FAILURE); } return EXIT_SUCCESS; }