diff --git a/CMakeLists.txt b/CMakeLists.txt index a3beb62..88dac13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,8 @@ else() set(enable_RESTORE_FILE "") endif() +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DREXBACKLIGHT_DEBUG") + configure_file( "${INCLUDE_PATH}/config.h.in" "${INCLUDE_PATH}/config.h" diff --git a/include/cmd.h b/include/cmd.h index 9eb435c..f037dac 100644 --- a/include/cmd.h +++ b/include/cmd.h @@ -56,7 +56,10 @@ struct arg_values{ int fade_steps; - unsigned char operation; + union{ + int operation; + int num_values; + }; }; diff --git a/include/common.h b/include/common.h index 63ffd70..d509161 100644 --- a/include/common.h +++ b/include/common.h @@ -19,6 +19,12 @@ #ifndef REXBACKLIGHT_COMMON_H #define REXBACKLIGHT_COMMON_H +#ifdef REXBACKLIGHT_DEBUG +#define DEBUG_PRINT(s, ...) printf(s, __VA_ARGS__) +#else +#define DEBUG_PRINT(s, ...) +#endif + #define RETVAL_INVALID_FILE 1 #define RETVAL_INVALID_DIR 2 #define RETVAL_UNRECOGNIZED_OPTION 3 @@ -45,6 +51,7 @@ struct string_array{ char** list; int size; }; +void free_string_array(struct string_array* s); void mem_error(void); _Noreturn void version(void); diff --git a/src/cmd.c b/src/cmd.c index 5ffeee7..3dceeca 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -155,6 +155,7 @@ struct arg_values init_arg_values(void){ struct arg_values process_cmd_args(int argc, char** argv){ struct arg_values ret = init_arg_values(); struct arg_values* curr = &ret; + int nvals = 0; int i; //Skip argv[0] @@ -189,6 +190,7 @@ struct arg_values process_cmd_args(int argc, char** argv){ *(curr->next) = init_arg_values(); curr = curr->next; curr->device = argv[++i]; + ++nvals; continue; } @@ -305,6 +307,8 @@ struct arg_values process_cmd_args(int argc, char** argv){ } } } + if(ret.next) + ret.num_values = nvals; return ret; } #undef CHECK_OPTION diff --git a/src/common.c b/src/common.c index de3fc51..cafc569 100644 --- a/src/common.c +++ b/src/common.c @@ -36,6 +36,13 @@ void io_error_3(const char* error, const char* type, const char* name, const cha fprintf(stderr, "Unable to %s %s '%s%s%s'!\n", error, type, name, name2, name3); } +//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); +} void mem_error(void){ fprintf(stderr, "Failed to allocate memory! Unable to continue!\n"); diff --git a/src/rexbacklight.c b/src/rexbacklight.c index 1f0f31c..1afa458 100644 --- a/src/rexbacklight.c +++ b/src/rexbacklight.c @@ -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