@@ -38,6 +38,7 @@
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
+#include <math.h>
#include <errno.h>
#include <glib.h>
@@ -734,11 +735,68 @@
}
};
+/** Questimate of the duration of the kernel delayed work */
+#define LED_CTRL_KERNEL_DELAY 10 // [ms]
+
+/** Minimum delay between breathing steps */
+#define LED_CTRL_BREATHING_DELAY 20 // [ms]
+
+/** Maximum number of breathing steps; rise and fall time combined */
+#define LED_CTRL_MAX_STEPS 256
+
+/** Minimum number of breathing steps on rise/fall time */
+#define LED_CTRL_MIN_STEPS 7
+
+/** Led request parameters */
+typedef struct
+{
+ int r,g,b;
+ int on,off;
+} led_request_t;
+
+/** Test for led request equality
+ */
+static bool led_request_is_equal(const led_request_t *self,
+ const led_request_t *that)
+{
+ return (self->r == that->r &&
+ self->g == that->g &&
+ self->b == that->b &&
+ self->on == that->on &&
+ self->off == that->off);
+}
+
+/** Test for active led request
+ */
+static bool led_request_has_color(const led_request_t *self)
+{
+ return self->r > 0 || self->g > 0 || self->b > 0;
+}
+
+/** Intensity curve for sw breathing */
+static struct {
+ size_t step;
+ size_t steps;
+ int delay;
+ uint8_t value[LED_CTRL_MAX_STEPS];
+} led_ctrl_breathe =
+{
+ .step = 0,
+ .steps = 0,
+ .delay = 0,
+};
+
/** Flag for: controls for RGB leds exist in sysfs */
-static bool led_sysfs = false;
+static bool led_ctrl_uses_sysfs = false;
+
+/** Flag for: breathing via sw is allowed */
+static bool led_ctrl_breathing_enabled = false;
+
+/** Currently active RGB led state; initialize to invalid */
+static led_request_t led_ctrl_curr = { .r = -1, };
/** Close all LED sysfs files */
-static void led_flush(void)
+static void led_ctrl_close_sysfs_files(void)
{
for( int i = 0; i < 3; ++i )
{
@@ -750,7 +808,7 @@
*
* @return true if required control files were available, false otherwise
*/
-static bool led_probe(void)
+static bool led_ctrl_probe_sysfs_files(void)
{
bool res = false;
@@ -768,239 +826,219 @@
if( !res )
{
- led_flush();
+ led_ctrl_close_sysfs_files();
}
return res;
}
-/** Change color and blinking attributes of a LED */
-static void led_control_blink(int chn, int on, int off)
+/** Change blinking attributes of a LED channel */
+static void led_ctrl_set_channel_blink(int chn, int on, int off)
{
led_state_set_blink(led_states + chn, on, off);
}
-/** Change color and blinking attributes of a LED */
-static void led_control_value(int chn, int val)
+/** Change intensity attribute of a LED channel */
+static void led_ctrl_set_channel_value(int chn, int val)
{
led_state_set_value(led_states + chn, val);
}
-/** Questimate of the duration of the kernel delayed work */
-#define LED_QUEUE_DELAY 10 // [ms]
-
-/** State data for led reprogramming "queue" */
-typedef struct
+/** Change blinking attributes of RGB led */
+static void led_ctrl_set_rgb_blink(int on, int off)
{
- int r,g,b;
- int on,off;
-
- guint id;
- bool need_reset;
- bool need_set;
+ led_ctrl_set_channel_blink(0, on, off);
+ led_ctrl_set_channel_blink(1, on, off);
+ led_ctrl_set_channel_blink(2, on, off);
+}
-} led_queue_t;
+/** Change intensity attributes of RGB led */
+static void led_ctrl_set_rgb_value(int r, int g, int b)
+{
+ led_ctrl_set_channel_value(0, r);
+ led_ctrl_set_channel_value(1, g);
+ led_ctrl_set_channel_value(2, b);
+}
-/** Set led to queued ON state if needed
- *
- * @param self led queue object
- *
- * @return true if led was programmed, false otherwise
+/** Generate intensity curve for use from breathing timer
*/
-static bool led_queue_set(led_queue_t *self)
+static void led_ctrl_generate_ramp(int ms_on, int ms_off)
{
- bool done;
+ int t = ms_on + ms_off;
+ int s = (t + LED_CTRL_MAX_STEPS - 1) / LED_CTRL_MAX_STEPS;
- if( (done = self->need_set) )
- {
- self->need_set = false;
+ if( s < LED_CTRL_BREATHING_DELAY ) {
+ s = LED_CTRL_BREATHING_DELAY;
+ }
+ int n = (t + s - 1) / s;
- if( self->r || self->g || self->b )
- {
- mce_log(LOG_DEBUG, "LED ON: %02x %02x %02x - %d %d",
- self->r, self->g, self->b,
- self->on, self->off);
-
- // blink setting
- if( self->r ) led_control_blink(0, self->on, self->off);
- if( self->g ) led_control_blink(1, self->on, self->off);
- if( self->b ) led_control_blink(2, self->on, self->off);
-
- // specify color
- if( self->r ) led_control_value(0, self->r);
- if( self->g ) led_control_value(1, self->g);
- if( self->b ) led_control_value(2, self->b);
- }
- else
- {
- // allow "set to off" cycles to end faster
- done = false;
- }
+ int steps_on = (n * ms_on + t / 2) / t;
+ int steps_off = n - steps_on;
+
+ const float m_pi_2 = (float)M_PI_2;
+
+ int k = 0;
+
+ for( int i = 0; i < steps_on; ++i ) {
+ float a = i * m_pi_2 / steps_on;
+ led_ctrl_breathe.value[k++] = (uint8_t)(sinf(a) * 255.0f);
+ }
+ for( int i = 0; i < steps_off; ++i ) {
+ float a = m_pi_2 + i * m_pi_2 / steps_off;
+ led_ctrl_breathe.value[k++] = (uint8_t)(sinf(a) * 255.0f);
|