leds: triggers: add led_trigger_range_event for RGB triggers
PATCH 2/3 leds: triggers: add led_trigger_range_event for RGB triggers
Add led_trigger_range_event() and supporting struct led_trigger_range allowing to map a value within a value range to a color within a color range.
Simple example would be to map a temperature with in a range to a color between green and red.
--- drivers/leds/led-triggers.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/linux/leds.h | 14 ++++++++++++++ 2 files changed, 56 insertions(+)
drivers/leds/led-triggers.c +42 -0
@@ -195,6 +195,9 @@ int led_trigger_register(struct led_trigger *trig)struct led_classdev *led_cdev;struct led_trigger *_trig; +if (trig->range && trig->range->start >= trig->range->end) +return -EINVAL ; +rwlock_init (&trig->leddev_list_lock);INIT_LIST_HEAD (&trig->led_cdevs);
@@ -294,6 +297,45 @@ void led_trigger_event(struct led_trigger *trig, }EXPORT_SYMBOL_GPL (led_trigger_event); +static inline int led_trigger_interpolate (int value, +const struct led_trigger_range *range, +int x_start,int x_end) +{ +return x_start +DIV_ROUND_CLOSEST ((value - range->start) * + (x_end - x_start), range->end - range->start); +} + +void led_trigger_range_event (struct led_trigger *trig,int value) +{ +int h, s, v, hs, he, ss, se, vs, ve, hdiff; + +if (!trig->range) +return ; + + hs = trig->range->color_start >>16 &0xff ; + he = trig->range->color_end >>16 &0xff ; + ss = trig->range->color_start >>8 &0xff ; + se = trig->range->color_end >>8 &0xff ; + vs = trig->range->color_start &0xff ; + ve = trig->range->color_end &0xff ; + hdiff = (252 + he - hs) %252 ; + +/* on color circle, choose shortest way from start to end */ +if (hdiff <=126 && he < hs) + he +=252 ; +else if (hdiff >126 && he > hs) + hs +=252 ; + + value =clamp (value, trig->range->start, trig->range->end); + + h =led_trigger_interpolate (value, trig->range, hs, he) %252 ; + s =led_trigger_interpolate (value, trig->range, ss, se); + v =led_trigger_interpolate (value, trig->range, vs, ve); + +led_trigger_event (trig,LED_SET_HUE_SAT | h <<16 | s <<8 | v); +} +EXPORT_SYMBOL_GPL (led_trigger_range_event); + static void led_trigger_blink_setup(struct led_trigger *trig, unsigned long *delay_on, unsigned long *delay_off,
include/linux/leds.h +14 -0
@@ -241,6 +241,14 @@ enum led_brightness led_hsv_to_rgb(enum led_brightness hsv);#define DEFINE_LED_TRIGGER (x) static struct led_trigger *x;#define DEFINE_LED_TRIGGER_GLOBAL (x) struct led_trigger *x; +struct led_trigger_range { +int start; +int end; +/* HSV color model */ +u32 color_start; +u32 color_end; +}; +#ifdef CONFIG_LEDS_TRIGGERS #define TRIG_NAME_MAX 50
@@ -251,6 +259,9 @@ struct led_trigger {u8 flags;#define LED_TRIG_CAP_RGB BIT(0) +/* optional element for usage with led_trigger_range_event */ +const struct led_trigger_range *range; +void (*activate)(struct led_classdev *led_cdev);void (*deactivate)(struct led_classdev *led_cdev);
@@ -278,6 +289,7 @@ extern void led_trigger_register_simple(const char *name,extern void led_trigger_unregister_simple (struct led_trigger *trigger);extern void led_trigger_event (struct led_trigger *trigger,enum led_brightness event); +extern void led_trigger_range_event (struct led_trigger *trigger,int value);extern void led_trigger_blink (struct led_trigger *trigger,unsigned long *delay_on,unsigned long *delay_off);
@@ -324,6 +336,8 @@ static inline void led_trigger_register_simple(const char *name,static inline void led_trigger_unregister_simple (struct led_trigger *trigger) {}static inline void led_trigger_event (struct led_trigger *trigger,enum led_brightness event) {} +static inline void led_trigger_range_event (struct led_trigger *trigger, +int value) {}static inline void led_trigger_blink (struct led_trigger *trigger,unsigned long *delay_on,unsigned long *delay_off) {}
Signature · 1 line
2.7.2
Quoted 17 lines · Heiner Kallweit
Add
led_trigger_range_event()and supporting structled_trigger_rangeallowing to map a value within a value range to a color within a color range.
Simple example would be to map a temperature with in a range to a color between green and red.Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-triggers.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/linux/leds.h | 14 ++++++++++++++ 2 files changed, 56 insertions(+)drivers/leds/led-triggers.c +0
-0
drivers/leds/led-triggers.c int led_trigger_register(struct led_trigger *trig) · line 200
Quoted 6 lines
drivers/leds/led-triggers.c +3
-0@@ -195,6 +195,9 @@ int led_trigger_register(struct led_trigger *trig)struct led_classdev *led_cdev;struct led_trigger *_trig; +if (trig->range && trig->range->start >= trig->range->end) +return -EINVAL ; +
The "range" property is not needed in struct led_trigger. We can have struct rgb_heartbeat_trig_data and assign it to trigger_data.
Quoted 36 lines
drivers/leds/led-triggers.c +29
-0rwlock_init (&trig->leddev_list_lock);INIT_LIST_HEAD (&trig->led_cdevs);@@ -294,6 +297,45 @@ void led_trigger_event(struct led_trigger *trig, }EXPORT_SYMBOL_GPL (led_trigger_event); +static inline int led_trigger_interpolate (int value, +const struct led_trigger_range *range, +int x_start,int x_end) +{ +return x_start +DIV_ROUND_CLOSEST ((value - range->start) * + (x_end - x_start), range->end - range->start); +} + +void led_trigger_range_event (struct led_trigger *trig,int value) +{ +int h, s, v, hs, he, ss, se, vs, ve, hdiff; + +if (!trig->range) +return ; + + hs = trig->range->color_start >>16 &0xff ; + he = trig->range->color_end >>16 &0xff ; + ss = trig->range->color_start >>8 &0xff ; + se = trig->range->color_end >>8 &0xff ; + vs = trig->range->color_start &0xff ; + ve = trig->range->color_end &0xff ; + hdiff = (252 + he - hs) %252 ; + +/* on color circle, choose shortest way from start to end */ +if (hdiff <=126 && he < hs) + he +=252 ; +else if (hdiff >126 && he > hs) + hs +=252 ; +
drivers/leds/led-triggers.c void led_trigger_event(struct led_trigger *trig, · line 338
Quoted 10 lines
drivers/leds/led-triggers.c +10
-0+ value =clamp (value, trig->range->start, trig->range->end); + + h =led_trigger_interpolate (value, trig->range, hs, he) %252 ; + s =led_trigger_interpolate (value, trig->range, ss, se); + v =led_trigger_interpolate (value, trig->range, vs, ve); + +led_trigger_event (trig,LED_SET_HUE_SAT | h <<16 | s <<8 | v); +} +EXPORT_SYMBOL_GPL (led_trigger_range_event); +
How about making this function a helper returning enum led_brightness and using it in rgb-heartbeat trigger? It would be trigger agnostic then. Later you could also create a new rgb-range trigger, which would expose sysfs attributes for configuring the color range.
It could be also moved to led-rgb-core.c and renamed to led_val_to_color_range or so.
Quoted 23 lines
drivers/leds/led-triggers.c +0
-0static void led_trigger_blink_setup(struct led_trigger *trig, unsigned long *delay_on, unsigned long *delay_off,include/linux/leds.h +8
-0@@ -241,6 +241,14 @@ enum led_brightness led_hsv_to_rgb(enum led_brightness hsv);#define DEFINE_LED_TRIGGER (x) static struct led_trigger *x;#define DEFINE_LED_TRIGGER_GLOBAL (x) struct led_trigger *x; +struct led_trigger_range { +int start; +int end; +/* HSV color model */ +u32 color_start; +u32 color_end; +}; +#ifdef CONFIG_LEDS_TRIGGERS #define TRIG_NAME_MAX 50
include/linux/leds.h struct led_trigger { · line 264
Quoted 6 lines
include/linux/leds.h +3
-0@@ -251,6 +259,9 @@ struct led_trigger {u8 flags;#define LED_TRIG_CAP_RGB BIT(0) +/* optional element for usage with led_trigger_range_event */ +const struct led_trigger_range *range; +
Let's drop it. trigger can carry this information on.
Quoted 21 lines
include/linux/leds.h +3
-0void (*activate)(struct led_classdev *led_cdev);void (*deactivate)(struct led_classdev *led_cdev);@@ -278,6 +289,7 @@ extern void led_trigger_register_simple(const char *name,extern void led_trigger_unregister_simple (struct led_trigger *trigger);extern void led_trigger_event (struct led_trigger *trigger,enum led_brightness event); +extern void led_trigger_range_event (struct led_trigger *trigger,int value);extern void led_trigger_blink (struct led_trigger *trigger,unsigned long *delay_on,unsigned long *delay_off);@@ -324,6 +336,8 @@ static inline void led_trigger_register_simple(const char *name,static inline void led_trigger_unregister_simple (struct led_trigger *trigger) {}static inline void led_trigger_event (struct led_trigger *trigger,enum led_brightness event) {} +static inline void led_trigger_range_event (struct led_trigger *trigger, +int value) {}static inline void led_trigger_blink (struct led_trigger *trigger,unsigned long *delay_on,unsigned long *delay_off) {}
Signature · 2 lines
Best regards, Jacek Anaszewski
Am 18.03.2016 um 14:09 schrieb Jacek Anaszewski:
Quoted 21 lines · Heiner Kallweit
Quoted 20 lines
Add
led_trigger_range_event()and supporting structled_trigger_rangeallowing to map a value within a value range to a color within a color range.
Simple example would be to map a temperature with in a range to a color between green and red.Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-triggers.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/linux/leds.h | 14 ++++++++++++++ 2 files changed, 56 insertions(+)drivers/leds/led-triggers.c +0
-0@@ -195,6 +195,9 @@ int led_trigger_register(struct led_trigger *trig)struct led_classdev *led_cdev;struct led_trigger *_trig;
Quoted 7 lines
drivers/leds/led-triggers.c int led_trigger_register(struct led_trigger *trig) · line 200
Quoted 3 lines
drivers/leds/led-triggers.c +3
-0+if (trig->range && trig->range->start >= trig->range->end) +return -EINVAL ; +The "range" property is not needed in struct
led_trigger. We can have structrgb_heartbeat_trig_dataand assign it totrigger_data.
Mapping a value range to a color range is a generic new feature and independent of the use in the new heartbeat (or better said: system load visualization) trigger.
Having struct led_trigger_range in the trigger struct has the advantage that we can do needed checking only once when registering the trigger and the caller doesn't have to pass a pointer to the struct with each call to led_trigger_range_event().
Quoted 43 lines
Quoted 43 lines
drivers/leds/led-triggers.c +36
-0rwlock_init (&trig->leddev_list_lock);INIT_LIST_HEAD (&trig->led_cdevs);@@ -294,6 +297,45 @@ void led_trigger_event(struct led_trigger *trig, }EXPORT_SYMBOL_GPL (led_trigger_event); +static inline int led_trigger_interpolate (int value, +const struct led_trigger_range *range, +int x_start,int x_end) +{ +return x_start +DIV_ROUND_CLOSEST ((value - range->start) * + (x_end - x_start), range->end - range->start); +} + +void led_trigger_range_event (struct led_trigger *trig,int value) +{ +int h, s, v, hs, he, ss, se, vs, ve, hdiff; + +if (!trig->range) +return ; + + hs = trig->range->color_start >>16 &0xff ; + he = trig->range->color_end >>16 &0xff ; + ss = trig->range->color_start >>8 &0xff ; + se = trig->range->color_end >>8 &0xff ; + vs = trig->range->color_start &0xff ; + ve = trig->range->color_end &0xff ; + hdiff = (252 + he - hs) %252 ; + +/* on color circle, choose shortest way from start to end */ +if (hdiff <=126 && he < hs) + he +=252 ; +else if (hdiff >126 && he > hs) + hs +=252 ; + + value =clamp (value, trig->range->start, trig->range->end); + + h =led_trigger_interpolate (value, trig->range, hs, he) %252 ; + s =led_trigger_interpolate (value, trig->range, ss, se); + v =led_trigger_interpolate (value, trig->range, vs, ve); + +led_trigger_event (trig,LED_SET_HUE_SAT | h <<16 | s <<8 | v);
Quoted 9 lines
drivers/leds/led-triggers.c void led_trigger_event(struct led_trigger *trig, · line 338
Quoted 3 lines
drivers/leds/led-triggers.c +3
-0+} +EXPORT_SYMBOL_GPL (led_trigger_range_event); +How about making this function a helper returning enum
led_brightnessand using it in rgb-heartbeat trigger? It would be trigger agnostic then. Later you could also create a new rgb-range trigger, which would expose sysfs attributes for configuring the color range.
Having the mapping as a helper would be an alternative. However then the caller would always need two calls instead of one:
enum led_brightness brightness = led_val_to_color_range(struct range *, val); led_trigger_event(trig, brightness);
But this might be ok considering that we gain the option to use the mapping feature independent of triggers.
Making the color range configurable via sysfs is an interesting idea. But for this we would first have to introduce generic sysfs handling for triggers I think. Maybe that's something for a next round of extensions.
Quoted 3 lines
It could be also moved to
led-rgb-core.cand renamed toled_val_to_color_rangeor so.
Yes, this would make sense.
Quoted 26 lines
Quoted 26 lines
drivers/leds/led-triggers.c +0
-0static void led_trigger_blink_setup(struct led_trigger *trig, unsigned long *delay_on, unsigned long *delay_off,include/linux/leds.h +8
-0@@ -241,6 +241,14 @@ enum led_brightness led_hsv_to_rgb(enum led_brightness hsv);#define DEFINE_LED_TRIGGER (x) static struct led_trigger *x;#define DEFINE_LED_TRIGGER_GLOBAL (x) struct led_trigger *x; +struct led_trigger_range { +int start; +int end; +/* HSV color model */ +u32 color_start; +u32 color_end; +}; +#ifdef CONFIG_LEDS_TRIGGERS #define TRIG_NAME_MAX 50@@ -251,6 +259,9 @@ struct led_trigger {u8 flags;#define LED_TRIG_CAP_RGB BIT(0)
Quoted 6 lines
include/linux/leds.h struct led_trigger { · line 264
Quoted 3 lines
include/linux/leds.h +3
-0+/* optional element for usage with led_trigger_range_event */ +const struct led_trigger_range *range; +Let's drop it. trigger can carry this information on.
If we have the mapping as a helper, independent of triggers, then we won't have the pointer to struct range here anyway.
Quoted 23 lines
Quoted 21 lines
include/linux/leds.h +3
-0void (*activate)(struct led_classdev *led_cdev);void (*deactivate)(struct led_classdev *led_cdev);@@ -278,6 +289,7 @@ extern void led_trigger_register_simple(const char *name,extern void led_trigger_unregister_simple (struct led_trigger *trigger);extern void led_trigger_event (struct led_trigger *trigger,enum led_brightness event); +extern void led_trigger_range_event (struct led_trigger *trigger,int value);extern void led_trigger_blink (struct led_trigger *trigger,unsigned long *delay_on,unsigned long *delay_off);@@ -324,6 +336,8 @@ static inline void led_trigger_register_simple(const char *name,static inline void led_trigger_unregister_simple (struct led_trigger *trigger) {}static inline void led_trigger_event (struct led_trigger *trigger,enum led_brightness event) {} +static inline void led_trigger_range_event (struct led_trigger *trigger, +int value) {}static inline void led_trigger_blink (struct led_trigger *trigger,unsigned long *delay_on,unsigned long *delay_off) {}