[go: up one dir, main page]

Menu

[r219]: / calise / system.py  Maximize  Restore  History

Download this file

282 lines (258 with data), 10.1 kB

  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
# Copyright (C) 2011 Nicolo' Barbon
#
# This file is part of Calise.
#
# Calise 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
# any later version.
#
# Calise 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 Calise. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import errno
from math import atan, pi
from time import time
'''Computation class
In this class are set custom equations to obtain:
- maximum lightness correction
- effective correction
- brightness percentage (using user-defined scale)
There are also backlight directory's functions. All parameters are briefly
explained below
'''
class computation():
def __init__(self):
self.scr = None # screen brightness 0 < 255
self.amb = None # ambient brightness 0 < 255
self.cor = None # calculated brightness correction
self.pct = None # calculated brightness percentage
self.bfile = None # brightness sys file that manages backlight level
self.bkstp = None # current backlight step
self.bkmax = None # maximum backlight step
self.bkpow = None # 0 = power-on, 1 = power-off
# calculates ambient brightness correction using screen backlight value
def correction(self,amb=.0,scr=.0,dstep=.0):
cor_max = 8+(atan((dstep+1)-2.55)*(dstep+1)**.3857*8)
self.cor = cor_max*(.5-atan(amb/15.0-4)/pi)*(scr/255.0)**1.5
# calculates ambient brightness percentage using user-defined scale
def percentage(self,amb,ofs=0.0,delta=255/(100**(1/.73)),scr=0,dstep=0):
if (scr == None)|(dstep == None):
self.cor = 0
scr = 0
dsetp = 0
else:
self.correction(amb, scr, dstep)
self.scr = scr
self.amb = amb
cor = self.cor
if cor < 0:
cor = 0
amb = amb - cor
if ofs > amb:
ofs = amb
self.pct = ((amb - ofs) / delta) ** .73
def read_backlight(self, ix=0, pt=None):
ret = None
af = ['brightness', 'max_brightness', 'bl_power', 'actual_brightness']
# check inputs
if not type(ix) in [int, float]:
ix = 0
if pt is None and self.bfile:
pt = self.bfile
if type(pt) in [str]:
if os.path.isdir(pt) and os.path.isfile(os.path.join(pt, af[ix])):
path = pt
elif os.path.isfile(os.path.join(os.path.dirname(pt), af[ix])):
path = os.path.dirname(pt)
else:
path = None
if path:
try:
with open(os.path.join(path, af[ix]), 'r') as fp:
ret = int(fp.readline())
except ValueError:
sys.stderr.write(
"ValueError: choosen \"%s\" file (%s) is not valid\n"
% (af[ix], path))
raise
except IOError as err:
if err.errno == errno.EACCES:
sys.stderr.write(
"IOError: [Errno %d] Permission denied: \"%s\"\n"
"Please set read permission for current user\n"
% (err.errno, path))
raise
if ret is None:
raise ValueError
if ix == 0 and not self.bfile:
self.bfile = os.path.join(path, af[ix])
return ret
# choice = step|max|power|all
def get_values(self, choice='step', path=None):
ret = None
if choice == 'step':
self.bkstp = self.read_backlight(0, path)
ret = self.bkstp
elif choice == 'max':
self.bkmax = self.read_backlight(1, path)
ret = self.bkmax
elif choice == 'power':
self.bkpow = self.read_backlight(2, path)
ret = self.bkpow
elif choice == 'actual':
self.actual = self.read_backlight(3, path)
ret = self.actual
elif choice == 'all':
self.bkstp = self.read_backlight(0, path)
self.bkstp = self.read_backlight(3, path)
self.bkmax = self.read_backlight(1, path)
self.bkpow = self.read_backlight(2, path)
ret = [self.bkstp, self.bkmax, self.bkpow]
return ret
'''Execution class
This class obtains a step value out of some vars that must be given manually
'''
class execution():
steps = None # number of backlight steps
bkofs = None # first step
invert = None # False: scale is min > max, True: max > min
ofs = None # equation offset (user defined, got from calibration)
delta = None # equation modifier (user defined, got from calibration)
pos = None # sys backlight device control folder
tol = None # percentage tolerance for hard drop
bfile = None # brightness sys file (taken from computation)
bkstp = None # current backlight step (taken from computation)
# each dictionary voice contains all previous valid measurements
data = {
'timestamp': [],
'ambient': [],
'screen': [],
'correction': [],
'percent': [],
'step': [],
'bkstp': [],
}
history = {
'timestamp': [],
'ambient': [],
'screen': [],
'correction': [],
'percent': [],
'step': [],
'bkstp': [],
}
def __init__(
self,
steps, bkofs, invert=False,
ofs=0.0, delta=255/(100**(1/.73)), tol=20,
pos=None
):
self.steps = steps
self.bkofs = bkofs
self.invert = invert
self.den = 100.00/self.steps
self.ofs = ofs
self.delta = delta
self.tol = tol
self.pos = pos
# set_flt needs a step value on the scale 0 < 9, so, if there's a
# different scale/offset, it has to be reduced to a 0 < 9 one.
def AdjustScale(self, cur):
if self.invert:
return (self.steps-1-(cur-self.bkofs))*(self.den/10.0)
else:
return (cur-self.bkofs)*(self.den/10.0)
# picks brightness percentages, backlight steps and offset and invert, then
# returns the corresponding backlight step
def SetStep(self,pct):
steps = self.steps
bkofs = self.bkofs
percs = self.data['percent']
average = sum(percs)/len(percs)
stp = int(average / self.den - .5 + bkofs)
if self.invert:
stp = steps - 1 + bkofs - stp + bkofs
# out-of-bounds control...
if stp > steps - 1 + bkofs:
stp = steps - 1 + bkofs
elif stp < bkofs:
stp = bkofs
self.data['step'].append(stp)
# updates value ambient and screen brightness list, can be ommitted if amb
# is specified in the elaborate() function
def store(self,amb,scr=None):
if type(amb) is float or type(amb) is int:
self.data['ambient'].append(amb)
else: raise TypeError('amb has to be either float or int')
if type(scr) is float or type(scr) is int:
self.data['screen'].append(scr)
elif scr is None and len(self.data['screen']) > 0:
self.data['screen'].append(self.data['screen'][-1])
elif scr is None and len(self.data['screen']) == 0:
self.data['screen'].append(0)
else:
raise TypeError('scr has to be either float or int (or None)')
# main function of the class, takes all class vars and returns a backlight
# step according to them. If there is a difference greater than 20 between
# two consequent percentages, resets all data
def elaborate(self,amb=None,scr=None):
if amb is not None:
self.store(amb,scr)
amb = self.data['ambient'][-1]
scr = self.data['screen'][-1]
if len(self.data['timestamp']) < len(self.data['ambient']):
self.data['timestamp'].append(round(time(),3))
comp = computation()
comp.get_values('step', self.pos)
comp.percentage(
amb, self.ofs, self.delta,
scr, self.AdjustScale(comp.bkstp)
)
self.data['correction'].append(comp.cor)
self.data['percent'].append(comp.pct)
if len(self.data['percent']) > 1:
if (
abs( self.data['percent'][-1] - self.data['percent'][-2] ) >
self.tol
):
for bookmark in self.data:
if bookmark is 'step':
self.data[bookmark] = []
else:
self.data[bookmark] = [ self.data[bookmark][-1] ]
self.SetStep(sum(self.data['percent'])/len(self.data['percent']))
self.data['bkstp'].append(comp.bkstp)
self.bfile = comp.bfile
# checks for read permission and writes current backlight step on sys
# brightness file (the one selected throug computation)
def WriteStep(self):
if self.data['step'][-1] != self.data['bkstp'][-1]:
try:
fp = open(self.bfile, 'w')
except IOError as err:
if err.errno == errno.EACCES:
sys.stderr.write("IOError: [Errno %d] Permission denied: "
"'%s'\nPlease set write permission for "
"current user\n"
% (err.errno, self.bfile))
quit()
raise
else:
with fp:
fp.write(str(self.data['step'][-1])+'\n')
return True
# takes the max number of values, checks if data exceeds that value and in
# that case pops out the first (oldest) value of each voice in the dict
def PopDataValues(self,n):
gap = len(self.data['percent']) - n
if gap >= 0:
for x in range(gap+1):
for bookmark in self.data:
del self.data[bookmark][0]