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 (braking && !battery_critical) {
123 pwmled_set_mode(0, mode0);
124 pwmled_set_mode(1, mode1);
125 pwmled_set_mode(2, mode2);
128 void led_set_pattern(unsigned char n, pattern_t *pattern)
131 pattern = off_pattern;
133 led_patterns[n] = pattern;
135 led_counters[n] = fibonacci[pattern->duration_fib];
138 pwmleds_update_mode();
139 } else if (n < N_LEDS) {
140 gpio_set(n - 1, pattern->mode);
148 for (i = 0; i < N_LEDS; i++)
149 led_set_pattern(i, NULL);
151 led_set_pattern(N_ILLUM_LED, boot_pattern);
154 pattern_t *number_pattern(unsigned char num, unsigned char inv)
160 return pattern_invnum
161 + sizeof(pattern_invnum)/sizeof(pattern_t)
165 + sizeof(pattern_num)/sizeof(pattern_t)
170 static pattern_t *pattern_select(unsigned char n)
173 case 0: return pwmled_pattern_select();
174 case N_STATUS_LED: return status_led_pattern_select();
175 case N_ILLUM_LED: return illumination_led_pattern_select();
176 case N_LASER_LED: return laser_pattern_select();
177 default: return NULL;
181 void pattern_reload()
185 for (i = 0; i < N_LEDS; i++)
186 led_set_pattern(i, pattern_select(i));
189 static void inline pattern_finished(unsigned char n)
193 led_patterns[n] = NULL;
196 led_set_pattern(0, pattern_select(0));
197 } else if (n == N_STATUS_LED) {
198 if (!led_patterns[N_ILLUM_LED])
199 led_set_pattern(N_ILLUM_LED,
200 pattern_select(N_ILLUM_LED));
201 } else if (n == N_ILLUM_LED) {
202 if (!led_patterns[N_STATUS_LED])
203 led_set_pattern(N_STATUS_LED,
204 pattern_select(N_STATUS_LED));
206 led_set_pattern(n, pattern_select(n));
210 void patterns_next_tick()
214 for (i = 0; i < N_LEDS; i++) {
215 if (!led_patterns[i]) {
220 if (--led_counters[i] == 0) {
221 pattern_t *p = led_patterns[i];
223 if (p->duration_fib == 0) { // END
224 /* Keep the last state, wait for others */
228 led_set_pattern(i, p);