From 30e1f9aee4630ac4220aab1924eaaae6d3c96fd7 Mon Sep 17 00:00:00 2001 From: Lars Greiss Date: Fri, 4 Oct 2013 19:44:40 +0200 Subject: tuna: add support for battery LED charging Device has multi-color RGB LED, enable charging function using existing custom lights library. --- liblight/lights.c | 114 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 29 deletions(-) (limited to 'liblight') 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; -- cgit v1.1