|
|
|
|
@@ -53,14 +53,6 @@ const char* restore_file_suffix(void){return "/.config/rexledctl.json";}
|
|
|
|
|
const char* brightness_file(void){return "brightness";}
|
|
|
|
|
const char* max_brightness_file(void){return "max_brightness";}
|
|
|
|
|
|
|
|
|
|
//Clean up a string array
|
|
|
|
|
void free_string_array(struct string_array* s){
|
|
|
|
|
int i;
|
|
|
|
|
for(i = 0;i < s->size;++i)
|
|
|
|
|
free(s->list[i]);
|
|
|
|
|
free(s->list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Get a list of led/backlight devices in sysfs
|
|
|
|
|
struct string_array get_device_sources(void){
|
|
|
|
|
DIR* fd;
|
|
|
|
|
@@ -83,8 +75,6 @@ struct string_array get_device_sources(void){
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MEMORY_ERROR() do{mem_error();return_value = RETVAL_MEM_ERROR;free_string_array(&arr);closedir(fd);}while(0)
|
|
|
|
|
|
|
|
|
|
for(arr.size = 0;(dir = readdir(fd));){
|
|
|
|
|
int slen;
|
|
|
|
|
if(!strncmp(dir->d_name, ".", 1) || !strncmp(dir->d_name, "..", 2)){
|
|
|
|
|
@@ -93,13 +83,15 @@ struct string_array get_device_sources(void){
|
|
|
|
|
|
|
|
|
|
//Resize list if more than 8 led/backlight devices exist (not likely)
|
|
|
|
|
if(arr.size >= list_size){
|
|
|
|
|
int j;
|
|
|
|
|
char** tmp = malloc(sizeof(const char*) * (list_size += 8));
|
|
|
|
|
if(!tmp){
|
|
|
|
|
MEMORY_ERROR();
|
|
|
|
|
mem_error();
|
|
|
|
|
return_value = RETVAL_MEM_ERROR;
|
|
|
|
|
free_string_array(&arr);
|
|
|
|
|
closedir(fd);
|
|
|
|
|
return (struct string_array){0};
|
|
|
|
|
}
|
|
|
|
|
for(j = 0;j < arr.size;++j){
|
|
|
|
|
for(int j = 0;j < arr.size;++j){
|
|
|
|
|
tmp[j] = arr.list[j];
|
|
|
|
|
}
|
|
|
|
|
free(arr.list);
|
|
|
|
|
@@ -109,16 +101,17 @@ struct string_array get_device_sources(void){
|
|
|
|
|
slen = strlen(dir->d_name);
|
|
|
|
|
arr.list[arr.size] = malloc(slen + 1);
|
|
|
|
|
if(!arr.list[arr.size]){
|
|
|
|
|
MEMORY_ERROR();
|
|
|
|
|
mem_error();
|
|
|
|
|
return_value = RETVAL_MEM_ERROR;
|
|
|
|
|
free_string_array(&arr);
|
|
|
|
|
closedir(fd);
|
|
|
|
|
return (struct string_array){0};
|
|
|
|
|
}
|
|
|
|
|
strcpy(arr.list[arr.size], dir->d_name);
|
|
|
|
|
strncpy(arr.list[arr.size], dir->d_name, slen);
|
|
|
|
|
arr.list[arr.size][slen] = 0;
|
|
|
|
|
++arr.size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef MEMORY_ERROR
|
|
|
|
|
|
|
|
|
|
closedir(fd);
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
@@ -142,42 +135,52 @@ float get_brightness(const char* file){
|
|
|
|
|
fclose(bright);
|
|
|
|
|
return atof(buff);
|
|
|
|
|
}
|
|
|
|
|
double get_time(void){
|
|
|
|
|
struct timespec t;
|
|
|
|
|
clock_gettime(CLOCK_BOOTTIME, &t);
|
|
|
|
|
return ((t.tv_sec * 1000.0) + (t.tv_nsec * 0.0000001));
|
|
|
|
|
}
|
|
|
|
|
void sleep_for(double time){
|
|
|
|
|
DEBUG_PRINT("sleeping for %lf milliseconds\n", time);
|
|
|
|
|
struct timespec ts;
|
|
|
|
|
ts.tv_sec = (long)(time*0.0001);
|
|
|
|
|
ts.tv_nsec = ((time) - ts.tv_sec*1000) * 1000*1000;
|
|
|
|
|
nanosleep(&ts, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//update brightness incrementally over requested millisecond time interval
|
|
|
|
|
void fade_out(const char* device_name, int iv, int fv, int ms_duration, int steps){
|
|
|
|
|
|
|
|
|
|
void fade_out(struct arg_values* arg, int iv, int fv){
|
|
|
|
|
FILE* fd;
|
|
|
|
|
struct timeval start, end;
|
|
|
|
|
double start, end;
|
|
|
|
|
double tdelta = 0; //amount of time that has passed in ms
|
|
|
|
|
float value = iv; //current value to write to file
|
|
|
|
|
int step_delta = ms_duration / steps;
|
|
|
|
|
int step_inc = step_delta;
|
|
|
|
|
float brdelta = (float)(fv - iv) / steps; //amount brightness needs to change per iteration
|
|
|
|
|
double step_delta = (double)arg->fade_duration / arg->fade_steps;
|
|
|
|
|
double step_inc = step_delta;
|
|
|
|
|
float brdelta = (float)(fv - iv) / arg->fade_steps; //amount brightness needs to change per iteration
|
|
|
|
|
|
|
|
|
|
while(ms_duration > tdelta){
|
|
|
|
|
while(arg->fade_duration > tdelta){
|
|
|
|
|
//write
|
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
|
start = get_time();
|
|
|
|
|
fd = fopen(brightness_file(), "w+");
|
|
|
|
|
if(!fd){
|
|
|
|
|
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), device_name, brightness_file());
|
|
|
|
|
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), arg->device, brightness_file());
|
|
|
|
|
return_value = RETVAL_INVALID_FILE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fprintf(fd, "%d", (int)value);
|
|
|
|
|
fclose(fd);
|
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
|
end = get_time();
|
|
|
|
|
|
|
|
|
|
//calc time delta
|
|
|
|
|
tdelta += (((end.tv_sec * 1000.0) + (end.tv_usec / 1000.0)) - ((start.tv_sec * 1000.0) + (start.tv_usec / 1000.0)));
|
|
|
|
|
tdelta += end - start;
|
|
|
|
|
|
|
|
|
|
//calc next value to write
|
|
|
|
|
value += brdelta;
|
|
|
|
|
|
|
|
|
|
//waste excess time until next step
|
|
|
|
|
if(step_delta > tdelta){
|
|
|
|
|
struct timespec ts;
|
|
|
|
|
ts.tv_sec = (long)((step_delta - tdelta)/1000);
|
|
|
|
|
ts.tv_nsec = ((step_delta - tdelta) - ts.tv_sec*1000) * 1000*1000;
|
|
|
|
|
nanosleep(&ts, NULL);
|
|
|
|
|
sleep_for(step_delta - tdelta);
|
|
|
|
|
tdelta = step_delta;
|
|
|
|
|
}
|
|
|
|
|
//calc end of next step
|
|
|
|
|
@@ -185,7 +188,7 @@ void fade_out(const char* device_name, int iv, int fv, int ms_duration, int step
|
|
|
|
|
}
|
|
|
|
|
fd = fopen(brightness_file(), "w+");
|
|
|
|
|
if(!fd){
|
|
|
|
|
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), device_name, brightness_file());
|
|
|
|
|
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), arg->device, brightness_file());
|
|
|
|
|
return_value = RETVAL_INVALID_FILE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -198,7 +201,7 @@ void fade_out(const char* device_name, int iv, int fv, int ms_duration, int step
|
|
|
|
|
void do_assignment(struct arg_values* arg, const char* device){
|
|
|
|
|
int start = get_brightness(brightness_file());
|
|
|
|
|
int out = process_op(arg, 0, start, get_brightness(max_brightness_file()));
|
|
|
|
|
fade_out(device, start, out, arg->fade_duration, arg->fade_steps);
|
|
|
|
|
fade_out(arg, start, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Run get operation
|
|
|
|
|
@@ -215,8 +218,7 @@ void do_get(const char* device){
|
|
|
|
|
|
|
|
|
|
//Run list operation
|
|
|
|
|
void do_list(struct string_array* names){
|
|
|
|
|
int i;
|
|
|
|
|
for(i = 0;i < names->size;++i)
|
|
|
|
|
for(int i = 0;i < names->size;++i)
|
|
|
|
|
fprintf(stdout, "%s\n", names->list[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -234,6 +236,9 @@ int individual_device_op(struct arg_values* curr){
|
|
|
|
|
case OP_GET:
|
|
|
|
|
do_get(curr->device);
|
|
|
|
|
break;
|
|
|
|
|
case OP_LIST:
|
|
|
|
|
printf("%s\n", curr->device);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(chdir(device_dir())){
|
|
|
|
|
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
|
|
|
|
|
@@ -275,64 +280,26 @@ void individual_device_loop(struct arg_values* a){
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//If no devices were specified, this function will run
|
|
|
|
|
void all_device_loop(struct string_array* device_names, struct arg_values* args){
|
|
|
|
|
int i;
|
|
|
|
|
switch(args->operation){
|
|
|
|
|
case OP_SET:
|
|
|
|
|
case OP_INC:
|
|
|
|
|
case OP_DEC:
|
|
|
|
|
for(i = 0;i < device_names->size;++i){
|
|
|
|
|
if(chdir(device_names->list[i])){
|
|
|
|
|
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), device_names->list[i]);
|
|
|
|
|
return_value = RETVAL_INVALID_DIR;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
do_assignment(args, device_names->list[i]);
|
|
|
|
|
if(chdir(device_dir())){
|
|
|
|
|
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
|
|
|
|
|
return_value = RETVAL_INVALID_DIR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#ifdef ENABLE_RESTORE_FILE
|
|
|
|
|
save_restore_file(device_names);
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case OP_LIST:
|
|
|
|
|
do_list(device_names);
|
|
|
|
|
break;
|
|
|
|
|
case OP_GET:
|
|
|
|
|
for(i = 0;i < device_names->size;++i){
|
|
|
|
|
if(chdir(device_names->list[i])){
|
|
|
|
|
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), device_names->list[i]);
|
|
|
|
|
return_value = RETVAL_INVALID_DIR;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
do_get(device_names->list[i]);
|
|
|
|
|
if(chdir(device_dir())){
|
|
|
|
|
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
|
|
|
|
|
return_value = RETVAL_INVALID_DIR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#ifdef ENABLE_RESTORE_FILE
|
|
|
|
|
case OP_RESTORE:;
|
|
|
|
|
all_restore();
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "Internal processing error!\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void populate_args(struct arg_values* arg, struct string_array* devices){
|
|
|
|
|
struct arg_values* curr = arg;
|
|
|
|
|
for(size_t i = 0;i < devices->size;++i){
|
|
|
|
|
curr->next = malloc(sizeof(struct arg_values));
|
|
|
|
|
curr->next->device = devices->list[i];
|
|
|
|
|
curr->next->delta = arg->delta;
|
|
|
|
|
curr->next->fade_duration = arg->fade_duration;
|
|
|
|
|
curr->next->fade_steps = arg->fade_steps;
|
|
|
|
|
curr->next->operation = arg->operation;
|
|
|
|
|
curr = curr->next;
|
|
|
|
|
}
|
|
|
|
|
curr->next = NULL;
|
|
|
|
|
arg->num_values = devices->size;
|
|
|
|
|
}
|
|
|
|
|
int main(int argc, char** argv){
|
|
|
|
|
|
|
|
|
|
struct arg_values args; //A linked list of devices and the requested settings.
|
|
|
|
|
struct string_array device_names; //List of all led/backlight devices in sysfs.
|
|
|
|
|
struct arg_values* curr;
|
|
|
|
|
|
|
|
|
|
args = process_cmd_args(argc, argv);
|
|
|
|
|
if(args.operation == OP_USAGE){
|
|
|
|
|
usage(return_value);
|
|
|
|
|
@@ -342,34 +309,28 @@ int main(int argc, char** argv){
|
|
|
|
|
|
|
|
|
|
device_names = get_device_sources();
|
|
|
|
|
|
|
|
|
|
//Macro for easy memory cleaning
|
|
|
|
|
#define CLEANUP() do{free_string_array(&device_names);free_cmd_args(&args);}while(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//If there are no led/backlights, we can't do anything
|
|
|
|
|
if(device_names.size == 0){
|
|
|
|
|
#ifdef REXBACKLIGHT
|
|
|
|
|
fprintf(stderr, "No backlights devices found!\n");
|
|
|
|
|
#elif defined(REXLEDCTL)
|
|
|
|
|
fprintf(stderr, "No led devices found!\n");
|
|
|
|
|
#else
|
|
|
|
|
#error "UNDEFINED PROGRAM NAME!"
|
|
|
|
|
#endif
|
|
|
|
|
CLEANUP();
|
|
|
|
|
free_string_array(&device_names);
|
|
|
|
|
free_cmd_args(&args);
|
|
|
|
|
return RETVAL_INVALID_DEVICE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Make sure all explicit devices actually exist
|
|
|
|
|
for(curr = args.next;curr;curr = curr->next){
|
|
|
|
|
int i;
|
|
|
|
|
for(i = 0;i < device_names.size;++i){
|
|
|
|
|
for(struct arg_values* curr = args.next;curr;curr = curr->next){
|
|
|
|
|
for(int i = 0;i < device_names.size;++i){
|
|
|
|
|
if(!strcmp(curr->device, device_names.list[i])){
|
|
|
|
|
goto continue_outer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "No such device '%s'\n", curr->device);
|
|
|
|
|
CLEANUP();
|
|
|
|
|
free_string_array(&device_names);
|
|
|
|
|
free_cmd_args(&args);
|
|
|
|
|
return RETVAL_INVALID_DEVICE;
|
|
|
|
|
continue_outer:;
|
|
|
|
|
}
|
|
|
|
|
@@ -377,21 +338,23 @@ int main(int argc, char** argv){
|
|
|
|
|
//Change to the base directory for all sysfs leds/backlights
|
|
|
|
|
if(chdir(device_dir())){
|
|
|
|
|
io_error(IO_ERROR_READ, IO_ERROR_DIR, device_dir());
|
|
|
|
|
CLEANUP();
|
|
|
|
|
free_string_array(&device_names);
|
|
|
|
|
free_cmd_args(&args);
|
|
|
|
|
return RETVAL_INVALID_DIR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Run selected operation
|
|
|
|
|
if(args.next){
|
|
|
|
|
individual_device_loop(&args);
|
|
|
|
|
}else{
|
|
|
|
|
populate_args(&args, &device_names);
|
|
|
|
|
individual_device_loop(&args);
|
|
|
|
|
}
|
|
|
|
|
#ifdef ENABLE_RESTORE_FILE
|
|
|
|
|
save_restore_file(&device_names);
|
|
|
|
|
#endif
|
|
|
|
|
}else{
|
|
|
|
|
all_device_loop(&device_names, &args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CLEANUP();
|
|
|
|
|
free_string_array(&device_names);
|
|
|
|
|
free_cmd_args(&args);
|
|
|
|
|
return return_value;
|
|
|
|
|
}
|
|
|
|
|
#undef CLEANUP
|
|
|
|
|
|