From 9aa6696eb86c982edba21e8f168f4c31abfb8f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 09:54:18 +0200 Subject: [PATCH 01/10] build: Let daemon dependency depend on generated enum headers Otherwise it might not be available in the tests --- src/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meson.build b/src/meson.build index 2ae7691..5be31e8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -61,7 +61,7 @@ fbd_lib = static_library( ) fbd_dep = declare_dependency( - sources: generated_dbus_sources, + sources: [generated_dbus_sources, fbd_enum_sources], include_directories : fbd_inc, link_with : fbd_lib, dependencies : fbd_deps, From 6e9e5700c0ec539faf63af112baa3948adefb2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 08:47:39 +0200 Subject: [PATCH 02/10] dev-led-multicolor: Use correct format specifier The values are unsigned int --- src/fbd-dev-led-multicolor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index 23fcf54..b211dfb 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -129,7 +129,8 @@ fbd_dev_led_multicolor_set_color (FbdDevLed *led, return FALSE; } - intensity = g_strdup_printf ("%d %d %d\n", colors[0], colors[1], colors[2]); + intensity = g_strdup_printf ("%u %u %u\n", colors[0], colors[1], colors[2]); + fbd_dev_led_set_brightness (led, max_brightness); success = fbd_udev_set_sysfs_path_attr_as_string (dev, LED_MULTI_INTENSITY_ATTR, From 17d910651d67da77e9cad7f815eb9342bd4015bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 10:13:20 +0200 Subject: [PATCH 03/10] doc: Document feedback types This allows us to remove the list from the README --- README.md | 8 ++------ doc/feedback-themes.rst | 30 ++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ef32aff..91067d7 100644 --- a/README.md +++ b/README.md @@ -181,12 +181,7 @@ examples: over `/usr/share/feedbackd/themes/pine64-pinephone-1.2.json` - etc... -The currently available feedback types are: - -- Sound (an audible sound from the sound naming spec) -- VibraRumble: haptic motor rumbling -- VibraPeriodic: periodic feedback from the haptic motor -- Led: Feedback via blinking LEDs +For available feeddback types see the [feedback-themes][](5) manpage. You can check the feedback theme and the classes (prefixed with Fbd) for available properties. Note that the feedback theme API (including @@ -271,3 +266,4 @@ GSETTINGS_SCHEMA_DIR=_build/data/ gsettings set org.sigxcpu.feedbackd.applicatio [debian/control]: ./debian/control#L5 [1]: https://source.puri.sm/Librem5/feedbackd-device-themes +[feedback-themes]: ./doc/feedback-themes.rst diff --git a/doc/feedback-themes.rst b/doc/feedback-themes.rst index 203f550..30029a4 100644 --- a/doc/feedback-themes.rst +++ b/doc/feedback-themes.rst @@ -9,7 +9,7 @@ Theme configuration for feedbackd --------------------------------- DESCRIPTION -=========== +----------- In order to reflect device specifics and user overrides the feedback (such as sound, haptic or led) that is being triggered by an event can @@ -19,12 +19,38 @@ format that can be validated with ``fbd-theme-validate``. For details on how to create or modify feedback themes see [feedbackd's documentation]( https://source.puri.sm/Librem5/feedbackd#feedback-theme). +Feedback types +-------------- + +To build a theme you can use several different feedback types: + +- `Sound`: Plays a sound from the installed sound theme +- `VibraRumble`: A single rumble using the haptic motor +- `VibraPeriodic`: A periodic rumble using the haptic motor +- `Led`: A LED blinking in a periodic pattern + Sound feedback -============== +~~~~~~~~~~~~~~ Sound feedbacks specify an event name from a XDG sound theme. Sound themes are described in the [Sound theme spec](https://freedesktop.org/wiki/Specifications/sound-theme-spec/). +VibraRumble feedback +~~~~~~~~~~~~~~~~~~~~ + +The `VibraRumble` feedback uses a single property + +- `duration`: The duration of the rumble in ms. + +LED feedback +~~~~~~~~~~~~ + +The `Led` feedback type uses two properties to specify the way a LED blinks. + +- `color`: This specifies the color a LED should blink with. It supports the fixed color names `red`, + `green`, `blue` and `white. +- `frequency`: The LEDs blinkinig frequencey in mHz. + See also ======== From 8d4c2590cbd087d22a196b1ee8134077fd1c6f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 10:33:56 +0200 Subject: [PATCH 04/10] doc: Fix URLs Don't use Markdown markup as it looks odd in the generated page. --- doc/feedback-themes.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/feedback-themes.rst b/doc/feedback-themes.rst index 30029a4..4676ae2 100644 --- a/doc/feedback-themes.rst +++ b/doc/feedback-themes.rst @@ -16,8 +16,8 @@ In order to reflect device specifics and user overrides the feedback be configured and overridden by so called themes. Feedback themes use a JSON format that can be validated with ``fbd-theme-validate``. -For details on how to create or modify feedback themes see [feedbackd's documentation]( -https://source.puri.sm/Librem5/feedbackd#feedback-theme). +For details on how to create or modify feedback themes see +``feedbackd's documentation`` at https://source.puri.sm/Librem5/feedbackd#feedback-theme Feedback types -------------- @@ -33,7 +33,7 @@ Sound feedback ~~~~~~~~~~~~~~ Sound feedbacks specify an event name from a XDG sound theme. Sound themes -are described in the [Sound theme spec](https://freedesktop.org/wiki/Specifications/sound-theme-spec/). +are described in the ``Sound theme spec`` at https://freedesktop.org/wiki/Specifications/sound-theme-spec/ VibraRumble feedback ~~~~~~~~~~~~~~~~~~~~ From 4551b1c9397c8a7e3dc17f323afa584faceae773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 08:47:40 +0200 Subject: [PATCH 05/10] fbd-feedback-led: Modernize property definitions Adapt current phosh coding style before making other changes --- src/fbd-feedback-led.c | 69 +++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/fbd-feedback-led.c b/src/fbd-feedback-led.c index 5013188..bc606ad 100644 --- a/src/fbd-feedback-led.c +++ b/src/fbd-feedback-led.c @@ -1,6 +1,8 @@ /* * Copyright (C) 2020 Purism SPC + * 2024 The Phosh Developers * SPDX-License-Identifier: GPL-3.0+ + * * Author: Guido Günther */ @@ -12,11 +14,9 @@ #include "fbd-feedback-manager.h" /** - * SECTION:fbd-feedback-led - * @short_description: Describes a led feedback - * @Title: FbdFeedbackLed + * FbdFeedbackLed: * - * The #FbdFeedbackLed describes a feedback via an LED. It currently + * The `FbdFeedbackLed` describes a feedback via an LED. It currently * only supports periodic patterns. */ @@ -68,6 +68,7 @@ fbd_feedback_led_set_property (GObject *object, } } + static void fbd_feedback_led_get_property (GObject *object, guint property_id, @@ -95,6 +96,7 @@ fbd_feedback_led_get_property (GObject *object, } } + static void fbd_feedback_led_run (FbdFeedbackBase *base) { @@ -112,6 +114,7 @@ fbd_feedback_led_run (FbdFeedbackBase *base) self->frequency); } + static void fbd_feedback_led_end (FbdFeedbackBase *base) { @@ -124,6 +127,7 @@ fbd_feedback_led_end (FbdFeedbackBase *base) fbd_feedback_base_done (FBD_FEEDBACK_BASE (self)); } + static gboolean fbd_feedback_led_is_available (FbdFeedbackBase *base) { @@ -133,6 +137,7 @@ fbd_feedback_led_is_available (FbdFeedbackBase *base) return FBD_IS_DEV_LEDS (dev); } + static void fbd_feedback_led_class_init (FbdFeedbackLedClass *klass) { @@ -146,38 +151,36 @@ fbd_feedback_led_class_init (FbdFeedbackLedClass *klass) base_class->end = fbd_feedback_led_end; base_class->is_available = fbd_feedback_led_is_available; + /** + * FbdFeedbackLed:frequency: + * + * The frequency the LED should blink with in mHz. + */ props[PROP_FREQUENCY] = - g_param_spec_uint ( - "frequency", - "Frequency", - "Led event frequency in mHz", - 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - + g_param_spec_uint ("frequency", "", "", + 0, G_MAXUINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * FbdFeedbackLed:color: + * + * The color the LED should blink with. + */ props[PROP_COLOR] = - g_param_spec_enum ( - "color", - "Color", - "The LED color", - FBD_TYPE_FEEDBACK_LED_COLOR, - FBD_FEEDBACK_LED_COLOR_WHITE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - + g_param_spec_enum ("color", "", "", + FBD_FEEDBACK_LED_COLOR_WHITE, + FBD_TYPE_FEEDBACK_LED_COLOR, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * FbdFeedbackLed:priority: * - * Priority of the led pattern. Led devices can only display a limited - * amount of patterns at time. In this case the pattern with the highest + * Priority of the LED pattern. LED devices can only display a limited + * amount of patterns at a time. In this case the pattern with the highest * priority wins. */ props[PROP_PRIORITY] = - g_param_spec_uint ( - "priority", - "Priority", - "The LED pattern priority", - 0, 255, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - + g_param_spec_uint ("priority", "", "", + 0, 255, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * FbdFeedbackLed:max-brightness: * @@ -185,16 +188,14 @@ fbd_feedback_led_class_init (FbdFeedbackLedClass *klass) * maximum brightness. */ props[PROP_MAX_BRIGHTNESS] = - g_param_spec_uint ( - "max-brightness", - "Maximum brightness percentage", - "Maximum brightness in the LED pattern", - 1, 100, 100, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_param_spec_uint ("max-brightness", "", "", + 1, 100, 100, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } + static void fbd_feedback_led_init (FbdFeedbackLed *self) { From 5bd398ed1870385de8a2f7e49d41d3480101b509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 08:47:41 +0200 Subject: [PATCH 06/10] feedback-led: Support colors as strings The FbdDevLedColor enum defines the hardware color of the LED. We used it for the feedbacks color value as long as the kernel mostly had single color LEDs. As multicolor LEDs are common nowadays switch the color to a string which will allow us to use RGB values later on. --- src/fbd-feedback-led.c | 63 ++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/src/fbd-feedback-led.c b/src/fbd-feedback-led.c index bc606ad..4cae94c 100644 --- a/src/fbd-feedback-led.c +++ b/src/fbd-feedback-led.c @@ -31,16 +31,35 @@ enum { static GParamSpec *props[PROP_LAST_PROP]; typedef struct _FbdFeedbackLed { - FbdFeedbackBase parent; + FbdFeedbackBase parent; - guint frequency; - guint priority; - guint max_brightness; - FbdFeedbackLedColor color; + guint frequency; + guint priority; + guint max_brightness; + char *color; } FbdFeedbackLed; G_DEFINE_TYPE (FbdFeedbackLed, fbd_feedback_led, FBD_TYPE_FEEDBACK_BASE) + +static FbdFeedbackLedColor +color_string_to_color (const char *color) +{ + + if (g_strcmp0 (color, "red") == 0) + return FBD_FEEDBACK_LED_COLOR_RED; + else if (g_strcmp0 (color, "green") == 0) + return FBD_FEEDBACK_LED_COLOR_GREEN; + else if (g_strcmp0 (color, "blue") == 0) + return FBD_FEEDBACK_LED_COLOR_BLUE; + else if (g_strcmp0 (color, "white") == 0) + return FBD_FEEDBACK_LED_COLOR_WHITE; + + g_warning_once ("Can't parse color '%s' using white", color); + return FBD_FEEDBACK_LED_COLOR_WHITE; +} + + static void fbd_feedback_led_set_property (GObject *object, guint property_id, @@ -60,7 +79,7 @@ fbd_feedback_led_set_property (GObject *object, self->max_brightness = g_value_get_uint (value); break; case PROP_COLOR: - self->color = g_value_get_enum (value); + self->color = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -88,7 +107,7 @@ fbd_feedback_led_get_property (GObject *object, g_value_set_uint (value, self->max_brightness); break; case PROP_COLOR: - g_value_set_enum (value, self->color); + g_value_set_string (value, self->color); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -103,13 +122,15 @@ fbd_feedback_led_run (FbdFeedbackBase *base) FbdFeedbackLed *self = FBD_FEEDBACK_LED (base); FbdFeedbackManager *manager = fbd_feedback_manager_get_default (); FbdDevLeds *dev = fbd_feedback_manager_get_dev_leds (manager); + FbdFeedbackLedColor color; g_return_if_fail (FBD_IS_DEV_LEDS (dev)); g_debug ("Periodic led feedback: self->max_brightness, self->frequency"); + color = color_string_to_color (self->color); /* FIXME: handle priority */ fbd_dev_leds_start_periodic (dev, - self->color, + color, self->max_brightness, self->frequency); } @@ -121,9 +142,11 @@ fbd_feedback_led_end (FbdFeedbackBase *base) FbdFeedbackLed *self = FBD_FEEDBACK_LED (base); FbdFeedbackManager *manager = fbd_feedback_manager_get_default (); FbdDevLeds *dev = fbd_feedback_manager_get_dev_leds (manager); + FbdFeedbackLedColor color; + color = color_string_to_color (self->color); if (dev) - fbd_dev_leds_stop (dev, self->color); + fbd_dev_leds_stop (dev, color); fbd_feedback_base_done (FBD_FEEDBACK_BASE (self)); } @@ -138,6 +161,17 @@ fbd_feedback_led_is_available (FbdFeedbackBase *base) } +static void +fbd_feedback_led_finalize (GObject *object) +{ + FbdFeedbackLed *self = FBD_FEEDBACK_LED (object); + + g_clear_pointer (&self->color, g_free); + + G_OBJECT_CLASS (fbd_feedback_led_parent_class)->finalize (object); +} + + static void fbd_feedback_led_class_init (FbdFeedbackLedClass *klass) { @@ -146,6 +180,7 @@ fbd_feedback_led_class_init (FbdFeedbackLedClass *klass) object_class->set_property = fbd_feedback_led_set_property; object_class->get_property = fbd_feedback_led_get_property; + object_class->finalize = fbd_feedback_led_finalize; base_class->run = fbd_feedback_led_run; base_class->end = fbd_feedback_led_end; @@ -163,13 +198,13 @@ fbd_feedback_led_class_init (FbdFeedbackLedClass *klass) /** * FbdFeedbackLed:color: * - * The color the LED should blink with. + * The color the LED should blink with. The color is given as color + * name or `rgb()` color value. */ props[PROP_COLOR] = - g_param_spec_enum ("color", "", "", - FBD_FEEDBACK_LED_COLOR_WHITE, - FBD_TYPE_FEEDBACK_LED_COLOR, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_param_spec_string ("color", "", "", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * FbdFeedbackLed:priority: * From 4afc8398e29568d2ceb328b88c1428e15bacfc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 08:47:41 +0200 Subject: [PATCH 07/10] feedbackd: Pass GMOBILE_USE_UNSTABLE_API to all files No need to ack that individually --- src/fbd-feedback-manager.c | 1 - src/meson.build | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index 0fa7f23..4560a95 100644 --- a/src/fbd-feedback-manager.c +++ b/src/fbd-feedback-manager.c @@ -16,7 +16,6 @@ #include "fbd-feedback-theme.h" #include "fbd-theme-expander.h" -#define GMOBILE_USE_UNSTABLE_API #include #include diff --git a/src/meson.build b/src/meson.build index 5be31e8..f538ef1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -57,6 +57,7 @@ fbd_lib = static_library( sources, include_directories : fbd_inc, dependencies : fbd_deps, + c_args: '-DGMOBILE_USE_UNSTABLE_API', install : false, ) From efd088daa8d99eeb80679fef1dd66770aad99425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 08:47:42 +0200 Subject: [PATCH 08/10] feedback-led: Document hw LED types --- src/fbd-feedback-led.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/fbd-feedback-led.h b/src/fbd-feedback-led.h index 783970f..8a6fe91 100644 --- a/src/fbd-feedback-led.h +++ b/src/fbd-feedback-led.h @@ -9,6 +9,16 @@ G_BEGIN_DECLS +/** + * FbdDevLedColor: + * @FBD_FEEDBACK_LED_COLOR_WHITE: A white LED + * @FBD_FEEDBACK_LED_COLOR_RED: A red LED + * @FBD_FEEDBACK_LED_COLOR_GREEN: A green LED + * @FBD_FEEDBACK_LED_COLOR_BLUE: A blue LED + * @FBD_FEEDBACK_LED_COLOR_RGB: A multicolor LED that can display arbitrary RGB values + * + * The color of a hardware LED. + */ typedef enum _FbdFeedbackLedColor { FBD_FEEDBACK_LED_COLOR_WHITE = 0, FBD_FEEDBACK_LED_COLOR_RED = 1, From a4c35a8e61bb880048670dbdf33243f394947212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 08:47:43 +0200 Subject: [PATCH 09/10] led: Parse color values and pass them down the chain We parse RGB color values as HEX ('#RRGGBB') and use those when a RGB LED is available. Single color LEDs won't see a change. --- doc/feedback-themes.rst | 4 +- src/fbd-dev-led-multicolor.c | 11 +++- src/fbd-dev-led.c | 24 ++++---- src/fbd-dev-led.h | 13 ++-- src/fbd-dev-leds.c | 12 ++-- src/fbd-dev-leds.h | 8 ++- src/fbd-feedback-led.c | 109 +++++++++++++++++++++++++++++++--- src/fbd-feedback-led.h | 4 ++ tests/meson.build | 1 + tests/test-fbd-feedback-led.c | 65 ++++++++++++++++++++ 10 files changed, 215 insertions(+), 36 deletions(-) create mode 100644 tests/test-fbd-feedback-led.c diff --git a/doc/feedback-themes.rst b/doc/feedback-themes.rst index 4676ae2..dea3682 100644 --- a/doc/feedback-themes.rst +++ b/doc/feedback-themes.rst @@ -48,7 +48,9 @@ LED feedback The `Led` feedback type uses two properties to specify the way a LED blinks. - `color`: This specifies the color a LED should blink with. It supports the fixed color names `red`, - `green`, `blue` and `white. + `green`, `blue` and `white` as well as values in the RGB HEX format (`#RRGGBB`) where + `RR`, `GG` and `BB` are two digit hex value between `00` and `FF` specifying the value of + each component. E.g. `#00FFFF` corresponds to cyan color. - `frequency`: The LEDs blinkinig frequencey in mHz. See also diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index b211dfb..e330155 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -91,7 +91,8 @@ fbd_dev_led_multicolor_probe (FbdDevLed *led, GError **error) static gboolean fbd_dev_led_multicolor_set_color (FbdDevLed *led, - FbdFeedbackLedColor color) + FbdFeedbackLedColor color, + FbdLedRgbColor *rgb) { FbdDevLedMulticolor *self = FBD_DEV_LED_MULTICOLOR (led); FbdDevLedMulticolorPrivate *priv = fbd_dev_led_multicolor_get_instance_private (self); @@ -124,12 +125,18 @@ fbd_dev_led_multicolor_set_color (FbdDevLed *led, colors[priv->green_index] = 0; colors[priv->blue_index] = max_brightness; break; + case FBD_FEEDBACK_LED_COLOR_RGB: + colors[priv->red_index] = rgb->r; + colors[priv->green_index] = rgb->g; + colors[priv->blue_index] = rgb->b; + break; default: g_warning("Unhandled color: %d\n", color); return FALSE; } intensity = g_strdup_printf ("%u %u %u\n", colors[0], colors[1], colors[2]); + g_debug ("Multicolor intensity: %s", intensity); fbd_dev_led_set_brightness (led, max_brightness); success = fbd_udev_set_sysfs_path_attr_as_string (dev, @@ -158,6 +165,8 @@ fbd_dev_led_multicolor_supports_color (FbdDevLed *led, return TRUE; case FBD_FEEDBACK_LED_COLOR_BLUE: return TRUE; + case FBD_FEEDBACK_LED_COLOR_RGB: + return TRUE; default: g_warning ("Color unsupported: %d", color); return FALSE; diff --git a/src/fbd-dev-led.c b/src/fbd-dev-led.c index f3b942f..1ec0812 100644 --- a/src/fbd-dev-led.c +++ b/src/fbd-dev-led.c @@ -33,10 +33,7 @@ static GParamSpec *props[PROP_LAST_PROP]; typedef struct _FbdDevLedPrivate { GUdevDevice *dev; guint max_brightness; - /* - * We just use the colors from the feedback until we - * do rgb mixing, etc - */ + FbdFeedbackLedColor color; } FbdDevLedPrivate; @@ -55,9 +52,6 @@ fbd_dev_led_probe_default (FbdDevLed *led, GError **error) gboolean success = FALSE; name = g_udev_device_get_name (priv->dev); - /* We don't know anything about diffusors that can combine different - color LEDSs so go with fixed colors until the kernel gives us - enough information */ for (int i = 0; i <= FBD_FEEDBACK_LED_COLOR_LAST; i++) { g_autofree char *color = NULL; g_autofree char *enum_name = NULL; @@ -94,7 +88,8 @@ fbd_dev_led_probe_default (FbdDevLed *led, GError **error) static gboolean fbd_dev_led_set_color_default (FbdDevLed *led, - FbdFeedbackLedColor color) + FbdFeedbackLedColor color, + FbdLedRgbColor *rgb) { /* Ignore setting color as we have a single color only */ return TRUE; @@ -270,9 +265,9 @@ fbd_dev_led_set_brightness (FbdDevLed *led, guint brightness) gboolean -fbd_dev_led_start_periodic (FbdDevLed *led, - guint max_brightness_percentage, - guint freq) +fbd_dev_led_start_periodic (FbdDevLed *led, + guint max_brightness_percentage, + guint freq) { FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_GET_CLASS (led); @@ -283,14 +278,15 @@ fbd_dev_led_start_periodic (FbdDevLed *led, gboolean -fbd_dev_led_set_color (FbdDevLed *led, - FbdFeedbackLedColor color) +fbd_dev_led_set_color (FbdDevLed *led, + FbdFeedbackLedColor color, + FbdLedRgbColor *rgb) { FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_GET_CLASS (led); g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); - return fbd_dev_led_class->set_color (led, color); + return fbd_dev_led_class->set_color (led, color, rgb); } diff --git a/src/fbd-dev-led.h b/src/fbd-dev-led.h index 0aba548..0122ecd 100644 --- a/src/fbd-dev-led.h +++ b/src/fbd-dev-led.h @@ -20,10 +20,12 @@ G_DECLARE_DERIVABLE_TYPE (FbdDevLed, fbd_dev_led, FBD, DEV_LED, GObject) FbdDevLed *fbd_dev_led_new (GUdevDevice *dev, GError **err); gboolean fbd_dev_led_set_brightness (FbdDevLed *led, guint brightness); guint fbd_dev_led_get_max_brightness (FbdDevLed *led); -gboolean fbd_dev_led_set_color (FbdDevLed *led, FbdFeedbackLedColor color); -gboolean fbd_dev_led_start_periodic (FbdDevLed *led, - guint max_brightness_percentage, - guint freq); +gboolean fbd_dev_led_set_color (FbdDevLed *led, + FbdFeedbackLedColor color, + FbdLedRgbColor *rgb); +gboolean fbd_dev_led_start_periodic (FbdDevLed *led, + guint max_brightness_percentage, + guint freq); gboolean fbd_dev_led_supports_color (FbdDevLed *led, FbdFeedbackLedColor color); struct _FbdDevLedClass { @@ -34,7 +36,8 @@ struct _FbdDevLedClass { guint max_brightness_percentage, guint freq); gboolean (*set_color) (FbdDevLed *led, - FbdFeedbackLedColor color); + FbdFeedbackLedColor color, + FbdLedRgbColor *rgb); gboolean (*supports_color) (FbdDevLed *led, FbdFeedbackLedColor color); }; diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index 418cf44..f0eb1df 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -180,15 +180,19 @@ fbd_dev_leds_new (GError **error) /** * fbd_dev_leds_start_periodic: * @self: The #FbdDevLeds - * @color: The color to use for the LED pattern + * @color: The color LED to use for the LED pattern + * @rgb: The rgb value to set (if `color` indicates an RGB led) * @max_brightness_percentage: The max brightness (in percent) to use for the pattern * @freq: The pattern's frequency in mHz * * Start periodic feedback. */ gboolean -fbd_dev_leds_start_periodic (FbdDevLeds *self, FbdFeedbackLedColor color, - guint max_brightness_percentage, guint freq) +fbd_dev_leds_start_periodic (FbdDevLeds *self, + FbdFeedbackLedColor color, + FbdLedRgbColor *rgb, + guint max_brightness_percentage, + guint freq) { FbdDevLed *led; @@ -197,7 +201,7 @@ fbd_dev_leds_start_periodic (FbdDevLeds *self, FbdFeedbackLedColor color, led = find_led_by_color (self, color); g_return_val_if_fail (led, FALSE); - fbd_dev_led_set_color (led, color); + fbd_dev_led_set_color (led, color, rgb); return fbd_dev_led_start_periodic (led, max_brightness_percentage, freq); } diff --git a/src/fbd-dev-leds.h b/src/fbd-dev-leds.h index 999dbd9..6387882 100644 --- a/src/fbd-dev-leds.h +++ b/src/fbd-dev-leds.h @@ -17,9 +17,11 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (FbdDevLeds, fbd_dev_leds, FBD, DEV_LEDS, GObject); FbdDevLeds *fbd_dev_leds_new (GError **error); -gboolean fbd_dev_leds_start_periodic (FbdDevLeds *self, - FbdFeedbackLedColor color, - guint max_brighness, guint freq); +gboolean fbd_dev_leds_start_periodic (FbdDevLeds *self, + FbdFeedbackLedColor color, + FbdLedRgbColor *rgb, + guint max_brighness, + guint freq); gboolean fbd_dev_leds_stop (FbdDevLeds *self, FbdFeedbackLedColor color); diff --git a/src/fbd-feedback-led.c b/src/fbd-feedback-led.c index 4cae94c..dc297b7 100644 --- a/src/fbd-feedback-led.c +++ b/src/fbd-feedback-led.c @@ -13,6 +13,8 @@ #include "fbd-feedback-led.h" #include "fbd-feedback-manager.h" +#include + /** * FbdFeedbackLed: * @@ -41,21 +43,110 @@ typedef struct _FbdFeedbackLed { G_DEFINE_TYPE (FbdFeedbackLed, fbd_feedback_led, FBD_TYPE_FEEDBACK_BASE) +/** + * ascii_to_int: + * @c: a character + * + * Interprets a character as digit. E.g. '1' will be converted to 1, + * 'C' or 'c' will be converted to 12. + * + * Returns: The integer value or -1 if the character isn't a hex digit. + */ +static int +hex_ascii_to_int (char c) +{ + switch (c) { + case '0'...'9': + return c - '0'; + break; + case 'a'...'f': + return 10 + c - 'a'; + break; + case 'A'...'F': + return 10 + c - 'A'; + break; + default: + return -1; + } +} + + +static gboolean +parse_hex_color (const char *color, FbdLedRgbColor *rgb) +{ + FbdLedRgbColor parsed = { 0 }; + + if (color[0] != '#') + return FALSE; + + if (strlen (color) != strlen ("#11AA00")) + return FALSE; + + if (!rgb) + return TRUE; + + for (int i = 1; color[i]; i++) { + int c = hex_ascii_to_int (color[i]); + + if (c < 0) + return FALSE; + + switch (i) { + case 1: + parsed.r |= hex_ascii_to_int (color[i]) << 4; + break; + case 2: + parsed.r |= hex_ascii_to_int (color[i]); + break; + case 3: + parsed.g |= hex_ascii_to_int (color[i]) << 4; + break; + case 4: + parsed.g |= hex_ascii_to_int (color[i]); + break; + case 5: + parsed.b |= hex_ascii_to_int (color[i]) << 4; + break; + case 6: + parsed.b |= hex_ascii_to_int (color[i]); + break; + } + } + + memcpy (rgb, &parsed, sizeof (FbdLedRgbColor)); + + return TRUE; +} + static FbdFeedbackLedColor -color_string_to_color (const char *color) +color_string_to_color (const char *color, FbdLedRgbColor *rgb) { + g_return_val_if_fail (!gm_str_is_null_or_empty (color), FBD_FEEDBACK_LED_COLOR_WHITE); - if (g_strcmp0 (color, "red") == 0) + if (g_strcmp0 (color, "red") == 0) { + if (rgb) + rgb->r = 255; return FBD_FEEDBACK_LED_COLOR_RED; - else if (g_strcmp0 (color, "green") == 0) + } else if (g_strcmp0 (color, "green") == 0) { + if (rgb) + rgb->g = 255; return FBD_FEEDBACK_LED_COLOR_GREEN; - else if (g_strcmp0 (color, "blue") == 0) + } else if (g_strcmp0 (color, "blue") == 0) { + if (rgb) + rgb->b = 255; return FBD_FEEDBACK_LED_COLOR_BLUE; - else if (g_strcmp0 (color, "white") == 0) + } else if (g_strcmp0 (color, "white") == 0) { + if (rgb) + rgb->r = rgb->g = rgb->b = 255; return FBD_FEEDBACK_LED_COLOR_WHITE; + } else if (parse_hex_color (color, rgb)) { + return FBD_FEEDBACK_LED_COLOR_RGB; + } g_warning_once ("Can't parse color '%s' using white", color); + if (rgb) + rgb->r = rgb->g = rgb->b = 255; return FBD_FEEDBACK_LED_COLOR_WHITE; } @@ -123,14 +214,16 @@ fbd_feedback_led_run (FbdFeedbackBase *base) FbdFeedbackManager *manager = fbd_feedback_manager_get_default (); FbdDevLeds *dev = fbd_feedback_manager_get_dev_leds (manager); FbdFeedbackLedColor color; + FbdLedRgbColor rgb; g_return_if_fail (FBD_IS_DEV_LEDS (dev)); - g_debug ("Periodic led feedback: self->max_brightness, self->frequency"); + g_debug ("Periodic led feedback: max brightness: %d, freq: %d", self->max_brightness, self->frequency); - color = color_string_to_color (self->color); + color = color_string_to_color (self->color, &rgb); /* FIXME: handle priority */ fbd_dev_leds_start_periodic (dev, color, + &rgb, self->max_brightness, self->frequency); } @@ -144,7 +237,7 @@ fbd_feedback_led_end (FbdFeedbackBase *base) FbdDevLeds *dev = fbd_feedback_manager_get_dev_leds (manager); FbdFeedbackLedColor color; - color = color_string_to_color (self->color); + color = color_string_to_color (self->color, NULL); if (dev) fbd_dev_leds_stop (dev, color); fbd_feedback_base_done (FBD_FEEDBACK_BASE (self)); diff --git a/src/fbd-feedback-led.h b/src/fbd-feedback-led.h index 8a6fe91..f67af6c 100644 --- a/src/fbd-feedback-led.h +++ b/src/fbd-feedback-led.h @@ -28,6 +28,10 @@ typedef enum _FbdFeedbackLedColor { FBD_FEEDBACK_LED_COLOR_LAST = FBD_FEEDBACK_LED_COLOR_RGB, } FbdFeedbackLedColor; +typedef struct { + guint r, g, b; +} FbdLedRgbColor; + #define FBD_TYPE_FEEDBACK_LED (fbd_feedback_led_get_type ()) G_DECLARE_FINAL_TYPE (FbdFeedbackLed, fbd_feedback_led, FBD, FEEDBACK_LED, FbdFeedbackBase); diff --git a/tests/meson.build b/tests/meson.build index a8672a3..509a663 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -78,6 +78,7 @@ test_fbd_deps = [ # HW independent tests fbd_tests = [ + 'fbd-feedback-led', 'fbd-feedback-profile', 'fbd-feedback-theme', 'fbd-event', diff --git a/tests/test-fbd-feedback-led.c b/tests/test-fbd-feedback-led.c new file mode 100644 index 0000000..2b7bb0e --- /dev/null +++ b/tests/test-fbd-feedback-led.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0+ + * + * Author: Guido Günther + */ + +#define GMOBILE_USE_UNSTABLE_API +#include "fbd-feedback-led.c" + + +static void +test_fbd_feedback_led_parse_color (void) +{ + FbdLedRgbColor rgb = { 0 }; + + g_assert_true (parse_hex_color ("#11aaBB", &rgb)); + g_assert_cmpint (rgb.r, ==, 0x11); + g_assert_cmpint (rgb.g, ==, 0xaa); + g_assert_cmpint (rgb.b, ==, 0xbb); + + g_assert_true (parse_hex_color ("#000000", &rgb)); + g_assert_cmpint (rgb.r, ==, 0x00); + g_assert_cmpint (rgb.g, ==, 0x00); + g_assert_cmpint (rgb.b, ==, 0x00); + + g_assert_false (parse_hex_color ("#1bc", &rgb)); + g_assert_false (parse_hex_color ("11aaBB", &rgb)); + g_assert_false (parse_hex_color ("", &rgb)); + g_assert_false (parse_hex_color ("#", &rgb)); + g_assert_false (parse_hex_color ("#QWERTY", &rgb)); +} + + +static void +test_fbd_feedback_led_color_string_to_color (void) +{ + FbdLedRgbColor rgb = { 0 }; + + g_assert_cmpint (color_string_to_color ("red", NULL), ==, FBD_FEEDBACK_LED_COLOR_RED); + + g_assert_cmpint (color_string_to_color ("#11aaBB", &rgb), ==, FBD_FEEDBACK_LED_COLOR_RGB); + g_assert_cmpint (rgb.r, ==, 0x11); + g_assert_cmpint (rgb.g, ==, 0xaa); + g_assert_cmpint (rgb.b, ==, 0xbb); + + g_assert_cmpint (color_string_to_color ("#00FF00", &rgb), ==, FBD_FEEDBACK_LED_COLOR_RGB); + g_assert_cmpint (rgb.r, ==, 0x00); + g_assert_cmpint (rgb.g, ==, 0xFF); + g_assert_cmpint (rgb.b, ==, 0x00); +} + + +gint +main (gint argc, gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func("/feedbackd/fbd/feedback-led/parse-color", test_fbd_feedback_led_parse_color); + g_test_add_func("/feedbackd/fbd/feedback-led/color-string-to-color", + test_fbd_feedback_led_color_string_to_color); + + return g_test_run(); +} From afdeb8d56f9f2beee5a41fc8bad56ce111b68809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 12 Jun 2024 08:50:17 +0200 Subject: [PATCH 10/10] theme: Use different colors for emails and calls This makes them a bit simpler to distinguish --- data/default.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/default.json b/data/default.json index 40e5858..521bf4e 100644 --- a/data/default.json +++ b/data/default.json @@ -171,13 +171,13 @@ { "event-name" : "phone-missed-call", "type" : "Led", - "color" : "blue", + "color" : "#00FFFF", "frequency" : 3000 }, { "event-name" : "message-missed-email", "type" : "Led", - "color" : "blue", + "color" : "#800080", "frequency" : 2000 }, {