liblight: Change flash mode control for RGB LEDs
Add support for LIGHT_FLASH_HARDWARE, and change to use LED timer
trigger interface to support LIGHT_FLASH_TIMED.
Change-Id: I9ff3c44f5c1346aba60b61318ca4c2a7a45fe51b
diff --git a/liblight/lights.c b/liblight/lights.c
index d511395..60ed911 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014, 2017 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2014, 2017-2018 The Linux Foundation. All rights reserved.
* Not a contribution
* Copyright (C) 2008 The Android Open Source Project
*
@@ -50,15 +50,6 @@
static int g_brightness_max = 0;
static bool g_has_persistence_node = false;
-char const*const RED_LED_FILE
- = "/sys/class/leds/red/brightness";
-
-char const*const GREEN_LED_FILE
- = "/sys/class/leds/green/brightness";
-
-char const*const BLUE_LED_FILE
- = "/sys/class/leds/blue/brightness";
-
char const*const LCD_FILE
= "/sys/class/leds/lcd-backlight/brightness";
@@ -68,18 +59,20 @@
char const*const BUTTON_FILE
= "/sys/class/leds/button-backlight/brightness";
-char const*const RED_BLINK_FILE
- = "/sys/class/leds/red/blink";
-
-char const*const GREEN_BLINK_FILE
- = "/sys/class/leds/green/blink";
-
-char const*const BLUE_BLINK_FILE
- = "/sys/class/leds/blue/blink";
-
char const*const PERSISTENCE_FILE
= "/sys/class/graphics/fb0/msm_fb_persist_mode";
+enum rgb_led {
+ LED_RED = 0,
+ LED_GREEN,
+ LED_BLUE,
+};
+
+char *led_names[] = {
+ "red",
+ "green",
+ "blue",
+};
/**
* device methods
*/
@@ -90,8 +83,7 @@
pthread_mutex_init(&g_lock, NULL);
}
-static int
-write_int(char const* path, int value)
+static int write_int(char const* path, int value)
{
int fd;
static int already_warned = 0;
@@ -105,13 +97,27 @@
return amt == -1 ? -errno : 0;
} else {
if (already_warned == 0) {
- ALOGE("write_int failed to open %s\n", path);
+ ALOGE("write_int failed to open %s, errno = %d\n", path, errno);
already_warned = 1;
}
return -errno;
}
}
+static bool file_exists(const char *file)
+{
+ int fd;
+
+ fd = open(file, O_RDWR);
+ if (fd < 0) {
+ ALOGE("failed to open %s, errno=%d\n", file, errno);
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
+
static int
is_lit(struct light_state_t const* state)
{
@@ -191,77 +197,104 @@
return err;
}
+static int set_rgb_led_brightness(enum rgb_led led, int brightness)
+{
+ char file[48];
+
+ snprintf(file, sizeof(file), "/sys/class/leds/%s/brightness", led_names[led]);
+ return write_int(file, brightness);
+}
+
+static int set_rgb_led_timer_trigger(enum rgb_led led, int onMS, int offMS)
+{
+ char file[48];
+ int rc;
+
+ snprintf(file, sizeof(file), "/sys/class/leds/%s/delay_off", led_names[led]);
+ rc = write_int(file, offMS);
+ if (rc < 0)
+ goto out;
+
+ snprintf(file, sizeof(file), "/sys/class/leds/%s/delay_on", led_names[led]);
+ rc = write_int(file, onMS);
+ if (rc < 0)
+ goto out;
+
+ return 0;
+out:
+ ALOGD("%s doesn't support timer trigger\n", led_names[led]);
+ return rc;
+}
+
+static int set_rgb_led_hw_blink(enum rgb_led led, int blink)
+{
+ char file[48];
+
+ snprintf(file, sizeof(file), "/sys/class/leds/%s/breath", led_names[led]);
+ if (!file_exists(file))
+ snprintf(file, sizeof(file), "/sys/class/leds/%s/blink", led_names[led]);
+
+ return write_int(file, blink);
+}
+
static int
set_speaker_light_locked(struct light_device_t* dev,
struct light_state_t const* state)
{
int red, green, blue;
- int blink;
int onMS, offMS;
unsigned int colorRGB;
+ int blink = 0;
+ int rc = 0;
if(!dev) {
return -1;
}
- switch (state->flashMode) {
- case LIGHT_FLASH_TIMED:
- onMS = state->flashOnMS;
- offMS = state->flashOffMS;
- break;
- case LIGHT_FLASH_NONE:
- default:
- onMS = 0;
- offMS = 0;
- break;
- }
-
colorRGB = state->color;
-
-#if 0
- ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
- state->flashMode, colorRGB, onMS, offMS);
-#endif
-
red = (colorRGB >> 16) & 0xFF;
green = (colorRGB >> 8) & 0xFF;
blue = colorRGB & 0xFF;
- if (onMS > 0 && offMS > 0) {
- /*
- * if ON time == OFF time
- * use blink mode 2
- * else
- * use blink mode 1
- */
- if (onMS == offMS)
- blink = 2;
- else
- blink = 1;
- } else {
- blink = 0;
+ onMS = state->flashOnMS;
+ offMS = state->flashOffMS;
+
+ if (onMS != 0 && offMS != 0)
+ blink = 1;
+
+ switch (state->flashMode) {
+ case LIGHT_FLASH_HARDWARE:
+ if (!!red)
+ rc = set_rgb_led_hw_blink(LED_RED, blink);
+ if (!!green)
+ rc |= set_rgb_led_hw_blink(LED_GREEN, blink);
+ if (!!blue)
+ rc |= set_rgb_led_hw_blink(LED_BLUE, blink);
+ /* fallback to timed blinking if breath is not supported */
+ if (rc == 0)
+ break;
+ case LIGHT_FLASH_TIMED:
+ if (!!red)
+ rc = set_rgb_led_timer_trigger(LED_RED, onMS, offMS);
+ if (!!green)
+ rc |= set_rgb_led_timer_trigger(LED_GREEN, onMS, offMS);
+ if (!!blue)
+ rc |= set_rgb_led_timer_trigger(LED_BLUE, onMS, offMS);
+ /* fallback to constant on if timed blinking is not supported */
+ if (rc == 0)
+ break;
+ case LIGHT_FLASH_NONE:
+ default:
+ rc = set_rgb_led_brightness(LED_RED, red);
+ rc |= set_rgb_led_brightness(LED_GREEN, green);
+ rc |= set_rgb_led_brightness(LED_BLUE, blue);
+ break;
}
- if (blink) {
- if (red) {
- if (write_int(RED_BLINK_FILE, blink))
- write_int(RED_LED_FILE, 0);
- }
- if (green) {
- if (write_int(GREEN_BLINK_FILE, blink))
- write_int(GREEN_LED_FILE, 0);
- }
- if (blue) {
- if (write_int(BLUE_BLINK_FILE, blink))
- write_int(BLUE_LED_FILE, 0);
- }
- } else {
- write_int(RED_LED_FILE, red);
- write_int(GREEN_LED_FILE, green);
- write_int(BLUE_LED_FILE, blue);
- }
+ ALOGD("set_speaker_light_locked mode=%d, colorRGB=%08X, onMS=%d, offMS=%d, rc=%d\n",
+ state->flashMode, colorRGB, onMS, offMS, rc);
- return 0;
+ return rc;
}
static void