230 lines
6.0 KiB
C
230 lines
6.0 KiB
C
/**
|
|
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>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "cmd.h"
|
|
#include "common.h"
|
|
|
|
#define GET_LONG_OPT "--get"
|
|
#define GET_SHORT_OPT "-g"
|
|
#define FADE_LONG_OPT "--fade"
|
|
#define FADE_SHORT_OPT "-f"
|
|
#define STEPS_LONG_OPT "--steps"
|
|
#define STEPS_SHORT_OPT "-s"
|
|
#define DEVICE_LONG_OPT "--device"
|
|
#define DEVICE_SHORT_OPT "-d"
|
|
#define LIST_LONG_OPT "--list"
|
|
#define LIST_SHORT_OPT "-l"
|
|
#define HELP_LONG_OPT "--help"
|
|
#define HELP_SHORT_OPT "-h"
|
|
|
|
|
|
#define CHECK_OPTION(opt, arg) (!strcmp(opt##_LONG_OPT, arg) || !strcmp(opt##_SHORT_OPT, arg))
|
|
|
|
struct cmd_arg rexbacklight_args[] = {
|
|
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, "select which device to control"},
|
|
{FADE_LONG_OPT, FADE_SHORT_OPT, "change brightness over time interval"},
|
|
{STEPS_LONG_OPT, STEPS_SHORT_OPT, "number of steps over which to fade"},
|
|
{GET_LONG_OPT, GET_SHORT_OPT, "print current brightness level to stdout"},
|
|
{LIST_LONG_OPT, LIST_SHORT_OPT, "print device names to stdout and exit"},
|
|
{HELP_LONG_OPT, HELP_SHORT_OPT, "print this help message and exit"}
|
|
};
|
|
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)
|
|
return;
|
|
free_cmd_args(a->next);
|
|
free(a->next);
|
|
}
|
|
|
|
#define CHECK_NEXT_ARG() \
|
|
do{ \
|
|
if(i == argc - 1){ \
|
|
fprintf(stderr, "Missing argument to '%s'\n\n", argv[i]); \
|
|
free_cmd_args(&ret); \
|
|
usage(RETVAL_MISSING_OPTION); \
|
|
} \
|
|
}while(0)
|
|
#define UNRECOGNIZED_OPTION() \
|
|
do{ \
|
|
fprintf(stderr, "Unrecognized command line option '%s'\n\n", argv[i]); \
|
|
free_cmd_args(&ret); \
|
|
usage(RETVAL_UNRECOGNIZED_OPTION); \
|
|
}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};
|
|
}
|
|
|
|
//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;
|
|
|
|
//Skip argv[0]
|
|
for(int i = 1;i < argc;i++){
|
|
|
|
//Check for switches
|
|
if(CHECK_OPTION(GET, argv[i])){
|
|
curr->operation |= OP_GET;
|
|
continue;
|
|
|
|
}else if(CHECK_OPTION(FADE, argv[i])){
|
|
CHECK_NEXT_ARG();
|
|
curr->fade_duration = strtol(argv[++i], NULL, 0);
|
|
continue;
|
|
}
|
|
|
|
else if(CHECK_OPTION(STEPS, argv[i])){
|
|
CHECK_NEXT_ARG();
|
|
curr->fade_steps = strtol(argv[++i], NULL, 0);
|
|
continue;
|
|
}
|
|
|
|
else if(CHECK_OPTION(DEVICE, argv[i])){
|
|
CHECK_NEXT_ARG();
|
|
curr->next = malloc(sizeof(struct arg_values));
|
|
*(curr->next) = init_arg_values();
|
|
curr = curr->next;
|
|
curr->device = argv[++i];
|
|
continue;
|
|
}
|
|
else if(CHECK_OPTION(LIST, argv[i])){
|
|
free_cmd_args(&ret);
|
|
ret.operation = OP_LIST;
|
|
ret.next = NULL;
|
|
return ret;
|
|
}
|
|
else if(CHECK_OPTION(HELP, argv[i])){
|
|
free_cmd_args(&ret);
|
|
usage(RETVAL_SUCCESS);
|
|
}
|
|
|
|
else if(!strcmp(argv[i], "max")){
|
|
curr->operation = OP_SET;
|
|
curr->delta = 100;
|
|
}
|
|
else if(!strcmp(argv[i], "min")){
|
|
curr->operation = OP_SET;
|
|
curr->delta = 0.1;
|
|
}
|
|
else if(!strcmp(argv[i], "off")){
|
|
curr->operation = OP_SET;
|
|
curr->delta = 0;
|
|
}
|
|
|
|
else if(argv[i][0] == '='){
|
|
curr->operation = OP_SET;
|
|
curr->delta = atof(argv[i] + 1);
|
|
}
|
|
else if(argv[i][0] == '+'){
|
|
curr->operation = OP_INC;
|
|
curr->delta = atof(argv[i] + 1);
|
|
}
|
|
else if(argv[i][0] == '-'){
|
|
//If we get a '-' followed by not a number, it's not a known option
|
|
if(argv[i][1] < '0' || argv[i][1] > '9'){
|
|
UNRECOGNIZED_OPTION();
|
|
|
|
//If we get a '-' followed by a number, it's a decrement request
|
|
}else{
|
|
curr->operation = OP_DEC;
|
|
curr->delta = atof(argv[i] + 1);
|
|
}
|
|
}
|
|
|
|
else{
|
|
for(int j = 0; j < 3;j++){
|
|
if(argv[i][j] == '\0')
|
|
break;
|
|
if(argv[i][j] < '0' || argv[i][j] > '9')
|
|
UNRECOGNIZED_OPTION();
|
|
}
|
|
curr->operation = OP_SET;
|
|
curr->delta = atof(argv[i]);
|
|
}
|
|
}
|
|
|
|
//If there isn't an operation defined in the global context and there is no specified device, there's nothing to do
|
|
if(!ret.operation){
|
|
if(!ret.next){
|
|
fprintf(stderr, "No operation requested!\n\n");
|
|
usage(RETVAL_MISSING_OPTION);
|
|
}
|
|
//if there is a device specified, make sure each one has a requested operation
|
|
for(curr = ret.next;curr;curr = curr->next){
|
|
if(!curr->operation){
|
|
fprintf(stderr, "No operation requested for device '%s'!\n\n", curr->device);
|
|
free_cmd_args(&ret);
|
|
usage(RETVAL_MISSING_OPTION);
|
|
}
|
|
}
|
|
//If there is a globally defined operation, apply it to the devices with no operation request
|
|
}else{
|
|
for(curr = ret.next;curr;curr = curr->next){
|
|
if(curr->operation == OP_NONE){
|
|
curr->operation = ret.operation;
|
|
if(!curr->delta)
|
|
curr->delta = ret.delta;
|
|
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
#undef CHECK_OPTION
|
|
#undef UNRECOGNIZED_OPTION
|
|
|
|
//Process an operation
|
|
int process_op(struct arg_values* arg, float min, float current, float max){
|
|
//Amount to inc/dec
|
|
int delta = max * arg->delta / 100.0;
|
|
|
|
switch(arg->operation){
|
|
case OP_SET:
|
|
if(delta >= max)
|
|
return max;
|
|
else if(delta <= min)
|
|
return min;
|
|
else
|
|
return delta;
|
|
case OP_INC:
|
|
delta += current;
|
|
if(delta >= max)
|
|
return max;
|
|
else
|
|
return delta;
|
|
case OP_DEC:
|
|
delta = current - delta;
|
|
if(delta <= min)
|
|
return min;
|
|
else
|
|
return delta;
|
|
default:
|
|
fprintf(stderr, "Internal error, please fix for me ;)\n");
|
|
exit(-99);
|
|
}
|
|
return current;
|
|
}
|
|
|