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)
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();
+ }
}
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()
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 ---
#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();
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);
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);
+}
#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
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();
#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
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);
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)
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()
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)
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;
}
}
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));
}
#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
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);
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)
}
}
+#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)
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;