diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c new file mode 100644 index 0000000..e0732aa --- /dev/null +++ b/src/fbd-dev-led-multicolor.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2023 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + * Author: Guido Günther + * + * See Documentation/ABI/testing/sysfs-class-led-trigger-pattern + */ + +#define G_LOG_DOMAIN "fbd-dev-led" + +#include "fbd-dev-led-priv.h" +#include "fbd-dev-led-multicolor.h" +#include "fbd-enums.h" +#include "fbd-udev.h" + +#include + +#define LED_MULTI_INDEX_ATTR "multi_index" +#define LED_MULTI_INDEX_RED "red" +#define LED_MULTI_INDEX_GREEN "green" +#define LED_MULTI_INDEX_BLUE "blue" +#define LED_MULTI_INTENSITY_ATTR "multi_intensity" + + +typedef struct _FbdDevLedMulticolor { + FbdDevLed parent; + + guint red_index; + guint green_index; + guint blue_index; +} FbdDevLedMulticolor; + + +G_DEFINE_TYPE (FbdDevLedMulticolor, fbd_dev_led_multicolor, FBD_TYPE_DEV_LED) + + +static gboolean +fbd_dev_led_probe_multicolor (FbdDevLed *led, GError **error) +{ + g_autoptr (GError) err = NULL; + FbdDevLedMulticolor *self = FBD_DEV_LED_MULTICOLOR (led); + GUdevDevice *dev = fbd_dev_led_get_device (led); + const gchar *name, *path; + const gchar * const *index; + guint counter = 0; + guint max_brightness; + + name = g_udev_device_get_name (dev); + + index = g_udev_device_get_sysfs_attr_as_strv (dev, LED_MULTI_INDEX_ATTR); + if (index == NULL) { + g_set_error (error, + G_FILE_ERROR, G_FILE_ERROR_FAILED, + "%s is no multicololor LED", name); + return FALSE; + } + + max_brightness = g_udev_device_get_sysfs_attr_as_int (dev, LED_MAX_BRIGHTNESS_ATTR); + if (!max_brightness) { + g_set_error (error, + G_FILE_ERROR, G_FILE_ERROR_FAILED, + "%s has no max_brightness", name); + return FALSE; + } + fbd_dev_led_set_max_brightness (led, max_brightness); + fbd_dev_led_set_color (led, FBD_FEEDBACK_LED_COLOR_RGB); + + for (int i = 0; index[i] != NULL; i++) { + g_debug ("Index: %s", index[i]); + if (g_strcmp0 (index[i], LED_MULTI_INDEX_RED) == 0) { + self->red_index = counter; + counter++; + } else if (g_strcmp0 (index[i], LED_MULTI_INDEX_GREEN) == 0) { + self->green_index = counter; + counter++; + } else if (g_strcmp0 (index[i], LED_MULTI_INDEX_BLUE) == 0) { + self->blue_index = counter; + counter++; + } else { + g_warning ("Unsupport LED color index: %d %s", counter, index[i]); + } + } + + path = g_udev_device_get_sysfs_path (dev); + g_debug ("LED at '%s' usable as multicolor", path); + return TRUE; +} + + +static gboolean +fbd_dev_led_start_periodic_multicolor (FbdDevLed *led, + FbdFeedbackLedColor color, + guint max_brightness_percentage, + guint freq) +{ + FbdDevLedMulticolor *self = FBD_DEV_LED_MULTICOLOR (led); + GUdevDevice *dev = fbd_dev_led_get_device (led); + g_autofree char *intensity = NULL; + g_autoptr (GError) err = NULL; + g_autofree gchar *str = NULL; + gboolean success = FALSE; + guint max_brightness; + guint colors[] = { 0, 0, 0 }; + + max_brightness = fbd_dev_led_get_max_brightness (led); + switch (color) { + case FBD_FEEDBACK_LED_COLOR_WHITE: + colors[self->red_index] = max_brightness; + colors[self->green_index] = max_brightness; + colors[self->blue_index] = max_brightness; + break; + case FBD_FEEDBACK_LED_COLOR_RED: + colors[self->red_index] = max_brightness; + colors[self->green_index] = 0; + colors[self->blue_index] = 0; + break; + case FBD_FEEDBACK_LED_COLOR_GREEN: + colors[self->red_index] = 0; + colors[self->green_index] = max_brightness; + colors[self->blue_index] = 0; + break; + case FBD_FEEDBACK_LED_COLOR_BLUE: + colors[self->red_index] = 0; + colors[self->green_index] = 0; + colors[self->blue_index] = max_brightness; + break; + default: + g_warning("Unhandled color: %d\n", color); + return FALSE; + } + + intensity = g_strdup_printf ("%d %d %d\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, + intensity, + &err); + if (!success) { + g_warning ("Failed to set multi intensity: %s", err->message); + return FALSE; + } + + /* Chain up to parent class to set the pattern */ + return FBD_DEV_LED_CLASS (fbd_dev_led_multicolor_parent_class)->start_periodic ( + led, color, max_brightness_percentage, freq); +} + + +static gboolean +fbd_dev_led_has_color_multicolor (FbdDevLed *led, FbdFeedbackLedColor color) +{ + return color == FBD_FEEDBACK_LED_COLOR_RGB; +} + + +static void +fbd_dev_led_multicolor_class_init (FbdDevLedMulticolorClass *klass) +{ + FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_CLASS (klass); + + fbd_dev_led_class->probe = fbd_dev_led_probe_multicolor; + fbd_dev_led_class->start_periodic = fbd_dev_led_start_periodic_multicolor; + fbd_dev_led_class->has_color = fbd_dev_led_has_color_multicolor; +} + + +static void +fbd_dev_led_multicolor_init (FbdDevLedMulticolor *self) +{ +} + + +FbdDevLed * +fbd_dev_led_multicolor_new (GUdevDevice *dev, GError **err) +{ + return g_initable_new (FBD_TYPE_DEV_LED_MULTICOLOR, NULL, err, "dev", dev, NULL); +} diff --git a/src/fbd-dev-led-multicolor.h b/src/fbd-dev-led-multicolor.h new file mode 100644 index 0000000..79f17fe --- /dev/null +++ b/src/fbd-dev-led-multicolor.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include "fbd-dev-led.h" + +G_BEGIN_DECLS + +#define FBD_TYPE_DEV_LED_MULTICOLOR fbd_dev_led_multicolor_get_type() + +G_DECLARE_FINAL_TYPE (FbdDevLedMulticolor, fbd_dev_led_multicolor, FBD, DEV_LED_MULTICOLOR, FbdDevLed) + +FbdDevLed *fbd_dev_led_multicolor_new (GUdevDevice *dev, GError **err); + +G_END_DECLS diff --git a/src/fbd-dev-led-priv.h b/src/fbd-dev-led-priv.h new file mode 100644 index 0000000..32b34e1 --- /dev/null +++ b/src/fbd-dev-led-priv.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include "fbd-dev-led.h" +#include "fbd-feedback-led.h" + +#include +#include + +G_BEGIN_DECLS + +#define LED_MAX_BRIGHTNESS_ATTR "max_brightness" + +GUdevDevice *fbd_dev_led_get_device (FbdDevLed *led); +void fbd_dev_led_set_max_brightness (FbdDevLed *led, guint max_brightness); +void fbd_dev_led_set_color (FbdDevLed *led, FbdFeedbackLedColor color); + +G_END_DECLS diff --git a/src/fbd-dev-led.c b/src/fbd-dev-led.c new file mode 100644 index 0000000..a68b3da --- /dev/null +++ b/src/fbd-dev-led.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2020 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + * Author: Guido Günther + * + * See Documentation/ABI/testing/sysfs-class-led-trigger-pattern + */ + +#define G_LOG_DOMAIN "fbd-dev-led" + +#include "fbd-dev-led.h" +#include "fbd-dev-led-priv.h" +#include "fbd-enums.h" +#include "fbd-udev.h" + +#include + +#define LED_BRIGHTNESS_ATTR "brightness" +#define LED_MULTI_INDEX_ATTR "multi_index" +#define LED_MULTI_INDEX_RED "red" +#define LED_MULTI_INDEX_GREEN "green" +#define LED_MULTI_INDEX_BLUE "blue" +#define LED_MULTI_INTENSITY_ATTR "multi_intensity" +#define LED_PATTERN_ATTR "pattern" + +enum { + PROP_0, + PROP_DEV, + PROP_LAST_PROP +}; +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; + + +static void initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (FbdDevLed, fbd_dev_led, G_TYPE_OBJECT, + G_ADD_PRIVATE (FbdDevLed) + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)) + +static gboolean +fbd_dev_led_probe_default (FbdDevLed *led, GError **error) +{ + FbdDevLedPrivate *priv = fbd_dev_led_get_instance_private (led); + const gchar *name, *path; + gboolean success; + + 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_RGB; i++) { + g_autofree char *color = NULL; + g_autofree char *enum_name = NULL; + gchar *c; + + enum_name = g_enum_to_string (FBD_TYPE_FEEDBACK_LED_COLOR, i); + c = strrchr (enum_name, '_'); + color = g_ascii_strdown (c+1, -1); + if (g_strstr_len (name, -1, color)) { + g_autoptr (GError) err = NULL; + guint brightness = g_udev_device_get_sysfs_attr_as_int (priv->dev, LED_MAX_BRIGHTNESS_ATTR); + + if (!brightness) + continue; + + priv->color = i; + fbd_dev_led_set_max_brightness (led, brightness); + + path = g_udev_device_get_sysfs_path (priv->dev); + g_debug ("LED at '%s' usable for %s", path, color); + success = TRUE; + break; + } + } + + if (!success) { + g_set_error (error, + G_FILE_ERROR, G_FILE_ERROR_FAILED, + "%s not usable as RBG LED", name); + } + + return success; +} + + +static gboolean +fbd_dev_led_start_periodic_default (FbdDevLed *led, + FbdFeedbackLedColor color, + guint max_brightness_percentage, + guint freq) +{ + FbdDevLedPrivate *priv; + g_autoptr (GError) err = NULL; + g_autofree gchar *str = NULL; + gboolean success = FALSE; + gdouble max; + gdouble t; + + g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); + priv = fbd_dev_led_get_instance_private (led); + + max = priv->max_brightness * (max_brightness_percentage / 100.0); + /* ms mHz T/2 */ + t = 1000.0 * 1000.0 / freq / 2.0; + str = g_strdup_printf ("0 %d %d %d\n", (gint)t, (gint)max, (gint)t); + g_debug ("Freq %d mHz, Brightness: %d%%, Blink pattern: %s", freq, max_brightness_percentage, str); + + success = fbd_udev_set_sysfs_path_attr_as_string (priv->dev, LED_PATTERN_ATTR, str, &err); + if (!success) + g_warning ("Failed to set led pattern: %s", err->message); + + return success; +} + + +static gboolean +fbd_dev_led_has_color_default (FbdDevLed *led, FbdFeedbackLedColor color) +{ + FbdDevLedPrivate *priv; + + g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); + priv = fbd_dev_led_get_instance_private (led); + + return priv->color == color; +} + + +static void +fbd_dev_led_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + FbdDevLed *led = FBD_DEV_LED (object); + FbdDevLedPrivate *priv = fbd_dev_led_get_instance_private (led); + + switch (property_id) { + case PROP_DEV: + priv->dev = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +fbd_dev_led_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + FbdDevLed *led = FBD_DEV_LED (object); + FbdDevLedPrivate *priv = fbd_dev_led_get_instance_private (led); + + switch (property_id) { + case PROP_DEV: + g_value_set_object (value, priv->dev); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +fbd_dev_led_finalize (GObject *object) +{ + FbdDevLed *self = FBD_DEV_LED (object); + FbdDevLedPrivate *priv = fbd_dev_led_get_instance_private (self); + + g_clear_object (&priv->dev); + + G_OBJECT_CLASS (fbd_dev_led_parent_class)->finalize (object); +} + + +static gboolean +initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_GET_CLASS (initable); + + return fbd_dev_led_class->probe (FBD_DEV_LED (initable), error); +} + + +static void +initable_iface_init (GInitableIface *iface) +{ + iface->init = initable_init; +} + + +static void +fbd_dev_led_class_init (FbdDevLedClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_CLASS (klass); + + object_class->get_property = fbd_dev_led_get_property; + object_class->set_property = fbd_dev_led_set_property; + object_class->finalize = fbd_dev_led_finalize; + + fbd_dev_led_class->probe = fbd_dev_led_probe_default; + fbd_dev_led_class->start_periodic = fbd_dev_led_start_periodic_default; + fbd_dev_led_class->has_color = fbd_dev_led_has_color_default; + + props[PROP_DEV] = + g_param_spec_object ("dev", "", "", + G_UDEV_TYPE_DEVICE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +fbd_dev_led_init (FbdDevLed *self) +{ +} + + +FbdDevLed * +fbd_dev_led_new (GUdevDevice *dev, GError **err) +{ + return g_initable_new (FBD_TYPE_DEV_LED, NULL, err, "dev", dev, NULL); +} + + +gboolean +fbd_dev_led_set_brightness (FbdDevLed *led, guint brightness) +{ + FbdDevLedPrivate *priv; + g_autoptr (GError) err = NULL; + + g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); + priv = fbd_dev_led_get_instance_private (led); + + if (!fbd_udev_set_sysfs_path_attr_as_int (priv->dev, LED_BRIGHTNESS_ATTR, brightness, &err)) { + g_warning ("Failed to setup brightness: %s", err->message); + return FALSE; + } + + return TRUE; +} + + +gboolean +fbd_dev_led_start_periodic (FbdDevLed *led, + FbdFeedbackLedColor color, + guint max_brightness_percentage, + guint freq) +{ + 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->start_periodic (led, color, max_brightness_percentage, freq); +} + + +gboolean +fbd_dev_led_has_color (FbdDevLed *led, FbdFeedbackLedColor color) +{ + 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->has_color (led, color); +} + + +guint +fbd_dev_led_get_max_brightness (FbdDevLed *led) +{ + FbdDevLedPrivate *priv; + + g_return_val_if_fail (FBD_IS_DEV_LED (led), 0); + priv = fbd_dev_led_get_instance_private (led); + + return priv->max_brightness; +} + +/* Functions for derived classes */ + +GUdevDevice * +fbd_dev_led_get_device (FbdDevLed *led) +{ + FbdDevLedPrivate *priv; + + g_return_val_if_fail (FBD_IS_DEV_LED (led), NULL); + priv = fbd_dev_led_get_instance_private (led); + + return priv->dev; +} + + +void +fbd_dev_led_set_color (FbdDevLed *led, FbdFeedbackLedColor color) +{ + FbdDevLedPrivate *priv; + + g_return_if_fail (FBD_IS_DEV_LED (led)); + priv = fbd_dev_led_get_instance_private (led); + + priv->color = color; +} + + +void +fbd_dev_led_set_max_brightness (FbdDevLed *led, guint max_brightness) +{ + FbdDevLedPrivate *priv; + + g_return_if_fail (FBD_IS_DEV_LED (led)); + priv = fbd_dev_led_get_instance_private (led); + + priv->max_brightness = max_brightness; +} diff --git a/src/fbd-dev-led.h b/src/fbd-dev-led.h new file mode 100644 index 0000000..139deec --- /dev/null +++ b/src/fbd-dev-led.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include "fbd-feedback-led.h" + +#include + +#include + +G_BEGIN_DECLS + +#define FBD_TYPE_DEV_LED fbd_dev_led_get_type() + +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_start_periodic (FbdDevLed *led, + FbdFeedbackLedColor color, + guint max_brightness_percentage, + guint freq); +gboolean fbd_dev_led_has_color (FbdDevLed *led, FbdFeedbackLedColor color); + +struct _FbdDevLedClass { + GObjectClass parent_class; + + gboolean (*probe) (FbdDevLed *led, GError **error); + gboolean (*start_periodic) (FbdDevLed *led, + FbdFeedbackLedColor color, + guint max_brightness_percentage, + guint freq); + gboolean (*has_color) (FbdDevLed *led, + FbdFeedbackLedColor color); +}; + +G_END_DECLS diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index bd498e2..34b4314 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -10,44 +10,24 @@ #include "fbd.h" #include "fbd-enums.h" +#include "fbd-dev-led.h" +#include "fbd-dev-led-multicolor.h" #include "fbd-dev-leds.h" #include "fbd-feedback-led.h" #include "fbd-udev.h" #include +#define LED_SUBSYSTEM "leds" + /** - * SECTION:fbd-dev-led - * @short_description: LED device interface - * @Title: FbdDevLeds + * FbdDevLeds: + * + * LED device interface * * #FbdDevLeds is used to interface with LEDS via sysfs * It currently only supports one pattern per led at a time. */ - -#define LED_BRIGHTNESS_ATTR "brightness" -#define LED_MAX_BRIGHTNESS_ATTR "max_brightness" -#define LED_MULTI_INDEX_ATTR "multi_index" -#define LED_MULTI_INTENSITY_ATTR "multi_intensity" -#define LED_MULTI_INDEX_RED "red" -#define LED_MULTI_INDEX_GREEN "green" -#define LED_MULTI_INDEX_BLUE "blue" -#define LED_PATTERN_ATTR "pattern" -#define LED_SUBSYSTEM "leds" - -typedef struct _FbdDevLed { - GUdevDevice *dev; - guint max_brightness; - guint red_index; - guint green_index; - guint blue_index; - /* - * We just use the colors from the feedback until we - * do rgb mixing, etc - */ - FbdFeedbackLedColor color; -} FbdDevLed; - typedef struct _FbdDevLeds { GObject parent; @@ -60,27 +40,6 @@ static void initable_iface_init (GInitableIface *iface); G_DEFINE_TYPE_WITH_CODE (FbdDevLeds, fbd_dev_leds, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)); - -static void -fbd_dev_led_free (FbdDevLed *led) -{ - g_object_unref (led->dev); - g_free (led); -} - -static gboolean -fbd_dev_led_set_brightness (FbdDevLed *led, guint brightness) -{ - g_autoptr (GError) err = NULL; - - if (!fbd_udev_set_sysfs_path_attr_as_int (led->dev, LED_BRIGHTNESS_ATTR, brightness, &err)) { - g_warning ("Failed to setup brightness: %s", err->message); - return FALSE; - } - - return TRUE; -} - static FbdDevLed * find_led_by_color (FbdDevLeds *self, FbdFeedbackLedColor color) { @@ -88,7 +47,7 @@ find_led_by_color (FbdDevLeds *self, FbdFeedbackLedColor color) for (GSList *l = self->leds; l != NULL; l = l->next) { FbdDevLed *led = l->data; - if (led->color == FBD_FEEDBACK_LED_COLOR_RGB || led->color == color) + if (fbd_dev_led_has_color (led, color)) return led; } @@ -111,66 +70,27 @@ initable_init (GInitable *initable, leds = g_udev_client_query_by_subsystem (self->client, LED_SUBSYSTEM); for (GList *l = leds; l != NULL; l = l->next) { + g_autoptr (GError) err = NULL; GUdevDevice *dev = G_UDEV_DEVICE (l->data); - const gchar *name, *path; - FbdDevLed *led = NULL; + FbdDevLed *led; if (g_strcmp0 (g_udev_device_get_property (dev, FEEDBACKD_UDEV_ATTR), FEEDBACKD_UDEV_VAL_LED)) { continue; } - name = g_udev_device_get_name (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; - const gchar * const *index; - guint counter = 0; - gchar *c; + /* Try multicolor first, fall back to single color */ + led = fbd_dev_led_multicolor_new (dev, &err); + if (led == NULL) { + g_debug ("Led not usable as multicolor: '%s'", err->message); + led = fbd_dev_led_new (dev, &err); + if (led == NULL) + g_debug ("Led not usable as single color: '%s'", err->message); + } - enum_name = g_enum_to_string (FBD_TYPE_FEEDBACK_LED_COLOR, i); - c = strrchr (enum_name, '_'); - color = g_ascii_strdown (c+1, -1); - if (g_strstr_len (name, -1, color)) { - g_autoptr (GError) err = NULL; - guint brightness = g_udev_device_get_sysfs_attr_as_int (dev, LED_MAX_BRIGHTNESS_ATTR); - index = g_udev_device_get_sysfs_attr_as_strv (dev, LED_MULTI_INDEX_ATTR); - - if (!brightness) - continue; - - led = g_malloc0 (sizeof(FbdDevLed)); - led->dev = g_object_ref (dev); - led->color = i; - led->max_brightness = brightness; - - if (index) { - for (int j = 0; j < g_strv_length ((gchar **) index); j++) { - g_debug ("Index: %s", index[j]); - if (g_strcmp0 (index[j], LED_MULTI_INDEX_RED) == 0) { - led->red_index = counter; - counter++; - } else if (g_strcmp0 (index[j], LED_MULTI_INDEX_GREEN) == 0) { - led->green_index = counter; - counter++; - } else if (g_strcmp0 (index[j], LED_MULTI_INDEX_BLUE) == 0) { - led->blue_index = counter; - counter++; - } else { - g_warning ("Unsupport LED color index: %d %s", counter, index[j]); - } - } - } - - path = g_udev_device_get_sysfs_path (dev); - g_debug ("LED at '%s' usable", path); - self->leds = g_slist_append (self->leds, led); - found = TRUE; - break; - } + if (led) { + self->leds = g_slist_append (self->leds, led); + found = TRUE; } } @@ -197,7 +117,7 @@ fbd_dev_leds_dispose (GObject *object) FbdDevLeds *self = FBD_DEV_LEDS (object); g_clear_object (&self->client); - g_slist_free_full (self->leds, (GDestroyNotify)fbd_dev_led_free); + g_slist_free_full (self->leds, (GDestroyNotify)g_object_unref); self->leds = NULL; G_OBJECT_CLASS (fbd_dev_leds_parent_class)->dispose (object); @@ -239,65 +159,13 @@ fbd_dev_leds_start_periodic (FbdDevLeds *self, FbdFeedbackLedColor color, guint max_brightness_percentage, guint freq) { FbdDevLed *led; - gdouble max; - gdouble t; - g_autofree gchar *str = NULL; - - g_autoptr (GError) err = NULL; - gboolean success; g_return_val_if_fail (FBD_IS_DEV_LEDS (self), FALSE); g_return_val_if_fail (max_brightness_percentage <= 100.0, FALSE); led = find_led_by_color (self, color); g_return_val_if_fail (led, FALSE); - if (led->color == FBD_FEEDBACK_LED_COLOR_RGB) { - g_autofree char *intensity = NULL; - guint colors[] = { 0, 0, 0 }; - switch (color) { - case FBD_FEEDBACK_LED_COLOR_WHITE: - colors[led->red_index] = led->max_brightness; - colors[led->green_index] = led->max_brightness; - colors[led->blue_index] = led->max_brightness; - break; - case FBD_FEEDBACK_LED_COLOR_RED: - colors[led->red_index] = led->max_brightness; - colors[led->green_index] = 0; - colors[led->blue_index] = 0; - break; - case FBD_FEEDBACK_LED_COLOR_GREEN: - colors[led->red_index] = 0; - colors[led->green_index] = led->max_brightness; - colors[led->blue_index] = 0; - break; - case FBD_FEEDBACK_LED_COLOR_BLUE: - colors[led->red_index] = 0; - colors[led->green_index] = 0; - colors[led->blue_index] = led->max_brightness; - break; - default: - g_warning("Unhandled color: %d\n", color); - return FALSE; - } - intensity = g_strdup_printf ("%d %d %d\n", colors[0], colors[1], colors[2]); - fbd_dev_led_set_brightness (led, led->max_brightness); - success = fbd_udev_set_sysfs_path_attr_as_string (led->dev, LED_MULTI_INTENSITY_ATTR, intensity, &err); - if (!success) { - g_warning ("Failed to set multi intensity: %s", err->message); - g_clear_error (&err); - } - } - - max = led->max_brightness * (max_brightness_percentage / 100.0); - /* ms mHz T/2 */ - t = 1000.0 * 1000.0 / freq / 2.0; - str = g_strdup_printf ("0 %d %d %d\n", (gint)t, (gint)max, (gint)t); - g_debug ("Freq %d mHz, Brightness: %d%%, Blink pattern: %s", freq, max_brightness_percentage, str); - success = fbd_udev_set_sysfs_path_attr_as_string (led->dev, LED_PATTERN_ATTR, str, &err); - if (!success) - g_warning ("Failed to set led pattern: %s", err->message); - - return success; + return fbd_dev_led_start_periodic (led, color, max_brightness_percentage, freq); } gboolean diff --git a/src/fbd-dev-leds.h b/src/fbd-dev-leds.h index 479be88..999dbd9 100644 --- a/src/fbd-dev-leds.h +++ b/src/fbd-dev-leds.h @@ -6,9 +6,9 @@ #pragma once #include "fbd-feedback-led.h" +#include "fbd-udev.h" #include -#include G_BEGIN_DECLS diff --git a/src/fbd-feedback-theme.c b/src/fbd-feedback-theme.c index 6d1bc22..3274920 100644 --- a/src/fbd-feedback-theme.c +++ b/src/fbd-feedback-theme.c @@ -42,9 +42,9 @@ G_DEFINE_TYPE_WITH_CODE (FbdFeedbackTheme, fbd_feedback_theme, G_TYPE_OBJECT, static JsonNode * fbd_theme_serializable_serialize_property (JsonSerializable *serializable, - const gchar *property_name, - const GValue *value, - GParamSpec *pspec) + const gchar *property_name, + const GValue *value, + GParamSpec *pspec) { FbdFeedbackTheme *self = FBD_FEEDBACK_THEME (serializable); JsonNode *node = NULL; @@ -71,10 +71,10 @@ fbd_theme_serializable_serialize_property (JsonSerializable *serializable, static gboolean fbd_theme_serializable_deserialize_property (JsonSerializable *serializable, - const gchar *property_name, - GValue *value, - GParamSpec *pspec, - JsonNode *property_node) + const gchar *property_name, + GValue *value, + GParamSpec *pspec, + JsonNode *property_node) { if (g_strcmp0 (property_name, "profiles") == 0) { if (JSON_NODE_TYPE (property_node) == JSON_NODE_NULL) { @@ -117,7 +117,7 @@ fbd_theme_serializable_deserialize_property (JsonSerializable *serializable, } static void -fbd_feedback_theme_set_property (GObject *object, +fbd_feedback_theme_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) diff --git a/src/meson.build b/src/meson.build index a75cf6d..8d2dcdb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -15,6 +15,8 @@ sources = [ 'fbd-error.c', 'fbd-dev-vibra.c', 'fbd-dev-sound.c', + 'fbd-dev-led.c', + 'fbd-dev-led-multicolor.c', 'fbd-dev-leds.c', 'fbd-event.c', 'fbd-feedback-base.c',