Merge lp:~sforshee/powerd/autobrightness into lp:powerd
- autobrightness
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michael Frey |
Approved revision: | 99 |
Merged at revision: | 87 |
Proposed branch: | lp:~sforshee/powerd/autobrightness |
Merge into: | lp:powerd |
Diff against target: |
1762 lines (+1467/-17) 16 files modified
CMakeLists.txt (+13/-0) data/device_configs/config-default.xml (+69/-0) data/device_configs/config-grouper.xml (+75/-0) data/device_configs/config-maguro.xml (+88/-0) data/device_configs/config-mako.xml (+75/-0) data/device_configs/config-manta.xml (+74/-0) debian/control (+1/-0) src/autobrightness.c (+357/-0) src/device-config.c (+407/-0) src/device-config.h (+34/-0) src/display.c (+57/-16) src/powerd-internal.h (+9/-0) src/powerd-sensors.cpp (+31/-1) src/powerd.cpp (+9/-0) src/spline.c (+140/-0) src/spline.h (+28/-0) |
To merge this branch: | bzr merge lp:~sforshee/powerd/autobrightness |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Frey (community) | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+182729@code.launchpad.net |
Commit message
Add support for automatically adjusting the display backlight in response to ambient brightness
Description of the change
Add support for automatically adjusting the display backlight in response to ambient brightness
PS Jenkins bot (ps-jenkins) wrote : | # |
Michael Frey (mfrey) wrote : | # |
tested and works nicely.
Comment.
Please rename "android-config" to "device-config"
I don't think the config is tied to android.
Seth Forshee (sforshee) wrote : | # |
It _is_ using android config files to get the data, but it doesn't matter much to me. I have the name changed locally but can't build due to package dependency problems in my pbuilder, so I'll repush as soon as someone gets that fixed.
- 97. By Seth Forshee
-
s/android_
config/ device_ config/
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:97
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 98. By Seth Forshee
-
Use tuna config file for maguro
It turns out that in Android maguro has two device configuration
overlay files, one under device/samsung/ maguro and the other
under device/samsung/ tuna. The tuna file is common to all Galaxy
Nexus devices.For powerd's use the tuna file has all the information we really
care about, so just use that one for maguro.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:98
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 99. By Seth Forshee
-
Strip down device configurations
Remove all variables except those which powerd is already using
or is likely to use soon.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:99
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2013-08-09 19:53:58 +0000 |
3 | +++ CMakeLists.txt 2013-08-29 21:23:26 +0000 |
4 | @@ -33,11 +33,17 @@ |
5 | ) |
6 | SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/src/${POWERD_GENERATED_SOURCES} PROPERTIES GENERATED 1) |
7 | |
8 | +set(POWERD_DEVICE_CONFIGS_PATH "${CMAKE_INSTALL_PREFIX}/share/powerd/device_configs") |
9 | +FILE(GLOB device_config_files "${CMAKE_CURRENT_SOURCE_DIR}/data/device_configs/*.xml") |
10 | +add_definitions(-DPOWERD_DEVICE_CONFIGS_PATH=\"${POWERD_DEVICE_CONFIGS_PATH}\") |
11 | + |
12 | set( |
13 | SRCS |
14 | |
15 | src/powerd.cpp |
16 | + src/autobrightness.c |
17 | src/backlight.c |
18 | + src/device-config.c |
19 | src/display.c |
20 | src/display-request.c |
21 | src/log.c |
22 | @@ -46,6 +52,7 @@ |
23 | src/powerd-client.c |
24 | src/powerd-object.c |
25 | src/powerd-sensors.cpp |
26 | + src/spline.c |
27 | src/stats.c |
28 | src/util.c |
29 | src/${GDBUS_NAME}.c |
30 | @@ -104,6 +111,7 @@ |
31 | ${GIO-UNIX_LIBRARIES} |
32 | ${PHABLET_LIBRARIES} |
33 | "-lubuntu_application_api" |
34 | + "-landroid-properties" |
35 | ${LIBUDEV_LIBRARIES} |
36 | ${UPOWER_GLIB_LIBRARIES} |
37 | ${UUID_LIBRARIES} |
38 | @@ -115,3 +123,8 @@ |
39 | LIBRARY DESTINATION lib |
40 | ARCHIVE DESTINATION lib/static |
41 | ) |
42 | + |
43 | +install( |
44 | + FILES ${device_config_files} |
45 | + DESTINATION ${POWERD_DEVICE_CONFIGS_PATH} |
46 | +) |
47 | |
48 | === added directory 'data/device_configs' |
49 | === added file 'data/device_configs/config-default.xml' |
50 | --- data/device_configs/config-default.xml 1970-01-01 00:00:00 +0000 |
51 | +++ data/device_configs/config-default.xml 2013-08-29 21:23:26 +0000 |
52 | @@ -0,0 +1,69 @@ |
53 | +<?xml version="1.0" encoding="utf-8"?> |
54 | +<!-- |
55 | +/* |
56 | +** Copyright 2009, The Android Open Source Project |
57 | +** |
58 | +** Licensed under the Apache License, Version 2.0 (the "License"); |
59 | +** you may not use this file except in compliance with the License. |
60 | +** You may obtain a copy of the License at |
61 | +** |
62 | +** http://www.apache.org/licenses/LICENSE-2.0 |
63 | +** |
64 | +** Unless required by applicable law or agreed to in writing, software |
65 | +** distributed under the License is distributed on an "AS IS" BASIS, |
66 | +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
67 | +** See the License for the specific language governing permissions and |
68 | +** limitations under the License. |
69 | +*/ |
70 | +--> |
71 | + |
72 | +<!-- These resources are around just to allow their values to be customized |
73 | + for different hardware and product builds. Do not translate. --> |
74 | +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
75 | + <!-- Flag indicating whether the we should enable the automatic brightness in Settings. |
76 | + Software implementation will be used if config_hardware_auto_brightness_available is not set --> |
77 | + <bool name="config_automatic_brightness_available">false</bool> |
78 | + |
79 | + <!-- Display low battery warning when battery level dips to this value. |
80 | + Also, the battery stats are flushed to disk when we hit this level. --> |
81 | + <integer name="config_criticalBatteryWarningLevel">4</integer> |
82 | + |
83 | + <!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. --> |
84 | + <integer name="config_shutdownBatteryTemperature">680</integer> |
85 | + |
86 | + <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support. |
87 | + The N entries of this array define N + 1 control points as follows: |
88 | + (1-based arrays) |
89 | + |
90 | + Point 1: (0, value[1]): lux <= 0 |
91 | + Point 2: (level[1], value[2]): 0 < lux <= level[1] |
92 | + Point 3: (level[2], value[3]): level[2] < lux <= level[3] |
93 | + ... |
94 | + Point N+1: (level[N], value[N+1]): level[N] < lux |
95 | + |
96 | + The control points must be strictly increasing. Each control point |
97 | + corresponds to an entry in the brightness backlight values arrays. |
98 | + For example, if LUX == level[1] (first element of the levels array) |
99 | + then the brightness will be determined by value[2] (second element |
100 | + of the brightness values array). |
101 | + |
102 | + Spline interpolation is used to determine the auto-brightness |
103 | + backlight values for LUX levels between these control points. |
104 | + |
105 | + Must be overridden in platform specific overlays --> |
106 | + <integer-array name="config_autoBrightnessLevels"> |
107 | + </integer-array> |
108 | + |
109 | + <!-- Screen brightness used to dim the screen when the user activity |
110 | + timeout expires. May be less than the minimum allowed brightness setting |
111 | + that can be set by the user. --> |
112 | + <integer name="config_screenBrightnessDim">10</integer> |
113 | + |
114 | + <!-- Array of output values for LCD backlight corresponding to the LUX values |
115 | + in the config_autoBrightnessLevels array. This array should have size one greater |
116 | + than the size of the config_autoBrightnessLevels array. |
117 | + The brightness values must be between 0 and 255 and be non-decreasing. |
118 | + This must be overridden in platform specific overlays --> |
119 | + <integer-array name="config_autoBrightnessLcdBacklightValues"> |
120 | + </integer-array> |
121 | +</resources> |
122 | |
123 | === added file 'data/device_configs/config-grouper.xml' |
124 | --- data/device_configs/config-grouper.xml 1970-01-01 00:00:00 +0000 |
125 | +++ data/device_configs/config-grouper.xml 2013-08-29 21:23:26 +0000 |
126 | @@ -0,0 +1,75 @@ |
127 | +<?xml version="1.0" encoding="utf-8"?> |
128 | +<!-- |
129 | +/* |
130 | +** Copyright 2009, The Android Open Source Project |
131 | +** |
132 | +** Licensed under the Apache License, Version 2.0 (the "License"); |
133 | +** you may not use this file except in compliance with the License. |
134 | +** You may obtain a copy of the License at |
135 | +** |
136 | +** http://www.apache.org/licenses/LICENSE-2.0 |
137 | +** |
138 | +** Unless required by applicable law or agreed to in writing, software |
139 | +** distributed under the License is distributed on an "AS IS" BASIS, |
140 | +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
141 | +** See the License for the specific language governing permissions and |
142 | +** limitations under the License. |
143 | +*/ |
144 | +--> |
145 | + |
146 | +<!-- These resources are around just to allow their values to be customized |
147 | + for different hardware and product builds. --> |
148 | +<resources> |
149 | + <!-- Flag indicating whether the we should enable the automatic brightness in Settings. |
150 | + Software implementation will be used if config_hardware_auto_brightness_available is not set --> |
151 | + <bool name="config_automatic_brightness_available">true</bool> |
152 | + |
153 | + <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support. |
154 | + The N entries of this array define N 1 zones as follows: |
155 | + |
156 | + Zone 0: 0 <= LUX < array[0] |
157 | + Zone 1: array[0] <= LUX < array[1] |
158 | + ... |
159 | + Zone N: array[N - 1] <= LUX < array[N] |
160 | + Zone N + 1 array[N] <= LUX < infinity |
161 | + |
162 | + Must be overridden in platform specific overlays --> |
163 | + <integer-array name="config_autoBrightnessLevels"> |
164 | + <item>5</item> |
165 | + <item>15</item> |
166 | + <item>50</item> |
167 | + <item>100</item> |
168 | + <item>200</item> |
169 | + <item>400</item> |
170 | + <item>1000</item> |
171 | + <item>2000</item> |
172 | + <item>3000</item> |
173 | + <item>5000</item> |
174 | + <item>10000</item> |
175 | + <item>30000</item> |
176 | + </integer-array> |
177 | + |
178 | + |
179 | + <!-- Array of output values for LCD backlight corresponding to the LUX values |
180 | + in the config_autoBrightnessLevels array. This array should have size one greater |
181 | + than the size of the config_autoBrightnessLevels array. |
182 | + This must be overridden in platform specific overlays --> |
183 | + <integer-array name="config_autoBrightnessLcdBacklightValues"> |
184 | + <item>5</item> <!-- 0-5 --> |
185 | + <item>20</item> <!-- 5-15 --> |
186 | + <item>30</item> <!-- 15-50 --> |
187 | + <item>40</item> <!-- 50-100 --> |
188 | + <item>50</item> <!-- 100-200 --> |
189 | + <item>60</item> <!-- 200-400 --> |
190 | + <item>70</item> <!-- 400-1000 --> |
191 | + <item>80</item> <!-- 1000-2000 --> |
192 | + <item>130</item> <!-- 2000-3000 --> |
193 | + <item>180</item> <!-- 3000-5000 --> |
194 | + <item>255</item> <!-- 5000-10000 --> |
195 | + <item>255</item> <!-- 10000-30000 --> |
196 | + <item>255</item> <!-- 30000+ --> |
197 | + </integer-array> |
198 | + |
199 | + <!-- Minimum screen brightness allowed by the power manager. --> |
200 | + <integer name="config_screenBrightnessDim">5</integer> |
201 | +</resources> |
202 | |
203 | === added file 'data/device_configs/config-maguro.xml' |
204 | --- data/device_configs/config-maguro.xml 1970-01-01 00:00:00 +0000 |
205 | +++ data/device_configs/config-maguro.xml 2013-08-29 21:23:26 +0000 |
206 | @@ -0,0 +1,88 @@ |
207 | +<?xml version="1.0" encoding="utf-8"?> |
208 | +<!-- |
209 | +/* |
210 | +** Copyright 2011, The Android Open Source Project |
211 | +** |
212 | +** Licensed under the Apache License, Version 2.0 (the "License"); |
213 | +** you may not use this file except in compliance with the License. |
214 | +** You may obtain a copy of the License at |
215 | +** |
216 | +** http://www.apache.org/licenses/LICENSE-2.0 |
217 | +** |
218 | +** Unless required by applicable law or agreed to in writing, software |
219 | +** distributed under the License is distributed on an "AS IS" BASIS, |
220 | +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
221 | +** See the License for the specific language governing permissions and |
222 | +** limitations under the License. |
223 | +*/ |
224 | +--> |
225 | + |
226 | +<!-- These resources are around just to allow their values to be customized |
227 | + for different hardware and product builds. --> |
228 | +<resources> |
229 | + <!-- Flag indicating whether we should enable the automatic brightness in Settings. |
230 | + config_hardware_automatic_brightness_available is not set, so we will use software implementation --> |
231 | + <bool name="config_automatic_brightness_available">true</bool> |
232 | + |
233 | + <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support. |
234 | + The N entries of this array define N + 1 zones as follows: |
235 | + |
236 | + Zone 0: 0 <= LUX < array[0] |
237 | + Zone 1: array[0] <= LUX < array[1] |
238 | + ... |
239 | + Zone N: array[N - 1] <= LUX < array[N] |
240 | + Zone N + 1: array[N] <= LUX < infinity |
241 | + |
242 | + Must be overridden in platform specific overlays --> |
243 | + <integer-array name="config_autoBrightnessLevels"> |
244 | + <item>6</item> |
245 | + <item>9</item> |
246 | + <item>14</item> |
247 | + <item>20</item> |
248 | + <item>30</item> |
249 | + <item>46</item> |
250 | + <item>68</item> |
251 | + <item>103</item> |
252 | + <item>154</item> |
253 | + <item>231</item> |
254 | + <item>346</item> |
255 | + <item>519</item> |
256 | + <item>778</item> |
257 | + <item>1168</item> |
258 | + <item>1752</item> |
259 | + <item>2627</item> |
260 | + <item>3941</item> |
261 | + <item>5912</item> |
262 | + <item>8867</item> |
263 | + </integer-array> |
264 | + |
265 | + <!-- Array of output values for LCD backlight corresponding to the LUX values |
266 | + in the config_autoBrightnessLevels array. This array should have size one greater |
267 | + than the size of the config_autoBrightnessLevels array. |
268 | + --> |
269 | + <integer-array name="config_autoBrightnessLcdBacklightValues"> |
270 | + <item>19</item> |
271 | + <item>23</item> |
272 | + <item>26</item> |
273 | + <item>30</item> |
274 | + <item>34</item> |
275 | + <item>39</item> |
276 | + <item>45</item> |
277 | + <item>51</item> |
278 | + <item>59</item> |
279 | + <item>67</item> |
280 | + <item>77</item> |
281 | + <item>88</item> |
282 | + <item>101</item> |
283 | + <item>116</item> |
284 | + <item>133</item> |
285 | + <item>152</item> |
286 | + <item>174</item> |
287 | + <item>199</item> |
288 | + <item>228</item> |
289 | + <item>250</item> |
290 | + </integer-array> |
291 | + |
292 | + <!-- Minimum screen brightness allowed by the power manager. --> |
293 | + <integer name="config_screenBrightnessDim">10</integer> |
294 | +</resources> |
295 | |
296 | === added file 'data/device_configs/config-mako.xml' |
297 | --- data/device_configs/config-mako.xml 1970-01-01 00:00:00 +0000 |
298 | +++ data/device_configs/config-mako.xml 2013-08-29 21:23:26 +0000 |
299 | @@ -0,0 +1,75 @@ |
300 | +<?xml version="1.0" encoding="utf-8"?> |
301 | +<!-- |
302 | +/* |
303 | +** Copyright 2012, The Android Open Source Project |
304 | +** |
305 | +** Licensed under the Apache License, Version 2.0 (the "License"); |
306 | +** you may not use this file except in compliance with the License. |
307 | +** You may obtain a copy of the License at |
308 | +** |
309 | +** http://www.apache.org/licenses/LICENSE-2.0 |
310 | +** |
311 | +** Unless required by applicable law or agreed to in writing, software |
312 | +** distributed under the License is distributed on an "AS IS" BASIS, |
313 | +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
314 | +** See the License for the specific language governing permissions and |
315 | +** limitations under the License. |
316 | +*/ |
317 | +--> |
318 | + |
319 | +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
320 | + |
321 | + <!-- Flag indicating whether the we should enable the automatic brightness in Settings. |
322 | + Software implementation will be used if config_hardware_auto_brightness_available is not set --> |
323 | + <bool name="config_automatic_brightness_available">true</bool> |
324 | + |
325 | + <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support. |
326 | + The N entries of this array define N 1 zones as follows: |
327 | + |
328 | + Zone 0: 0 <= LUX < array[0] |
329 | + Zone 1: array[0] <= LUX < array[1] |
330 | + ... |
331 | + Zone N: array[N - 1] <= LUX < array[N] |
332 | + Zone N + 1 array[N] <= LUX < infinity |
333 | + |
334 | + Must be overridden in platform specific overlays --> |
335 | + <integer-array name="config_autoBrightnessLevels"> |
336 | + <item>10</item> |
337 | + <item>50</item> |
338 | + <item>100</item> |
339 | + <item>200</item> |
340 | + <item>400</item> |
341 | + <item>500</item> |
342 | + <item>800</item> |
343 | + <item>1000</item> |
344 | + <item>1600</item> |
345 | + <item>3000</item> |
346 | + <item>10000</item> |
347 | + </integer-array> |
348 | + |
349 | + <!-- Array of output values for LCD backlight corresponding to the LUX values |
350 | + in the config_autoBrightnessLevels array. This array should have size one greater |
351 | + than the size of the config_autoBrightnessLevels array. |
352 | + This must be overridden in platform specific overlays --> |
353 | + <integer-array name="config_autoBrightnessLcdBacklightValues"> |
354 | + <item>14</item> <!-- 0-10 --> |
355 | + <item>28</item> <!-- 10-50 --> |
356 | + <item>37</item> <!-- 50-100 --> |
357 | + <item>51</item> <!-- 100-200 --> |
358 | + <item>71</item> <!-- 200-400 --> |
359 | + <item>80</item> <!-- 400-500 --> |
360 | + <item>96</item> <!-- 500-800 --> |
361 | + <item>108</item> <!-- 800-1000 --> |
362 | + <item>144</item> <!-- 1000-1600 --> |
363 | + <item>181</item> <!-- 1600-3000 --> |
364 | + <item>254</item> <!-- 3000-10000 --> |
365 | + <item>255</item> <!-- 10000+ --> |
366 | + </integer-array> |
367 | + |
368 | + <!-- Minimum screen brightness allowed by the power manager. --> |
369 | + <integer name="config_screenBrightnessDim">1</integer> |
370 | + |
371 | + <!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. --> |
372 | + <integer name="config_shutdownBatteryTemperature">600</integer> |
373 | + |
374 | +</resources> |
375 | |
376 | === added file 'data/device_configs/config-manta.xml' |
377 | --- data/device_configs/config-manta.xml 1970-01-01 00:00:00 +0000 |
378 | +++ data/device_configs/config-manta.xml 2013-08-29 21:23:26 +0000 |
379 | @@ -0,0 +1,74 @@ |
380 | +<?xml version="1.0" encoding="utf-8"?> |
381 | +<!-- |
382 | +/* |
383 | +** Copyright 2009, The Android Open Source Project |
384 | +** |
385 | +** Licensed under the Apache License, Version 2.0 (the "License"); |
386 | +** you may not use this file except in compliance with the License. |
387 | +** You may obtain a copy of the License at |
388 | +** |
389 | +** http://www.apache.org/licenses/LICENSE-2.0 |
390 | +** |
391 | +** Unless required by applicable law or agreed to in writing, software |
392 | +** distributed under the License is distributed on an "AS IS" BASIS, |
393 | +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
394 | +** See the License for the specific language governing permissions and |
395 | +** limitations under the License. |
396 | +*/ |
397 | +--> |
398 | + |
399 | +<!-- These resources are around just to allow their values to be customized |
400 | + for different hardware and product builds. --> |
401 | +<resources> |
402 | + <!-- Flag indicating whether we should enable the automatic brightness in Settings. |
403 | + config_hardware_automatic_brightness_available is not set, so we will use software implementation --> |
404 | + <bool name="config_automatic_brightness_available">true</bool> |
405 | + |
406 | + <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support. |
407 | + The N entries of this array define N + 1 control points as follows: |
408 | + (1-based arrays) |
409 | + |
410 | + Point 1: (0, value[1]): lux <= 0 |
411 | + Point 2: (level[1], value[2]): 0 < lux <= level[1] |
412 | + Point 3: (level[2], value[3]): level[2] < lux <= level[3] |
413 | + ... |
414 | + Point N+1: (level[N], value[N+1]): level[N] < lux |
415 | + |
416 | + The control points must be strictly increasing. Each control point |
417 | + corresponds to an entry in the brightness backlight values arrays. |
418 | + For example, if LUX == level[1] (first element of the levels array) |
419 | + then the brightness will be determined by value[2] (second element |
420 | + of the brightness values array). |
421 | + |
422 | + Spline interpolation is used to determine the auto-brightness |
423 | + backlight values for LUX levels between these control points. |
424 | + |
425 | + Must be overridden in platform specific overlays --> |
426 | + <integer-array name="config_autoBrightnessLevels"> |
427 | + <item>10</item> <!-- Pitch black 0, and 9 is next possible value. --> |
428 | + <item>30</item> <!-- Sensor in dark office: 60, well lit: 220 --> |
429 | + <item>90</item> <!-- Sensor in dark office: 60, well lit: 220 --> |
430 | + <item>15000</item> <!-- Screen under direct sunlight, but not sensor. --> |
431 | + <item>225000</item> <!-- Sensor under direct sunlight. --> |
432 | + </integer-array> |
433 | + |
434 | + <!-- Array of output values for LCD backlight corresponding to the LUX values |
435 | + in the config_autoBrightnessLevels array. This array should have size one greater |
436 | + than the size of the config_autoBrightnessLevels array. |
437 | + The brightness values must be between 0 and 255 and be non-decreasing. |
438 | + This must be overridden in platform specific overlays --> |
439 | + <integer-array name="config_autoBrightnessLcdBacklightValues"> |
440 | + <item>10</item> |
441 | + <item>13</item> |
442 | + <item>65</item> |
443 | + <item>85</item> |
444 | + <item>220</item> |
445 | + <item>255</item> |
446 | + </integer-array> |
447 | + |
448 | + <!-- Screen brightness used to dim the screen when the user activity |
449 | + timeout expires. May be less than the minimum allowed brightness setting |
450 | + that can be set by the user. --> |
451 | + <integer name="config_screenBrightnessDim">2</integer> |
452 | + |
453 | +</resources> |
454 | |
455 | === modified file 'debian/control' |
456 | --- debian/control 2013-08-03 08:21:09 +0000 |
457 | +++ debian/control 2013-08-29 21:23:26 +0000 |
458 | @@ -8,6 +8,7 @@ |
459 | libhybris-dev, |
460 | libudev-dev, |
461 | python, |
462 | + libandroid-properties-dev, |
463 | libplatform-api1-dev, |
464 | libupower-glib-dev, |
465 | uuid-dev, |
466 | |
467 | === added file 'src/autobrightness.c' |
468 | --- src/autobrightness.c 1970-01-01 00:00:00 +0000 |
469 | +++ src/autobrightness.c 2013-08-29 21:23:26 +0000 |
470 | @@ -0,0 +1,357 @@ |
471 | +/* |
472 | + * Copyright 2013 Canonical Ltd. |
473 | + * |
474 | + * This file is part of powerd. |
475 | + * |
476 | + * powerd is free software; you can redistribute it and/or modify |
477 | + * it under the terms of the GNU General Public License as published by |
478 | + * the Free Software Foundation; version 3. |
479 | + * |
480 | + * powerd is distributed in the hope that it will be useful, |
481 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
482 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
483 | + * GNU General Public License for more details. |
484 | + * |
485 | + * You should have received a copy of the GNU General Public License |
486 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
487 | + */ |
488 | + |
489 | +#include <stdlib.h> |
490 | +#include <errno.h> |
491 | +#include <math.h> |
492 | +#include <glib.h> |
493 | + |
494 | +#include "powerd-internal.h" |
495 | +#include "device-config.h" |
496 | +#include "log.h" |
497 | +#include "spline.h" |
498 | + |
499 | +/* |
500 | + * Autobrightness Control Algorithm |
501 | + * |
502 | + * Automatic backlight adjustments should respond quickly to changes in |
503 | + * the ambient brightness without constantly adjusting for minor or |
504 | + * transient changes in ambient brightness. The following mechanisms are |
505 | + * employed to maintain this balance. |
506 | + * |
507 | + * EXPONENTIAL SMOOTHING |
508 | + * |
509 | + * Rather than processing incoming lux values directly, an exponential |
510 | + * moving average is calculated using an algorithm based off of the |
511 | + * formulation known as "Brown's simple exponential smoothing" [1]: |
512 | + * |
513 | + * S(n) = a * x(n) + (1 - a) * S(n - 1) |
514 | + * = S(n - 1) + a * (x(n) - S(n - 1)) |
515 | + * |
516 | + * where 0 <= a <= 1. To make smoothing time-based, a is calculated |
517 | + * based on the amount of time spent at a given lux value. |
518 | + * |
519 | + * delta_t = t(n) - t(n - 1) |
520 | + * a(n) = delta_t / (C + delta_t) |
521 | + * |
522 | + * This gives decreasing weight to older samples. Smaller values of C |
523 | + * will cause faster decay of old samples, giving a faster response |
524 | + * time, while larger values of C create slower decay and give more |
525 | + * filtering of transient events. |
526 | + * |
527 | + * This code usese two moving averages, one which responds slowly to |
528 | + * changes and another which responds quickly. The slow average is used |
529 | + * to detect the trend with less sensitivity to transient events, while |
530 | + * the fast average is used for picking the brightness once we've |
531 | + * decided to change it. |
532 | + * |
533 | + * HYSTERESIS |
534 | + * |
535 | + * To avoid making constant adjustments to screen brightness in response |
536 | + * to small changes in ambient lighting conditions, the change in lux is |
537 | + * required to exceed some threshold before changing screen brightness. |
538 | + * |
539 | + * DEBOUNCING |
540 | + * |
541 | + * Changes in ambient brightness which exceed the hysteresis threshold |
542 | + * must do so for some minimum amount of time before any changes in |
543 | + * screen brightness will be made. This "debounces" the incoming lux |
544 | + * values and also helps to filter out transient changes in ambient |
545 | + * conditions. |
546 | + * |
547 | + * [1] http://en.wikipedia.org/wiki/Exponential_smoothing |
548 | + */ |
549 | + |
550 | +#define SMOOTHING_FACTOR_SLOW 2000.0f |
551 | +#define SMOOTHING_FACTOR_FAST 200.0f |
552 | +#define HYSTERESIS_FACTOR 0.10f |
553 | +#define DEBOUNCE_MS 4000 |
554 | + |
555 | +enum ab_state { |
556 | + AB_STATE_DISABLED, |
557 | + AB_STATE_INITIALIZING, |
558 | + AB_STATE_IDLE, /* Idle, nothing to do */ |
559 | + AB_STATE_DEBOUNCE, /* Debouncing lux change */ |
560 | +}; |
561 | + |
562 | +struct ab_status { |
563 | + enum ab_state state; |
564 | + guint source_id; |
565 | + double last_lux, applied_lux; |
566 | + double average_slow, average_fast; |
567 | + gint64 last_lux_ms; |
568 | + struct ab_spline *spline; |
569 | +}; |
570 | + |
571 | +static gboolean ab_supported = FALSE; |
572 | +static struct ab_status ab_status; |
573 | +struct spline *ab_spline; |
574 | + |
575 | +static gint64 get_ms(void) |
576 | +{ |
577 | + return g_get_monotonic_time() / 1000; |
578 | +} |
579 | + |
580 | +static double aggregate_lux(double old_average, double new_lux, |
581 | + double smoothing_factor, double time_delta) |
582 | +{ |
583 | + double alpha; |
584 | + if (time_delta < 0.0f) |
585 | + time_delta = 0.0f; |
586 | + alpha = time_delta / (smoothing_factor + time_delta); |
587 | + return old_average + alpha * (new_lux - old_average); |
588 | +} |
589 | + |
590 | +static enum ab_state process_state_debounce(guint *delay_ms) |
591 | +{ |
592 | + gint64 now; |
593 | + double time_delta; |
594 | + double slow_lux, fast_lux; |
595 | + double hysteresis, slow_delta, fast_delta; |
596 | + enum ab_state next; |
597 | + |
598 | + next = AB_STATE_IDLE; |
599 | + *delay_ms = 0; |
600 | + |
601 | + now = get_ms(); |
602 | + time_delta = (double)(now - ab_status.last_lux_ms); |
603 | + slow_lux = aggregate_lux(ab_status.average_slow, ab_status.last_lux, |
604 | + SMOOTHING_FACTOR_SLOW, time_delta); |
605 | + fast_lux = aggregate_lux(ab_status.average_fast, ab_status.last_lux, |
606 | + SMOOTHING_FACTOR_FAST, time_delta); |
607 | + powerd_debug("%lld slow avg %f fast avg %f last %f", |
608 | + now, slow_lux, fast_lux, ab_status.last_lux); |
609 | + |
610 | + /* |
611 | + * Require that both slow and fast averages exceed hysteresis, |
612 | + * and in the same direction. |
613 | + */ |
614 | + hysteresis = ab_status.applied_lux * HYSTERESIS_FACTOR; |
615 | + if (hysteresis < 2) |
616 | + hysteresis = 2; |
617 | + slow_delta = slow_lux - ab_status.applied_lux; |
618 | + fast_delta = fast_lux - ab_status.applied_lux; |
619 | + if ((slow_delta >= hysteresis && fast_delta >= hysteresis) || |
620 | + (-slow_delta >= hysteresis && -fast_delta >= hysteresis)) { |
621 | + int brightness = (int)(spline_interpolate(ab_spline, fast_lux) + 0.5); |
622 | + powerd_debug("set brightness %d", brightness); |
623 | + powerd_set_brightness(brightness); |
624 | + ab_status.applied_lux = fast_lux; |
625 | + } |
626 | + |
627 | + hysteresis = ab_status.last_lux * HYSTERESIS_FACTOR; |
628 | + if (hysteresis < 2) |
629 | + hysteresis = 2; |
630 | + if (fabs(fast_lux - ab_status.last_lux) >= hysteresis) { |
631 | + /* |
632 | + * Average should settle near the last reported lux. If |
633 | + * it hasn't made it there yet, continue debouncing. |
634 | + */ |
635 | + next = AB_STATE_DEBOUNCE; |
636 | + *delay_ms = DEBOUNCE_MS; |
637 | + } |
638 | + |
639 | + return next; |
640 | +} |
641 | + |
642 | +static gboolean ab_process(gpointer unused) |
643 | +{ |
644 | + guint delay = 0; |
645 | + |
646 | + ab_status.source_id = 0; |
647 | + |
648 | + switch (ab_status.state) { |
649 | + case AB_STATE_DISABLED: |
650 | + case AB_STATE_INITIALIZING: |
651 | + case AB_STATE_IDLE: |
652 | + /* Nothing to do */ |
653 | + break; |
654 | + case AB_STATE_DEBOUNCE: |
655 | + ab_status.state = process_state_debounce(&delay); |
656 | + break; |
657 | + default: |
658 | + powerd_warn("Unexpected autobrightness state %d\n", ab_status.state); |
659 | + ab_status.state = AB_STATE_IDLE; |
660 | + break; |
661 | + } |
662 | + |
663 | + if (delay != 0 && ab_status.state != AB_STATE_IDLE) |
664 | + ab_status.source_id = g_timeout_add(delay, ab_process, NULL); |
665 | + return FALSE; |
666 | +} |
667 | + |
668 | +static gboolean handle_new_lux(gpointer data) |
669 | +{ |
670 | + gint64 now; |
671 | + double lux; |
672 | + |
673 | + if (!ab_supported) |
674 | + return FALSE; |
675 | + |
676 | + now = get_ms(); |
677 | + lux = *(double *)data; |
678 | + g_free(data); |
679 | + |
680 | + if (ab_status.state == AB_STATE_DISABLED) |
681 | + return FALSE; |
682 | + |
683 | + if (ab_status.state == AB_STATE_INITIALIZING) { |
684 | + int brightness = (int)(spline_interpolate(ab_spline, lux) + 0.5); |
685 | + powerd_debug("set brightness %d", brightness); |
686 | + powerd_set_brightness(brightness); |
687 | + |
688 | + ab_status.average_slow = lux; |
689 | + ab_status.average_fast = lux; |
690 | + ab_status.applied_lux = lux; |
691 | + ab_status.state = AB_STATE_IDLE; |
692 | + } else { |
693 | + double time_delta; |
694 | + /* Ignore duplicates */ |
695 | + if (lux == ab_status.last_lux) |
696 | + return FALSE; |
697 | + time_delta = (double)(now - ab_status.last_lux_ms); |
698 | + ab_status.average_slow = aggregate_lux(ab_status.average_slow, lux, |
699 | + SMOOTHING_FACTOR_SLOW, |
700 | + time_delta); |
701 | + ab_status.average_fast = aggregate_lux(ab_status.average_fast, lux, |
702 | + SMOOTHING_FACTOR_FAST, |
703 | + time_delta); |
704 | + } |
705 | + ab_status.last_lux = lux; |
706 | + ab_status.last_lux_ms = now; |
707 | + |
708 | + if (ab_status.state == AB_STATE_IDLE) { |
709 | + ab_status.state = AB_STATE_DEBOUNCE; |
710 | + ab_status.source_id = g_timeout_add(DEBOUNCE_MS, ab_process, NULL); |
711 | + } |
712 | + |
713 | + return FALSE; |
714 | +} |
715 | + |
716 | +void powerd_new_als_event(double lux) |
717 | +{ |
718 | + double *p_lux = g_memdup(&lux, sizeof(lux)); |
719 | + g_timeout_add(0, handle_new_lux, p_lux); |
720 | +} |
721 | + |
722 | +/* Must be run from main loop */ |
723 | +void powerd_autobrightness_enable(void) |
724 | +{ |
725 | + /* Must not leave disabled state if we can't map lux to brightness */ |
726 | + if (!ab_supported) |
727 | + return; |
728 | + |
729 | + if (ab_status.state == AB_STATE_DISABLED) { |
730 | + ab_status.state = AB_STATE_INITIALIZING; |
731 | + powerd_sensors_als_enable(); |
732 | + } |
733 | +} |
734 | + |
735 | +/* Must be run from main loop */ |
736 | +void powerd_autobrightness_disable(void) |
737 | +{ |
738 | + if (ab_status.state != AB_STATE_DISABLED) { |
739 | + ab_status.state = AB_STATE_DISABLED; |
740 | + powerd_sensors_als_disable(); |
741 | + if (ab_status.source_id != 0) |
742 | + g_source_remove(ab_status.source_id); |
743 | + } |
744 | +} |
745 | + |
746 | +int powerd_autobrightness_init(void) |
747 | +{ |
748 | + GValue v = G_VALUE_INIT; |
749 | + GArray *levels = NULL, *lux = NULL; |
750 | + double (*mappings)[2] = NULL; |
751 | + int i; |
752 | + int ret = -ENODEV; |
753 | + |
754 | + if (device_config_get("automatic_brightness_available", &v)) { |
755 | + powerd_info("Could not determine platform autobrightness capability, disabling"); |
756 | + goto error; |
757 | + } |
758 | + |
759 | + if (!G_VALUE_HOLDS_BOOLEAN(&v) || !g_value_get_boolean(&v)) { |
760 | + powerd_info("Platform does not support autobrightness, disabling"); |
761 | + goto error; |
762 | + } |
763 | + g_value_unset(&v); |
764 | + |
765 | + if (device_config_get("autoBrightnessLevels", &v)) { |
766 | + powerd_info("No device-specific autobrightness lux table defined, disabling"); |
767 | + goto error; |
768 | + } |
769 | + if (G_VALUE_HOLDS_BOXED(&v)) |
770 | + lux = g_value_dup_boxed(&v); |
771 | + g_value_unset(&v); |
772 | + if (!lux || lux->len == 0) { |
773 | + powerd_info("Invalid autobrighness lux levels, disabling"); |
774 | + goto error; |
775 | + } |
776 | + |
777 | + if (device_config_get("autoBrightnessLcdBacklightValues", &v)) { |
778 | + powerd_info("No device-specific autobrightness backlight levels defined, disabling"); |
779 | + goto error; |
780 | + } |
781 | + if (G_VALUE_HOLDS_BOXED(&v)) |
782 | + levels = g_value_dup_boxed(&v); |
783 | + g_value_unset(&v); |
784 | + if (!levels || levels->len == 0) { |
785 | + powerd_info("Invalid autobrighness backlight levels, disabling"); |
786 | + goto error; |
787 | + } |
788 | + |
789 | + /* We should have one more backlight level than lux values */ |
790 | + if (levels->len != lux->len + 1) { |
791 | + powerd_info("Invalid lux->brightness mappings, autobrightness disabled"); |
792 | + goto error; |
793 | + } |
794 | + |
795 | + mappings = g_malloc(2 * sizeof(double) * levels->len); |
796 | + for (i = 0; i < levels->len; i++) { |
797 | + mappings[i][0] = (double)((i == 0) ? 0 : g_array_index(lux, guint, i-1)); |
798 | + mappings[i][1] = (double)g_array_index(levels, guint, i); |
799 | + } |
800 | + |
801 | + ab_status.state = AB_STATE_DISABLED; |
802 | + ab_spline = spline_new(mappings, levels->len); |
803 | + if (!ab_spline) { |
804 | + ret = -ENOMEM; |
805 | + goto error; |
806 | + } |
807 | + g_free(mappings); |
808 | + ab_supported = TRUE; |
809 | + return 0; |
810 | + |
811 | +error: |
812 | + if (levels) |
813 | + g_array_unref(levels); |
814 | + if (lux) |
815 | + g_array_unref(lux); |
816 | + if (mappings) |
817 | + g_free(mappings); |
818 | + return ret; |
819 | +} |
820 | + |
821 | +void powerd_autobrightness_deinit(void) |
822 | +{ |
823 | + powerd_autobrightness_disable(); |
824 | + ab_supported = FALSE; |
825 | + if (ab_spline) |
826 | + spline_free(ab_spline); |
827 | +} |
828 | |
829 | === added file 'src/device-config.c' |
830 | --- src/device-config.c 1970-01-01 00:00:00 +0000 |
831 | +++ src/device-config.c 2013-08-29 21:23:26 +0000 |
832 | @@ -0,0 +1,407 @@ |
833 | +/* |
834 | + * Copyright 2013 Canonical Ltd. |
835 | + * |
836 | + * This file is part of powerd. |
837 | + * |
838 | + * powerd is free software; you can redistribute it and/or modify |
839 | + * it under the terms of the GNU General Public License as published by |
840 | + * the Free Software Foundation; version 3. |
841 | + * |
842 | + * powerd is distributed in the hope that it will be useful, |
843 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
844 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
845 | + * GNU General Public License for more details. |
846 | + * |
847 | + * You should have received a copy of the GNU General Public License |
848 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
849 | + */ |
850 | + |
851 | +#include <stdlib.h> |
852 | +#include <string.h> |
853 | +#include <errno.h> |
854 | +#include <sys/types.h> |
855 | +#include <sys/stat.h> |
856 | +#include <fcntl.h> |
857 | +#include <unistd.h> |
858 | + |
859 | +#include <glib.h> |
860 | +#include <glib-object.h> |
861 | +#include <hybris/properties/properties.h> |
862 | + |
863 | +#include "powerd-internal.h" |
864 | +#include "device-config.h" |
865 | +#include "log.h" |
866 | + |
867 | +/* |
868 | + * Android defines various device-specific parameters in files named |
869 | + * config.xml. The general structure of the tags is: |
870 | + * |
871 | + * <type name="config_foo">...</type> |
872 | + * |
873 | + * This will define a config option named "foo" of type "type". Types |
874 | + * for arrays are included. For example, the following defines an |
875 | + * array of integers: |
876 | + * |
877 | + * <integer-array name="config_myIntArray"> |
878 | + * <item>0</item> |
879 | + * <item>1</item> |
880 | + * </integer-array> |
881 | + * |
882 | + * In powerd we are only interested in a few specific variables. The |
883 | + * code here offers fairly general parsing of the config files, but |
884 | + * handling of only a few specific types is present. |
885 | + */ |
886 | + |
887 | +enum elem_type { |
888 | + ELEM_TYPE_NONE, |
889 | + ELEM_TYPE_BOOL, |
890 | + ELEM_TYPE_INT, |
891 | + ELEM_TYPE_STRING, |
892 | + ELEM_TYPE_FRACTION, |
893 | + ELEM_TYPE_DIMENSION, |
894 | + ELEM_TYPE_INT_ARRAY, |
895 | + ELEM_TYPE_STRING_ARRAY, |
896 | + ELEM_TYPE_ITEM, |
897 | + |
898 | + NUM_ELEM_TYPES |
899 | +}; |
900 | + |
901 | +static const char *elem_strs[NUM_ELEM_TYPES] = { |
902 | + [ELEM_TYPE_BOOL] = "bool", |
903 | + [ELEM_TYPE_INT] = "integer", |
904 | + [ELEM_TYPE_STRING] = "string", |
905 | + [ELEM_TYPE_FRACTION] = "fraction", |
906 | + [ELEM_TYPE_DIMENSION] = "dimen", |
907 | + [ELEM_TYPE_INT_ARRAY] = "integer-array", |
908 | + [ELEM_TYPE_STRING_ARRAY] = "string-array", |
909 | + [ELEM_TYPE_ITEM] = "item", |
910 | +}; |
911 | + |
912 | +struct parser_state { |
913 | + enum elem_type type; |
914 | + gboolean in_item; |
915 | + gchar *name; |
916 | + GValue value; |
917 | +}; |
918 | + |
919 | +static struct parser_state state = { |
920 | + .value = G_VALUE_INIT, |
921 | +}; |
922 | +static GHashTable *config_hash; |
923 | + |
924 | +static enum elem_type get_elem_type(const gchar *name) |
925 | +{ |
926 | + int i; |
927 | + for (i = 0; i < NUM_ELEM_TYPES; i++) { |
928 | + if (elem_strs[i] && !strcmp(name, elem_strs[i])) |
929 | + break; |
930 | + } |
931 | + if (i >= NUM_ELEM_TYPES) |
932 | + return ELEM_TYPE_NONE; |
933 | + return i; |
934 | +} |
935 | + |
936 | +static const gchar *get_elem_name(const gchar **attr_names, |
937 | + const gchar **attr_values) |
938 | +{ |
939 | + int i; |
940 | + for (i = 0; attr_names[i]; i++) { |
941 | + if (!strcmp(attr_names[i], "name")) |
942 | + break; |
943 | + } |
944 | + if (!attr_names[i]) |
945 | + return NULL; |
946 | + return attr_values[i]; |
947 | +} |
948 | + |
949 | +static void on_start_elem(GMarkupParseContext *context, const gchar *name, |
950 | + const gchar **attr_names, const gchar **attr_values, |
951 | + gpointer user_data, GError **error) |
952 | +{ |
953 | + const gchar *config_name; |
954 | + enum elem_type type; |
955 | + |
956 | + type = get_elem_type(name); |
957 | + if (type == ELEM_TYPE_NONE) |
958 | + return; |
959 | + if (type == ELEM_TYPE_ITEM) { |
960 | + if (state.type == ELEM_TYPE_INT_ARRAY || |
961 | + state.type == ELEM_TYPE_STRING_ARRAY) |
962 | + state.in_item = TRUE; |
963 | + return; |
964 | + } |
965 | + if (state.type != ELEM_TYPE_NONE) { |
966 | + g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, |
967 | + "Nested elements not supported"); |
968 | + return; |
969 | + } |
970 | + |
971 | + config_name = get_elem_name(attr_names, attr_values); |
972 | + if (!config_name) |
973 | + return; |
974 | + /* Strip leading "config_" if present, not all vars have it */ |
975 | + if (!strncmp(config_name, "config_", 7)) |
976 | + config_name += 7; |
977 | + |
978 | + switch (type) { |
979 | + case ELEM_TYPE_BOOL: |
980 | + g_value_init(&state.value, G_TYPE_BOOLEAN); |
981 | + break; |
982 | + case ELEM_TYPE_INT: |
983 | + g_value_init(&state.value, G_TYPE_UINT); |
984 | + break; |
985 | + case ELEM_TYPE_INT_ARRAY: |
986 | + { |
987 | + GArray *a; |
988 | + g_value_init(&state.value, G_TYPE_ARRAY); |
989 | + a = g_array_new(FALSE, FALSE, sizeof(guint32)); |
990 | + g_value_set_boxed(&state.value, a); |
991 | + break; |
992 | + } |
993 | + default: |
994 | + /* Type not supported at this time */ |
995 | + return; |
996 | + } |
997 | + |
998 | + state.type = type; |
999 | + state.in_item = FALSE; |
1000 | + state.name = g_strdup(config_name); |
1001 | +} |
1002 | + |
1003 | +static void on_end_elem(GMarkupParseContext *context, const gchar *name, |
1004 | + gpointer user_data, GError **error) |
1005 | +{ |
1006 | + enum elem_type type; |
1007 | + GValue *value; |
1008 | + |
1009 | + if (state.type == ELEM_TYPE_NONE) |
1010 | + return; |
1011 | + |
1012 | + type = get_elem_type(name); |
1013 | + if (type == ELEM_TYPE_NONE) |
1014 | + return; |
1015 | + if (type == ELEM_TYPE_ITEM) { |
1016 | + state.in_item = FALSE; |
1017 | + return; |
1018 | + } |
1019 | + |
1020 | + if (type == state.type) { |
1021 | + value = g_new0(GValue, 1); |
1022 | + g_value_init(value, G_VALUE_TYPE(&state.value)); |
1023 | + g_value_copy(&state.value, value); |
1024 | + g_hash_table_replace(config_hash, state.name, value); |
1025 | + /* Note: state.name is not freed as it is used for hash table key */ |
1026 | + } else { |
1027 | + g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, |
1028 | + "Start and end element types don't match"); |
1029 | + g_free(state.name); |
1030 | + } |
1031 | + |
1032 | + state.type = ELEM_TYPE_NONE; |
1033 | + state.name = NULL; |
1034 | + g_value_unset(&state.value); |
1035 | +} |
1036 | + |
1037 | +/* WARNING: pt_text is not nul-terminated */ |
1038 | +static void on_text(GMarkupParseContext *context, const gchar *pt_text, |
1039 | + gsize text_len, gpointer user_data, GError **error) |
1040 | +{ |
1041 | + gchar *text = g_strndup(pt_text, text_len); |
1042 | + switch (state.type) { |
1043 | + case ELEM_TYPE_BOOL: |
1044 | + { |
1045 | + gboolean value; |
1046 | + if (!G_VALUE_HOLDS_BOOLEAN(&state.value)) { |
1047 | + g_warning("Incorrect GValue type"); |
1048 | + break; |
1049 | + } |
1050 | + value = !g_ascii_strcasecmp(text, "true"); |
1051 | + g_value_set_boolean(&state.value, value); |
1052 | + break; |
1053 | + } |
1054 | + case ELEM_TYPE_INT: |
1055 | + { |
1056 | + guint value; |
1057 | + gchar *endp; |
1058 | + if (!G_VALUE_HOLDS_UINT(&state.value)) { |
1059 | + g_warning("Incorrect GValue type"); |
1060 | + break; |
1061 | + } |
1062 | + value = (guint)g_ascii_strtoll(text, &endp, 0); |
1063 | + if (endp - text == text_len) |
1064 | + g_value_set_uint(&state.value, value); |
1065 | + break; |
1066 | + } |
1067 | + case ELEM_TYPE_INT_ARRAY: |
1068 | + { |
1069 | + GArray *a; |
1070 | + guint value; |
1071 | + gchar *endp; |
1072 | + if (!state.in_item) |
1073 | + break; |
1074 | + if (!G_VALUE_HOLDS_BOXED(&state.value)) { |
1075 | + g_warning("Incorrect GValue type"); |
1076 | + break; |
1077 | + } |
1078 | + value = (guint)g_ascii_strtoll(text, &endp, 0); |
1079 | + if (endp - text == text_len) { |
1080 | + a = g_value_get_boxed(&state.value); |
1081 | + g_array_append_val(a, value); |
1082 | + } |
1083 | + } |
1084 | + break; |
1085 | + default: |
1086 | + break; |
1087 | + } |
1088 | + g_free(text); |
1089 | +} |
1090 | + |
1091 | +static GMarkupParser parser = { |
1092 | + .start_element = on_start_elem, |
1093 | + .end_element = on_end_elem, |
1094 | + .text = on_text, |
1095 | +}; |
1096 | + |
1097 | +static void config_hash_destroy_key(gpointer data) |
1098 | +{ |
1099 | + g_free(data); |
1100 | +} |
1101 | + |
1102 | +static void config_hash_destroy_value(gpointer data) |
1103 | +{ |
1104 | + GValue *v = data; |
1105 | + if (G_VALUE_HOLDS_BOXED(v)) { |
1106 | + /* Currently only boxed data is arrays */ |
1107 | + GArray *a = g_value_get_boxed(v); |
1108 | + g_array_free(a, TRUE); |
1109 | + } |
1110 | + g_value_unset(v); |
1111 | + g_free(v); |
1112 | +} |
1113 | + |
1114 | +static int process_config(const char *fname) |
1115 | +{ |
1116 | + int fd, ret = 0; |
1117 | + gchar *buf = NULL; |
1118 | + int buf_len; |
1119 | + ssize_t len; |
1120 | + GMarkupParseContext *context = NULL; |
1121 | + GError *error; |
1122 | + |
1123 | + fd = open(fname, O_RDONLY); |
1124 | + if (fd == -1) { |
1125 | + powerd_warn("Could not open device config %s: %s", |
1126 | + fname, strerror(errno)); |
1127 | + return -errno; |
1128 | + } |
1129 | + |
1130 | + buf_len = (int)sysconf(_SC_PAGESIZE); |
1131 | + buf = malloc(buf_len); |
1132 | + if (!buf) { |
1133 | + ret = -ENOMEM; |
1134 | + goto out; |
1135 | + } |
1136 | + |
1137 | + context = g_markup_parse_context_new(&parser, 0, NULL, NULL); |
1138 | + do { |
1139 | + len = read(fd, buf, buf_len); |
1140 | + if (len == 0) |
1141 | + break; |
1142 | + if (len == -1) { |
1143 | + if (errno == EINTR) |
1144 | + continue; |
1145 | + powerd_warn("Error reading %s: %s", fname, strerror(errno)); |
1146 | + ret = -errno; |
1147 | + break; |
1148 | + } |
1149 | + |
1150 | + error = NULL; |
1151 | + if (!g_markup_parse_context_parse(context, buf, len, &error)) { |
1152 | + powerd_warn("Failed parsing device config %s\n", fname); |
1153 | + if (error) { |
1154 | + powerd_warn("%s", error->message); |
1155 | + g_error_free(error); |
1156 | + } |
1157 | + ret = -EIO; |
1158 | + } |
1159 | + } while (!ret); |
1160 | + |
1161 | +out: |
1162 | + if (context) |
1163 | + g_markup_parse_context_free(context); |
1164 | + if (buf) |
1165 | + free(buf); |
1166 | + close(fd); |
1167 | + return ret; |
1168 | +} |
1169 | + |
1170 | +/* |
1171 | + * Get the device config option specified by @name. The leading |
1172 | + * "config_" characters should be stripped from the name if present. |
1173 | + * Returns 0 if the given variable is found. |
1174 | + * |
1175 | + * @value should be an initialized GValue. On success, the value of |
1176 | + * the variable will be copied to the GValue, and the caller is |
1177 | + * responsible for freeing the memory. E.g.: |
1178 | + * |
1179 | + * GValue v = G_VALUE_INIT; |
1180 | + * if (!device_config_get("myVar", &v)) { |
1181 | + * do_something_with_value(&v); |
1182 | + * g_value_unset(&v); |
1183 | + * } |
1184 | + */ |
1185 | +int device_config_get(const char *name, GValue *value) |
1186 | +{ |
1187 | + GValue *v; |
1188 | + |
1189 | + if (!config_hash) |
1190 | + return -ENODEV; |
1191 | + |
1192 | + v = g_hash_table_lookup(config_hash, name); |
1193 | + if (!v) |
1194 | + return -ENOENT; |
1195 | + |
1196 | + g_value_init(value, G_VALUE_TYPE(v)); |
1197 | + g_value_copy(v, value); |
1198 | + return 0; |
1199 | +} |
1200 | + |
1201 | +void device_config_init(void) |
1202 | +{ |
1203 | + char device[PROP_VALUE_MAX]; |
1204 | + char *xml_path; |
1205 | + |
1206 | + if (!property_get("ro.product.device", device, NULL)) { |
1207 | + powerd_warn("Could not determine device, running without config"); |
1208 | + return; |
1209 | + } |
1210 | + powerd_info("Running on %s\n", device); |
1211 | + |
1212 | + config_hash = g_hash_table_new_full(g_str_hash, g_str_equal, |
1213 | + config_hash_destroy_key, |
1214 | + config_hash_destroy_value); |
1215 | + |
1216 | + /* |
1217 | + * Always start with config-default.xml for defaults, then |
1218 | + * the device-specific config |
1219 | + */ |
1220 | + if (process_config(POWERD_DEVICE_CONFIGS_PATH "/config-default.xml")) |
1221 | + goto error; |
1222 | + xml_path = g_strdup_printf("%s/config-%s.xml", |
1223 | + POWERD_DEVICE_CONFIGS_PATH, device); |
1224 | + if (process_config(xml_path)) |
1225 | + goto error; |
1226 | + g_free(xml_path); |
1227 | + return; |
1228 | + |
1229 | +error: |
1230 | + device_config_deinit(); |
1231 | +} |
1232 | + |
1233 | +void device_config_deinit(void) |
1234 | +{ |
1235 | + if (config_hash) { |
1236 | + g_hash_table_destroy(config_hash); |
1237 | + config_hash = NULL; |
1238 | + } |
1239 | +} |
1240 | |
1241 | === added file 'src/device-config.h' |
1242 | --- src/device-config.h 1970-01-01 00:00:00 +0000 |
1243 | +++ src/device-config.h 2013-08-29 21:23:26 +0000 |
1244 | @@ -0,0 +1,34 @@ |
1245 | +/* |
1246 | + * Copyright 2013 Canonical Ltd. |
1247 | + * |
1248 | + * This file is part of powerd. |
1249 | + * |
1250 | + * powerd is free software; you can redistribute it and/or modify |
1251 | + * it under the terms of the GNU General Public License as published by |
1252 | + * the Free Software Foundation; version 3. |
1253 | + * |
1254 | + * powerd is distributed in the hope that it will be useful, |
1255 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1256 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1257 | + * GNU General Public License for more details. |
1258 | + * |
1259 | + * You should have received a copy of the GNU General Public License |
1260 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1261 | + */ |
1262 | + |
1263 | +#ifndef __DEVICE_CONFIG_H__ |
1264 | +#define __DEVICE_CONFIG_H__ |
1265 | + |
1266 | +#ifdef __cplusplus |
1267 | +extern "C" { |
1268 | +#endif |
1269 | + |
1270 | +void device_config_init(void); |
1271 | +void device_config_deinit(void); |
1272 | +int device_config_get(const char *name, GValue *value); |
1273 | + |
1274 | +#ifdef __cplusplus |
1275 | +} |
1276 | +#endif |
1277 | + |
1278 | +#endif /* __DEVICE_CONFIG_H__ */ |
1279 | |
1280 | === modified file 'src/display.c' |
1281 | --- src/display.c 2013-07-29 16:05:34 +0000 |
1282 | +++ src/display.c 2013-08-29 21:23:26 +0000 |
1283 | @@ -36,11 +36,17 @@ |
1284 | |
1285 | #include "powerd.h" |
1286 | #include "powerd-internal.h" |
1287 | +#include "device-config.h" |
1288 | #include "log.h" |
1289 | |
1290 | /* Treat "don't care" display state as off */ |
1291 | #define DISPLAY_STATE_OFF POWERD_DISPLAY_STATE_DONT_CARE |
1292 | |
1293 | +/* Autobrightness only enabled when bright && !disabled */ |
1294 | +#define AB_ENABLED_MASK (POWERD_DISPLAY_FLAG_BRIGHT | \ |
1295 | + POWERD_DISPLAY_FLAG_DISABLE_AUTOBRIGHTNESS) |
1296 | +#define AB_ENABLED POWERD_DISPLAY_FLAG_BRIGHT |
1297 | + |
1298 | static gint saved_brightness = 255; |
1299 | static gint target_brightness; |
1300 | static gint dim_brightness; |
1301 | @@ -92,10 +98,18 @@ |
1302 | return display_state_strs[state]; |
1303 | } |
1304 | |
1305 | -static void turn_on_display(void) { |
1306 | +static gboolean ab_enabled(guint32 flags) |
1307 | +{ |
1308 | + return (flags & AB_ENABLED_MASK) == AB_ENABLED; |
1309 | +} |
1310 | + |
1311 | +static void turn_on_display(gboolean autobrightness) { |
1312 | powerd_debug("turning on display"); |
1313 | sf_unblank(0); |
1314 | - powerd_set_brightness(target_brightness); |
1315 | + if (autobrightness) |
1316 | + powerd_autobrightness_enable(); |
1317 | + else |
1318 | + powerd_set_brightness(target_brightness); |
1319 | } |
1320 | |
1321 | gboolean powerd_display_enabled(void) |
1322 | @@ -127,19 +141,25 @@ |
1323 | static void update_display_state(struct powerd_display_request *req) |
1324 | { |
1325 | enum powerd_display_state state = req->state; |
1326 | + gboolean use_ab, using_ab; |
1327 | int applied_state; |
1328 | int ret; |
1329 | int hw_brightness; |
1330 | |
1331 | + use_ab = ab_enabled(req->flags); |
1332 | + using_ab = ab_enabled(internal_state.flags); |
1333 | + |
1334 | hw_brightness = powerd_get_brightness(); |
1335 | if (hw_brightness < 0) |
1336 | hw_brightness = saved_brightness; |
1337 | |
1338 | - if ((internal_state.flags & POWERD_DISPLAY_FLAG_BRIGHT) && |
1339 | - (hw_brightness != 0)) |
1340 | + if (!using_ab && hw_brightness != 0 && |
1341 | + (internal_state.flags & POWERD_DISPLAY_FLAG_BRIGHT)) |
1342 | saved_brightness = hw_brightness; |
1343 | - target_brightness = get_target_brightness((!!(req->flags & POWERD_DISPLAY_FLAG_BRIGHT)), |
1344 | - hw_brightness); |
1345 | + if (!use_ab) |
1346 | + target_brightness = get_target_brightness( |
1347 | + !!(req->flags & POWERD_DISPLAY_FLAG_BRIGHT), |
1348 | + hw_brightness); |
1349 | |
1350 | applied_state = screen_off_overrides ? DISPLAY_STATE_OFF : state; |
1351 | |
1352 | @@ -151,6 +171,8 @@ |
1353 | } |
1354 | |
1355 | powerd_debug("turning off display"); |
1356 | + if (using_ab) |
1357 | + powerd_autobrightness_disable(); |
1358 | powerd_set_brightness(0); |
1359 | sf_blank(0); |
1360 | |
1361 | @@ -179,12 +201,21 @@ |
1362 | * Otherwise we can turn on the screen right away. |
1363 | */ |
1364 | if (fb_state == FB_AWAKE) |
1365 | - turn_on_display(); |
1366 | + turn_on_display(use_ab); |
1367 | } else { |
1368 | /* Only changing brightness */ |
1369 | - if ((req->flags & POWERD_DISPLAY_FLAG_BRIGHT) != |
1370 | - (internal_state.flags & POWERD_DISPLAY_FLAG_BRIGHT)) |
1371 | - powerd_set_brightness(target_brightness); |
1372 | + if (use_ab) { |
1373 | + if (!using_ab) |
1374 | + powerd_autobrightness_enable(); |
1375 | + } else { |
1376 | + if (using_ab) { |
1377 | + powerd_autobrightness_disable(); |
1378 | + powerd_set_brightness(target_brightness); |
1379 | + } else if ((req->flags & POWERD_DISPLAY_FLAG_BRIGHT) != |
1380 | + (internal_state.flags & POWERD_DISPLAY_FLAG_BRIGHT)) { |
1381 | + powerd_set_brightness(target_brightness); |
1382 | + } |
1383 | + } |
1384 | } |
1385 | break; |
1386 | default: |
1387 | @@ -198,7 +229,6 @@ |
1388 | static void update_flags(guint32 flags) |
1389 | { |
1390 | int prox_enabled, internal_prox_enabled; |
1391 | - /* XXX: Handle autobrightness flag */ |
1392 | |
1393 | prox_enabled = (flags & POWERD_DISPLAY_FLAG_USE_PROXIMITY); |
1394 | internal_prox_enabled = (internal_state.flags & POWERD_DISPLAY_FLAG_USE_PROXIMITY); |
1395 | @@ -323,7 +353,7 @@ |
1396 | fb_state = (enum fb_state)data; |
1397 | powerd_debug("fb state %s", fb_state == FB_SLEEP ? "sleep" : "awake"); |
1398 | if (fb_state == FB_AWAKE && powerd_display_enabled()) |
1399 | - turn_on_display(); |
1400 | + turn_on_display(ab_enabled(internal_state.flags)); |
1401 | return FALSE; |
1402 | } |
1403 | |
1404 | @@ -350,14 +380,17 @@ |
1405 | int powerd_display_init(void) |
1406 | { |
1407 | GError *error; |
1408 | + GValue v = G_VALUE_INIT; |
1409 | int brightness, max_brightness; |
1410 | |
1411 | /* |
1412 | * Warning: much hand waving follows |
1413 | * |
1414 | * Right now there's no coherent system brightness policy, so we |
1415 | - * just do the best we can. For "dim" brightness we just go with |
1416 | - * 5% of maximum. For "bright" brightness, it's more complicated. |
1417 | + * just do the best we can. For "dim" brightness we try to read |
1418 | + * the value from the Android config files, otherwise we just go |
1419 | + * with 5% of maximum. For "bright" brightness, it's more |
1420 | + * complicated. |
1421 | * |
1422 | * Our first preference for the bright value is whatever the screen |
1423 | * is currently set to. However, the screen could be off or dimmed |
1424 | @@ -365,15 +398,23 @@ |
1425 | * happens. |
1426 | */ |
1427 | |
1428 | + if (!device_config_get("screenBrightnessDim", &v)) { |
1429 | + if (G_VALUE_HOLDS_UINT(&v)) |
1430 | + dim_brightness = (int)g_value_get_uint(&v); |
1431 | + g_value_unset(&v); |
1432 | + } |
1433 | + |
1434 | max_brightness = powerd_get_max_brightness(); |
1435 | |
1436 | if (max_brightness <= 0) { |
1437 | powerd_warn("Could not read maximum brightness, guessing at dim/bright values"); |
1438 | - dim_brightness = 5; |
1439 | saved_brightness = 100; |
1440 | + if (dim_brightness == 0) |
1441 | + dim_brightness = 5; |
1442 | } else { |
1443 | - dim_brightness = max_brightness / 20; |
1444 | saved_brightness = (3 * max_brightness) / 4; |
1445 | + if (dim_brightness == 0) |
1446 | + dim_brightness = max_brightness / 20; |
1447 | } |
1448 | |
1449 | brightness = powerd_get_brightness(); |
1450 | |
1451 | === modified file 'src/powerd-internal.h' |
1452 | --- src/powerd-internal.h 2013-08-12 04:45:17 +0000 |
1453 | +++ src/powerd-internal.h 2013-08-29 21:23:26 +0000 |
1454 | @@ -57,6 +57,13 @@ |
1455 | void powerd_dbus_init_complete(void); |
1456 | int powerd_is_mainloop(void); |
1457 | |
1458 | +/* Autobrightness functions */ |
1459 | +void powerd_new_als_event(double lux); |
1460 | +void powerd_autobrightness_enable(void); |
1461 | +void powerd_autobrightness_disable(void); |
1462 | +int powerd_autobrightness_init(void); |
1463 | +void powerd_autobrightness_deinit(void); |
1464 | + |
1465 | /* Backlight functions */ |
1466 | int powerd_backlight_init(void); |
1467 | void powerd_backlight_deinit(void); |
1468 | @@ -147,6 +154,8 @@ |
1469 | /* Sensor functions */ |
1470 | void powerd_sensors_proximity_enable(void); |
1471 | void powerd_sensors_proximity_disable(void); |
1472 | +void powerd_sensors_als_enable(void); |
1473 | +void powerd_sensors_als_disable(void); |
1474 | |
1475 | /* Power source functions */ |
1476 | int powerd_ps_init(void); |
1477 | |
1478 | === modified file 'src/powerd-sensors.cpp' |
1479 | --- src/powerd-sensors.cpp 2013-06-07 23:02:23 +0000 |
1480 | +++ src/powerd-sensors.cpp 2013-08-29 21:23:26 +0000 |
1481 | @@ -21,10 +21,13 @@ |
1482 | |
1483 | #include "powerd-internal.h" |
1484 | #include "powerd-sensors.h" |
1485 | +#include "log.h" |
1486 | |
1487 | +#include <ubuntu/application/sensors/light.h> |
1488 | #include <ubuntu/application/sensors/proximity.h> |
1489 | |
1490 | UASensorsProximity* prox_sensor; |
1491 | +UASensorsLight* light_sensor; |
1492 | |
1493 | void on_new_proximity_event(UASProximityEvent *event, void *context) |
1494 | { |
1495 | @@ -53,13 +56,40 @@ |
1496 | ua_sensors_proximity_disable(prox_sensor); |
1497 | } |
1498 | |
1499 | +void on_new_als_event(UASLightEvent *event, void *context) |
1500 | +{ |
1501 | + float lux = uas_light_event_get_light(event); |
1502 | + powerd_new_als_event(lux); |
1503 | +} |
1504 | + |
1505 | +void powerd_sensors_als_enable(void) |
1506 | +{ |
1507 | + if (light_sensor) |
1508 | + ua_sensors_light_enable(light_sensor); |
1509 | +} |
1510 | + |
1511 | +void powerd_sensors_als_disable(void) |
1512 | +{ |
1513 | + if (light_sensor) |
1514 | + ua_sensors_light_disable(light_sensor); |
1515 | +} |
1516 | + |
1517 | void powerd_sensors_init(void) |
1518 | { |
1519 | prox_sensor = ua_sensors_proximity_new(); |
1520 | - |
1521 | if (prox_sensor != NULL) { |
1522 | ua_sensors_proximity_set_reading_cb(prox_sensor, |
1523 | on_new_proximity_event, |
1524 | NULL); |
1525 | + } else { |
1526 | + powerd_warn("Failed to allocate proximity sensor"); |
1527 | + } |
1528 | + |
1529 | + light_sensor = ua_sensors_light_new(); |
1530 | + if (light_sensor) { |
1531 | + ua_sensors_light_set_reading_cb(light_sensor, on_new_als_event, |
1532 | + NULL); |
1533 | + } else { |
1534 | + powerd_warn("Failed to allocate ambient light sensor"); |
1535 | } |
1536 | } |
1537 | |
1538 | === modified file 'src/powerd.cpp' |
1539 | --- src/powerd.cpp 2013-08-09 19:53:58 +0000 |
1540 | +++ src/powerd.cpp 2013-08-29 21:23:26 +0000 |
1541 | @@ -40,6 +40,7 @@ |
1542 | #include "powerd-object.h" |
1543 | #include "powerd-dbus.h" |
1544 | #include "powerd-sensors.h" |
1545 | +#include "device-config.h" |
1546 | #include "log.h" |
1547 | |
1548 | #include <hybris/input/input_stack_compatibility_layer.h> |
1549 | @@ -471,6 +472,9 @@ |
1550 | powerd_debug("Activity Timeout is %d seconds\n", activity_timeout); |
1551 | powerd_debug("Auto-dim Timeout is %d seconds\n", dim_timeout); |
1552 | |
1553 | + /* Init this first, data is used by other inits */ |
1554 | + device_config_init(); |
1555 | + |
1556 | libsuspend_init(0); |
1557 | powerd_stats_init(); |
1558 | powerd_client_init(); |
1559 | @@ -478,6 +482,7 @@ |
1560 | display_request_init(); |
1561 | dbus_name_watch_init(); |
1562 | powerd_backlight_init(); |
1563 | + powerd_autobrightness_init(); |
1564 | powerd_display_init(); |
1565 | powerd_sensors_init(); |
1566 | powerd_ps_init(); |
1567 | @@ -497,6 +502,9 @@ |
1568 | android_input_stack_initialize(&listener, &config); |
1569 | android_input_stack_start(); |
1570 | |
1571 | + /* Config use should be done during init, okay to free now */ |
1572 | + device_config_deinit(); |
1573 | + |
1574 | /* This needs to be the first thing to run on the main loop */ |
1575 | g_idle_add_full(G_PRIORITY_HIGH, main_init, NULL, NULL); |
1576 | |
1577 | @@ -509,6 +517,7 @@ |
1578 | |
1579 | powerd_ps_deinit(); |
1580 | dbus_name_watch_deinit(); |
1581 | + powerd_autobrightness_deinit(); |
1582 | powerd_backlight_deinit(); |
1583 | display_request_deinit(); |
1584 | power_request_deinit(); |
1585 | |
1586 | === added file 'src/spline.c' |
1587 | --- src/spline.c 1970-01-01 00:00:00 +0000 |
1588 | +++ src/spline.c 2013-08-29 21:23:26 +0000 |
1589 | @@ -0,0 +1,140 @@ |
1590 | +/* |
1591 | + * Copyright 2013 Canonical Ltd. |
1592 | + * |
1593 | + * This file is part of powerd. |
1594 | + * |
1595 | + * powerd is free software; you can redistribute it and/or modify |
1596 | + * it under the terms of the GNU General Public License as published by |
1597 | + * the Free Software Foundation; version 3. |
1598 | + * |
1599 | + * powerd is distributed in the hope that it will be useful, |
1600 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1601 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1602 | + * GNU General Public License for more details. |
1603 | + * |
1604 | + * You should have received a copy of the GNU General Public License |
1605 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1606 | + */ |
1607 | + |
1608 | +#include <stdio.h> |
1609 | +#include <stdlib.h> |
1610 | +#include <string.h> |
1611 | + |
1612 | +struct spline_params { |
1613 | + double k, m; |
1614 | +}; |
1615 | + |
1616 | +struct spline { |
1617 | + double (*points)[2]; |
1618 | + int n; |
1619 | + struct spline_params params[0]; |
1620 | +}; |
1621 | + |
1622 | +int spline_sort_comp(const void *a, const void *b) |
1623 | +{ |
1624 | + double x1 = *(double *)a; |
1625 | + double x2 = *(double *)b; |
1626 | + return (int)(x1 - x2); |
1627 | +} |
1628 | + |
1629 | +/* |
1630 | + * Initializes a monotone cubic Hermite spline for interpolating |
1631 | + * between the input points, using the Fritsch–Carlson method. |
1632 | + * |
1633 | + * http://en.wikipedia.org/wiki/Monotone_cubic_interpolation |
1634 | + * |
1635 | + * The interpolated points are guaranteed to have piecewise |
1636 | + * monotonicity, and will be fully monotone if the input points |
1637 | + * are monotone. |
1638 | + */ |
1639 | +struct spline *spline_new(double (*points)[2], int num_points) |
1640 | +{ |
1641 | + struct spline *s; |
1642 | + struct spline_params *param; |
1643 | + double (*p)[2]; |
1644 | + int i; |
1645 | + double alpha, beta, prev_beta; |
1646 | + |
1647 | + s = malloc(sizeof(struct spline) + |
1648 | + sizeof(struct spline_params) * num_points); |
1649 | + if (!s) |
1650 | + return NULL; |
1651 | + s->points = malloc(2 * sizeof(double) * num_points); |
1652 | + if (!s->points) { |
1653 | + free(s); |
1654 | + return NULL; |
1655 | + } |
1656 | + s->n = num_points; |
1657 | + |
1658 | + /* |
1659 | + * Input points are likely to already be in order of increasing |
1660 | + * x, but sort them just in case. |
1661 | + */ |
1662 | + memcpy(s->points, points, 2 * sizeof(double) * num_points); |
1663 | + qsort(s->points, num_points, 2 * sizeof(double), spline_sort_comp); |
1664 | + |
1665 | + p = s->points; |
1666 | + param = s->params; |
1667 | + |
1668 | + for (i = 0; i < s->n - 1; i++) |
1669 | + param[i].k = (p[i+1][1] - p[i][1]) / (p[i+1][0] - p[i][0]); |
1670 | + |
1671 | + param[0].m = param[0].k; |
1672 | + for (i = 1; i < s->n; i++) |
1673 | + param[i].m = (param[i-1].k + param[i].k) / 2; |
1674 | + param[s->n - 1].m = param[s->n - 2].k; |
1675 | + |
1676 | + beta = 0; |
1677 | + for (i = 0; i < s->n - 1; i++) { |
1678 | + if (p[i][1] == p[i+1][1]) { |
1679 | + param[i].m = 0; |
1680 | + param[++i].m = 0; |
1681 | + beta = 0; |
1682 | + continue; |
1683 | + } |
1684 | + prev_beta = beta; |
1685 | + alpha = param[i].m / param[i].k; |
1686 | + beta = param[i+1].m / param[i].k; |
1687 | + if (alpha < 0 || prev_beta < 0) { |
1688 | + param[i].m = 0; |
1689 | + continue; |
1690 | + } |
1691 | + if (alpha > 3) |
1692 | + param[i].m = 3 * param[i].k; |
1693 | + if (beta > 3) |
1694 | + param[i+1].m = 3 * param[i].k; |
1695 | + } |
1696 | + |
1697 | + return s; |
1698 | +} |
1699 | + |
1700 | +void spline_free(struct spline *s) |
1701 | +{ |
1702 | + free(s->points); |
1703 | + free(s); |
1704 | +} |
1705 | + |
1706 | +double spline_interpolate(struct spline *s, double x) |
1707 | +{ |
1708 | + int i; |
1709 | + double h, t, ret; |
1710 | + |
1711 | + for (i = 0; i < s->n - 1; i++) { |
1712 | + if (x >= s->points[i][0] && x < s->points[i+1][0]) |
1713 | + break; |
1714 | + } |
1715 | + |
1716 | + /* Handle out-of-bounds and boundary cases */ |
1717 | + if (i == 0 && x <= s->points[0][0]) |
1718 | + return s->points[0][1]; |
1719 | + if (i >= s->n - 1) |
1720 | + return s->points[s->n - 1][1]; |
1721 | + |
1722 | + h = s->points[i+1][0] - s->points[i][0]; |
1723 | + t = (x - s->points[i][0]) / h; |
1724 | + ret = s->points[i][1] * (1 + t * t * (2 * t - 3)); |
1725 | + ret += h * s->params[i].m * t * (1 + t * (t - 2)); |
1726 | + ret += s->points[i+1][1] * t * t * (3 - 2 * t); |
1727 | + ret += h * s->params[i+1].m * t * t * (t - 1); |
1728 | + return ret; |
1729 | +} |
1730 | |
1731 | === added file 'src/spline.h' |
1732 | --- src/spline.h 1970-01-01 00:00:00 +0000 |
1733 | +++ src/spline.h 2013-08-29 21:23:26 +0000 |
1734 | @@ -0,0 +1,28 @@ |
1735 | +/* |
1736 | + * Copyright 2013 Canonical Ltd. |
1737 | + * |
1738 | + * This file is part of powerd. |
1739 | + * |
1740 | + * powerd is free software; you can redistribute it and/or modify |
1741 | + * it under the terms of the GNU General Public License as published by |
1742 | + * the Free Software Foundation; version 3. |
1743 | + * |
1744 | + * powerd is distributed in the hope that it will be useful, |
1745 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1746 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1747 | + * GNU General Public License for more details. |
1748 | + * |
1749 | + * You should have received a copy of the GNU General Public License |
1750 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1751 | + */ |
1752 | + |
1753 | +#ifndef __SPLINE_H__ |
1754 | +#define __SPLINE_H__ |
1755 | + |
1756 | +struct spline; |
1757 | + |
1758 | +struct spline *spline_new(double (*points)[2], int num_points); |
1759 | +void spline_free(struct spline *s); |
1760 | +double spline_interpolate(struct spline *s, double x); |
1761 | + |
1762 | +#endif |
PASSED: Continuous integration, rev:96 jenkins. qa.ubuntu. com/job/ powerd- ci/109/ jenkins. qa.ubuntu. com/job/ powerd- saucy-armhf- ci/63 jenkins. qa.ubuntu. com/job/ powerd- saucy-armhf- ci/63/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ powerd- ci/109/ rebuild
http://