Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42dee2de78 | ||
|
|
61e36bed19 | ||
|
|
50412e0006 | ||
|
|
19d736bc84 | ||
|
|
db3036e85b | ||
|
|
26bd685296 | ||
|
|
fa187be8b0 | ||
|
|
bbce4dc8fe | ||
|
|
9c4425ff54 | ||
|
|
2e0ee84ca7 | ||
|
|
f868074f0c | ||
|
|
2fdd9fa13b | ||
|
|
40eec1fb23 | ||
|
|
42f93ba026 | ||
|
|
44ddaae28d | ||
|
|
5986fa8133 | ||
|
|
479e7c1f17 | ||
|
|
2dd52c32b7 | ||
|
|
87b7dd2503 | ||
|
|
3c2e3f35a0 | ||
|
|
00062612f5 | ||
|
|
eab07e49cf | ||
|
|
94ce061013 | ||
|
|
80eda899e7 | ||
|
|
cf45749af2 | ||
|
|
a394ade61e | ||
|
|
9a1856ace5 | ||
|
|
b5815149a3 | ||
|
|
1d5a5d9d69 | ||
|
|
04dcd0684a |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,4 +4,4 @@ rexbacklight
|
||||
rexledctl
|
||||
*.swp
|
||||
build
|
||||
include/config.h
|
||||
include/version.h
|
||||
|
||||
@@ -1,15 +1,49 @@
|
||||
include(CMakeDependentOption)
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
project(rexbacklight)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
include(CMakeDependentOption)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
#setup common defines for C files
|
||||
set(rexbacklight_VERSION_MAJOR 1)
|
||||
set(rexbacklight_VERSION_MINOR 3)
|
||||
set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include)
|
||||
set(SCRIPT_DIR ${CMAKE_SOURCE_DIR}/scripts)
|
||||
|
||||
#set project include directory
|
||||
set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include)
|
||||
include_directories("${INCLUDE_PATH}")
|
||||
|
||||
set(GIT_VERSION_FILE ${CMAKE_SOURCE_DIR}/include/version.h)
|
||||
set(GIT_VERSION_TMP_FILE ${CMAKE_SOURCE_DIR}/include/verison.h.tmp)
|
||||
|
||||
#require python on windows
|
||||
#i know this program can't be built on windows, but i wanted to figure out how to do this
|
||||
if(WIN32)
|
||||
find_package(PythonInterp 3 REQUIRED)
|
||||
else()
|
||||
find_package(PythonInterp 3 QUIET)
|
||||
endif()
|
||||
|
||||
if(PYTHONINTERP_FOUND)
|
||||
add_custom_command(
|
||||
OUTPUT ${GIT_VERSION_TMP_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "//File generated by CMake. Do not edit!" > ${GIT_VERSION_TMP_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#define GIT_TAG_NAME \"v1.5.2\"" > ${GIT_VERSION_TMP_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GIT_VERSION_TMP_FILE} ${GIT_VERSION_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${GIT_VERSION_TMP_FILE}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Regenerating version.h"
|
||||
VERBATIM
|
||||
)
|
||||
elseif(UNIX)
|
||||
add_custom_command(
|
||||
OUTPUT ${GIT_VERSION_TMP_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "//File generated by CMake. Do not edit!" > ${GIT_VERSION_TMP_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#define GIT_TAG_NAME \"v1.5.2\"" > ${GIT_VERSION_TMP_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GIT_VERSION_TMP_FILE} ${GIT_VERSION_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${GIT_VERSION_TMP_FILE}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Regenerating version.h"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
#setup cmake options
|
||||
option(BUILD_REXLEDCTL "Build led control program" ON)
|
||||
option(BUILD_REXBACKLIGHT "Build backlight control program" ON)
|
||||
@@ -23,49 +57,50 @@ set(UDEV_DIR "/etc/udev/rules.d" CACHE STRING "Set the output directory for udev
|
||||
mark_as_advanced(UDEV_DIR)
|
||||
|
||||
if(XBACKLIGHT_COMPAT)
|
||||
add_definitions(-DXBACKLIGHT_COMPAT_OPTIONS)
|
||||
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)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(RJP REQUIRED rjp)
|
||||
#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")
|
||||
add_definitions("-DENABLE_RESTORE_FILE")
|
||||
else()
|
||||
add_library(common_srcs OBJECT src/cmd.c src/common.c)
|
||||
set(enable_RESTORE_FILE "")
|
||||
endif()
|
||||
target_sources(common_srcs PUBLIC ${GIT_VERSION_TMP_FILE})
|
||||
|
||||
configure_file(
|
||||
"${INCLUDE_PATH}/config.h.in"
|
||||
"${INCLUDE_PATH}/config.h"
|
||||
)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DREXBACKLIGHT_DEBUG")
|
||||
|
||||
#build led control program
|
||||
if(BUILD_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"
|
||||
if(ENABLE_RESTORE_FILE)
|
||||
target_link_libraries(rexledctl PRIVATE "${RJP_LIBRARIES}") #link with rjp
|
||||
target_include_directories(rexledctl PUBLIC "${RJP_INCLUDE_DIRS}") #include rjp.h directory
|
||||
target_compile_options(rexledctl PUBLIC ${RJP_CFLAGS_OTHER})
|
||||
endif()
|
||||
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()
|
||||
#build backlight control program
|
||||
if(BUILD_REXBACKLIGHT)
|
||||
add_executable (rexbacklight src/rexbacklight.c)
|
||||
add_dependencies(rexledctl common_srcs)
|
||||
add_dependencies(rexbacklight 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>)
|
||||
if(ENABLE_RESTORE_FILE)
|
||||
target_link_libraries(rexbacklight PRIVATE "${RJP_LIBRARIES}")
|
||||
target_include_directories(rexbacklight PUBLIC "${RJP_INCLUDE_DIRS}")
|
||||
target_compile_options(rexbacklight PUBLIC ${RJP_CFLAGS_OTHER})
|
||||
endif()
|
||||
install(TARGETS rexbacklight RUNTIME DESTINATION bin)
|
||||
if(INSTALL_UDEV_BACKLIGHT_RULE)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/rules/91-backlight.rules DESTINATION ${UDEV_DIR})
|
||||
|
||||
31
README.md
31
README.md
@@ -1,31 +1,37 @@
|
||||
# README
|
||||
|
||||
## About
|
||||
rexbacklight is a program designed to operate similarly to xbacklight, though it's not a drop in replacement (possibly adding drop in replacement configure option at some point). Unlike xbacklight, this program does not use X11 to control the backlight devices. rexbacklight directly interacts with sysfs to change backlight levels, read their current status, and find their max output level. This has the advantage of allowing rexbacklight to run without the X server running and will work even if X doesn't recognize your backlight device, which was my original inspiration to make this project.
|
||||
rexbacklight is a program designed to operate similarly to xbacklight. There is even a configure option to enable xbacklight arguments to make this a drop in replacement. However unlike xbacklight, this program does not use X11 to control the backlight devices. rexbacklight directly interacts with sysfs to change backlight levels, read their current status, and find their max output level. This has the advantage of allowing rexbacklight to run without the X server running and will work even if X doesn't recognize your backlight device, which was my original inspiration to make this project.
|
||||
|
||||
I've also since added a program to control LED devices, rexledctl (best name I could think of). This one was inspired by the fact that my laptop's keyboard backlight wasn't controllable by any program I had and the hardware button didn't work either. So now I have my own program which can control it. It was so similar in function to rexbacklight that I decided to just add some compile time `#define`'s and make a few things more modular in the code and have the same source files make 2 different programs.
|
||||
|
||||
Either program can be built alone or both together. This is configured using some cmake magic.
|
||||
|
||||
Current version is 1.0 as of writing this, so if the version is much newer, remind me to update this readme.
|
||||
Current version is 1.5.2 as of writing this, so if the version is much newer, remind me to update this readme.
|
||||
|
||||
```
|
||||
rexbacklight version v1.5.2
|
||||
|
||||
Usage: rexbacklight [argument] [options] [argument]
|
||||
|
||||
Options:
|
||||
--device|-d
|
||||
--device|-d
|
||||
select which device to control
|
||||
--fade|-f
|
||||
--fade|-f
|
||||
change brightness over time interval
|
||||
--steps|-s
|
||||
--steps|-s
|
||||
number of steps over which to fade
|
||||
--get|-g
|
||||
--get|-g
|
||||
print current brightness level to stdout
|
||||
--list|-l
|
||||
--list|-l
|
||||
print device names to stdout and exit
|
||||
--help|-h
|
||||
--restore|-R
|
||||
reassign previously saved device values
|
||||
--no-save|-N
|
||||
do not write any data to the restore file
|
||||
--help|-h
|
||||
print this help message and exit
|
||||
--version
|
||||
--version
|
||||
print program version and exit
|
||||
|
||||
Arguments:
|
||||
@@ -36,7 +42,7 @@ Arguments:
|
||||
max
|
||||
min
|
||||
|
||||
rexbacklight Copyright (C) 2018 rexy712
|
||||
rexbacklight Copyright (C) 2018-2021 rexy712
|
||||
This program comes with ABSOLUTELY NO WARRANTY.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; see the GNU GPLv3 for details.
|
||||
@@ -44,7 +50,8 @@ 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.
|
||||
Requires the rjp ([rexy's json parser][rjp]) library for reading restore file, though this can be disabled via cmake configuration.
|
||||
Either python3 or sh compatible shell to run some build scripts.
|
||||
|
||||
## Building
|
||||
##### Run the following commands
|
||||
@@ -72,3 +79,5 @@ sudo udevadm trigger
|
||||
```
|
||||
sudo make uninstall
|
||||
```
|
||||
|
||||
[rjp]: https://gitlab.com/rexy712/rjp
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -29,6 +29,9 @@
|
||||
#define OP_VERSION 254
|
||||
#define OP_USAGE 255
|
||||
|
||||
#define ARG_FLAG_NONE 0
|
||||
#define ARG_FLAG_NO_SAVE 1
|
||||
|
||||
struct cmd_arg{
|
||||
const char* lopt;
|
||||
const char* sopt;
|
||||
@@ -48,7 +51,11 @@ struct arg_values{
|
||||
//NULL means all devices
|
||||
const char* device;
|
||||
|
||||
//What value to put in the backlight file
|
||||
//starting brightness
|
||||
int act_start;
|
||||
//value to write in backlight file
|
||||
int act_delta;
|
||||
//output percentage
|
||||
float delta;
|
||||
|
||||
//How many seconds to transition
|
||||
@@ -56,7 +63,11 @@ struct arg_values{
|
||||
|
||||
int fade_steps;
|
||||
|
||||
unsigned char operation;
|
||||
union{
|
||||
int operation;
|
||||
int num_values;
|
||||
};
|
||||
int flags;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -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
|
||||
@@ -34,19 +40,19 @@
|
||||
#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 free_string_array(struct string_array* s);
|
||||
|
||||
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);
|
||||
void mem_error(void);
|
||||
|
||||
_Noreturn void version(void);
|
||||
_Noreturn void usage(int exit_val);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -19,10 +19,17 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define REXBACKLIGHT_VERSION_MAJOR @rexbacklight_VERSION_MAJOR@
|
||||
#define REXBACKLIGHT_VERSION_MINOR @rexbacklight_VERSION_MINOR@
|
||||
#include "version.h"
|
||||
|
||||
@enable_RESTORE_FILE@
|
||||
#ifdef GIT_TAG_NAME
|
||||
#ifdef GIT_DIRTY
|
||||
#define REXBACKLIGHT_VERSION GIT_TAG_NAME "-dirty"
|
||||
#else
|
||||
#define REXBACKLIGHT_VERSION GIT_TAG_NAME
|
||||
#endif
|
||||
#else
|
||||
#define REXBACKLIGHT_VERSION GIT_BRANCH_NAME "-" GIT_COMMIT_HASH
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -24,9 +24,9 @@
|
||||
#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);
|
||||
void save_restore_file(struct string_array* devices, struct arg_values* args);
|
||||
int restore_to_delta(struct arg_values* curr);
|
||||
void prep_restore(struct arg_values* a);
|
||||
RJP_value* find_matching_json_device(const char* name, RJP_value* root);
|
||||
RJP_value* read_restore_file(const char* file);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
|
||||
8
scripts/git_branch_name.py
Executable file
8
scripts/git_branch_name.py
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import subprocess
|
||||
|
||||
output = subprocess.run(['git', 'rev-parse', "--abbrev-ref", "HEAD"], stdout=subprocess.PIPE).stdout.decode('utf-8').rstrip()
|
||||
|
||||
if output:
|
||||
print("#define GIT_BRANCH_NAME " + '"' + output + '"')
|
||||
7
scripts/git_branch_name.sh
Executable file
7
scripts/git_branch_name.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
output="$(git rev-parse --abbrev-ref HEAD)"
|
||||
|
||||
if test -n "$output";then
|
||||
echo "#define GIT_BRANCH_NAME \"$output\" //test"
|
||||
fi
|
||||
10
scripts/git_commit_hash.py
Executable file
10
scripts/git_commit_hash.py
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import subprocess
|
||||
|
||||
output = subprocess.run(['git', 'describe', "--always", "--dirty", "--abbrev", "--match=\"NeVeRmAtCh\""], stdout=subprocess.PIPE).stdout.decode('utf-8').rstrip()
|
||||
|
||||
if output:
|
||||
print("#define GIT_COMMIT_HASH " + '"' + output + '"')
|
||||
if output.find("dirty") != -1:
|
||||
print("#define GIT_DIRTY")
|
||||
10
scripts/git_commit_hash.sh
Executable file
10
scripts/git_commit_hash.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
output="$(git describe --always --dirty --abbrev --match="NeVeRmAtCh")"
|
||||
|
||||
if test -n output;then
|
||||
echo "#define GIT_COMMIT_HASH \"$output\""
|
||||
if grep -q "dirty" <<< "$output";then
|
||||
echo "#define GIT_DIRTY"
|
||||
fi
|
||||
fi
|
||||
9
scripts/git_tag_name.py
Executable file
9
scripts/git_tag_name.py
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import subprocess
|
||||
|
||||
output = subprocess.run(['git', 'tag', "--points-at", "HEAD"], stdout=subprocess.PIPE).stdout.decode('utf-8').rstrip()
|
||||
|
||||
if output:
|
||||
if output[0] == 'v' or output[0] == 'V':
|
||||
print("#define GIT_TAG_NAME " + '"' + output[1:] + '"')
|
||||
9
scripts/git_tag_name.sh
Executable file
9
scripts/git_tag_name.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
output="$(git tag --points-at HEAD)"
|
||||
|
||||
if test -n "$output";then
|
||||
if test "${output:0:1}" = "v" || test "${output:0:1}" = "V";then
|
||||
echo "#define GIT_TAG_NAME \"${output:1}\""
|
||||
fi
|
||||
fi
|
||||
93
src/cmd.c
93
src/cmd.c
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -58,6 +58,9 @@
|
||||
#define RESTORE_LONG_OPT "--restore"
|
||||
#define RESTORE_SHORT_OPT "-R"
|
||||
#define RESTORE_XBACK_OPT NO_OPT
|
||||
#define NO_SAVE_LONG_OPT "--no-save"
|
||||
#define NO_SAVE_SHORT_OPT "-N"
|
||||
#define NO_SAVE_XBACK_OPT NO_OPT
|
||||
|
||||
#define DEVICE_DESC "select which device to control"
|
||||
#define FADE_DESC "change brightness over time interval"
|
||||
@@ -69,9 +72,10 @@
|
||||
#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"
|
||||
#define RESTORE_DESC "reassign previously saved device values"
|
||||
#define NO_SAVE_DESC "do not write any data to the restore file"
|
||||
|
||||
int strcmp_handle_null(const char* one, const char* two){
|
||||
static inline int strcmp_handle_null(const char* one, const char* two){
|
||||
if(!one)
|
||||
return 1;
|
||||
if(!two)
|
||||
@@ -79,49 +83,37 @@ int strcmp_handle_null(const char* one, const char* two){
|
||||
return strcmp(one, two);
|
||||
}
|
||||
|
||||
#define CHECK_SHORT_OPTION(opt, arg) (!strcmp(opt##_SHORT_OPT, arg))
|
||||
#define CHECK_LONG_OPTION(opt, arg) (!strcmp(opt##_LONG_OPT, arg))
|
||||
#define CHECK_XBACK_OPTION(opt, arg) (!strcmp(opt##_XBACK_OPT, arg))
|
||||
#define CHECK_SHORT_OPTION(opt, arg) (!strcmp_handle_null(opt##_SHORT_OPT, arg))
|
||||
#define CHECK_LONG_OPTION(opt, arg) (!strcmp_handle_null(opt##_LONG_OPT, arg))
|
||||
#define CHECK_XBACK_OPTION(opt, arg) (!strcmp_handle_null(opt##_XBACK_OPT, arg))
|
||||
|
||||
#ifdef XBACKLIGHT_COMPAT_OPTIONS
|
||||
|
||||
#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},
|
||||
{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}
|
||||
};
|
||||
|
||||
#define OPTION(x) {x##_LONG_OPT, x##_SHORT_OPT, x##_XBACK_OPT, x##_DESC}
|
||||
#define CHECK_OPTION(opt, arg) (CHECK_LONG_OPTION(opt, arg) || CHECK_SHORT_OPTION(opt, arg) || CHECK_XBACK_OPTION(opt, arg))
|
||||
#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},
|
||||
#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}
|
||||
};
|
||||
#define OPTION(x) {x##_LONG_OPT, x##_SHORT_OPT, x##_DESC}
|
||||
#define CHECK_OPTION(opt, arg) (CHECK_LONG_OPTION(opt, arg) || CHECK_SHORT_OPTION(opt, arg))
|
||||
#endif //XBACKLIGHT_COMPAT_OPTIONS
|
||||
|
||||
struct cmd_arg rexbacklight_args[] = {
|
||||
OPTION(DEVICE),
|
||||
OPTION(SET),
|
||||
OPTION(INC),
|
||||
OPTION(DEC),
|
||||
OPTION(FADE),
|
||||
OPTION(STEPS),
|
||||
OPTION(GET),
|
||||
OPTION(LIST),
|
||||
#ifdef ENABLE_RESTORE_FILE
|
||||
OPTION(RESTORE),
|
||||
OPTION(NO_SAVE),
|
||||
#endif
|
||||
OPTION(HELP),
|
||||
OPTION(VERSION)
|
||||
};
|
||||
|
||||
int rexbacklight_args_length = sizeof(rexbacklight_args) / sizeof(rexbacklight_args[0]);
|
||||
|
||||
\
|
||||
//Clean up a cmd_arg struct
|
||||
void free_cmd_args(struct arg_values* a){
|
||||
if(!a->next)
|
||||
@@ -148,13 +140,14 @@ void free_cmd_args(struct arg_values* a){
|
||||
}while(0);
|
||||
|
||||
struct arg_values init_arg_values(void){
|
||||
return (struct arg_values){.next = NULL, .device = NULL, .delta = 0, .fade_duration = 0, .fade_steps = 20, .operation = 0};
|
||||
return (struct arg_values){.next = NULL, .device = NULL, .delta = 0, .fade_duration = 0, .fade_steps = 20, .operation = 0, .flags = 0};
|
||||
}
|
||||
|
||||
//Convert command line arguments to flags
|
||||
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]
|
||||
@@ -162,7 +155,7 @@ struct arg_values process_cmd_args(int argc, char** argv){
|
||||
|
||||
//Check for switches
|
||||
if(CHECK_OPTION(GET, argv[i])){
|
||||
curr->operation |= OP_GET;
|
||||
curr->operation = OP_GET;
|
||||
continue;
|
||||
|
||||
}else if(CHECK_OPTION(FADE, argv[i])){
|
||||
@@ -189,6 +182,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;
|
||||
}
|
||||
|
||||
@@ -202,14 +196,14 @@ struct arg_values process_cmd_args(int argc, char** argv){
|
||||
}
|
||||
|
||||
else if(CHECK_OPTION(LIST, argv[i])){
|
||||
free_cmd_args(&ret);
|
||||
ret.operation = OP_LIST;
|
||||
ret.next = NULL;
|
||||
return ret;
|
||||
curr->operation = OP_LIST;
|
||||
}
|
||||
#ifdef ENABLE_RESTORE_FILE
|
||||
else if(CHECK_OPTION(RESTORE, argv[i])){
|
||||
ret.operation = OP_RESTORE;
|
||||
curr->operation = OP_RESTORE;
|
||||
}
|
||||
else if(CHECK_OPTION(NO_SAVE, argv[i])){
|
||||
curr->flags |= ARG_FLAG_NO_SAVE;
|
||||
}
|
||||
#endif
|
||||
else if(!strcmp(argv[i], "max")){
|
||||
@@ -301,14 +295,19 @@ struct arg_values process_cmd_args(int argc, char** argv){
|
||||
curr->operation = ret.operation;
|
||||
if(!curr->delta)
|
||||
curr->delta = ret.delta;
|
||||
|
||||
}
|
||||
if(curr->flags == ARG_FLAG_NONE){
|
||||
curr->flags = ret.flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ret.next)
|
||||
ret.num_values = nvals;
|
||||
return ret;
|
||||
}
|
||||
#undef CHECK_OPTION
|
||||
#undef UNRECOGNIZED_OPTION
|
||||
#undef OPTION
|
||||
|
||||
//Process an operation
|
||||
int process_op(struct arg_values* arg, float min, float current, float max){
|
||||
|
||||
26
src/common.c
26
src/common.c
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -35,20 +35,26 @@ void io_error_2(const char* error, const char* type, const char* name, const cha
|
||||
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");
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
_Noreturn void version(void){
|
||||
printf("%s version %d.%d\n", executable_name(), REXBACKLIGHT_VERSION_MAJOR, REXBACKLIGHT_VERSION_MINOR);
|
||||
printf("%s version %s\n", executable_name(), REXBACKLIGHT_VERSION);
|
||||
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("%s version %s\n\n", executable_name(), REXBACKLIGHT_VERSION);
|
||||
printf("Usage: %s [argument] [options] [argument]\n\n", executable_name());
|
||||
|
||||
printf("Options:\n");
|
||||
@@ -69,11 +75,15 @@ _Noreturn void usage(int exit_val){
|
||||
if(rexbacklight_args[i].xopt){
|
||||
if(printed)
|
||||
printf("|");
|
||||
else
|
||||
printed = 1;
|
||||
printf("%s", rexbacklight_args[i].xopt);
|
||||
}
|
||||
#endif //XBACKLIGHT_COMPAT_OPTIONS
|
||||
printf("\n");
|
||||
printf(" %s\n", rexbacklight_args[i].desc);
|
||||
if(printed){
|
||||
printf("\n");
|
||||
printf(" %s\n", rexbacklight_args[i].desc);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("Arguments:\n");
|
||||
@@ -84,7 +94,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-2021 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");
|
||||
|
||||
118
src/restore.c
118
src/restore.c
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -66,7 +66,6 @@ RJP_value* read_restore_file(const char* file){
|
||||
int i;
|
||||
FILE* fp = fopen(file, "r");
|
||||
if(!fp){
|
||||
fprintf(stderr, "Could not restore! No restore file found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -78,88 +77,85 @@ RJP_value* read_restore_file(const char* file){
|
||||
i = fread(file_contents, filesize, 1, fp);
|
||||
fclose(fp);
|
||||
file_contents[filesize] = 0;
|
||||
RJP_value* root = rjp_parse(file_contents);
|
||||
RJP_value* root = rjp_parse(file_contents, RJP_PARSE_NO_EXT, NULL);
|
||||
free(file_contents);
|
||||
return root;
|
||||
}
|
||||
|
||||
static RJP_value* restore_file_handle(void){
|
||||
static RJP_value* rf = NULL;
|
||||
if(!rf){
|
||||
char* f = restore_file();
|
||||
rf = read_restore_file(f);
|
||||
free(f);
|
||||
}
|
||||
return rf;
|
||||
}
|
||||
|
||||
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)){
|
||||
RJP_object_iterator it;
|
||||
rjp_init_object_iterator(&it, root);
|
||||
for(RJP_value* curr = rjp_object_iterator_current(&it);curr;curr = rjp_object_iterator_next(&it)){
|
||||
if(!strcmp(rjp_member_key(curr)->value, 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;
|
||||
}
|
||||
//convert a restoration operation to a set operation
|
||||
int restore_to_delta(struct arg_values* curr){
|
||||
RJP_value* root = restore_file_handle();
|
||||
if(!root){
|
||||
fprintf(stderr, "Could not restore! No restore file found!\n");
|
||||
return 0;
|
||||
}
|
||||
RJP_value* match = find_matching_json_device(curr->device, *root);
|
||||
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);
|
||||
curr->delta = rjp_get_float(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);
|
||||
void prep_restore(struct arg_values* a){
|
||||
for(struct arg_values* curr = a;curr;curr = curr->next){
|
||||
restore_to_delta(curr);
|
||||
}
|
||||
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;
|
||||
void save_restore_file(struct string_array* devices, struct arg_values* args){
|
||||
RJP_object_iterator it;
|
||||
RJP_value* rf = restore_file_handle();
|
||||
if(!rf)
|
||||
rf = rjp_new_object();
|
||||
rjp_init_object_iterator(&it, rf);
|
||||
for(RJP_value* mem = rjp_object_iterator_current(&it);mem;mem = rjp_object_iterator_next(&it)){
|
||||
for(struct arg_values* curr = args->next, *prev = args;curr;prev = curr, curr = curr->next){
|
||||
if(curr->operation != OP_SET || curr->flags & ARG_FLAG_NO_SAVE){
|
||||
prev->next = curr->next;
|
||||
free(curr);
|
||||
curr = prev;
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(rjp_member_key(mem)->value, curr->device)){
|
||||
rjp_set_float(mem, curr->delta);
|
||||
prev->next = curr->next;
|
||||
free(curr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
char* tmp = rjp_to_json(root);
|
||||
for(struct arg_values* curr = args->next;curr;curr = curr->next){
|
||||
if(curr->operation == OP_SET){
|
||||
RJP_value* newmem = rjp_new_member(rf, curr->device, 0);
|
||||
rjp_set_float(newmem, curr->delta);
|
||||
}
|
||||
}
|
||||
free_cmd_args(args);
|
||||
|
||||
char* tmp = rjp_to_json(rf, RJP_FORMAT_NONE);
|
||||
char* rfil = restore_file();
|
||||
FILE* restf = fopen(rfil, "w");
|
||||
if(!restf){
|
||||
@@ -170,7 +166,7 @@ void save_restore_file(struct string_array* devices){
|
||||
}
|
||||
free(rfil);
|
||||
rjp_free(tmp);
|
||||
rjp_free_value(root);
|
||||
rjp_free_value(rf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
rexbacklight
|
||||
Copyright (C) 2018 rexy712
|
||||
Copyright (C) 2018-2021 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
|
||||
@@ -31,34 +31,45 @@
|
||||
#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
|
||||
const char* device_dir(void){return "/sys/class/backlight/";}
|
||||
//name of the program being run so that we print the correct name in the usage
|
||||
const char* executable_name(void){return "rexbacklight";}
|
||||
//location of the restore file in the home directory
|
||||
const char* restore_file_suffix(void){return "/.config/rexbacklight.json";}
|
||||
|
||||
#elif defined(REXLEDCTL)
|
||||
|
||||
//This is where led devices can be found in sysfs
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//create a copy of a string and append a '/' character to the end
|
||||
char* add_slash_to(const char* name, size_t namelen){
|
||||
char* newname = malloc(namelen + 2);
|
||||
memcpy(newname, name, namelen);
|
||||
newname[namelen++] = '/';
|
||||
newname[namelen] = 0;
|
||||
return newname;
|
||||
}
|
||||
|
||||
//Get a list of led/backlight devices in sysfs
|
||||
@@ -83,23 +94,24 @@ 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)){
|
||||
//ignore '.' and '..'
|
||||
if(!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")){
|
||||
continue;
|
||||
}
|
||||
|
||||
//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 +121,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;
|
||||
}
|
||||
@@ -143,41 +156,62 @@ float get_brightness(const char* file){
|
||||
return atof(buff);
|
||||
}
|
||||
|
||||
//update brightness incrementally over requested millisecond time interval
|
||||
void fade_out(const char* device_name, int iv, int fv, int ms_duration, int steps){
|
||||
FILE* fd;
|
||||
struct timeval 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
|
||||
//return milliseconds since last boot
|
||||
double get_time(void){
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_BOOTTIME, &t);
|
||||
return ((t.tv_sec * 1000.0) + (t.tv_nsec * 0.0000001));
|
||||
}
|
||||
//sleep thread for milliseconds
|
||||
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);
|
||||
}
|
||||
|
||||
while(ms_duration > tdelta){
|
||||
void return_to_root_dir(void){
|
||||
if(chdir(device_dir())){
|
||||
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
|
||||
return_value = RETVAL_INVALID_DIR;
|
||||
}
|
||||
}
|
||||
//update brightness incrementally over requested millisecond time interval
|
||||
void fade_out(struct arg_values* arg){
|
||||
FILE* fd;
|
||||
double start, end;
|
||||
double tdelta = 0; //amount of time that has passed in ms
|
||||
float value = arg->act_start; //current value to write to file
|
||||
double step_delta = (double)arg->fade_duration / arg->fade_steps;
|
||||
double step_inc = step_delta;
|
||||
float brdelta = (float)(arg->act_delta - arg->act_start) / arg->fade_steps; //amount brightness needs to change per iteration
|
||||
|
||||
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());
|
||||
char* devname = add_slash_to(arg->device, strlen(arg->device));
|
||||
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), devname, brightness_file());
|
||||
return_value = RETVAL_INVALID_FILE;
|
||||
free(devname);
|
||||
return_to_root_dir();
|
||||
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,154 +219,121 @@ 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());
|
||||
char* devname = add_slash_to(arg->device, strlen(arg->device));
|
||||
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), devname, brightness_file());
|
||||
return_value = RETVAL_INVALID_FILE;
|
||||
free(devname);
|
||||
return_to_root_dir();
|
||||
return;
|
||||
}
|
||||
fprintf(fd, "%d", fv);
|
||||
fprintf(fd, "%d", arg->act_delta);
|
||||
|
||||
fclose(fd);
|
||||
return_to_root_dir();
|
||||
}
|
||||
|
||||
//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()));
|
||||
fade_out(device, start, out, arg->fade_duration, arg->fade_steps);
|
||||
int prep_offset(struct arg_values* args){
|
||||
if(chdir(args->device)){
|
||||
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), args->device);
|
||||
return RETVAL_INVALID_DIR;
|
||||
}
|
||||
args->act_start = get_brightness(brightness_file());
|
||||
float act_max = get_brightness(max_brightness_file());
|
||||
args->act_delta = process_op(args, 0, args->act_start, act_max);
|
||||
float start_pec = (args->act_start / act_max) * 100.0;
|
||||
if(args->operation == OP_INC){
|
||||
args->delta = start_pec + args->delta;
|
||||
}else if(args->operation == OP_DEC){
|
||||
args->delta = start_pec - args->delta;
|
||||
}
|
||||
if(args->delta > 100)
|
||||
args->delta = 100;
|
||||
else if(args->delta < 0)
|
||||
args->delta = 0;
|
||||
args->operation = OP_SET;
|
||||
//chdir back in do_assignment
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Run get operation
|
||||
void do_get(const char* device){
|
||||
int do_get(struct arg_values* args){
|
||||
float curr, max;
|
||||
if(chdir(args->device)){
|
||||
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), args->device);
|
||||
return RETVAL_INVALID_DIR;
|
||||
}
|
||||
curr = get_brightness(brightness_file());
|
||||
max = get_brightness(max_brightness_file());
|
||||
if(return_value == RETVAL_INVALID_FILE && (!curr || !max)){
|
||||
fprintf(stdout, "%s", device);
|
||||
fprintf(stdout, "%s", args->device);
|
||||
}else{
|
||||
fprintf(stdout, "%-25s %.2f\n", device, curr / max * 100);
|
||||
}
|
||||
}
|
||||
|
||||
//Run list operation
|
||||
void do_list(struct string_array* names){
|
||||
int i;
|
||||
for(i = 0;i < names->size;++i)
|
||||
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;
|
||||
fprintf(stdout, "%-25s %.2f\n", args->device, curr / max * 100);
|
||||
}
|
||||
if(chdir(device_dir())){
|
||||
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
|
||||
return RETVAL_INTERNAL_ERROR;
|
||||
return RETVAL_INVALID_DIR;
|
||||
}
|
||||
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(curr->operation == OP_RESTORE){
|
||||
if(!individual_restore(curr, &root, &try_restore))
|
||||
continue;
|
||||
}
|
||||
return_value = individual_device_op(curr);
|
||||
if(return_value == RETVAL_INTERNAL_ERROR){
|
||||
rjp_free_value(root);
|
||||
return;
|
||||
}
|
||||
}
|
||||
rjp_free_value(root);
|
||||
//Run list operation
|
||||
void do_list(struct arg_values* args){
|
||||
printf("%s\n", args->device);
|
||||
}
|
||||
#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){
|
||||
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;
|
||||
//Run requested operation on a per device basis
|
||||
int run_device_operations(struct arg_values* a){
|
||||
int changes = 0;
|
||||
for(a = a->next;a;a = a->next){
|
||||
switch(a->operation){
|
||||
case OP_LIST:
|
||||
do_list(device_names);
|
||||
do_list(a);
|
||||
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;
|
||||
}
|
||||
}
|
||||
return_value = do_get(a);
|
||||
break;
|
||||
#ifdef ENABLE_RESTORE_FILE
|
||||
case OP_RESTORE:;
|
||||
all_restore();
|
||||
break;
|
||||
case OP_RESTORE:
|
||||
if(!restore_to_delta(a)){
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "Internal processing error!\n");
|
||||
case OP_INC:
|
||||
case OP_DEC:
|
||||
case OP_SET:
|
||||
if(prep_offset(a))
|
||||
break;
|
||||
++changes;
|
||||
fade_out(a);
|
||||
break;
|
||||
};
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
//If a global operation is requested, run this to fill arg with all devices, each with the global operation
|
||||
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->next->flags = arg->flags;
|
||||
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;
|
||||
int should_save = 0;
|
||||
|
||||
args = process_cmd_args(argc, argv);
|
||||
if(args.operation == OP_USAGE){
|
||||
usage(return_value);
|
||||
@@ -342,34 +343,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");
|
||||
fprintf(stderr, "No backlight 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 +372,25 @@ 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);
|
||||
#ifdef ENABLE_RESTORE_FILE
|
||||
save_restore_file(&device_names);
|
||||
#endif
|
||||
}else{
|
||||
all_device_loop(&device_names, &args);
|
||||
//on a global operation, populate list with all devices
|
||||
if(!args.next){
|
||||
populate_args(&args, &device_names);
|
||||
}
|
||||
should_save = (run_device_operations(&args) > 0);
|
||||
#ifdef ENABLE_RESTORE_FILE
|
||||
if(should_save)
|
||||
save_restore_file(&device_names, &args); //performs cleanup on args
|
||||
else
|
||||
free_cmd_args(&args);
|
||||
#else
|
||||
free_cmd_args(&args);
|
||||
#endif
|
||||
|
||||
CLEANUP();
|
||||
free_string_array(&device_names);
|
||||
return return_value;
|
||||
}
|
||||
#undef CLEANUP
|
||||
|
||||
Reference in New Issue
Block a user