summaryrefslogtreecommitdiffstats
path: root/liblight
diff options
context:
space:
mode:
authorLars Greiss <kufikugel@googlemail.com>2013-10-04 19:44:40 +0200
committerZiyan <jaraidaniel@gmail.com>2014-12-13 00:39:24 +0100
commit30e1f9aee4630ac4220aab1924eaaae6d3c96fd7 (patch)
tree8a22b0f1c9e8307ccccf854c7f2500568de51e29 /liblight
parent82162d35709e02e9679a540743c5b6b05d36bced (diff)
downloaddevice_samsung_tuna-30e1f9aee4630ac4220aab1924eaaae6d3c96fd7.zip
device_samsung_tuna-30e1f9aee4630ac4220aab1924eaaae6d3c96fd7.tar.gz
device_samsung_tuna-30e1f9aee4630ac4220aab1924eaaae6d3c96fd7.tar.bz2
tuna: add support for battery LED charging
Device has multi-color RGB LED, enable charging function using existing custom lights library.
Diffstat (limited to 'liblight')
-rw-r--r--liblight/lights.c114
1 files changed, 85 insertions, 29 deletions
diff --git a/liblight/lights.c b/liblight/lights.c
index 1dfcd8b..e155d70 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -35,16 +35,27 @@ char const *const LED_FILE = "/dev/an30259a_leds";
#define IMAX 0 // 12.75mA power consumption
// Slope values, based on total blink of 1000ms
-#define SLOPE_UP_1 450
-#define SLOPE_UP_2 (500-SLOPE_UP_1)
+#define SLOPE_UP_1 450
+#define SLOPE_UP_2 (500-SLOPE_UP_1)
#define SLOPE_DOWN_1 SLOPE_UP_2
#define SLOPE_DOWN_2 SLOPE_UP_1
// brightness at mid-slope, on 0 - 127 scale
#define MID_BRIGHTNESS 31
+enum LED_Type {
+ LED_TYPE_ATTENTION = 0,
+ LED_TYPE_NOTIFICATION = 1,
+ LED_TYPE_CHARGING = 2,
+ LED_TYPE_LAST = 3
+};
+
+// a "stack" of virtual LED states
+static struct an30259a_pr_control g_led_states[LED_TYPE_LAST];
+
void init_g_lock(void)
{
pthread_mutex_init(&g_lock, NULL);
+ memset(g_led_states, 0, sizeof(g_led_states));
}
static int write_int(char const *path, int value)
@@ -132,48 +143,91 @@ static int write_leds(struct an30259a_pr_control *led)
return err;
}
+// similar to write_leds(), but deals with the priority of certain virtual LEDs over others
+static int write_leds_priority()
+{
+ // find the highest priority virtual LED that should be illuminated and
+ // call write_leds() with it
+ int i;
+
+ for (i = 0; i < LED_TYPE_LAST; i++) {
+ // if the LED isn't off and isn't "black" then use it
+ if (g_led_states[i].state != LED_LIGHT_OFF) {
+ return write_leds(&g_led_states[i]);
+ }
+ }
+
+ // nothing should be lit? make sure to turn it off
+ return write_leds(&g_led_states[LED_TYPE_LAST - 1]);
+}
+
static int set_light_leds(struct light_state_t const *state, int type)
{
- struct an30259a_pr_control led;
-
- memset(&led, 0, sizeof(led));
-
- switch (state->flashMode) {
- case LIGHT_FLASH_NONE:
- led.state = LED_LIGHT_OFF;
- break;
- case LIGHT_FLASH_TIMED:
- case LIGHT_FLASH_HARDWARE:
- led.state = LED_LIGHT_SLOPE;
- led.color = state->color & 0x00ffffff;
- // tweak to eliminate purplish tint from white color
- if (led.color == 0x00ffffff)
- led.color = 0x80ff80;
- // scale slope times based on flashOnMS
- led.time_slope_up_1 = (SLOPE_UP_1 * state->flashOnMS) / 1000;
- led.time_slope_up_2 = (SLOPE_UP_2 * state->flashOnMS) / 1000;
- led.time_slope_down_1 = (SLOPE_DOWN_1 * state->flashOnMS) / 1000;
- led.time_slope_down_2 = (SLOPE_DOWN_2 * state->flashOnMS) / 1000;
- led.mid_brightness = MID_BRIGHTNESS;
- led.time_off = state->flashOffMS;
- break;
- default:
+ if (type < 0 || type >= LED_TYPE_LAST) {
return -EINVAL;
}
- return write_leds(&led);
+ struct an30259a_pr_control *led_state = &g_led_states[type];
+
+ // set the LED information to the proper element of the array without actually
+ // changing the physical LED yet
+ memset(led_state, 0, sizeof(*led_state));
+
+ // if the color is 0, turn off the LED
+ if (state->color & 0xffffff) {
+ led_state->color = state->color & 0x00ffffff;
+ // tweak to eliminate purplish tint from white color
+ if (led_state->color == 0x00ffffff) {
+ led_state->color = 0x80ff80;
+ }
+
+ switch (state->flashMode) {
+ case LIGHT_FLASH_NONE:
+ led_state->state = LED_LIGHT_ON;
+ break;
+ case LIGHT_FLASH_TIMED:
+ case LIGHT_FLASH_HARDWARE:
+ led_state->state = LED_LIGHT_SLOPE;
+ // scale slope times based on flashOnMS
+ led_state->time_slope_up_1 = (SLOPE_UP_1 * state->flashOnMS) / 1000;
+ led_state->time_slope_up_2 = (SLOPE_UP_2 * state->flashOnMS) / 1000;
+ led_state->time_slope_down_1 = (SLOPE_DOWN_1 * state->flashOnMS) / 1000;
+ led_state->time_slope_down_2 = (SLOPE_DOWN_2 * state->flashOnMS) / 1000;
+ led_state->mid_brightness = MID_BRIGHTNESS;
+ led_state->time_off = state->flashOffMS;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ led_state->state = LED_LIGHT_OFF;
+ }
+
+ // allow write_leds_priority determine if the physical LED should be changed
+ return write_leds_priority();
}
static int set_light_leds_notifications(struct light_device_t *dev,
struct light_state_t const *state)
{
- return set_light_leds(state, 0);
+ return set_light_leds(state, LED_TYPE_NOTIFICATION);
}
static int set_light_leds_attention(struct light_device_t *dev,
struct light_state_t const *state)
{
- return set_light_leds(state, 1);
+ struct light_state_t attention_state = *state;
+ if (attention_state.flashMode == LIGHT_FLASH_NONE) {
+ // that's actually NotificationManager's way of turning it off
+ attention_state.color = 0;
+ }
+ return set_light_leds(&attention_state, LED_TYPE_ATTENTION);
+}
+
+static int set_light_leds_battery(struct light_device_t *dev,
+ struct light_state_t const *state)
+{
+ return set_light_leds(state, LED_TYPE_CHARGING);
}
static int open_lights(const struct hw_module_t *module, char const *name,
@@ -188,6 +242,8 @@ static int open_lights(const struct hw_module_t *module, char const *name,
set_light = set_light_leds_notifications;
else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
set_light = set_light_leds_attention;
+ else if (0 == strcmp(LIGHT_ID_BATTERY, name))
+ set_light = set_light_leds_battery;
else
return -EINVAL;