Merge lp:~sforshee/powerd/thermal-shutdown into lp:powerd
- thermal-shutdown
- Merge into trunk
Proposed by
Seth Forshee
Status: | Superseded |
---|---|
Proposed branch: | lp:~sforshee/powerd/thermal-shutdown |
Merge into: | lp:powerd |
Diff against target: |
1845 lines (+1492/-23) 17 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/power-source.c (+25/-6) 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/thermal-shutdown |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+180392@code.launchpad.net |
This proposal has been superseded by a proposal from 2013-08-30.
Commit message
Add thermal shutdown support
Description of the change
Add thermal shutdown support
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
- 89. By Seth Forshee
-
Merge with autobrightness
- 90. By Seth Forshee
-
power-source: Read thermal shutdown temperature from device config
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2013-08-09 19:53:58 +0000 |
3 | +++ CMakeLists.txt 2013-08-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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-30 13:59:21 +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/power-source.c' |
1452 | --- src/power-source.c 2013-07-12 21:12:31 +0000 |
1453 | +++ src/power-source.c 2013-08-30 13:59:21 +0000 |
1454 | @@ -21,9 +21,11 @@ |
1455 | #include <libupower-glib/upower.h> |
1456 | |
1457 | #include "powerd-internal.h" |
1458 | +#include "device-config.h" |
1459 | #include "log.h" |
1460 | |
1461 | static UpClient *up_client; |
1462 | +double shutdown_temp = 68.0f; |
1463 | |
1464 | static void up_device_changed_cb(UpClient *client, UpDevice *device, |
1465 | gpointer unused) |
1466 | @@ -31,13 +33,14 @@ |
1467 | gboolean on_battery; |
1468 | GPtrArray *devices; |
1469 | int i; |
1470 | - gboolean shutdown = TRUE; |
1471 | + gboolean low_batt_shutdown = TRUE; |
1472 | + gboolean thermal_shutdown = FALSE; |
1473 | |
1474 | g_object_get(up_client, |
1475 | "on_battery", &on_battery, |
1476 | NULL); |
1477 | if (!on_battery) |
1478 | - return; |
1479 | + low_batt_shutdown = FALSE; |
1480 | devices = up_client_get_devices(up_client); |
1481 | for (i = 0; i < devices->len; i++) { |
1482 | UpDevice *device = g_ptr_array_index(devices, i); |
1483 | @@ -48,21 +51,25 @@ |
1484 | "is-present", &is_present, |
1485 | NULL); |
1486 | if (kind == UP_DEVICE_KIND_BATTERY && is_present) { |
1487 | - double percentage; |
1488 | + double percentage, temp; |
1489 | g_object_get(device, |
1490 | "percentage", &percentage, |
1491 | + "temperature", &temp, |
1492 | NULL); |
1493 | /* |
1494 | * Android shuts down when percentage reaches 0. We |
1495 | * use 1% to leave a little more headroom. |
1496 | */ |
1497 | - if (percentage > 1.0) { |
1498 | - shutdown = FALSE; |
1499 | + if (percentage > 1.0) |
1500 | + low_batt_shutdown = FALSE; |
1501 | + if (temp >= shutdown_temp) { |
1502 | + powerd_warn("Critical battery temperature %f\n", temp); |
1503 | + thermal_shutdown = TRUE; |
1504 | break; |
1505 | } |
1506 | } |
1507 | } |
1508 | - if (shutdown) { |
1509 | + if (low_batt_shutdown || thermal_shutdown) { |
1510 | powerd_warn("Initiating emergency shutdown"); |
1511 | powerd_shutdown(); |
1512 | } |
1513 | @@ -70,7 +77,19 @@ |
1514 | |
1515 | int powerd_ps_init(void) |
1516 | { |
1517 | + GValue v = G_VALUE_INIT; |
1518 | gboolean ret; |
1519 | + |
1520 | + /* |
1521 | + * Override default shutdown temperature with device-specific |
1522 | + * value, if avaialable |
1523 | + */ |
1524 | + if (!device_config_get("shutdownBatteryTemperature", &v) && |
1525 | + G_VALUE_HOLDS_UINT(&v)) { |
1526 | + shutdown_temp = (double)g_value_get_uint(&v) / 10.0f; |
1527 | + g_value_unset(&v); |
1528 | + } |
1529 | + |
1530 | up_client = up_client_new(); |
1531 | if (!up_client) { |
1532 | powerd_warn("Could not allocate upower client"); |
1533 | |
1534 | === modified file 'src/powerd-internal.h' |
1535 | --- src/powerd-internal.h 2013-08-12 04:45:17 +0000 |
1536 | +++ src/powerd-internal.h 2013-08-30 13:59:21 +0000 |
1537 | @@ -57,6 +57,13 @@ |
1538 | void powerd_dbus_init_complete(void); |
1539 | int powerd_is_mainloop(void); |
1540 | |
1541 | +/* Autobrightness functions */ |
1542 | +void powerd_new_als_event(double lux); |
1543 | +void powerd_autobrightness_enable(void); |
1544 | +void powerd_autobrightness_disable(void); |
1545 | +int powerd_autobrightness_init(void); |
1546 | +void powerd_autobrightness_deinit(void); |
1547 | + |
1548 | /* Backlight functions */ |
1549 | int powerd_backlight_init(void); |
1550 | void powerd_backlight_deinit(void); |
1551 | @@ -147,6 +154,8 @@ |
1552 | /* Sensor functions */ |
1553 | void powerd_sensors_proximity_enable(void); |
1554 | void powerd_sensors_proximity_disable(void); |
1555 | +void powerd_sensors_als_enable(void); |
1556 | +void powerd_sensors_als_disable(void); |
1557 | |
1558 | /* Power source functions */ |
1559 | int powerd_ps_init(void); |
1560 | |
1561 | === modified file 'src/powerd-sensors.cpp' |
1562 | --- src/powerd-sensors.cpp 2013-06-07 23:02:23 +0000 |
1563 | +++ src/powerd-sensors.cpp 2013-08-30 13:59:21 +0000 |
1564 | @@ -21,10 +21,13 @@ |
1565 | |
1566 | #include "powerd-internal.h" |
1567 | #include "powerd-sensors.h" |
1568 | +#include "log.h" |
1569 | |
1570 | +#include <ubuntu/application/sensors/light.h> |
1571 | #include <ubuntu/application/sensors/proximity.h> |
1572 | |
1573 | UASensorsProximity* prox_sensor; |
1574 | +UASensorsLight* light_sensor; |
1575 | |
1576 | void on_new_proximity_event(UASProximityEvent *event, void *context) |
1577 | { |
1578 | @@ -53,13 +56,40 @@ |
1579 | ua_sensors_proximity_disable(prox_sensor); |
1580 | } |
1581 | |
1582 | +void on_new_als_event(UASLightEvent *event, void *context) |
1583 | +{ |
1584 | + float lux = uas_light_event_get_light(event); |
1585 | + powerd_new_als_event(lux); |
1586 | +} |
1587 | + |
1588 | +void powerd_sensors_als_enable(void) |
1589 | +{ |
1590 | + if (light_sensor) |
1591 | + ua_sensors_light_enable(light_sensor); |
1592 | +} |
1593 | + |
1594 | +void powerd_sensors_als_disable(void) |
1595 | +{ |
1596 | + if (light_sensor) |
1597 | + ua_sensors_light_disable(light_sensor); |
1598 | +} |
1599 | + |
1600 | void powerd_sensors_init(void) |
1601 | { |
1602 | prox_sensor = ua_sensors_proximity_new(); |
1603 | - |
1604 | if (prox_sensor != NULL) { |
1605 | ua_sensors_proximity_set_reading_cb(prox_sensor, |
1606 | on_new_proximity_event, |
1607 | NULL); |
1608 | + } else { |
1609 | + powerd_warn("Failed to allocate proximity sensor"); |
1610 | + } |
1611 | + |
1612 | + light_sensor = ua_sensors_light_new(); |
1613 | + if (light_sensor) { |
1614 | + ua_sensors_light_set_reading_cb(light_sensor, on_new_als_event, |
1615 | + NULL); |
1616 | + } else { |
1617 | + powerd_warn("Failed to allocate ambient light sensor"); |
1618 | } |
1619 | } |
1620 | |
1621 | === modified file 'src/powerd.cpp' |
1622 | --- src/powerd.cpp 2013-08-09 19:53:58 +0000 |
1623 | +++ src/powerd.cpp 2013-08-30 13:59:21 +0000 |
1624 | @@ -40,6 +40,7 @@ |
1625 | #include "powerd-object.h" |
1626 | #include "powerd-dbus.h" |
1627 | #include "powerd-sensors.h" |
1628 | +#include "device-config.h" |
1629 | #include "log.h" |
1630 | |
1631 | #include <hybris/input/input_stack_compatibility_layer.h> |
1632 | @@ -471,6 +472,9 @@ |
1633 | powerd_debug("Activity Timeout is %d seconds\n", activity_timeout); |
1634 | powerd_debug("Auto-dim Timeout is %d seconds\n", dim_timeout); |
1635 | |
1636 | + /* Init this first, data is used by other inits */ |
1637 | + device_config_init(); |
1638 | + |
1639 | libsuspend_init(0); |
1640 | powerd_stats_init(); |
1641 | powerd_client_init(); |
1642 | @@ -478,6 +482,7 @@ |
1643 | display_request_init(); |
1644 | dbus_name_watch_init(); |
1645 | powerd_backlight_init(); |
1646 | + powerd_autobrightness_init(); |
1647 | powerd_display_init(); |
1648 | powerd_sensors_init(); |
1649 | powerd_ps_init(); |
1650 | @@ -497,6 +502,9 @@ |
1651 | android_input_stack_initialize(&listener, &config); |
1652 | android_input_stack_start(); |
1653 | |
1654 | + /* Config use should be done during init, okay to free now */ |
1655 | + device_config_deinit(); |
1656 | + |
1657 | /* This needs to be the first thing to run on the main loop */ |
1658 | g_idle_add_full(G_PRIORITY_HIGH, main_init, NULL, NULL); |
1659 | |
1660 | @@ -509,6 +517,7 @@ |
1661 | |
1662 | powerd_ps_deinit(); |
1663 | dbus_name_watch_deinit(); |
1664 | + powerd_autobrightness_deinit(); |
1665 | powerd_backlight_deinit(); |
1666 | display_request_deinit(); |
1667 | power_request_deinit(); |
1668 | |
1669 | === added file 'src/spline.c' |
1670 | --- src/spline.c 1970-01-01 00:00:00 +0000 |
1671 | +++ src/spline.c 2013-08-30 13:59:21 +0000 |
1672 | @@ -0,0 +1,140 @@ |
1673 | +/* |
1674 | + * Copyright 2013 Canonical Ltd. |
1675 | + * |
1676 | + * This file is part of powerd. |
1677 | + * |
1678 | + * powerd is free software; you can redistribute it and/or modify |
1679 | + * it under the terms of the GNU General Public License as published by |
1680 | + * the Free Software Foundation; version 3. |
1681 | + * |
1682 | + * powerd is distributed in the hope that it will be useful, |
1683 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1684 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1685 | + * GNU General Public License for more details. |
1686 | + * |
1687 | + * You should have received a copy of the GNU General Public License |
1688 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1689 | + */ |
1690 | + |
1691 | +#include <stdio.h> |
1692 | +#include <stdlib.h> |
1693 | +#include <string.h> |
1694 | + |
1695 | +struct spline_params { |
1696 | + double k, m; |
1697 | +}; |
1698 | + |
1699 | +struct spline { |
1700 | + double (*points)[2]; |
1701 | + int n; |
1702 | + struct spline_params params[0]; |
1703 | +}; |
1704 | + |
1705 | +int spline_sort_comp(const void *a, const void *b) |
1706 | +{ |
1707 | + double x1 = *(double *)a; |
1708 | + double x2 = *(double *)b; |
1709 | + return (int)(x1 - x2); |
1710 | +} |
1711 | + |
1712 | +/* |
1713 | + * Initializes a monotone cubic Hermite spline for interpolating |
1714 | + * between the input points, using the Fritsch–Carlson method. |
1715 | + * |
1716 | + * http://en.wikipedia.org/wiki/Monotone_cubic_interpolation |
1717 | + * |
1718 | + * The interpolated points are guaranteed to have piecewise |
1719 | + * monotonicity, and will be fully monotone if the input points |
1720 | + * are monotone. |
1721 | + */ |
1722 | +struct spline *spline_new(double (*points)[2], int num_points) |
1723 | +{ |
1724 | + struct spline *s; |
1725 | + struct spline_params *param; |
1726 | + double (*p)[2]; |
1727 | + int i; |
1728 | + double alpha, beta, prev_beta; |
1729 | + |
1730 | + s = malloc(sizeof(struct spline) + |
1731 | + sizeof(struct spline_params) * num_points); |
1732 | + if (!s) |
1733 | + return NULL; |
1734 | + s->points = malloc(2 * sizeof(double) * num_points); |
1735 | + if (!s->points) { |
1736 | + free(s); |
1737 | + return NULL; |
1738 | + } |
1739 | + s->n = num_points; |
1740 | + |
1741 | + /* |
1742 | + * Input points are likely to already be in order of increasing |
1743 | + * x, but sort them just in case. |
1744 | + */ |
1745 | + memcpy(s->points, points, 2 * sizeof(double) * num_points); |
1746 | + qsort(s->points, num_points, 2 * sizeof(double), spline_sort_comp); |
1747 | + |
1748 | + p = s->points; |
1749 | + param = s->params; |
1750 | + |
1751 | + for (i = 0; i < s->n - 1; i++) |
1752 | + param[i].k = (p[i+1][1] - p[i][1]) / (p[i+1][0] - p[i][0]); |
1753 | + |
1754 | + param[0].m = param[0].k; |
1755 | + for (i = 1; i < s->n; i++) |
1756 | + param[i].m = (param[i-1].k + param[i].k) / 2; |
1757 | + param[s->n - 1].m = param[s->n - 2].k; |
1758 | + |
1759 | + beta = 0; |
1760 | + for (i = 0; i < s->n - 1; i++) { |
1761 | + if (p[i][1] == p[i+1][1]) { |
1762 | + param[i].m = 0; |
1763 | + param[++i].m = 0; |
1764 | + beta = 0; |
1765 | + continue; |
1766 | + } |
1767 | + prev_beta = beta; |
1768 | + alpha = param[i].m / param[i].k; |
1769 | + beta = param[i+1].m / param[i].k; |
1770 | + if (alpha < 0 || prev_beta < 0) { |
1771 | + param[i].m = 0; |
1772 | + continue; |
1773 | + } |
1774 | + if (alpha > 3) |
1775 | + param[i].m = 3 * param[i].k; |
1776 | + if (beta > 3) |
1777 | + param[i+1].m = 3 * param[i].k; |
1778 | + } |
1779 | + |
1780 | + return s; |
1781 | +} |
1782 | + |
1783 | +void spline_free(struct spline *s) |
1784 | +{ |
1785 | + free(s->points); |
1786 | + free(s); |
1787 | +} |
1788 | + |
1789 | +double spline_interpolate(struct spline *s, double x) |
1790 | +{ |
1791 | + int i; |
1792 | + double h, t, ret; |
1793 | + |
1794 | + for (i = 0; i < s->n - 1; i++) { |
1795 | + if (x >= s->points[i][0] && x < s->points[i+1][0]) |
1796 | + break; |
1797 | + } |
1798 | + |
1799 | + /* Handle out-of-bounds and boundary cases */ |
1800 | + if (i == 0 && x <= s->points[0][0]) |
1801 | + return s->points[0][1]; |
1802 | + if (i >= s->n - 1) |
1803 | + return s->points[s->n - 1][1]; |
1804 | + |
1805 | + h = s->points[i+1][0] - s->points[i][0]; |
1806 | + t = (x - s->points[i][0]) / h; |
1807 | + ret = s->points[i][1] * (1 + t * t * (2 * t - 3)); |
1808 | + ret += h * s->params[i].m * t * (1 + t * (t - 2)); |
1809 | + ret += s->points[i+1][1] * t * t * (3 - 2 * t); |
1810 | + ret += h * s->params[i+1].m * t * t * (t - 1); |
1811 | + return ret; |
1812 | +} |
1813 | |
1814 | === added file 'src/spline.h' |
1815 | --- src/spline.h 1970-01-01 00:00:00 +0000 |
1816 | +++ src/spline.h 2013-08-30 13:59:21 +0000 |
1817 | @@ -0,0 +1,28 @@ |
1818 | +/* |
1819 | + * Copyright 2013 Canonical Ltd. |
1820 | + * |
1821 | + * This file is part of powerd. |
1822 | + * |
1823 | + * powerd is free software; you can redistribute it and/or modify |
1824 | + * it under the terms of the GNU General Public License as published by |
1825 | + * the Free Software Foundation; version 3. |
1826 | + * |
1827 | + * powerd is distributed in the hope that it will be useful, |
1828 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1829 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1830 | + * GNU General Public License for more details. |
1831 | + * |
1832 | + * You should have received a copy of the GNU General Public License |
1833 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1834 | + */ |
1835 | + |
1836 | +#ifndef __SPLINE_H__ |
1837 | +#define __SPLINE_H__ |
1838 | + |
1839 | +struct spline; |
1840 | + |
1841 | +struct spline *spline_new(double (*points)[2], int num_points); |
1842 | +void spline_free(struct spline *s); |
1843 | +double spline_interpolate(struct spline *s, double x); |
1844 | + |
1845 | +#endif |
PASSED: Continuous integration, rev:88 jenkins. qa.ubuntu. com/job/ powerd- ci/108/ jenkins. qa.ubuntu. com/job/ powerd- saucy-armhf- ci/62 jenkins. qa.ubuntu. com/job/ powerd- saucy-armhf- ci/62/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/108/ rebuild
http://