X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?p=bike-lights.git;a=blobdiff_plain;f=firmware%2Fpattern.c;h=989009e6c237b55ebc8e3ba96fa1050753ce8b5d;hp=a39be3657c579a4e4cf8d5a5a65ebb61c729f7f8;hb=HEAD;hpb=b475975f99700f3e887df281130a3b9de62368c5 diff --git a/firmware/pattern.c b/firmware/pattern.c index a39be36..b4edcc4 100644 --- a/firmware/pattern.c +++ b/firmware/pattern.c @@ -1,92 +1,124 @@ #include +#include // for NULL #include "lights.h" -typedef struct { - unsigned char mode: 3; - unsigned char duration: 5; -} pattern_t; - static unsigned char led_counters[N_LEDS]; static pattern_t *led_patterns[N_LEDS]; -#define PATTERN_END { 0, 0 } -pattern_t off_pattern[] = { - { 0, 0x1F }, - PATTERN_END +static unsigned char fibonacci[8] = { + 0, 1, 2, 3, 5, 8, 13, 21, }; -pattern_t blink_pattern[] = { - { 1, 0x4 }, - { 0, 0x8 }, +static pattern_t boot_pattern[] = { + { 1, D_5 }, + { 0, D_5 }, + { 1, D_3 }, + { 0, D_3 }, + { 1, D_2 }, + { 0, D_2 }, + { 1, D_1 }, + { 0, D_1 }, + { 1, D_1 }, + { 0, D_1 }, + { 1, D_1 }, + { 0, D_1 }, + { 1, D_1 }, + { 0, D_1 }, + { 1, D_8 }, + { 0, D_8 }, PATTERN_END }; -pattern_t mode1_pattern[] = { - { 3, 0x1 }, - { 0, 0x1 }, - { 3, 0x1 }, - { 0, 0x8 }, - { 1, 0x1 }, - { 0, 0x1 }, - { 1, 0x1 }, - { 0, 0x8 }, +static pattern_t pattern_num[] = { + { 0, D_5 }, + { 1, D_1 }, /* 10 */ + { 0, D_5 }, + { 1, D_1 }, /* 9 */ + { 0, D_5 }, + { 1, D_1 }, /* 8 */ + { 0, D_5 }, + { 1, D_1 }, /* 7 */ + { 0, D_5 }, + { 1, D_1 }, /* 6 */ + { 0, D_5 }, + { 1, D_1 }, /* 5 */ + { 0, D_5 }, + { 1, D_1 }, /* 4 */ + { 0, D_5 }, + { 1, D_1 }, /* 3 */ + { 0, D_5 }, + { 1, D_1 }, /* 2 */ + { 0, D_5 }, + { 1, D_1 }, /* 1 */ + { 0, D_13 }, PATTERN_END }; -pattern_t boot_pattern[] = { - { 1, 0x6 }, - { 0, 0x6 }, - { 1, 0x3 }, - { 0, 0x3 }, - { 1, 0x2 }, - { 0, 0x2 }, - { 1, 0x1 }, - { 0, 0x1 }, - { 1, 0x1 }, - { 0, 0x1 }, - { 1, 0x1 }, - { 0, 0x1 }, - { 1, 0x1 }, - { 0, 0x1 }, - { 1, 0x10 }, - { 0, 0x10 }, +static pattern_t pattern_invnum[] = { + { 1, D_5 }, + { 0, D_1 }, /* 10 */ + { 1, D_5 }, + { 0, D_1 }, /* 9 */ + { 1, D_5 }, + { 0, D_1 }, /* 8 */ + { 1, D_5 }, + { 0, D_1 }, /* 7 */ + { 1, D_5 }, + { 0, D_1 }, /* 6 */ + { 1, D_5 }, + { 0, D_1 }, /* 5 */ + { 1, D_5 }, + { 0, D_1 }, /* 4 */ + { 1, D_5 }, + { 0, D_1 }, /* 3 */ + { 1, D_5 }, + { 0, D_1 }, /* 2 */ + { 1, D_5 }, + { 0, D_1 }, /* 1 */ + { 1, D_13 }, PATTERN_END }; -pattern_t pattern_num[] = { - { 1, 0x1 }, /* 10 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 9 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 8 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 7 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 6 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 5 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 4 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 3 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 2 */ - { 0, 0x4 }, - { 1, 0x1 }, /* 1 */ - { 0, 0x1F }, +pattern_t off_pattern[] = { + { 0, D_1 }, PATTERN_END }; -static unsigned char test_running; - -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 (err_flags.braking && !err_flags.err_battery) { + 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) @@ -95,41 +127,80 @@ void led_set_pattern(unsigned char n, pattern_t *pattern) pattern = off_pattern; led_patterns[n] = pattern; - led_counters[n] = pattern->duration; - led_set_mode(n, pattern->mode); + + led_counters[n] = fibonacci[pattern->duration_fib]; + + if (n == 0) { + pwmleds_update_mode(); + } else if (n < N_LEDS) { + gpio_set(n - 1, pattern->mode); + } } -void pattern_init() +void init_pattern() { unsigned char i; - for (i = 0; i < N_LEDS; i++) { - led_counters[i] = 0; - led_patterns[i] = off_pattern; + for (i = 0; i < N_LEDS; i++) + led_set_pattern(i, NULL); + + led_set_pattern(N_ILLUM_LED, boot_pattern); +} + +pattern_t *number_pattern(unsigned char num, unsigned char inv) +{ + if (num >= 10) + num = 10; + + if (inv) { + return pattern_invnum + + sizeof(pattern_invnum)/sizeof(pattern_t) + - 2 - 2*num; + } else { + return pattern_num + + sizeof(pattern_num)/sizeof(pattern_t) + - 2 - 2*num; + } +} + +static pattern_t *pattern_select(unsigned char n) +{ + switch(n) { + 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_set_pattern(N_PWMLEDS+1, boot_pattern); - test_running = 0; } -static pattern_t *number_pattern(unsigned char num) +void pattern_reload() { - if (num >= 9) - num = 9; + unsigned char i; - return pattern_num + sizeof(pattern_num)/sizeof(pattern_t) - - 1 - 2*num; + for (i = 0; i < N_LEDS; i++) + led_set_pattern(i, pattern_select(i)); } -static inline pattern_t *pattern_select(unsigned char n) +static void inline pattern_finished(unsigned char n) { - if (n < N_PWMLEDS && !pwmled_enabled(n)) - return off_pattern; // Don't mess with non-enabled LEDs + unsigned char i; - if (n == 2) { - return mode1_pattern; + led_patterns[n] = NULL; + + 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)); } - return number_pattern(1+ambient_zone); - // return off_pattern; } void patterns_next_tick() @@ -137,20 +208,22 @@ void patterns_next_tick() unsigned char i; for (i = 0; i < N_LEDS; i++) { - if (led_counters[i] == 0) { + if (!led_patterns[i]) { + pattern_finished(i); + continue; + } + + if (--led_counters[i] == 0) { pattern_t *p = led_patterns[i]; p++; - if (p->duration == 0) { // END - p = pattern_select(i); + if (p->duration_fib == 0) { // END + /* Keep the last state, wait for others */ + pattern_finished(i); + continue; } led_set_pattern(i, p); } - led_counters[i]--; } } -void led_set_status(unsigned char status) -{ - led_set_pattern(N_PWMLEDS+1, number_pattern(status)); -}