2 #include <stdlib.h> // for NULL
6 static unsigned char led_counters[N_LEDS];
7 static pattern_t *led_patterns[N_LEDS];
9 static unsigned char fibonacci[8] = {
10 0, 1, 2, 3, 5, 8, 13, 21,
13 static pattern_t boot_pattern[] = {
33 static pattern_t pattern_num[] = {
58 static pattern_t pattern_invnum[] = {
83 pattern_t off_pattern[] = {
89 * This is tricky: we use a single pattern for all three pwmleds,
90 * but on some occasions, we want to be able to modify only a single
91 * pwmled status without affecting other outputs. For example, during
92 * braking, we want to modify only the rear pwmled status. We don't
93 * use a separate "braking" pattern for every other pattern used, but instead
94 * we change the pwmled0 status regardless of the original value when
95 * braking. The rule is the following:
96 * - if during braking the pwmled2 (front) is at mode 2, we switch it to
97 * mode 3 (which has the same target current) to avoid flicker.
98 * - if pwmled0 (rear) is off, we set it to mode 2
99 * (if it is with mode 1, we keep it at mode 1)
100 * TODO: something similar should be done for the "entering the dark area"
101 * condition, where we want to switch pwmled2 (front) on, to mode 2.
103 void pwmleds_update_mode()
105 unsigned char mode, mode0, mode1, mode2;
107 mode = led_patterns[0]->mode;
110 mode1 = (mode >> 2) & 1;
111 mode2 = (mode >> 3) & 3;
113 if (err_flags.braking && !err_flags.err_battery) {
119 pwmled_set_mode(0, mode0);
120 pwmled_set_mode(1, mode1);
121 pwmled_set_mode(2, mode2);
124 void led_set_pattern(unsigned char n, pattern_t *pattern)
127 pattern = off_pattern;
129 led_patterns[n] = pattern;
131 led_counters[n] = fibonacci[pattern->duration_fib];
134 pwmleds_update_mode();
135 } else if (n < N_LEDS) {
136 gpio_set(n - 1, pattern->mode);
144 for (i = 0; i < N_LEDS; i++)
145 led_set_pattern(i, NULL);
147 led_set_pattern(N_ILLUM_LED, boot_pattern);
150 pattern_t *number_pattern(unsigned char num, unsigned char inv)
156 return pattern_invnum
157 + sizeof(pattern_invnum)/sizeof(pattern_t)
161 + sizeof(pattern_num)/sizeof(pattern_t)
166 static pattern_t *pattern_select(unsigned char n)
169 case 0: return pwmled_pattern_select();
170 case N_STATUS_LED: return status_led_pattern_select();
171 case N_ILLUM_LED: return illumination_led_pattern_select();
172 case N_LASER_LED: return laser_pattern_select();
173 default: return NULL;
177 void pattern_reload()
181 for (i = 0; i < N_LEDS; i++)
182 led_set_pattern(i, pattern_select(i));
185 static void inline pattern_finished(unsigned char n)
189 led_patterns[n] = NULL;
192 led_set_pattern(0, pattern_select(0));
193 } else if (n == N_STATUS_LED) {
194 if (!led_patterns[N_ILLUM_LED])
195 led_set_pattern(N_ILLUM_LED,
196 pattern_select(N_ILLUM_LED));
197 } else if (n == N_ILLUM_LED) {
198 if (!led_patterns[N_STATUS_LED])
199 led_set_pattern(N_STATUS_LED,
200 pattern_select(N_STATUS_LED));
202 led_set_pattern(n, pattern_select(n));
206 void patterns_next_tick()
210 for (i = 0; i < N_LEDS; i++) {
211 if (!led_patterns[i]) {
216 if (--led_counters[i] == 0) {
217 pattern_t *p = led_patterns[i];
219 if (p->duration_fib == 0) { // END
220 /* Keep the last state, wait for others */
224 led_set_pattern(i, p);