Browse Source

Merge pull request #61 from haikarainen/device-rewrite

Rewrite codebase, add device-system pewpew
Fredrik Svantesson 5 years ago
parent
commit
a5caacb532
No account linked to committer's email
13 changed files with 1733 additions and 1234 deletions
  1. 230
    0
      DOCUMENTATION.md
  2. 47
    97
      README.md
  3. 1
    1
      configure.ac
  4. 2
    2
      src/Makefile.am
  5. 101
    69
      src/helpers.c
  6. 32
    32
      src/helpers.h
  7. 1
    0
      src/impl/razer.c
  8. 1
    0
      src/impl/razer.h
  9. 250
    0
      src/impl/sysfs.c
  10. 24
    0
      src/impl/sysfs.h
  11. 895
    922
      src/light.c
  12. 134
    99
      src/light.h
  13. 15
    12
      src/main.c

+ 230
- 0
DOCUMENTATION.md View File

@@ -0,0 +1,230 @@
1
+# Developer Instructions
2
+
3
+This file is aimed at developers of light, or developers who want to implement "drivers" (enumerators) for their own hardware.
4
+
5
+## Coding Standards
6
+
7
+Light is a small project, which helps keep it clean. However we still would like to see a consistent styling throughout the project, as well as in third-party enumerator implementations. The actual source code may not be fully "up to code" yet, but it's getting there.
8
+
9
+We use 4 spaces for indentation. We have an empty line at the top and bottom of each file.
10
+
11
+The following two sources should be clear enough examples of our coding style:
12
+
13
+### Header files 
14
+
15
+```c
16
+    
17
+    #pragma once
18
+    
19
+    #include <stdbool.h>
20
+    #include <stdint.h>
21
+    #include <stdfoo.h> /* foo_type_t */
22
+    
23
+    
24
+    typedef struct _some_struct_t some_struct_t;
25
+    struct _some_struct_t 
26
+    {
27
+        uint64_t    id;
28
+        foo_type_t  my_foo_thing;
29
+        foo_type_t  *my_foo_ptr;
30
+    }
31
+    
32
+    /* Describe what the purpose of this function is, what it does with/to foo_struct, and what it returns. */
33
+    bool do_some_stuff(some_struct_t *foo_struct);
34
+    
35
+```
36
+
37
+### Source files
38
+
39
+The second line of each source file should be the include to the corresponding header file, followed by an empty line.
40
+
41
+Internal/static functions are always prefixed with an underscore (_).
42
+
43
+```c
44
+
45
+#include "some_struct.h"
46
+
47
+static void _increment_one(uint64_t *out_value)
48
+{
49
+    *out_value += 1;
50
+}
51
+
52
+bool do_some_stuff(some_struct_t *foo_struct)
53
+{
54
+    _increment_one(foo_struct->id);
55
+    
56
+    if(foo_struct->id > 33)
57
+    {
58
+        return false;
59
+    }
60
+    
61
+    if(foo_struct->my_foo_ptr != NULL)
62
+    {
63
+        free(foo_struct->my_foo_ptr);
64
+    }
65
+    
66
+    foo_struct->my_foo_ptr = malloc(sizeof(foo_type_t));
67
+    
68
+    return true;
69
+}
70
+
71
+```
72
+
73
+## Implementing an enumerator 
74
+
75
+Implementing your own devices through an enumerator is pretty easy. The required steps are as follows:
76
+
77
+### Step 1
78
+
79
+Create a headerfile and a corresponding sourcefile under the `impl` folder, Call them `foo.h` and `foo.c`. Open up the `sysfs.c` and `sysfs.h` files for reference implementations.
80
+
81
+### Step 2
82
+
83
+In the header, you need to first do a `#pragma once` (obviously), then `#include "light.h"` to get access to some struct declarations, then at the bare minimum declare 6 functions. If you need to store your own data for each device or device-target, you will need to declare structs for these as well.
84
+
85
+```c
86
+
87
+#pragma once 
88
+
89
+#include "light.h"
90
+
91
+// Implementation of the foo enumerator
92
+// Enumerates devices for quacking ducks
93
+
94
+// Device target data 
95
+struct _impl_foo_data_t
96
+{
97
+    int32_t internal_quack_id;
98
+};
99
+
100
+typedef struct _impl_foo_data_t impl_foo_data_t;
101
+
102
+bool impl_foo_init(light_device_enumerator_t *enumerator);
103
+bool impl_foo_free(light_device_enumerator_t *enumerator);
104
+
105
+bool impl_foo_set(light_device_target_t *target, uint64_t in_value);
106
+bool impl_foo_get(light_device_target_t *target, uint64_t *out_value);
107
+bool impl_foo_getmax(light_device_target_t *target, uint64_t *out_value);
108
+bool impl_foo_command(light_device_target_t *target, char const *command_string);
109
+
110
+```
111
+
112
+### Step 3
113
+
114
+In the sourcefile, you need to implement the 6 methods. Make sure to return `true` on success and `false` on failure. If you do not actually implement a function (for example `impl_foo_command`), just return `true`.
115
+
116
+The job of the enumerator is to identify/enumerate a bunch of different devices (or just one, or even zero if it doesnt find any). You are also responsible to create the device targets for them (i.e, the things that you actually write to on the device). You do this by setting the devices and targets up in `impl_foo_init` and to free these in `impl_foo_free`. The enumerator (this code) owns the memory of the devices and targets, and thus is in charge of allocating and freeing it. 
117
+
118
+```c
119
+
120
+#include "impl/foo.h"
121
+
122
+#include "light.h"
123
+#include "helpers.h"
124
+
125
+bool impl_foo_init(light_device_enumerator_t *enumerator)
126
+{
127
+    /* Lets create a single device, with a single target, for simplicity */
128
+    
129
+    /* Allocate a new device */
130
+    light_device_t *new_device = malloc(sizeof(light_device_t));
131
+    
132
+    /* Set the name of the new device to "new_device_name" */
133
+    snprintf(leds_device->name, sizeof(leds_device->name), "%s", "new_device_name");
134
+    
135
+    /* Add the newly created device to the enumerator */
136
+    light_add_enumerator_device(enumerator, new_device);
137
+
138
+    
139
+    
140
+    /* Allocate a new device target for the newly created device */
141
+    light_device_target_t *new_target = malloc(sizeof(light_device_target_t));
142
+    
143
+    /* Set the name of the new target */
144
+    snprintf(new_target->name, sizeof(new_target->name), "%s", "new_target_name");
145
+    
146
+    /* Setup the function bindings for this target, i.e. what functions will run internally when you run different commands on this device target */
147
+    new_target->set_value = impl_foo_set;
148
+    new_target->get_value = impl_foo_get;
149
+    new_target->get_max_value = impl_foo_getmax;
150
+    new_target->custom_command = impl_foo_command;
151
+    
152
+    /* Finally add the target to the device */
153
+    light_add_device_target(new_device, new_target);
154
+    
155
+    
156
+    
157
+    /* Optional: Setup data specific to either a device or a target, or both. */ 
158
+    /* Useful to for example reference an ID in a third-party API or likewise */
159
+    impl_foo_data_t *custom_data = malloc(sizeof(impl_foo_data_t));
160
+    custom_data->internal_quack_id = 333;
161
+    
162
+    /* You can set it to the device itself, or to a target */
163
+    new_device->device_data = custom_data;
164
+    new_target->device_target_data = custom_data;
165
+
166
+    /* Return true because we didnt get any errors! */
167
+    return true;
168
+}
169
+
170
+bool impl_foo_free(light_device_enumerator_t *enumerator)
171
+{
172
+    /* We are responsible to free the memory we allocated in init, so lets do that */
173
+    
174
+    /* Iterate through the devices in the enumerator */
175
+    for(uint64_t d = 0; d < enumerator->num_devices; d++)
176
+    {
177
+        light_device_t *curr_device = enumerator->devices[d];
178
+
179
+        /* Iterate throug hthe targets in the device */
180
+        for(uint64_t t = 0; t < curr_device->num_targets; t++)
181
+        {
182
+            light_device_target_t *curr_target = curr_device->targets[t];
183
+            
184
+            /* If we allocated any target data, free it here */
185
+            if(curr_target->device_target_data != NULL)
186
+            {
187
+                free(curr_target->device_target_data);
188
+            }
189
+            
190
+            free(curr_target);
191
+        }
192
+
193
+        /* If we allocated any device data, free it here */
194
+        if(curr_device->device_data != NULL)
195
+        {
196
+            free(curr_device->device_data);
197
+        }
198
+        
199
+        /* We need to 'dispose' of the device when we are done with it, to free some internal memory. Always do this when you are about to free a device that you allocated. */
200
+        light_dispose_device(curr_device);
201
+        
202
+        /* Free the device */
203
+        free(curr_device);
204
+    }
205
+    
206
+    return true;
207
+}
208
+
209
+/* Implement the other functions to do their thing. Get, Set and GetMax should be self-explanatory. Command is reserved for future use, but basically will allow the user to run custom commands on a target. */
210
+
211
+```
212
+
213
+### Step 4
214
+
215
+Now that you have implemented your enumerator, it is time to inject it to the application itself. You will be able to compile your enumerator into a plugin in the future, but for now, locate the `light_initialize` function inside `light.c`. You will see some calls (perhaps just one call) to `light_create_enumerator` inside of this function. Add one more call to this function to register your enumerator in the application:
216
+
217
+The first argument is the application context, the second is the name that your enumerator will get, and the last two are the init and free functions that we implemented.
218
+
219
+```c
220
+light_create_enumerator(new_ctx, "foo", &impl_foo_init, &impl_foo_free);
221
+```
222
+
223
+Once you do this, you should be able to find your device target when running `light -L`, and it should be called something like `foo/new_device_name/new_target_name` if you followed this guide.
224
+
225
+The only thing left now is to create a pull request so that the rest of the world can share the functionality that you just implemented!
226
+
227
+
228
+## Troubleshooting
229
+
230
+If you run into any issues, feel free to create a new Github issue, even if you are just asking for "support" or likewise.

+ 47
- 97
README.md View File

@@ -1,11 +1,11 @@
1
-Light - A Program to Control Backlight Controllers
1
+Light - A program to control backlights (and other hardware lights) in GNU/Linux
2 2
 ==================================================
3 3
 
4 4
 - [Introduction](#introduction)
5 5
 - [Examples](#examples)
6 6
 - [Usage](#usage)
7
-  - [Commands](#commands)
8
-  - [Options](#options)
7
+  - [Command options](#command-options)
8
+  - [Extra options](#extra-options)
9 9
 - [Installation](#installation)
10 10
   - [Arch Linux](#arch-linux)
11 11
   - [Fedora](#fedora)
@@ -17,25 +17,22 @@ Light - A Program to Control Backlight Controllers
17 17
 Introduction
18 18
 ------------
19 19
 
20
-[Light][] is a program to control backlight controllers under GNU/Linux:
20
+[Light][] is a program to control backlights and other lights under GNU/Linux:
21 21
 
22
-* Works, in particular when other software, e.g. xbacklight, does not
23
-* Does not rely on X
24
-* Automatically detects the best controller
25
-* Possibility to set a minimum brightness value
22
+* Works where other software has proven unreliable (xbacklight etc.)
23
+* Works even in a fully CLI-environment, i.e. it does not rely on X
24
+* Provides functionality to automatically control backlights with the highest precision available
25
+* Extra features, like setting a minimum brightness value for controllers, or saving/restoring the value for poweroffs/boots.
26 26
 
27
-Let's get started with a few examples!  See the following sections for
28
-the detailed descriptions of all available commands, options and how to
29
-access different controllers.
27
+See the following sections for the detailed descriptions of all available commands, options and how to access different controllers.
30 28
 
31
-Light is available in many GNU/Linux distributions already, and it also
32
-has a fork called [brillo][] by [Cameron Nemo](@CameronNemo).
29
+Light is available in many GNU/Linux distributions already.
33 30
 
34 31
 
35 32
 Examples
36 33
 --------
37 34
 
38
-Get the current brightness in percent
35
+Get the current backlight brightness in percent
39 36
 
40 37
     light -G
41 38
 
@@ -43,99 +40,58 @@ or
43 40
 
44 41
      light
45 42
 
46
-Increase brightness by 5 percent
43
+Increase backlight brightness by 5 percent
47 44
 
48 45
     light -A 5
49 46
 
50
-Set the minimum cap to 2 in raw value on the acpi_video0 controller:
47
+Set the minimum cap to 2 in raw value on the sysfs/backlight/acpi_video0 device:
51 48
 
52
-    light -cr -s acpi_video0 -S 2
49
+    light -Nrs "sysfs/backlight/acpi_video0" 2
53 50
 
54
-Try to set the brightness to 0 after that, it will be changed to the
55
-minimum 2:
51
+List available devices
56 52
 
57
-    light -r -s acpi_video0 -S 0
53
+    light -L
58 54
 
59
-Find keyboard controllers:
60
-
61
-    light -k -L
62
-
63
-Activate `ScrollLock` LED, here `input15` is used, but this varies
55
+Activate the Num. Lock keyboard LED, here `sysfs/leds/input3::numlock` is used, but this varies
64 56
 between different systems:
65 57
 
66
-    light -k -s "input15::scrolllock" -S 100
67
-
68
-Usually, LEDs only take 0 or 1 in raw value (i.e. for off/on), so you
69
-can instead write:
70
-
71
-    light -kr -s "input15::scrolllock" -S 1
72
-
73
-Verify by reading back the max brightness, you should get a value of 1:
74
-
75
-    light -kr -m -s "input15::scrolllock
58
+    light -Srs "sysfs/leds/input3::numlock" 1
76 59
 
77 60
 
78 61
 Usage
79 62
 -----
80 63
 
81
-### Commands
82
-
83
-* `-G`: Get (read) brightness/data from controllers/files
84
-* `-S VAL`: Set (write)brightness/data to controllers/files
85
-* `-A VAL`: Like `-S`, but adds the given value
86
-* `-U VAL`: Like `-S`, but subtracts the given value
87
-* `-O`: Save the current brightness for later use (usually used on shutdown)
88
-* `-I`: Restore the previously saved brightness (usually used on boot)
89
-* `-L`: List available controllers, see below `-k` option as well
64
+Usage follows the following pattern, where options are optional and the neccesity of value depends on the options used
65
+    
66
+    light [options] <value>
90 67
 
91
-Without any options (below) the commands operate on the brightness of an
92
-automatically selected controller.  Values are given in percent, unless
93
-the below `r` option is also given.
68
+### Command options
94 69
 
95
-**Note:** like most UNIX applications, light only gives output on
96
-  errors.  If something goes wrong try the verbosity option `-v VAL`:
70
+You may only specify one command flag at a time. These flags decide what the program will ultimately end up doing.
97 71
 
98
-* 0: No debug output
99
-* 1: Errors
100
-* 2: Errors, warnings
101
-* 3: Errors, warnings, notices
72
+*  `-H` Show help and exit
73
+*  `-V` Show program version and exit
74
+*  `-L` List available devices
75
+*  `-A` Increase brightness by value (value needed!)
76
+*  `-U` Decrease brightness by value (value needed!)
77
+*  `-S` Set brightness to value (value needed!)
78
+*  `-G` Get brightness
79
+*  `-N` Set minimum brightness to value (value needed!)
80
+*  `-P` Get minimum brightness
81
+*  `-I` Save the current brightness
82
+*  `-O` Restore the previously saved brightness
102 83
 
103
-### Options
84
+Without any extra options, the command will operate on the device called `sysfs/backlight/auto`, which works as it's own device however it proxies the backlight device that has the highest controller resolution (read: highest precision). Values are interpreted and printed as percentage between 0.0 - 100.0.
104 85
 
105
-Values may be given, or presented, in percent or raw mode.  Raw mode is
106
-the format specific to the controller.  The default is in percent, but
107
-raw mode may be required for precise control, or when the steps are very
108
-few, e.g. for most keyboard backlight controllers.
86
+**Note:** If something goes wrong, you can find out by maxing out the verbosity flag by passing `-v 3` to the options. This will activate the logging of warnings, errors and notices. Light will never print these by default, as it is designed to primarily interface with other applications and not humanbeings directly.
109 87
 
110
-* `-p`: Percent, default
111
-* `-r`: Raw mode
88
+### Extra options
112 89
 
113
-By default the screen is the active target for all commands, use `-k` to
114
-select the keyboard instead.  In either case you may need to select a
115
-different controller, see below.
90
+These can be mixed, combined and matched after convenience. 
116 91
 
117
-* `-l`: Act on screen backlight, default
118
-* `-k`: Act on keyboard backlight and LEDs
119
-
120
-By default commands act on the brightness property, which is read+write.
121
-The maximum brightness is a read-only property.  The minimum brightness
122
-cap is a feature implemented to protect against setting brightness too
123
-low, since some controllers make the screen go pitch black at 0%.  For
124
-controllers like that it is recommended to set this value.
125
-
126
-* `-b`: Current brightness of selected controller, default
127
-* `-m`: Max. brightness of selected controller
128
-* `-c`: Min. brightness (cap) of selected controller (recommend raw mode)
129
-
130
-Controller is automatically done to select the controller with maximum
131
-precision.  It can however also be done manually and we recommend the
132
-`-L` and `-Lk` commands to list available controllers:
133
-
134
-* `-a`: Automatic controller selection
135
-* `-s ARG`: Manual controller selection
136
-
137
-**Note:** Without the `-s` flag on _every_ command light will default
138
-  to automatic controller selection.
92
+* `-r` Raw mode, values (printed and interpreted from commandline) will be treated as integers in the controllers native range, instead of in percent.
93
+* `-v <verbosity>` Specifies the verbosity level. 0 is default and prints nothing. 1 prints only errors, 2 prints only errors and warnings, and 3 prints both errors, warnings and notices.
94
+* `-s <devicepath>` Specifies which device to work on. List available devices with the -L command. Full path is needed.
139 95
 
140 96
 
141 97
 Installation
@@ -145,11 +101,8 @@ Installation
145 101
 
146 102
 If you run Arch Linux, there exists 2 packages;
147 103
 
148
-* [light-git][] - For the absolutely latest version
149
-* [light-tag][] - For the latest tagged release
150
-
151
-We recommend you go with light-git as you might miss important features
152
-and bugfixes if you do not.
104
+* [light-git][] - For the latest development branch (master)
105
+* [light][] - For the latest stable release
153 106
 
154 107
 
155 108
 ### Fedora
@@ -163,17 +116,15 @@ and you're good to go.
163 116
 
164 117
 ### Manual
165 118
 
166
-We recommended downloading a versioned tarball from the relases page on
167
-GitHub.  Download and untar the archive:
119
+If you download a stable release, these are the commands that will get you up and running:
168 120
 
169 121
     tar xf light-x.yy.tar.gz
170 122
     cd light-x.yy/
171 123
     ./configure && make
172 124
     sudo make install
173 125
 
174
-However, should you want to try the latest GitHub source you first need
175
-to clone the repository and run the `autogen.sh` script.  This requires
176
-`automake` and `autoconf` to be installed on your system.
126
+However the latest development branch requires some extras. Clone the repository and run the `autogen.sh` script.  This requires that
127
+`automake` and `autoconf` is installed on your system.
177 128
 
178 129
     ./autogen.sh
179 130
     ./configure && make
@@ -209,6 +160,5 @@ This is free software, see the source for copying conditions.  There is NO
209 160
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
210 161
 
211 162
 [Light]:     https://github.com/haikarainen/light/
212
-[brillo]:    https://gitlab.com/cameronnemo/brillo/
213 163
 [light-git]: https://aur.archlinux.org/packages/light-git
214
-[light-tag]: https://aur.archlinux.org/packages/light
164
+[light]: https://aur.archlinux.org/packages/light

+ 1
- 1
configure.ac View File

@@ -1,5 +1,5 @@
1 1
 AC_INIT([light], [1.2-dev], [https://github.com/haikarainen/light/issues])
2
-AM_INIT_AUTOMAKE([1.11 foreign])
2
+AM_INIT_AUTOMAKE([1.11 foreign subdir-objects])
3 3
 AM_SILENT_RULES([yes])
4 4
 
5 5
 AC_CONFIG_SRCDIR([src/light.c])

+ 2
- 2
src/Makefile.am View File

@@ -1,7 +1,7 @@
1 1
 bin_PROGRAMS   = light
2
-light_SOURCES  = main.c light.c light.h helpers.c helpers.h
2
+light_SOURCES  = main.c light.c light.h helpers.c helpers.h impl/sysfs.c impl/sysfs.h
3 3
 light_CPPFLAGS = -I../include -D_GNU_SOURCE
4
-light_CFLAGS   = -W -Wall -Wextra -std=gnu99 -Wno-type-limits
4
+light_CFLAGS   = -W -Wall -Wextra -std=gnu18 -Wno-type-limits -Wno-format-truncation -Wno-unused-parameter
5 5
 
6 6
 if CLASSIC
7 7
 install-exec-hook:

+ 101
- 69
src/helpers.c View File

@@ -5,106 +5,138 @@
5 5
 #include <string.h>
6 6
 #include <sys/types.h>
7 7
 #include <dirent.h>
8
+#include <errno.h> // errno
9
+#include <libgen.h> // dirname 
8 10
 
9
-bool light_file_read_val(char const *filename, unsigned long *val)
10
-{
11
-	FILE *fp;
12
-	unsigned long data;
13
-
14
-	fp = fopen(filename, "r");
15
-	if (!fp) {
16
-		LIGHT_PERMERR("reading");
17
-		return false;
18
-	}
19
-
20
-	if (fscanf(fp, "%lu", &data) != 1) {
21
-		LIGHT_ERR("Couldn't parse a positive integer number from '%s'", filename);
22
-		fclose(fp);
23
-		return false;
24
-	}
25 11
 
26
-	*val = data;
27
-
28
-	fclose(fp);
29
-	return true;
12
+bool light_file_read_uint64(char const *filename, uint64_t *val)
13
+{
14
+    FILE *fp;
15
+    uint64_t data;
16
+
17
+    fp = fopen(filename, "r");
18
+    if (!fp)
19
+    {
20
+        LIGHT_PERMERR("reading");
21
+        return false;
22
+    }
23
+
24
+    if (fscanf(fp, "%lu", &data) != 1)
25
+    {
26
+        LIGHT_ERR("Couldn't parse an unsigned integer from '%s'", filename);
27
+        fclose(fp);
28
+        return false;
29
+    }
30
+
31
+    *val = data;
32
+
33
+    fclose(fp);
34
+    return true;
30 35
 }
31 36
 
32
-bool light_file_write_val(char const *filename, unsigned long val)
37
+bool light_file_write_uint64(char const *filename, uint64_t val)
33 38
 {
34
-	FILE *fp;
35
-
36
-	fp = fopen(filename, "w");
37
-	if (!fp) {
38
-		LIGHT_PERMERR("writing");
39
-		return false;
40
-	}
41
-
42
-	if (fprintf(fp, "%lu", val) < 0) {
43
-		LIGHT_ERR("fprintf failed");
44
-		fclose(fp);
45
-		return false;
46
-	}
47
-
48
-	fclose(fp);
49
-	return true;
39
+    FILE *fp;
40
+
41
+    fp = fopen(filename, "w");
42
+    if (!fp)
43
+    {
44
+        LIGHT_PERMERR("writing");
45
+        return false;
46
+    }
47
+
48
+    if (fprintf(fp, "%lu", val) < 0)
49
+    {
50
+        LIGHT_ERR("fprintf failed");
51
+        fclose(fp);
52
+        return false;
53
+    }
54
+
55
+    fclose(fp);
56
+    return true;
50 57
 }
51 58
 
52 59
 /* Returns true if file is writable, false otherwise */
53 60
 bool light_file_is_writable(char const *filename)
54 61
 {
55
-	FILE *fp;
62
+    FILE *fp;
56 63
 
57
-	fp = fopen(filename, "r+");
58
-	if (!fp) {
59
-		LIGHT_PERMWARN("writing");
60
-		return false;
61
-	}
64
+    fp = fopen(filename, "r+");
65
+    if (!fp)
66
+    {
67
+        LIGHT_PERMWARN("writing");
68
+        return false;
69
+    }
62 70
 
63
-	fclose(fp);
64
-	return true;
71
+    fclose(fp);
72
+    return true;
65 73
 }
66 74
 
67 75
 /* Returns true if file is readable, false otherwise */
68 76
 bool light_file_is_readable(char const *filename)
69 77
 {
70
-	FILE *fp;
78
+    FILE *fp;
71 79
 
72
-	fp = fopen(filename, "r");
73
-	if (!fp) {
74
-		LIGHT_PERMWARN("reading");
75
-		return false;
76
-	}
80
+    fp = fopen(filename, "r");
81
+    if (!fp)
82
+    {
83
+        LIGHT_PERMWARN("reading");
84
+        return false;
85
+    }
77 86
 
78
-	fclose(fp);
79
-	return true;
87
+    fclose(fp);
88
+    return true;
80 89
 }
81 90
 
82 91
 /* Prints a notice about a value which was below `x` and was adjusted to it */
83
-unsigned long light_log_clamp_min(unsigned long min)
92
+uint64_t light_log_clamp_min(uint64_t min)
84 93
 {
85
-	LIGHT_NOTE("too small value, adjusting to mininum %lu (raw)", min);
86
-	return min;
94
+    LIGHT_NOTE("too small value, adjusting to mininum %lu (raw)", min);
95
+    return min;
87 96
 }
88 97
 
89 98
 /* Prints a notice about a value which was above `x` and was adjusted to it */
90
-unsigned long light_log_clamp_max(unsigned long max)
99
+uint64_t light_log_clamp_max(uint64_t max)
91 100
 {
92
-	LIGHT_NOTE("too large value, adjusting to mavalimum %lu (raw)", max);
93
-	return max;
101
+    LIGHT_NOTE("too large value, adjusting to mavalimum %lu (raw)", max);
102
+    return max;
94 103
 }
95 104
 
96 105
 /* Clamps the `percent` value between 0% and 100% */
97 106
 double light_percent_clamp(double val)
98 107
 {
99
-	if (val < 0.0) {
100
-		LIGHT_WARN("specified value %g%% is not valid, adjusting it to 0%%", val);
101
-		return 0.0;
102
-	}
103
-
104
-	if (val > 100.0) {
105
-		LIGHT_WARN("specified value %g%% is not valid, adjusting it to 100%%", val);
106
-		return 100.0;
107
-	}
108
+    if (val < 0.0)
109
+    {
110
+        LIGHT_WARN("specified value %g%% is not valid, adjusting it to 0%%", val);
111
+        return 0.0;
112
+    }
113
+
114
+    if (val > 100.0)
115
+    {
116
+        LIGHT_WARN("specified value %g%% is not valid, adjusting it to 100%%", val);
117
+        return 100.0;
118
+    }
119
+
120
+    return val;
121
+}
108 122
 
109
-	return val;
123
+int light_mkpath(char *dir, mode_t mode)
124
+{
125
+    struct stat sb;
126
+
127
+    if (!dir)
128
+    {
129
+        errno = EINVAL;
130
+        return -1;
131
+    }
132
+
133
+    if (!stat(dir, &sb))
134
+        return 0;
135
+
136
+    char *tempdir = strdup(dir);
137
+    light_mkpath(dirname(tempdir), mode);
138
+    free(tempdir);
139
+    
140
+    return mkdir(dir, mode);
110 141
 }
142
+

+ 32
- 32
src/helpers.h View File

@@ -1,55 +1,55 @@
1
-#ifndef LIGHT_HELPERS_H
2
-#define LIGHT_HELPERS_H
1
+
2
+#pragma once
3 3
 
4 4
 #include <stdbool.h>
5
+#include <stdint.h>
6
+#include <sys/stat.h>
7
+#include <stdio.h>
5 8
 
6 9
 /* Clamps x(value) between y(min) and z(max) in a nested ternary operation */
7
-#define LIGHT_CLAMP(val, min, max)					\
8
-	(val < min							\
9
-	 ? light_log_clamp_min(min)					\
10
-	 : (val > max							\
11
-	    ? light_log_clamp_max(max)					\
12
-	    : val ))
10
+#define LIGHT_CLAMP(val, min, max) (val < min ? light_log_clamp_min(min) : (val > max ? light_log_clamp_max(max) : val))
13 11
 
14 12
 /* Verbosity levels: 
15
- * 0 - No output
16
- * 1 - Errors
17
- * 2 - Errors, warnings 
18
- * 3 - Errors, warnings, notices
19
- */
13
+* 0 - No output
14
+* 1 - Errors
15
+* 2 - Errors, warnings 
16
+* 3 - Errors, warnings, notices
17
+*/
20 18
 typedef enum {
21
-	LIGHT_ERROR_LEVEL = 1,
22
-	LIGHT_WARN_LEVEL,
23
-	LIGHT_NOTE_LEVEL
19
+    LIGHT_ERROR_LEVEL = 1,
20
+    LIGHT_WARN_LEVEL,
21
+    LIGHT_NOTE_LEVEL
24 22
 } light_loglevel_t;
25 23
 
26 24
 light_loglevel_t light_loglevel;
27 25
 
28
-#define LIGHT_LOG(lvl, fp, fmt, args...)				\
29
-	if (light_loglevel >= lvl)					\
30
-		fprintf(fp, "%s:%d:" fmt "\n", __FILE__, __LINE__, ##args)
26
+#define LIGHT_LOG(lvl, fp, fmt, args...)\
27
+    if (light_loglevel >= lvl)\
28
+        fprintf(fp, "%s:%d:" fmt "\n", __FILE__, __LINE__, ##args)
31 29
 
32
-#define LIGHT_NOTE(fmt, args...) LIGHT_LOG(LIGHT_NOTE_LEVEL,  stdout, "NOTE:" fmt, ##args)
33
-#define LIGHT_WARN(fmt, args...) LIGHT_LOG(LIGHT_WARN_LEVEL,  stderr, "WARN:" fmt, ##args)
34
-#define LIGHT_ERR(fmt, args...)  LIGHT_LOG(LIGHT_ERROR_LEVEL, stderr, "!ERR:" fmt, ##args)
30
+#define LIGHT_NOTE(fmt, args...) LIGHT_LOG(LIGHT_NOTE_LEVEL,  stdout, " Notice: " fmt, ##args)
31
+#define LIGHT_WARN(fmt, args...) LIGHT_LOG(LIGHT_WARN_LEVEL,  stderr, " Warning: " fmt, ##args)
32
+#define LIGHT_ERR(fmt, args...)  LIGHT_LOG(LIGHT_ERROR_LEVEL, stderr, " Error: " fmt, ##args)
35 33
 #define LIGHT_MEMERR()           LIGHT_ERR("memory error");
36
-#define LIGHT_PERMLOG(act, log)						\
37
-	do {								\
38
-		log("could not open '%s' for " act, filename);		\
39
-		log("Verify it exists with the right permissions");	\
40
-	} while (0)
34
+#define LIGHT_PERMLOG(act, log)\
35
+    do {\
36
+        log("could not open '%s' for " act, filename);\
37
+        log("Verify it exists with the right permissions");\
38
+    } while (0)
39
+
41 40
 #define LIGHT_PERMERR(x)         LIGHT_PERMLOG(x, LIGHT_ERR)
42 41
 #define LIGHT_PERMWARN(x)        LIGHT_PERMLOG(x, LIGHT_WARN)
43 42
 
44
-bool light_file_write_val   (char const *filename, unsigned long val);
45
-bool light_file_read_val    (char const *filename, unsigned long *val);
43
+bool light_file_write_uint64   (char const *filename, uint64_t val);
44
+bool light_file_read_uint64    (char const *filename, uint64_t *val);
46 45
 
47 46
 bool light_file_is_writable (char const *filename);
48 47
 bool light_file_is_readable (char const *filename);
49 48
 
50
-unsigned long light_log_clamp_min(unsigned long min);
51
-unsigned long light_log_clamp_max(unsigned long max);
49
+uint64_t light_log_clamp_min(uint64_t min);
50
+uint64_t light_log_clamp_max(uint64_t max);
52 51
 
53 52
 double light_percent_clamp(double percent);
54 53
 
55
-#endif /* LIGHT_HELPERS_H */
54
+int light_mkpath(char *dir, mode_t mode);
55
+

+ 1
- 0
src/impl/razer.c View File

@@ -0,0 +1 @@
1
+ 

+ 1
- 0
src/impl/razer.h View File

@@ -0,0 +1 @@
1
+ 

+ 250
- 0
src/impl/sysfs.c View File

@@ -0,0 +1,250 @@
1
+
2
+#include "impl/sysfs.h"
3
+#include "light.h"
4
+#include "helpers.h"
5
+
6
+#include <stdio.h> //snprintf
7
+#include <stdlib.h> // malloc, free
8
+#include <dirent.h> // opendir, readdir
9
+
10
+static bool _impl_sysfs_init_leds(light_device_enumerator_t *enumerator)
11
+{
12
+    // Create a new backlight device
13
+    light_device_t *leds_device = malloc(sizeof(light_device_t));
14
+    snprintf(leds_device->name, sizeof(leds_device->name), "%s", "leds");
15
+    
16
+    // Add it to the enumerator 
17
+    light_add_enumerator_device(enumerator, leds_device);
18
+    
19
+    // Iterate through the led controllers and create a device_target for each controller 
20
+    DIR *leds_dir;
21
+    struct dirent *curr_entry;
22
+    
23
+    if((leds_dir = opendir("/sys/class/leds")) == NULL)
24
+    {
25
+        LIGHT_ERR("failed to open leds controller directory for reading");
26
+        return false;
27
+    }
28
+    
29
+    while((curr_entry = readdir(leds_dir)) != NULL)
30
+    {
31
+        // Skip dot entries
32
+        if(curr_entry->d_name[0] == '.')
33
+        {
34
+            continue;
35
+        }
36
+        
37
+        // Create a new device target for the controller 
38
+        light_device_target_t *led_controller = malloc(sizeof(light_device_target_t));
39
+        snprintf(led_controller->name, sizeof(led_controller->name), "%s", curr_entry->d_name);
40
+        
41
+        // Setup the function bindings
42
+        led_controller->set_value = impl_sysfs_set;
43
+        led_controller->get_value = impl_sysfs_get;
44
+        led_controller->get_max_value = impl_sysfs_getmax;
45
+        led_controller->custom_command = impl_sysfs_command;
46
+        
47
+        // Setup the target data 
48
+        impl_sysfs_data_t *dev_data = malloc(sizeof(impl_sysfs_data_t));
49
+        led_controller->device_target_data = dev_data;
50
+        snprintf(dev_data->brightness, sizeof(dev_data->brightness), "/sys/class/leds/%s/brightness", curr_entry->d_name);
51
+        snprintf(dev_data->max_brightness, sizeof(dev_data->max_brightness), "/sys/class/leds/%s/max_brightness", curr_entry->d_name);
52
+        
53
+        // Add it to the device
54
+        light_add_device_target(leds_device, led_controller);
55
+    }
56
+    
57
+    closedir(leds_dir);
58
+    
59
+    return true;
60
+}
61
+
62
+static bool _impl_sysfs_init_backlight(light_device_enumerator_t *enumerator)
63
+{
64
+    // Create a new backlight device
65
+    light_device_t *backlight_device = malloc(sizeof(light_device_t));
66
+    snprintf(backlight_device->name, sizeof(backlight_device->name), "%s", "backlight");
67
+    
68
+    // Add it to the enumerator 
69
+    light_add_enumerator_device(enumerator, backlight_device);
70
+    
71
+    // Iterate through the backlight controllers and create a device_target for each controller 
72
+    DIR *backlight_dir;
73
+    struct dirent *curr_entry;
74
+    
75
+    // Keep track of the best controller, and create an autodevice from that
76
+    char best_controller[NAME_MAX];
77
+    uint64_t best_value = 0;
78
+    
79
+    if((backlight_dir = opendir("/sys/class/backlight")) == NULL)
80
+    {
81
+        LIGHT_ERR("failed to open backlight controller directory for reading");
82
+        return false;
83
+    }
84
+    
85
+    while((curr_entry = readdir(backlight_dir)) != NULL)
86
+    {
87
+        // Skip dot entries
88
+        if(curr_entry->d_name[0] == '.')
89
+        {
90
+            continue;
91
+        }
92
+        
93
+        // Create a new device target for the controller 
94
+        light_device_target_t *backlight_controller = malloc(sizeof(light_device_target_t));
95
+        snprintf(backlight_controller->name, sizeof(backlight_controller->name), "%s", curr_entry->d_name);
96
+        
97
+        // Setup the function bindings
98
+        backlight_controller->set_value = impl_sysfs_set;
99
+        backlight_controller->get_value = impl_sysfs_get;
100
+        backlight_controller->get_max_value = impl_sysfs_getmax;
101
+        backlight_controller->custom_command = impl_sysfs_command;
102
+        
103
+        // Setup the target data 
104
+        impl_sysfs_data_t *dev_data = malloc(sizeof(impl_sysfs_data_t));
105
+        backlight_controller->device_target_data = dev_data;
106
+        snprintf(dev_data->brightness, sizeof(dev_data->brightness), "/sys/class/backlight/%s/brightness", curr_entry->d_name);
107
+        snprintf(dev_data->max_brightness, sizeof(dev_data->max_brightness), "/sys/class/backlight/%s/max_brightness", curr_entry->d_name);
108
+        
109
+        // Read the max brightness to get the best one
110
+        uint64_t curr_value = 0;
111
+        if(light_file_read_uint64(dev_data->max_brightness, &curr_value))
112
+        {
113
+            if(curr_value > best_value)
114
+            {
115
+                best_value = curr_value;
116
+                snprintf(best_controller, sizeof(best_controller), "%s", backlight_controller->name);
117
+            }
118
+        }
119
+        
120
+        // Add it to the device
121
+        light_add_device_target(backlight_device, backlight_controller);
122
+    }
123
+    
124
+    closedir(backlight_dir);
125
+    
126
+    // Create an auto controller 
127
+    light_device_target_t *auto_controller = malloc(sizeof(light_device_target_t));
128
+    snprintf(auto_controller->name, sizeof(auto_controller->name), "%s", "auto");
129
+    
130
+    // Setup the function bindings
131
+    auto_controller->set_value = impl_sysfs_set;
132
+    auto_controller->get_value = impl_sysfs_get;
133
+    auto_controller->get_max_value = impl_sysfs_getmax;
134
+    auto_controller->custom_command = impl_sysfs_command;
135
+    
136
+    // Setup the target data 
137
+    impl_sysfs_data_t *dev_data = malloc(sizeof(impl_sysfs_data_t));
138
+    auto_controller->device_target_data = dev_data;
139
+    snprintf(dev_data->brightness, sizeof(dev_data->brightness), "/sys/class/backlight/%s/brightness", best_controller);
140
+    snprintf(dev_data->max_brightness, sizeof(dev_data->max_brightness), "/sys/class/backlight/%s/max_brightness", best_controller);
141
+    
142
+    // Add it to the device
143
+    light_add_device_target(backlight_device, auto_controller);
144
+    
145
+    return true;
146
+}
147
+
148
+bool impl_sysfs_init(light_device_enumerator_t *enumerator)
149
+{
150
+    // Create a device for the backlight 
151
+    _impl_sysfs_init_backlight(enumerator);
152
+    
153
+    // Create devices for the leds
154
+    _impl_sysfs_init_leds(enumerator);
155
+    
156
+    return true;
157
+}
158
+
159
+bool impl_sysfs_free(light_device_enumerator_t *enumerator)
160
+{
161
+    // Iterate through the devices in the enumerator
162
+    for(uint64_t d = 0; d < enumerator->num_devices; d++)
163
+    {
164
+        light_device_t *curr_device = enumerator->devices[d];
165
+        
166
+        // If the given device points to NULL, we can safely skip it
167
+        if(curr_device == NULL)
168
+        {
169
+            continue;
170
+        }
171
+        
172
+        for(uint64_t t = 0; t < curr_device->num_targets; t++)
173
+        {
174
+            light_device_target_t *curr_target = curr_device->targets[t];
175
+            
176
+            if(curr_target == NULL)
177
+            {
178
+                continue;
179
+            }
180
+            
181
+            if(curr_target->device_target_data != NULL)
182
+            {
183
+                free(curr_target->device_target_data);
184
+            }
185
+            
186
+            free(curr_target);
187
+        }
188
+        
189
+        // If the given device has any device_data, free it
190
+        if(curr_device->device_data != NULL)
191
+        {
192
+            free(curr_device->device_data);
193
+        }
194
+                
195
+        light_dispose_device(curr_device);    
196
+
197
+        // Free the device
198
+        free(curr_device);
199
+    }
200
+    
201
+    return true;
202
+}
203
+
204
+bool impl_sysfs_set(light_device_target_t *target, uint64_t in_value)
205
+{
206
+    impl_sysfs_data_t *data = (impl_sysfs_data_t*)target->device_target_data;
207
+
208
+    if(!light_file_write_uint64(data->brightness, in_value))
209
+    {
210
+        LIGHT_ERR("failed to write to sysfs device");
211
+        return false;
212
+    }
213
+    
214
+    return true;
215
+}
216
+
217
+bool impl_sysfs_get(light_device_target_t *target, uint64_t *out_value)
218
+{
219
+    impl_sysfs_data_t *data = (impl_sysfs_data_t*)target->device_target_data;
220
+
221
+    if(!light_file_read_uint64(data->brightness, out_value))
222
+    {
223
+        LIGHT_ERR("failed to read from sysfs device");
224
+        return false;
225
+    }
226
+    
227
+    return true;
228
+}
229
+
230
+bool impl_sysfs_getmax(light_device_target_t *target, uint64_t *out_value)
231
+{
232
+    impl_sysfs_data_t *data = (impl_sysfs_data_t*)target->device_target_data;
233
+
234
+    if(!light_file_read_uint64(data->max_brightness, out_value))
235
+    {
236
+        LIGHT_ERR("failed to read from sysfs device");
237
+        return false;
238
+    }
239
+    
240
+    return true;
241
+}
242
+
243
+bool impl_sysfs_command(light_device_target_t *target, char const *command_string)
244
+{
245
+    // No current need for custom commands in sysfs enumerator
246
+    // To implement support, simply parse the command string to your liking, and return false on invalid input or results!
247
+    return true;
248
+}
249
+
250
+

+ 24
- 0
src/impl/sysfs.h View File

@@ -0,0 +1,24 @@
1
+
2
+#pragma once 
3
+
4
+#include "light.h"
5
+
6
+// Implementation of the sysfs enumerator
7
+// Enumerates devices for backlights and leds
8
+
9
+// Device target data 
10
+struct _impl_sysfs_data_t
11
+{
12
+    char brightness[NAME_MAX];
13
+    char max_brightness[NAME_MAX];
14
+};
15
+
16
+typedef struct _impl_sysfs_data_t impl_sysfs_data_t;
17
+
18
+bool impl_sysfs_init(light_device_enumerator_t *enumerator);
19
+bool impl_sysfs_free(light_device_enumerator_t *enumerator);
20
+
21
+bool impl_sysfs_set(light_device_target_t *target, uint64_t in_value);
22
+bool impl_sysfs_get(light_device_target_t *target, uint64_t *out_value);
23
+bool impl_sysfs_getmax(light_device_target_t *target, uint64_t *out_value);
24
+bool impl_sysfs_command(light_device_target_t *target, char const *command_string);

+ 895
- 922
src/light.c
File diff suppressed because it is too large
View File


+ 134
- 99
src/light.h View File

@@ -1,105 +1,140 @@
1
-#ifndef LIGHT_H_
2
-#define LIGHT_H_
3 1
 
4
-#include "config.h"
5
-#include "helpers.h"
2
+#pragma once
6 3
 
4
+#include <stdint.h>
7 5
 #include <stdbool.h>
8
-#include <sys/types.h>
9
-#include <dirent.h>
10
-#include <linux/limits.h>
6
+#include <limits.h> // NAME_MAX
7
+#include <stddef.h> // NULL
8
+
9
+#include "config.h"
11 10
 
12
-#define LIGHT_YEAR   "2012-2018"
11
+#define LIGHT_YEAR   "2012 - 2018"
13 12
 #define LIGHT_AUTHOR "Fredrik Haikarainen"
14 13
 
15
-#define ASSERT_SET(t, v)						\
16
-	if (v) {							\
17
-		fprintf(stderr, t " cannot be used more than once.\n"); \
18
-		return false;						\
19
-	}								\
20
-	v = true;
21
-
22
-#define ASSERT_CMDSET()    ASSERT_SET("Commands", cmd_set)
23
-#define ASSERT_TARGETSET() ASSERT_SET("Targets", target_set)
24
-#define ASSERT_FIELDSET()  ASSERT_SET("Fields", field_set)
25
-#define ASSERT_CTRLSET()   ASSERT_SET("Controllers", ctrl_set)
26
-#define ASSERT_VALSET()    ASSERT_SET("Values", val_set)
27
-
28
-typedef enum {
29
-	LIGHT_BRIGHTNESS = 0,
30
-	LIGHT_MAX_BRIGHTNESS,
31
-	LIGHT_MIN_CAP,
32
-	LIGHT_SAVERESTORE
33
-} light_field_t;
34
-
35
-typedef enum {
36
-	LIGHT_BACKLIGHT = 0,
37
-	LIGHT_KEYBOARD
38
-} light_target_t;
39
-
40
-typedef enum {
41
-	LIGHT_AUTO = 0,
42
-	LIGHT_SPECIFY
43
-} light_ctrl_mode_t;
44
-
45
-typedef enum {
46
-	LIGHT_GET = 0,
47
-	LIGHT_SET,
48
-	LIGHT_ADD,
49
-	LIGHT_SUB,
50
-	LIGHT_PRINT_HELP,	/* Prints help and exits  */
51
-	LIGHT_PRINT_VERSION,	/* Prints version info and exits */
52
-	LIGHT_LIST_CTRL,
53
-	LIGHT_RESTORE,
54
-	LIGHT_SAVE
55
-} light_cmd_t;
56
-
57
-typedef enum {
58
-	LIGHT_RAW = 0,
59
-	LIGHT_PERCENT
60
-} light_val_mode_t;
61
-
62
-typedef struct {
63
-	/* Cache file prefix */
64
-	char               prefix[NAME_MAX];
65
-
66
-	/* Which controller to use */
67
-	light_ctrl_mode_t  ctrl;
68
-	char               ctrl_name[NAME_MAX + 1];
69
-
70
-	/* What to do with the controller */
71
-	light_cmd_t        cmd;
72
-	light_val_mode_t   val_mode;
73
-	unsigned long      val_raw;	/* The specified value in raw mode */
74
-	double             val_percent;	/* The specified value in percent */
75
-
76
-	light_target_t     target;
77
-	light_field_t      field;
78
-
79
-	/* Cache data */
80
-	bool               has_cached_brightness_max;
81
-	unsigned long      cached_brightness_max;
82
-} light_ctx_t;
83
-
84
-/* -- Global variable holding the settings for the current run -- */
85
-light_ctx_t ctx;
86
-
87
-bool light_initialize              (int argc, char **argv);
88
-bool light_execute                 (void);
89
-void light_free                    (void);
90
-
91
-bool light_ctrl_list               (void);
92
-bool light_ctrl_probe              (char *controller, size_t len);
93
-bool light_ctrl_exist              (char const *controller);
94
-
95
-bool light_ctrl_get_brightness     (char const *controller, unsigned long *v);
96
-bool light_ctrl_set_brightness     (char const *controller, unsigned long v);
97
-bool light_ctrl_get_brightness_max (char const *controller, unsigned long *v);
98
-
99
-bool light_ctrl_get_cap_min        (char const *controller, bool *hasMinCap, unsigned long *minCap);
100
-bool light_ctrl_set_cap_min        (char const *controller, unsigned long val);
101
-
102
-bool light_ctrl_save_brightness    (char const *controller, unsigned long val);
103
-bool light_ctrl_restore_brightness (char const *controller);
104
-
105
-#endif /* LIGHT_H_ */
14
+struct _light_device_target_t;
15
+typedef struct _light_device_target_t light_device_target_t;
16
+
17
+struct _light_device_t;
18
+typedef struct _light_device_t light_device_t;
19
+
20
+struct _light_device_enumerator_t;
21
+typedef struct _light_device_enumerator_t light_device_enumerator_t;
22
+
23
+/* Function pointers that implementations have to set for device targets */
24
+typedef bool (*LFUNCVALSET)(light_device_target_t*, uint64_t);
25
+typedef bool (*LFUNCVALGET)(light_device_target_t*, uint64_t*);
26
+typedef bool (*LFUNCMAXVALGET)(light_device_target_t*, uint64_t*);
27
+typedef bool (*LFUNCCUSTOMCMD)(light_device_target_t*, char const *);
28
+
29
+/* Describes a target within a device (for example a led on a keyboard, or a controller for a backlight) */
30
+struct _light_device_target_t
31
+{
32
+    char           name[256];
33
+    LFUNCVALSET    set_value;
34
+    LFUNCVALGET    get_value;
35
+    LFUNCMAXVALGET get_max_value;
36
+    LFUNCCUSTOMCMD custom_command;
37
+    void           *device_target_data;
38
+    light_device_t *device;
39
+};
40
+
41
+/* Describes a device (a backlight, a keyboard, a led-strip) */
42
+struct _light_device_t
43
+{
44
+    char                  name[256];
45
+    light_device_target_t **targets;
46
+    uint64_t              num_targets;
47
+    void                  *device_data;
48
+    light_device_enumerator_t *enumerator;
49
+};
50
+
51
+
52
+typedef bool (*LFUNCENUMINIT)(light_device_enumerator_t*);
53
+typedef bool (*LFUNCENUMFREE)(light_device_enumerator_t*);
54
+
55
+/* An enumerator that is responsible for creating and freeing devices as well as their targets */
56
+struct _light_device_enumerator_t
57
+{
58
+    char            name[256];
59
+    LFUNCENUMINIT   init;
60
+    LFUNCENUMFREE   free;
61
+
62
+    light_device_t  **devices;
63
+    uint64_t        num_devices;
64
+};
65
+
66
+typedef struct _light_context_t light_context_t;
67
+
68
+// A command that can be run (set, get, add, subtract, print help, print version, list devices etc.)
69
+typedef bool (*LFUNCCOMMAND)(light_context_t *);
70
+
71
+struct _light_context_t
72
+{
73
+    struct 
74
+    {
75
+        LFUNCCOMMAND            command; // What command was issued 
76
+        uint64_t                value; // The input value, in raw mode
77
+        bool                    raw_mode; // Whether or not we use raw or percentage mode
78
+        light_device_target_t   *device_target; // The device target to act on
79
+    } run_params;
80
+
81
+    struct
82
+    {
83
+        char                    conf_dir[NAME_MAX]; // The path to the application cache directory 
84
+    } sys_params;
85
+    
86
+    light_device_enumerator_t   **enumerators;
87
+    uint64_t                    num_enumerators;
88
+};
89
+
90
+// The different available commands
91
+bool light_cmd_print_help(light_context_t *ctx); // H,h 
92
+bool light_cmd_print_version(light_context_t *ctx); // V
93
+bool light_cmd_list_devices(light_context_t *ctx); // L
94
+bool light_cmd_set_brightness(light_context_t *ctx); // S
95
+bool light_cmd_get_brightness(light_context_t *ctx); // G
96
+bool light_cmd_get_max_brightness(light_context_t *ctx); // M
97
+bool light_cmd_set_min_brightness(light_context_t *ctx); // N
98
+bool light_cmd_get_min_brightness(light_context_t *ctx); // P
99
+bool light_cmd_add_brightness(light_context_t *ctx); // A
100
+bool light_cmd_sub_brightness(light_context_t *ctx); // U
101
+bool light_cmd_save_brightness(light_context_t *ctx); // O
102
+bool light_cmd_restore_brightness(light_context_t *ctx); // I
103
+
104
+/* Initializes the application, given the command-line. Returns a context. */
105
+light_context_t* light_initialize(int argc, char **argv);
106
+
107
+/* Executes the given context. Returns true on success, false on failure. */
108
+bool light_execute(light_context_t*);
109
+
110
+/* Frees the given context */
111
+void light_free(light_context_t*);
112
+
113
+/* Create a device enumerator in the given context */
114
+light_device_enumerator_t * light_create_enumerator(light_context_t *ctx, char const * name, LFUNCENUMINIT, LFUNCENUMFREE);
115
+
116
+/* Initializes all the device enumerators (and its devices, targets) */
117
+bool light_init_enumerators(light_context_t *ctx);
118
+
119
+/* Frees all the device enumerators (and its devices, targets) */
120
+bool light_free_enumerators(light_context_t *ctx);
121
+
122
+void light_add_enumerator_device(light_device_enumerator_t *enumerator, light_device_t *new_device);
123
+
124
+void light_add_device_target(light_device_t *device, light_device_target_t *new_target);
125
+
126
+typedef struct _light_target_path_t light_target_path_t;
127
+struct _light_target_path_t 
128
+{
129
+    char enumerator[NAME_MAX];
130
+    char device[NAME_MAX];
131
+    char target[NAME_MAX];
132
+};
133
+
134
+bool light_split_target_path(char const * in_path, light_target_path_t *out_path);
135
+
136
+/* Returns the found device target, or null. Name should be enumerator/device/target */
137
+light_device_target_t* light_find_device_target(light_context_t *ctx, char const * name);
138
+
139
+/* Frees any runtime-allocated data inside a device. Call this before you free a device. */
140
+void light_dispose_device(light_device_t *device);

+ 15
- 12
src/main.c View File

@@ -1,6 +1,8 @@
1
+
1 2
 #include "light.h"
3
+#include "helpers.h"
2 4
 
3
-#include <stdio.h>
5
+//#include <stdio.h>
4 6
 
5 7
 #define LIGHT_RETURNVAL_INITFAIL  2
6 8
 #define LIGHT_RETURNVAL_EXECFAIL  1
@@ -8,17 +10,18 @@
8 10
 
9 11
 int main(int argc, char **argv)
10 12
 {
11
-	if (!light_initialize(argc, argv)) {
12
-		LIGHT_ERR("Initialization failed");
13
-		return LIGHT_RETURNVAL_INITFAIL;
14
-	}
13
+    light_context_t *light_ctx = light_initialize(argc, argv);
14
+    if (light_ctx == NULL) {
15
+        LIGHT_ERR("Initialization failed");
16
+        return LIGHT_RETURNVAL_INITFAIL;
17
+    }
15 18
 
16
-	if (!light_execute()) {
17
-		LIGHT_ERR("Execution failed");
18
-		light_free();
19
-		return LIGHT_RETURNVAL_EXECFAIL;
20
-	}
19
+    if (!light_execute(light_ctx)) {
20
+        LIGHT_ERR("Execution failed");
21
+        light_free(light_ctx);
22
+        return LIGHT_RETURNVAL_EXECFAIL;
23
+    }
21 24
 
22
-	light_free();
23
-	return LIGHT_RETURNVAL_SUCCESS;
25
+    light_free(light_ctx);
26
+    return LIGHT_RETURNVAL_SUCCESS;
24 27
 }