]> www.fi.muni.cz Git - bike-lights.git/commitdiff
Merge branch 'sync_patterns'
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Wed, 26 Jun 2013 22:21:46 +0000 (00:21 +0200)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Wed, 26 Jun 2013 22:21:46 +0000 (00:21 +0200)
This branch implements handling all three pwmleds in one pattern
in order to avoid having multiple outputs on simultaneously (when possible).

Also, this separates brightness settings from patterns, so we can have
only one blinking pattern for more ambient light levels, and set the
brightness (current) of the pattern separately.

firmware/ambient.c
firmware/buttons.c
firmware/control.c
firmware/lights.h
firmware/pattern.c
firmware/pwmled.c

index 4818ab4a8e7a63f596103dc92afca45386c664f0..48a752d4b35bf744fcf11992684a2b1fef521e44 100644 (file)
@@ -72,18 +72,10 @@ void ambient_log_min_max()
        ambient_16drop = 0;
 }
 
-void ambient_zone_changed()
+static inline void ambient_zone_changed()
 {
-#if 1
-       log_byte(0xab);
-       log_byte(ambient_zone);
-       log_word(ambient_val);
-       log_flush();
-#endif
-
-       // led_set_pattern(N_PWMLEDS, status_led_pattern_select());
-       // led_set_pattern(N_PWMLEDS+1, illumination_led_pattern_select());
-       // pattern_reload();
+       pwmled_select_brightness();
+       pattern_reload();
 }
 
 void ambient_adc(uint16_t adcval)
@@ -116,14 +108,14 @@ void ambient_adc(uint16_t adcval)
 
        if (ambient_max < byte_val)
                ambient_max = byte_val;
-#if 0
        if (old_zone != ambient_zone) {
+#if 0
                log_byte(0xab);
                log_byte(ambient_zone);
                log_word(adcval);
                log_flush();
-       }
-               // ambient_zone_changed();
 #endif
+               ambient_zone_changed();
+       }
 }
 
index f611c2725babe845a763911153215bb1baa91aa6..15c70e28f5b594eb983bc4fbc4b379b7f3aeac0a 100644 (file)
@@ -37,7 +37,7 @@ static uint16_t user_params_starttime;
 
 static void inline set_status_led(unsigned char n, pattern_t *pattern)
 {
-       led_set_pattern(n + N_PWMLEDS, pattern);
+       led_set_pattern(n + 1, pattern);
 }
 
 unsigned char buttons_setup_in_progress()
@@ -171,7 +171,7 @@ static void handle_button(unsigned char button, unsigned char cur,
                uint16_t duration = jiffies - button_start[button];
 
                if (duration >= LONG_PRESS_MIN) {
-                       set_status_led(button, on1_pattern);
+                       set_status_led(button, on_pattern);
                                // acknowledge long press
                }
        } else if (!cur && prev) {            // --- just released ---
index a219f19205947b8a11a6b3d3ee9efb1ccad37b94..c5ba92fe2c2e79b42fe150df6a08769cce305f02 100644 (file)
 #include "lights.h"
 
 static pattern_t panic_pattern[] = {
-       { 3, D_1 }, // FIXME: will be 4, but let's be safe while testing
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_1 },
        PATTERN_END
 };
 
-pattern_t on1_pattern [] = {
-       { 1, D_8 },
-       PATTERN_END
-};
-
-static pattern_t on2_pattern [] = {
-       { 2, D_8 },
-       PATTERN_END
-};
-
-static pattern_t on3_pattern [] = {
-       { 3, D_8 },
-       PATTERN_END
-};
-
-static pattern_t brake_pattern [] = {
-       { 4, D_2 },
-       { 3, D_8 },
-       PATTERN_END
-};
-
-static pattern_t normal2_pattern[] = {
-       { 2, D_1 },
-       { 0, D_1 },
-       { 2, D_1 },
-       { 0, D_8 },
-       { 1, D_1 },
-       { 0, D_1 },
-       { 1, D_1 },
-       { 0, D_8 },
-       PATTERN_END
-};
-
-static pattern_t normal3_pattern[] = {
-       { 3, D_1 },
-       { 0, D_1 },
-       { 3, D_1 },
-       { 0, D_8 },
-       { 1, D_1 },
-       { 0, D_1 },
-       { 1, D_1 },
-       { 0, D_8 },
+static pattern_t slow_pattern[] = {
+       { PWM_PAT(1, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 1), D_1 },
+       { PWM_PAT(0, 0, 0), D_13 },
        PATTERN_END
 };
 
-static pattern_t normal4_pattern[] = {
-       { 4, D_1 },
-       { 0, D_1 },
-       { 4, D_1 },
-       { 0, D_8 },
-       { 1, D_1 },
-       { 0, D_1 },
-       { 1, D_1 },
-       { 0, D_8 },
+static pattern_t fast_pattern[] = {
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(2, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 2), D_1 },
+       { PWM_PAT(0, 0, 0), D_8 },
+       { PWM_PAT(1, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 1), D_1 },
+       { PWM_PAT(1, 0, 0), D_1 },
+       { PWM_PAT(0, 0, 1), D_1 },
+       { PWM_PAT(0, 0, 0), D_8 },
        PATTERN_END
 };
 
-static pattern_t slow1_pattern[] = {
-       { 1, D_1 },
-       { 0, D_13 },
+static pattern_t night_pattern[] = {
+       { PWM_PAT(3, 0, 1), D_3 },
+       { PWM_PAT(2, 0, 0), D_8 },
+       { PWM_PAT(3, 0, 1), D_1 },
+       { PWM_PAT(2, 0, 0), D_2 },
+       { PWM_PAT(3, 0, 1), D_1 },
+       { PWM_PAT(2, 0, 0), D_8 },
        PATTERN_END
 };
 
-static pattern_t slow2_pattern[] = {
-       { 2, D_1 },
-       { 0, D_13 },
+pattern_t on_pattern[] = {
+       { 1, D_8 },
        PATTERN_END
 };
 
-static pattern_t slow3_pattern[] = {
-       { 3, D_1 },
-       { 0, D_13 },
+// #define TEST_PATTERN 1
+#ifdef TEST_PATTERN
+pattern_t test_pattern[] = {
+       { PWM_PAT(1, 0, 0), D_13 },
+       { PWM_PAT(2, 0, 0), D_13 },
+       { PWM_PAT(0, 0, 1), D_13 },
+       { PWM_PAT(0, 0, 2), D_13 },
        PATTERN_END
 };
+#endif
 
-static unsigned char dim_mode, towbar_mode, braking;
+volatile unsigned char braking;
+static unsigned char dim_mode, towbar_mode;
 
 void init_control()
 {
        dim_mode = 0;
        towbar_mode = 0;
        braking = 0;
+
+       pwmled_select_brightness();
 }
 
 void brake_on()
 {
        braking = 1;
        gpio_set(0, 1);
-       led_set_pattern(N_PWMLEDS, status_led_pattern_select());
-       led_set_pattern(0, pwmled0_pattern_select());
+       led_set_pattern(N_STATUS_LED, status_led_pattern_select());
+       pwmleds_update_mode();
 }
 
 void brake_off()
 {
        braking = 0;
        gpio_set(0, 0);
-       led_set_pattern(N_PWMLEDS, status_led_pattern_select());
-       led_set_pattern(0, pwmled0_pattern_select());
+       led_set_pattern(N_STATUS_LED, status_led_pattern_select());
+       pwmleds_update_mode();
 }
 
 void toggle_dim_mode()
 {
        dim_mode = !dim_mode;
+       pwmled_select_brightness();
        pattern_reload();
 }
 
 void set_panic_mode()
 {
-       if (!dim_mode)
-               led_set_pattern(0, panic_pattern);
-
-       led_set_pattern(1, panic_pattern);
-       led_set_pattern(2, panic_pattern);
-       led_set_pattern(4, panic_pattern);
-}
-
-pattern_t *pwmled0_pattern_select()
-{
-       if (battery_critical)
-               return on1_pattern;
-
-       if (towbar_mode)
-               return NULL;
-
-       if (braking)
-               return brake_pattern;
-
-       switch (ambient_zone) {
-       case 0: return dim_mode ? NULL : number_pattern(2, 1);
-       case 1: return dim_mode ? slow1_pattern : normal2_pattern;
-       case 2: return dim_mode ? slow2_pattern : normal3_pattern;
-       case 3:
-       default: return dim_mode ? slow3_pattern : normal4_pattern;
-       }
+       led_set_pattern(0, panic_pattern);
+       led_set_pattern(N_ILLUM_LED, panic_pattern);
 }
 
-pattern_t *pwmled1_pattern_select()
+pattern_t *pwmled_pattern_select()
 {
-#ifndef TESTING_FW
-       return NULL;
-#else
-       if (battery_critical)
-               return on1_pattern;
+#ifdef TEST_PATTERN
+       return tmp_pattern;
 #endif
-
-       if (towbar_mode) {
-               switch (ambient_zone) {
-               case 0:
-               case 1:
-                       return dim_mode ? on2_pattern : on1_pattern;
-               case 2: return dim_mode ? NULL : on2_pattern;
-               case 3:
-               default: return dim_mode ? NULL : on3_pattern;
-               }
-       } else {
-               switch (ambient_zone) {
-               case 0: return dim_mode ? slow1_pattern : normal2_pattern;
-               case 1: return dim_mode ? slow2_pattern : normal3_pattern;
-               case 2: return dim_mode ? NULL : normal4_pattern;
-               case 3:
-               default: return NULL;
-               }
-       }
-}
-
-pattern_t *pwmled2_pattern_select()
-{
-#ifndef TESTING_FW
        if (battery_critical)
-               return on1_pattern;
-#endif
+               return slow_pattern;
 
        switch (ambient_zone) {
-       case 0: return dim_mode ? on2_pattern : on3_pattern;
-       case 1: return dim_mode ? slow1_pattern : normal2_pattern;
+       case 0: return night_pattern;
+       case 1:
        case 2:
        case 3:
        default:
-               return dim_mode ? slow2_pattern : normal3_pattern;
+               return dim_mode ? slow_pattern : fast_pattern;
        }
 }
 
 pattern_t *status_led_pattern_select()
 {
        if (braking)
-               return on1_pattern;
+               return on_pattern;
 
        if (buttons_setup_in_progress())
                return buttons_setup_status0_pattern_select();
@@ -231,7 +154,7 @@ pattern_t *illumination_led_pattern_select()
        switch (ambient_zone) {
        case 0: return dim_mode
                ? number_pattern(1, 1)
-               : on1_pattern;
+               : on_pattern;
        case 1: return dim_mode
                ? number_pattern(2, 1)
                : number_pattern(3, 1);
@@ -252,3 +175,23 @@ pattern_t *laser_pattern_select()
        else
                return NULL;
 }
+
+void pwmled_select_brightness()
+{
+       uint16_t brightness = PWMLED_BRIGHTNESS(0, 2, 1, 0, 2); // default
+
+       if (battery_critical) {
+               brightness = PWMLED_BRIGHTNESS(0, 0, 0, 0, 0);
+       } else if (ambient_zone < 2) {
+               if (dim_mode)
+                       brightness = PWMLED_BRIGHTNESS(0, 1, 0, 0, 1);
+               else
+                       brightness = PWMLED_BRIGHTNESS(0, 2, 1, 0, 2);
+       } else if (ambient_zone == 2) {
+               brightness = PWMLED_BRIGHTNESS(1, 3, 2, 1, 3);
+       } else if (ambient_zone == 3) {
+               brightness = PWMLED_BRIGHTNESS(2, 4, 2, 2, 4);
+       }
+
+       pwmled_set_brightness(brightness);
+}
index 7e7e2a4d850b18d46e469c8e75668b42f1ca1f32..9d0386878bf9b79ff774a1e6de929ee74f6cb2f2 100644 (file)
@@ -3,9 +3,13 @@
 
 #define TESTING_FW 1
 
-#define N_LEDS 7
+#define N_LEDS 4
+#define N_STATUS_LED 1
+#define N_ILLUM_LED 2
+#define N_LASER_LED 4
+
 #define N_PWMLEDS 3
-#define N_PWMLED_MODES 4
+#define N_PWMLED_MODES 3
 
 #define N_BUTTONS 2
 
@@ -57,6 +61,14 @@ void susp_tmr();
 void init_pwmled();
 void pwmled_adc(unsigned char n, uint16_t adcval);
 void pwmled_set_mode(unsigned char n, unsigned char mode);
+void pwmled_set_brightness(uint16_t brightness);
+#define PWMLED_BRIGHTNESS(l0_lo, l0_hi, l1, l2_lo, l2_hi) ( \
+          (uint16_t)(l0_lo) \
+       | ((uint16_t)(l0_hi) << 3) \
+       | ((uint16_t)(l1)    << 6) \
+       | ((uint16_t)(l2_lo) << 9) \
+       | ((uint16_t)(l2_hi) << 12) \
+       )
 
 /* gpio.c */
 void init_gpio();
@@ -86,11 +98,17 @@ typedef struct {
 #define D_13 6
 #define D_21 7
 
+#define PWM_PAT(L2, L1, L0)    ( \
+       (((L2) & 3) << 3) | \
+       (((L1) & 1) << 2) | \
+       (((L0) & 3)) )
+
 void init_pattern();
 void patterns_next_tick();
 void led_set_pattern(unsigned char led, pattern_t *pattern);
 pattern_t *number_pattern(unsigned char num, unsigned char inv);
 void pattern_reload();
+void pwmleds_update_mode();
 
 /* buttons.c */
 #define MAX_USER_PARAMS 3
@@ -111,19 +129,19 @@ void init_battery();
 unsigned char battery_gauge();
 
 /* control.c */
-extern pattern_t on1_pattern[];
+extern pattern_t on_pattern[];
+extern volatile unsigned char braking;
 
 void init_control();
 void brake_on();
 void brake_off();
 void toggle_dim_mode();
 void set_panic_mode();
-pattern_t *pwmled0_pattern_select();
-pattern_t *pwmled1_pattern_select();
-pattern_t *pwmled2_pattern_select();
+pattern_t *pwmled_pattern_select();
 pattern_t *status_led_pattern_select();
 pattern_t *illumination_led_pattern_select();
 pattern_t *laser_pattern_select();
+void pwmled_select_brightness();
 
 /* main.c */
 void power_down(unsigned char err);
index 3354c6f5e5d59b8a46e4c5991d736ab70e6e4a55..83a932e2e0abc21b5fb075920b985bfeff7bf4f8 100644 (file)
@@ -85,13 +85,40 @@ pattern_t off_pattern[] = {
        PATTERN_END
 };
 
-static void led_set_mode(unsigned char n, unsigned char mode)
+/*
+ * This is tricky: we use a single pattern for all three pwmleds,
+ * but on some occasions, we want to be able to modify only a single
+ * pwmled status without affecting other outputs. For example, during
+ * braking, we want to modify only the rear pwmled status. We don't
+ * use a separate "braking" pattern for every other pattern used, but instead
+ * we change the pwmled0 status regardless of the original value when
+ * braking. The rule is the following:
+ * - if during braking the pwmled2 (front) is at mode 2, we switch it to
+ *   mode 3 (which has the same target current) to avoid flicker.
+ * - if pwmled0 (rear) is off, we set it to mode 2
+ *     (if it is with mode 1, we keep it at mode 1)
+ * TODO: something similar should be done for the "entering the dark area"
+ *     condition, where we want to switch pwmled2 (front) on, to mode 2.
+ */
+void pwmleds_update_mode()
 {
-       if (n < N_PWMLEDS) {
-               pwmled_set_mode(n, mode);
-       } else if (n < N_LEDS) {
-               gpio_set(n - N_PWMLEDS, mode);
+       unsigned char mode, mode0, mode1, mode2;
+
+       mode = led_patterns[0]->mode;
+
+       mode0 = mode & 3;
+       mode1 = (mode >> 2) & 1;
+       mode2 = (mode >> 3) & 3;
+
+       if (braking && !battery_critical) {
+               mode0 = 2;
+               if (mode2 == 2)
+                       mode2 = 3;
        }
+
+       pwmled_set_mode(0, mode0);
+       pwmled_set_mode(1, mode1);
+       pwmled_set_mode(2, mode2);
 }
 
 void led_set_pattern(unsigned char n, pattern_t *pattern)
@@ -103,7 +130,11 @@ void led_set_pattern(unsigned char n, pattern_t *pattern)
 
        led_counters[n] = fibonacci[pattern->duration_fib];
 
-       led_set_mode(n, pattern->mode);
+       if (n == 0) {
+               pwmleds_update_mode();
+       } else if (n < N_LEDS) {
+               gpio_set(n - 1, pattern->mode);
+       }
 }
 
 void init_pattern()
@@ -113,7 +144,7 @@ void init_pattern()
        for (i = 0; i < N_LEDS; i++)
                led_set_pattern(i, NULL);
 
-       led_set_pattern(N_PWMLEDS+1, boot_pattern);
+       led_set_pattern(N_ILLUM_LED, boot_pattern);
 }
 
 pattern_t *number_pattern(unsigned char num, unsigned char inv)
@@ -135,12 +166,10 @@ pattern_t *number_pattern(unsigned char num, unsigned char inv)
 static pattern_t *pattern_select(unsigned char n)
 {
        switch(n) {
-       case 0: return pwmled0_pattern_select();
-       case 1: return pwmled1_pattern_select();
-       case 2: return pwmled2_pattern_select();
-       case 3: return status_led_pattern_select();
-       case 4: return illumination_led_pattern_select();
-       case 6: return laser_pattern_select();
+       case 0: return pwmled_pattern_select();
+       case N_STATUS_LED: return status_led_pattern_select();
+       case N_ILLUM_LED:  return illumination_led_pattern_select();
+       case N_LASER_LED:  return laser_pattern_select();
        default: return NULL;
        }
 }
@@ -159,20 +188,16 @@ static void inline pattern_finished(unsigned char n)
 
        led_patterns[n] = NULL;
 
-       if (n < N_PWMLEDS) {
-               for (i = 0; i < N_PWMLEDS; i++)
-                       if (led_patterns[i])
-                               return;
-
-               /* all pwmleds finished; restart them */
-               for (i = 0; i < N_PWMLEDS; i++)
-                       led_set_pattern(i, pattern_select(i));
-       } else if (n == 3) {
-               if (!led_patterns[4])
-                       led_set_pattern(4, pattern_select(4));
-       } else if (n == 4) {
-               if (!led_patterns[3])
-                       led_set_pattern(3, pattern_select(3));
+       if (n == 0) {
+               led_set_pattern(0, pattern_select(0));
+       } else if (n == N_STATUS_LED) {
+               if (!led_patterns[N_ILLUM_LED])
+                       led_set_pattern(N_ILLUM_LED,
+                               pattern_select(N_ILLUM_LED));
+       } else if (n == N_ILLUM_LED) {
+               if (!led_patterns[N_STATUS_LED])
+                       led_set_pattern(N_STATUS_LED,
+                               pattern_select(N_STATUS_LED));
        } else {
                led_set_pattern(n, pattern_select(n));
        }
index db1cb862c75f21043acb8d34e668ff4037e63429..82237dca936b6783c38c778b6e820277bd8742f6 100644 (file)
@@ -42,42 +42,37 @@ static uint16_t adc_max[N_PWMLEDS] = {
 #endif
 };
 
-static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES] = {
-#ifdef TESTING_FW
-       /* pwmled0 */
+static uint16_t adc_targets_0[] = {
        MA_GAIN_TO_ADC(  50, 20),
        MA_GAIN_TO_ADC( 100, 20),
        MA_GAIN_TO_ADC( 200, 20),
        MA_GAIN_TO_ADC( 350, 20),
-       /* pwmled1 */
+};
+
+static uint16_t adc_targets_1[] = {
        MA_GAIN_TO_ADC(   5, 20),
        MA_GAIN_TO_ADC(  10, 20),
-       MA_GAIN_TO_ADC(  15, 20),
        MA_GAIN_TO_ADC(  20, 20),
-       /* pwmled2 */
+};
+
+static uint16_t adc_targets_2[] = {
+#ifdef TESTING_FW
        MA_GAIN_TO_ADC(  50,  1),
-       MA_GAIN_TO_ADC(  80,  1),
+       MA_GAIN_TO_ADC( 100,  1),
        MA_GAIN_TO_ADC( 150,  1),
-       MA_GAIN_TO_ADC( 200,  1)
+       MA_GAIN_TO_ADC( 240,  1),
+       MA_GAIN_TO_ADC( 350,  1),
 #else
-       /* pwmled0 */
-       MA_GAIN_TO_ADC(  50, 20),
-       MA_GAIN_TO_ADC( 100, 20),
-       MA_GAIN_TO_ADC( 200, 20),
-       MA_GAIN_TO_ADC( 350, 20),
-       /* pwmled1 */
-       MA_GAIN_TO_ADC(   5, 20),
-       MA_GAIN_TO_ADC(  10, 20),
-       MA_GAIN_TO_ADC(  18, 20),
-       MA_GAIN_TO_ADC(  23, 20),
-       /* pwmled2 */
        MA_GAIN_TO_ADC( 150,  1),
        MA_GAIN_TO_ADC( 300,  1),
+       MA_GAIN_TO_ADC( 500,  1),
        MA_GAIN_TO_ADC( 800,  1),
-       MA_GAIN_TO_ADC(1500,  1)
+       MA_GAIN_TO_ADC(1200,  1),
 #endif
 };
 
+static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES];
+
 #define ST_DISABLED 0
 #define ST_OFF      1
 #define ST_PROBING  2
@@ -96,7 +91,7 @@ void init_pwmled()
                led->target = adc_vals[i*N_PWMLED_MODES];
                led->mode = 1;
                led->probe_steady = 0;
-               led->state = ST_PROBING;
+               led->state = ST_OFF;
                led->pwm = 1;
                pwm_set(i, led->pwm);
 
@@ -105,6 +100,8 @@ void init_pwmled()
                        led->err_sums[j] = 0;
                }
        }
+
+       pwmled_set_brightness(PWMLED_BRIGHTNESS(0, 2, 1, 0, 2));
 }
 
 void pwmled_set_mode(unsigned char n, unsigned char mode)
@@ -134,6 +131,40 @@ void pwmled_set_mode(unsigned char n, unsigned char mode)
        }
 }
 
+#define CHECK_BRIGHTNESS(var, expr, array) \
+       do { \
+               (var) = (expr); \
+               if ((var) >= sizeof(array)/sizeof(array[0])) \
+                       (var) = sizeof(array)/sizeof(array[0]) - 1; \
+       } while (0)
+
+void pwmled_set_brightness(uint16_t brightness)
+{
+       unsigned char i;
+
+       CHECK_BRIGHTNESS(i, brightness & 0x7, adc_targets_0);
+       adc_vals[0] = adc_targets_0[i];
+       CHECK_BRIGHTNESS(i, (brightness >> 3) & 0x7, adc_targets_0);
+       adc_vals[1] = adc_targets_0[i];
+       adc_vals[2] = adc_vals[1];
+
+       CHECK_BRIGHTNESS(i, (brightness >> 6) & 0x7, adc_targets_1);
+       adc_vals[3] = adc_targets_1[i];
+       adc_vals[4] = adc_vals[3];
+       adc_vals[5] = adc_vals[3];
+
+       CHECK_BRIGHTNESS(i, (brightness >> 9) & 0x7, adc_targets_2);
+       adc_vals[6] = adc_targets_2[i];
+       CHECK_BRIGHTNESS(i, (brightness >> 12) & 0x7, adc_targets_2);
+       adc_vals[7] = adc_targets_2[i];
+       adc_vals[8] = adc_vals[7];
+
+       for (i = 0; i < N_PWMLEDS; i++) {
+               pwmleds[i].err_sum = 0;
+               pwmled_set_mode(i, pwmleds[i].mode);
+       }
+}
+
 #define PWMLED_PROBE_STEADY_COUNT 10
 
 static inline unsigned char pwmled_probed_ok(unsigned char n, uint16_t old_pwm)
@@ -215,7 +246,8 @@ void pwmled_adc(unsigned char n, uint16_t adcval)
 
        old_pwm = led->pwm;
 
-       shift = led->state == ST_PROBING ? 3 : 8;
+       // shift = led->state == ST_PROBING ? 3 : 8;
+       shift = 3;
 
        sum = ((int32_t)led->pwm << shift)
                + led->err_sum + led->target - adcval;