-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbacklight.go
333 lines (273 loc) · 7.23 KB
/
backlight.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
package main
import (
"fmt"
"os"
"io/ioutil"
"bufio"
"path/filepath"
"strconv"
"strings"
"flag"
"math"
)
func debug(format string, a...interface{} ) {
return
fmt.Printf("DEBUG: ")
fmt.Printf(format,a...)
}
type Options struct {
help bool // show help
list bool // show list of all values
id int // select by id
name string // select by name
val float64 // value to update
min uint // minimum value
perc bool // val is a percentage
rel bool // val is relative
}
func ParseOptions() Options {
var op_help = flag.Bool( "h", false, "show this help")
var op_list = flag.Bool( "l", false, "show list of all brightness controls")
var op_id = flag.Int( "i", -1, "select brightness control by id")
var op_name = flag.String("n", "", "select brightness control by name")
var op_val = flag.String("s", "", "set/adjust brightness (absolute value, relative value or percentage)")
var op_min = flag.Int( "m", 0, "set minimum brightness (default: 0)")
flag.Parse()
// store the results in a nice struct
var options Options
options.help = *op_help
options.list = *op_list
options.id = *op_id
options.name = *op_name
options.val = math.NaN()
options.min = 0
options.perc = false
options.rel = false
// now for the manual parsing.
var str = *op_val
if len(str)>0 {
// first check if adjustment is absolute or relative
if str[0]=='+' || str[0]=='-' {
options.rel = true
}
// then check if we're dealing with a percentage
if str[len(str)-1]=='%' {
options.perc = true
}
str = strings.TrimSuffix(str,"%")
val, err := strconv.ParseFloat(str,64)
if err!=nil { panic(err) }
options.val = val
debug("parsed options; val=%v rel=%v perc=%v\n",options.val,options.rel,options.perc)
}
if (*op_min>0) {
options.min = uint(*op_min)
}
// some logic
if *op_help {
flag.PrintDefaults()
os.Exit(0)
}
if len(*op_val)==0 {
// no adjustment specified, assume listing
options.list = true
}
if (options.id!=-1 && options.id<0) {
// illegal brightness icontrol id
fmt.Printf("Illegal control id (must be positive)\n")
os.Exit(1)
}
if len(*op_val)>0 && !(options.id!=-1 || len(options.name)>0) {
// adjustment specified, but no control id. error out
fmt.Printf("Brightness control not specified. Please use -i or -n\n")
os.Exit(1)
}
if options.id!=-1 && len(options.name)>0 {
// both -n and -i specified
fmt.Printf("Can't specify backlight control by name and id at the same time\n")
fmt.Printf("Please use either -i or -n\n")
os.Exit(1)
}
return options
}
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
func FileIsDir(name string) bool {
if info, err := os.Stat(name); err != nil {
return false
} else {
return info.IsDir()
}
}
func ScanDir( basedir string ) []string {
var dirs = []string{}
entries, err := ioutil.ReadDir(basedir)
if err!=nil { panic(err) } // TODO: better handling of error
OUTER:
for i, e := range entries {
debug("%d %04o %v %s\n", i, e.Mode(), e.IsDir(), e.Name())
var d = filepath.Join(basedir,e.Name())
if !FileIsDir(d) { continue }
debug("Searching %s\n", d)
for _, f := range []string{"brightness","max_brightness"} {
var file = filepath.Join(d,f)
debug("Checking for %s...", file)
if !FileExists(file) {
debug("no\n")
continue OUTER
}
debug("yes\n")
}
// found "brightness" and "max_brightness" in this dir, so save it
dirs = append(dirs,d)
}
return dirs
}
func ScanDirs( dirs...string) []string {
var result = []string{}
for _, d := range dirs {
var thisresult = ScanDir(d)
result = append(result,thisresult...)
}
return result
}
func BLRead(dir string, file string) uint {
var filename = filepath.Join(dir,file)
fd, err := os.Open(filename)
if err!=nil { panic(err) }
defer fd.Close()
var scanner = bufio.NewScanner(fd)
scanner.Split(bufio.ScanWords)
scanner.Scan()
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading input:", err)
}
var str = scanner.Text()
debug("read `%s' from %s\n", str, filename)
var val = 0
val, err = strconv.Atoi(str)
if err!=nil { panic(err) }
if val<0 {
// should never occur
panic("negative brightness")
}
return uint(val)
}
func BLReadMax(dir string) uint {
return BLRead(dir,"max_brightness")
}
func BLReadCurrent(dir string) uint {
return BLRead(dir,"brightness")
}
func BLWrite(dir string, file string, brightness uint) {
var filename = filepath.Join(dir,file)
debug("Writing to file `%v'\n", filename)
fd, err := os.Create(filename)
if err!=nil { panic(err) }
defer fd.Close()
debug("File opened\n")
var str = fmt.Sprintf("%v", brightness);
debug("Writing `%v'\n", str)
fd.WriteString(str)
}
func BLWriteCurrent(dir string, brightness uint) {
BLWrite(dir, "brightness", brightness)
}
func SelectDirs(all_dirs []string, options Options) string {
if options.id!=-1 {
debug("Selecting by id\n")
if (options.id < len(all_dirs)) {
return all_dirs[options.id]
} else {
fmt.Printf("Brightness control %v was not found\n", options.id)
os.Exit(2);
}
} else if len(options.name)>0 {
debug("Selecting by name\n")
for _, d := range all_dirs {
if filepath.Base(d) == options.name {
return d
}
}
fmt.Printf("Brightness control named `%v' not found (try -l)\n", options.name)
os.Exit(2);
} else {
debug("Selecting all\n")
return ""
}
return "NEVER REACHED"
}
func Round(f float64) int {
if f<0 {
return -Round(-f)
} else {
return int(f+0.5)
}
}
func CalcBacklight(bl_max uint, bl_min uint, bl_cur uint, val float64, is_rel bool, is_perc bool) uint {
var bl = 0.0
// "calculations"
if is_rel && is_perc {
bl = float64(bl_cur) + float64(bl_max)*val/100
} else if is_rel && !is_perc {
bl = float64(bl_cur) + val
} else if !is_rel && is_perc {
bl = val/100*float64(bl_max)
} else if !is_rel && !is_perc {
bl = val
} else {
panic("Never reached")
}
// sanity check
if bl<0 || uint(bl)<bl_min {
return bl_min
} else if bl>float64(bl_max) {
return bl_max
} else {
return uint(Round(bl))
}
}
func main() {
var options = ParseOptions()
var dirs = ScanDirs("/sys/class/backlight","/sys/class/leds")
var selected_dir = SelectDirs(dirs, options)
debug("Selected dir is `%v'\n", selected_dir)
if options.list {
debug("Listing all controls\n");
for i, dir := range dirs {
if selected_dir!="" && dir!=selected_dir {
// we only want to list this specific dir
continue
}
var bl_max = BLReadMax(dir)
var bl_cur = BLReadCurrent(dir)
var bl_perc = 100.0*float64(bl_cur)/float64(bl_max)
fmt.Printf("%2d %25s %4d %4d %6.2f\n", i, filepath.Base(dir), bl_cur, bl_max, bl_perc)
}
os.Exit(0)
}
if !math.IsNaN(options.val) {
if selected_dir=="" {
// should never happen
panic("Invalid state")
}
var bl_max = BLReadMax(selected_dir)
var bl_cur = BLReadCurrent(selected_dir)
var bl_new = CalcBacklight(bl_max, options.min, bl_cur, options.val, options.rel, options.perc)
fmt.Printf("Setting backlight to %v\n",bl_new)
BLWriteCurrent(selected_dir, bl_new)
}
/*
dir = Select_dir(dirs)
bl_max = ReadMax(dir)
bl_current = ReadCurrent(dir)
bl_new = CalcBacklight(bl_current, bl_max, options)
WriteBacklight(dir, bl_new)
*/
}