Merge lp:~sforshee/powerd/thermal-shutdown into lp:powerd

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
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)
lp:~sforshee/powerd/thermal-shutdown updated
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

Subscribers

People subscribed via source and target branches