8 Commits
v1.2 ... v1.3

Author SHA1 Message Date
rexy712
dbfa9b9d12 Made restoration files optional 2018-12-06 13:37:01 -08:00
rexy712
8244ebb50b moved restore file to user's home directory 2018-12-06 12:59:25 -08:00
rexy712
abb03dcd40 Moved restore file logic into its own file 2018-12-04 13:13:51 -08:00
rexy712
82369b4d67 changed restore file signature 2018-12-01 10:17:41 -08:00
rexy712
38793bf575 writing to restore file 2018-12-01 10:10:40 -08:00
rexy712
904abe3294 Now can read from predefined restore file at /var/tmp/rexbacklight.json 2018-12-01 08:36:56 -08:00
rexy712
e1b2bb8ce9 Update readme 2018-11-24 10:10:57 -08:00
rexy712
37ec303118 Improved cmake build efficiency 2018-11-24 09:41:09 -08:00
12 changed files with 483 additions and 114 deletions

View File

@@ -1,17 +1,19 @@
include(CMakeDependentOption)
cmake_minimum_required(VERSION 3.0.2)
project(rexbacklight)
#setup common defines for C files
set(rexbacklight_VERSION_MAJOR 1)
set(rexbacklight_VERSION_MINOR 2)
set(rexbacklight_VERSION_MINOR 3)
set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include)
configure_file(
"${INCLUDE_PATH}/config.h.in"
"${INCLUDE_PATH}/config.h"
)
#set project include directory
include_directories("${INCLUDE_PATH}")
#setup cmake options
option(BUILD_REXLEDCTL "Build led control program" ON)
option(BUILD_REXBACKLIGHT "Build backlight control program" ON)
option(ENABLE_RESTORE_FILE "Enable backlight restoration from generated save file" ON)
option(XBACKLIGHT_COMPAT "Use xbacklight style options (eg -get -inc -dec)" OFF)
CMAKE_DEPENDENT_OPTION(INSTALL_UDEV_LED_RULE "Install the udev rule to allow users of video group to control led devices" ON
"BUILD_REXLEDCTL" OFF)
@@ -24,21 +26,51 @@ if(XBACKLIGHT_COMPAT)
add_definitions(-DXBACKLIGHT_COMPAT_OPTIONS)
endif()
#locate rjp library requirements
if(ENABLE_RESTORE_FILE)
find_library(RJP_LIB rjp)
find_path(RJP_HEADER_DIR rjp.h)
#temporary library (no actual library generated)
add_library(common_srcs OBJECT src/cmd.c src/common.c src/restore.c)
set(enable_RESTORE_FILE "#define ENABLE_RESTORE_FILE")
else()
add_library(common_srcs OBJECT src/cmd.c src/common.c)
set(enable_RESTORE_FILE "")
endif()
configure_file(
"${INCLUDE_PATH}/config.h.in"
"${INCLUDE_PATH}/config.h"
)
if(BUILD_REXLEDCTL)
add_executable (rexledctl src/rexbacklight.c src/cmd.c src/common.c)
target_compile_definitions(rexledctl PRIVATE REXLEDCTL)
add_executable (rexledctl src/rexbacklight.c)
add_dependencies(rexledctl common_srcs) #force common_srcs to be built first
target_compile_definitions(rexledctl PRIVATE REXLEDCTL) #define REXLEDCTL in C files
if(ENABLE_RESTORE_FILE)
target_link_libraries(rexledctl PRIVATE "${RJP_LIB}") #link with rjp
target_include_directories(rexledctl PUBLIC "${RJP_HEADER_DIR}") #include rjp.h directory
endif()
target_link_libraries(rexledctl PRIVATE $<TARGET_OBJECTS:common_srcs>) #link with the common_srcs "library"
install(TARGETS rexledctl RUNTIME DESTINATION bin)
if(INSTALL_UDEV_LED_RULE)
install(FILES ${CMAKE_SOURCE_DIR}/rules/91-leds.rules DESTINATION ${UDEV_DIR})
endif()
endif()
if(BUILD_REXBACKLIGHT)
add_executable (rexbacklight src/rexbacklight.c src/cmd.c src/common.c)
add_executable (rexbacklight src/rexbacklight.c)
add_dependencies(rexledctl common_srcs)
target_compile_definitions(rexbacklight PRIVATE REXBACKLIGHT)
if(ENABLE_RESTORE_FILE)
target_link_libraries(rexbacklight PRIVATE "${RJP_LIB}")
target_include_directories(rexbacklight PUBLIC "${RJP_HEADER_DIR}")
endif()
target_link_libraries(rexbacklight PRIVATE $<TARGET_OBJECTS:common_srcs>)
install(TARGETS rexbacklight RUNTIME DESTINATION bin)
if(INSTALL_UDEV_BACKLIGHT_RULE)
install(FILES ${CMAKE_SOURCE_DIR}/rules/91-backlight.rules DESTINATION ${UDEV_DIR})
endif()
endif()
#uninstall target
add_custom_target(uninstall cat install_manifest.txt | xargs rm)

View File

@@ -43,6 +43,8 @@ under certain conditions; see the GNU GPLv3 for details.
A copy of the GPLv3 is available with the source in the file 'LICENSE'
```
## Dependencies
Requires the rjp (rexy's json parser) library for reading restore file.
## Building
##### Run the following commands

View File

@@ -16,13 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RECBACKLIGHT_CMD_H
#ifndef REXBACKLIGHT_CMD_H
#define REXBACKLIGHT_CMD_H
#define OP_INC 1
#define OP_DEC 2
#define OP_SET 4
#define OP_LIST 8
#define OP_RESTORE 16
#define OP_GET 128
#define OP_NONE 0
#define OP_VERSION 254

View File

@@ -16,8 +16,6 @@
along with this program, If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#ifndef REXBACKLIGHT_COMMON_H
#define REXBACKLIGHT_COMMON_H
@@ -29,11 +27,27 @@
#define RETVAL_MEM_ERROR 6
#define RETVAL_INTERNAL_ERROR 7
#define RETVAL_SUCCESS EXIT_SUCCESS
#define IO_ERROR_DIR "directory"
#define IO_ERROR_FILE "file"
#define IO_ERROR_OPEN "open"
#define IO_ERROR_READ "read"
#define IO_ERROR_WRITE "write to"
void io_error(const char* error, const char* type, const char* name);
void io_error_2(const char* error, const char* type, const char* name, const char* name2);
void io_error_3(const char* error, const char* type, const char* name, const char* name2, const char* name3);
extern int return_value;
struct string_array{
char** list;
int size;
};
void mem_error(void);
_Noreturn void version(void);
_Noreturn void usage(int exit_val);
#endif

View File

@@ -22,5 +22,7 @@
#define REXBACKLIGHT_VERSION_MAJOR @rexbacklight_VERSION_MAJOR@
#define REXBACKLIGHT_VERSION_MINOR @rexbacklight_VERSION_MINOR@
@enable_RESTORE_FILE@
#endif

28
include/globals.h Normal file
View File

@@ -0,0 +1,28 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBALS_H
#define GLOBALS_H
const char* device_dir(void);
const char* executable_name(void);
const char* restore_file_suffix(void);
const char* brightness_file(void);
const char* max_brightness_file(void);
#endif

33
include/restore.h Normal file
View File

@@ -0,0 +1,33 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RESTORE_H
#define RESTORE_H
#include <rjp.h>
#include "common.h"
#include "cmd.h"
void save_restore_file(struct string_array* devices);
void all_restore(void);
int individual_restore(struct arg_values* curr, RJP_value** root, int* try_restore);
RJP_value* find_matching_json_device(const char* name, RJP_value* root);
RJP_value* read_restore_file(const char* file);
#endif

27
include/rexbacklight.h Normal file
View File

@@ -0,0 +1,27 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXBACKLIGHT_H
#define REXBACKLIGHT_H
#include "cmd.h"
float get_brightness(const char* file);
int individual_device_op(struct arg_values* curr);
#endif

View File

@@ -16,12 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h> //fprintf
#include <string.h> //strcmp
#include <stdlib.h> //malloc, free, strtol, atof
#include "cmd.h"
#include "common.h"
#include "config.h"
#define NO_OPT NULL
#define GET_LONG_OPT "--get"
@@ -54,6 +55,9 @@
#define DEC_LONG_OPT NO_OPT
#define DEC_SHORT_OPT NO_OPT
#define DEC_XBACK_OPT "-dec"
#define RESTORE_LONG_OPT "--restore"
#define RESTORE_SHORT_OPT "-R"
#define RESTORE_XBACK_OPT NO_OPT
#define DEVICE_DESC "select which device to control"
#define FADE_DESC "change brightness over time interval"
@@ -65,6 +69,7 @@
#define SET_DESC "set backlight device to specified value"
#define INC_DESC "increase backlight device by specified value"
#define DEC_DESC "decrease backlight device by specified value"
#define RESTORE_DESC "reassign previously saved backlight values"
int strcmp_handle_null(const char* one, const char* two){
if(!one)
@@ -82,28 +87,35 @@ int strcmp_handle_null(const char* one, const char* two){
#define CHECK_OPTION(opt, arg) (!strcmp_handle_null(opt##_LONG_OPT, arg) || !strcmp_handle_null(opt##_SHORT_OPT, arg) || !strcmp_handle_null(opt##_XBACK_OPT, arg))
struct cmd_arg rexbacklight_args[] = {
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, DEVICE_XBACK_OPT, DEVICE_DESC},
{NO_OPT, NO_OPT, SET_XBACK_OPT, SET_DESC},
{NO_OPT, NO_OPT, INC_XBACK_OPT, INC_DESC},
{NO_OPT, NO_OPT, DEC_XBACK_OPT, DEC_DESC},
{FADE_LONG_OPT, FADE_SHORT_OPT, FADE_XBACK_OPT, FADE_DESC},
{STEPS_LONG_OPT, STEPS_SHORT_OPT, STEPS_XBACK_OPT, STEPS_DESC},
{GET_LONG_OPT, GET_SHORT_OPT, GET_XBACK_OPT, GET_DESC},
{HELP_LONG_OPT, HELP_SHORT_OPT, HELP_XBACK_OPT, HELP_DESC},
{VERSION_LONG_OPT, NO_OPT, VERSION_XBACK_OPT, VERSION_DESC}
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, DEVICE_XBACK_OPT, DEVICE_DESC},
{NO_OPT, NO_OPT, SET_XBACK_OPT, SET_DESC},
{NO_OPT, NO_OPT, INC_XBACK_OPT, INC_DESC},
{NO_OPT, NO_OPT, DEC_XBACK_OPT, DEC_DESC},
{FADE_LONG_OPT, FADE_SHORT_OPT, FADE_XBACK_OPT, FADE_DESC},
{STEPS_LONG_OPT, STEPS_SHORT_OPT, STEPS_XBACK_OPT, STEPS_DESC},
{GET_LONG_OPT, GET_SHORT_OPT, GET_XBACK_OPT, GET_DESC},
{LIST_LONG_OPT, LIST_SHORT_OPT, LIST_XBACK_OPT, LIST_DESC},
#ifdef ENABLE_RESTORE_FILE
{RESTORE_LONG_OPT, RESTORE_SHORT_OPT, RESTORE_XBACK_OPT, RESTORE_DESC},
#endif
{HELP_LONG_OPT, HELP_SHORT_OPT, HELP_XBACK_OPT, HELP_DESC},
{VERSION_LONG_OPT, NO_OPT, VERSION_XBACK_OPT, VERSION_DESC}
};
#else //XBACKLIGHT_COMPAT_OPTIONS
#define CHECK_OPTION(opt, arg) (!strcmp_handle_null(opt##_LONG_OPT, arg) || !strcmp_handle_null(opt##_SHORT_OPT, arg))
struct cmd_arg rexbacklight_args[] = {
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, DEVICE_DESC},
{FADE_LONG_OPT, FADE_SHORT_OPT, FADE_DESC},
{STEPS_LONG_OPT, STEPS_SHORT_OPT, STEPS_DESC},
{GET_LONG_OPT, GET_SHORT_OPT, GET_DESC},
{LIST_LONG_OPT, LIST_SHORT_OPT, LIST_DESC},
{HELP_LONG_OPT, HELP_SHORT_OPT, HELP_DESC},
{VERSION_LONG_OPT, NO_OPT, VERSION_DESC}
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, DEVICE_DESC},
{FADE_LONG_OPT, FADE_SHORT_OPT, FADE_DESC},
{STEPS_LONG_OPT, STEPS_SHORT_OPT, STEPS_DESC},
{GET_LONG_OPT, GET_SHORT_OPT, GET_DESC},
{LIST_LONG_OPT, LIST_SHORT_OPT, LIST_DESC},
#ifdef ENABLE_RESTORE_FILE
{RESTORE_LONG_OPT, RESTORE_SHORT_OPT, RESTORE_DESC},
#endif
{HELP_LONG_OPT, HELP_SHORT_OPT, HELP_DESC},
{VERSION_LONG_OPT, NO_OPT, VERSION_DESC}
};
#endif //XBACKLIGHT_COMPAT_OPTIONS
@@ -195,6 +207,11 @@ struct arg_values process_cmd_args(int argc, char** argv){
ret.next = NULL;
return ret;
}
#ifdef ENABLE_RESTORE_FILE
else if(CHECK_OPTION(RESTORE, argv[i])){
ret.operation = OP_RESTORE;
}
#endif
else if(!strcmp(argv[i], "max")){
curr->operation = OP_SET;
curr->delta = 100;

View File

@@ -19,27 +19,37 @@
#include "config.h"
#include "common.h"
#include "cmd.h"
#include "globals.h"
#include <stdio.h>
#include <stdio.h> //printf
#include <stdlib.h> //exit
int return_value = RETVAL_SUCCESS;
void io_error(const char* error, const char* type, const char* name){
fprintf(stderr, "Unable to %s %s '%s'!\n", error, type, name);
}
void io_error_2(const char* error, const char* type, const char* name, const char* name2){
fprintf(stderr, "Unable to %s %s '%s%s'!\n", error, type, name, name2);
}
void io_error_3(const char* error, const char* type, const char* name, const char* name2, const char* name3){
fprintf(stderr, "Unable to %s %s '%s%s%s'!\n", error, type, name, name2, name3);
}
void mem_error(void){
fprintf(stderr, "Failed to allocate memory! Unable to continue!\n");
}
//name of the program being run so that we print the correct name in the usage
extern const char* executable_name;
_Noreturn void version(void){
printf("%s version %d.%d\n", executable_name, REXBACKLIGHT_VERSION_MAJOR, REXBACKLIGHT_VERSION_MINOR);
printf("%s version %d.%d\n", executable_name(), REXBACKLIGHT_VERSION_MAJOR, REXBACKLIGHT_VERSION_MINOR);
exit(return_value);
}
_Noreturn void usage(int exit_val){
int i;
printf("%s version %d.%d\n\n", executable_name, REXBACKLIGHT_VERSION_MAJOR, REXBACKLIGHT_VERSION_MINOR);
printf("Usage: %s [argument] [options] [argument]\n\n", executable_name);
printf("%s version %d.%d\n\n", executable_name(), REXBACKLIGHT_VERSION_MAJOR, REXBACKLIGHT_VERSION_MINOR);
printf("Usage: %s [argument] [options] [argument]\n\n", executable_name());
printf("Options:\n");
for(i = 0;i < rexbacklight_args_length;++i){
@@ -74,7 +84,7 @@ _Noreturn void usage(int exit_val){
printf(" max\n");
printf(" min\n");
printf("\n%s Copyright (C) 2018 rexy712\n", executable_name);
printf("\n%s Copyright (C) 2018 rexy712\n", executable_name());
printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
printf("This is free software, and you are welcome to redistribute it\n");
printf("under certain conditions; see the GNU GPLv3 for details.\n");

177
src/restore.c Normal file
View File

@@ -0,0 +1,177 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h> //printf
#include <string.h> //strcmp, strlen
#include <rjp.h>
#include <sys/types.h> //getpwnam
#include <pwd.h> //getpwnam
#include <unistd.h> //chdir
#include <stdlib.h> //malloc, free
#include "restore.h"
#include "common.h"
#include "cmd.h"
#include "globals.h"
#include "rexbacklight.h"
static char* get_home_folder(void){
char* user = getenv("SUDO_USER");
char* home = getenv("HOME");
if(!home || user){
if(!user){
return NULL;
}
struct passwd* pw_entry = getpwnam(user);
if(!pw_entry){
return NULL;
}
home = pw_entry->pw_dir;
}
return home;
}
static char* restore_file(void){
char* home_folder = get_home_folder();
if(!home_folder)
return NULL;
//"/.config/rexbacklight.json"
size_t home_folder_len = strlen(home_folder);
size_t conf_len = strlen(restore_file_suffix());
char* rest_file = malloc(home_folder_len + conf_len + 1);
strncpy(rest_file, home_folder, home_folder_len);
strncpy(rest_file+home_folder_len, restore_file_suffix(), conf_len);
rest_file[home_folder_len+conf_len] = 0;
return rest_file;
}
RJP_value* read_restore_file(const char* file){
size_t filesize;
char* file_contents;
int i;
FILE* fp = fopen(file, "r");
if(!fp){
fprintf(stderr, "Could not restore! No restore file found!\n");
return NULL;
}
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
file_contents = malloc(filesize+1);
i = fread(file_contents, filesize, 1, fp);
fclose(fp);
file_contents[filesize] = 0;
RJP_value* root = rjp_parse(file_contents);
free(file_contents);
return root;
}
RJP_value* find_matching_json_device(const char* name, RJP_value* root){
for(RJP_value* curr = rjp_get_member(root);curr;curr = rjp_next_member(curr)){
if(!strcmp(rjp_member_name(curr), name)){
return curr;
}
}
return NULL;
}
//run restore on individual device
int individual_restore(struct arg_values* curr, RJP_value** root, int* try_restore){
if(!*root && *try_restore){
char* tmp = restore_file();
*root = read_restore_file(tmp);
free(tmp);
if(!*root){
*try_restore = 0;
return 0;
}
}
RJP_value* match = find_matching_json_device(curr->device, *root);
if(!match){
fprintf(stderr, "No matching device '%s' in restore file!\n", curr->device);
return 0;
}
curr->operation = OP_SET;
curr->delta = rjp_value_dfloat(match);
return 1;
}
//run restore on all devices
void all_restore(void){
char* rfil = restore_file();
RJP_value* root = read_restore_file(rfil);
free(rfil);
if(!root)
return;
struct arg_values tmp = {.next = NULL,
.fade_duration = 0,
.fade_steps = 1,
.operation = OP_SET};
for(RJP_value* curr = rjp_get_member(root);curr;curr = rjp_next_member(curr)){
tmp.device = rjp_member_name(curr);
tmp.delta = rjp_value_dfloat(curr);
individual_device_op(&tmp);
}
rjp_free_value(root);
}
void save_restore_file(struct string_array* devices){
RJP_value* root = rjp_init_json();
for(size_t i = 0;i < devices->size;++i){
if(chdir(devices->list[i])){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), devices->list[i]);
return_value = RETVAL_INVALID_DIR;
continue;
}
size_t esc_name_len = rjp_escape_strlen(devices->list[i]);
char* esc_str = rjp_alloc(esc_name_len + 1);
rjp_escape_strcpy(esc_str, devices->list[i]);
float curr = get_brightness(brightness_file());
float max = get_brightness(max_brightness_file());
if(return_value == RETVAL_INVALID_FILE && (!curr || !max)){
rjp_add_member(root, 0, esc_str, 0, rjp_null());
}else{
rjp_add_member(root, 0, esc_str, 0, rjp_dfloat(curr/max*100));
}
if(chdir(device_dir())){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return_value = RETVAL_INVALID_DIR;
rjp_free_value(root);
free(esc_str);
return;
}
}
char* tmp = rjp_to_json(root);
char* rfil = restore_file();
FILE* restf = fopen(rfil, "w");
if(!restf){
io_error(IO_ERROR_OPEN, IO_ERROR_FILE, rfil);
}else{
fprintf(restf, "//File generated by %s\n%s\n", executable_name(), tmp);
fclose(restf);
}
free(rfil);
rjp_free(tmp);
rjp_free_value(root);
}

View File

@@ -16,57 +16,42 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Needed for usleep to work
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h> //fprintf
#include <stdlib.h> //malloc, free
#include <string.h> //strlen, strcpy
#include <unistd.h> //chdir
#include <sys/types.h> //opendir
#include <dirent.h> //opendir
#include <sys/time.h> //gettimeofday
#include <time.h> //nanosleep
#include "common.h"
#include "cmd.h"
#include "globals.h"
#include "config.h"
#ifdef ENABLE_RESTORE_FILE
#include <rjp.h>
#include "restore.h"
#endif
//name of the program being run so that we print the correct name in the usage
#ifdef REXBACKLIGHT
//This is where backlight devices can be found in sysfs
static const char* device_dir = "/sys/class/backlight/";
const char* executable_name = "rexbacklight";
const char* device_dir(void){return "/sys/class/backlight/";}
const char* executable_name(void){return "rexbacklight";}
const char* restore_file_suffix(void){return "/.config/rexbacklight.json";}
#elif defined(REXLEDCTL)
//This is where led devices can be found in sysfs
static const char* device_dir = "/sys/class/leds";
const char* executable_name = "rexledctl";
const char* device_dir(void){return "/sys/class/leds/";}
const char* executable_name(void){return "rexledctl";}
const char* restore_file_suffix(void){return "/.config/rexledctl.json";}
#else
#error "UNDEFINED PROGRAM NAME!"
#endif
static const char* brightness_file = "brightness";
static const char* max_brightness_file = "max_brightness";
//Used to store a dynamic array of dynamic strings and number of strings
struct string_array{
char** list;
int size;
};
#define IO_ERROR_DIR "directory"
#define IO_ERROR_FILE "file"
#define IO_ERROR_OPEN "open"
#define IO_ERROR_READ "read"
#define IO_ERROR_WRITE "write to"
void io_error(const char* error, const char* type, const char* name){
fprintf(stderr, "Unable to %s %s '%s'!\n", error, type, name);
}
void io_error_2(const char* error, const char* type, const char* name, const char* name2){
fprintf(stderr, "Unable to %s %s '%s/%s'!\n", error, type, name, name2);
}
void io_error_3(const char* error, const char* type, const char* name, const char* name2, const char* name3){
fprintf(stderr, "Unable to %s %s '%s/%s/%s'!\n", error, type, name, name2, name3);
}
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){
@@ -83,9 +68,9 @@ struct string_array get_device_sources(void){
struct string_array arr = {0};
int list_size = 8;
fd = opendir(device_dir);
fd = opendir(device_dir());
if(!fd){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir);
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return_value = RETVAL_INVALID_DIR;
return arr;
}
@@ -171,9 +156,9 @@ void fade_out(const char* device_name, int iv, int fv, int ms_duration, int step
while(ms_duration > tdelta){
//write
gettimeofday(&start, NULL);
fd = fopen(brightness_file, "w+");
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(), device_name, brightness_file());
return_value = RETVAL_INVALID_FILE;
return;
}
@@ -198,9 +183,9 @@ void fade_out(const char* device_name, int iv, int fv, int ms_duration, int step
//calc end of next step
step_delta += step_inc;
}
fd = fopen(brightness_file, "w+");
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(), device_name, brightness_file());
return_value = RETVAL_INVALID_FILE;
return;
}
@@ -211,20 +196,20 @@ void fade_out(const char* device_name, int iv, int fv, int ms_duration, int step
//Write value to device files
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));
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);
}
//Run get operation
void do_get(const char* device){
float curr, max;
curr = get_brightness(brightness_file);
max = get_brightness(max_brightness_file);
curr = get_brightness(brightness_file());
max = get_brightness(max_brightness_file());
if(return_value == RETVAL_INVALID_FILE && (!curr || !max)){
fprintf(stdout, "%s", device);
}else{
fprintf(stdout, "%-25s %.2f\n", device, get_brightness(brightness_file) / get_brightness(max_brightness_file) * 100);
fprintf(stdout, "%-25s %.2f\n", device, curr / max * 100);
}
}
@@ -235,32 +220,60 @@ void do_list(struct string_array* names){
fprintf(stdout, "%s\n", names->list[i]);
}
int individual_device_op(struct arg_values* curr){
if(chdir(curr->device)){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), curr->device);
return RETVAL_INVALID_DIR;
}
switch(curr->operation){
case OP_SET:
case OP_INC:
case OP_DEC:
do_assignment(curr, curr->device);
break;
case OP_GET:
do_get(curr->device);
break;
}
if(chdir(device_dir())){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return RETVAL_INTERNAL_ERROR;
}
return return_value;
}
#ifdef ENABLE_RESTORE_FILE
//If devices were specified, this function will run
void individual_device_loop(struct arg_values* a){
struct arg_values* curr;
RJP_value* root = 0;
int try_restore = 1;
for(curr = a->next;curr;curr = curr->next){
if(chdir(curr->device)){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir, curr->device);
return_value = RETVAL_INVALID_DIR;
continue;
if(curr->operation == OP_RESTORE){
if(!individual_restore(curr, &root, &try_restore))
continue;
}
switch(curr->operation){
case OP_SET:
case OP_INC:
case OP_DEC:
do_assignment(curr, curr->device);
break;
case OP_GET:
do_get(curr->device);
break;
}
if(chdir(device_dir)){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir);
return_value = RETVAL_INVALID_DIR;
return_value = individual_device_op(curr);
if(return_value == RETVAL_INTERNAL_ERROR){
rjp_free_value(root);
return;
}
}
rjp_free_value(root);
}
#else
//If devices were specified, this function will run
void individual_device_loop(struct arg_values* a){
struct arg_values* curr;
int try_restore = 1;
for(curr = a->next;curr;curr = curr->next){
return_value = individual_device_op(curr);
if(return_value == RETVAL_INTERNAL_ERROR)
return;
}
}
#endif
//If no devices were specified, this function will run
void all_device_loop(struct string_array* device_names, struct arg_values* args){
@@ -271,17 +284,20 @@ void all_device_loop(struct string_array* device_names, struct arg_values* args)
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]);
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);
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);
@@ -289,22 +305,29 @@ void all_device_loop(struct string_array* device_names, struct arg_values* args)
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]);
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);
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;
}
}
int main(int argc, char** argv){
struct arg_values args; //A linked list of devices and the requested settings.
@@ -352,8 +375,8 @@ 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);
if(chdir(device_dir())){
io_error(IO_ERROR_READ, IO_ERROR_DIR, device_dir());
CLEANUP();
return RETVAL_INVALID_DIR;
}
@@ -361,6 +384,9 @@ int main(int argc, char** argv){
//Run selected operation
if(args.next){
individual_device_loop(&args);
#ifdef ENABLE_RESTORE_FILE
save_restore_file(&device_names);
#endif
}else{
all_device_loop(&device_names, &args);
}