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;
120 pwmled_set_mode(0, mode0);
121 pwmled_set_mode(1, mode1);
122 pwmled_set_mode(2, mode2);
125 void led_set_pattern(unsigned char n, pattern_t *pattern)
128 pattern = off_pattern;
130 led_patterns[n] = pattern;
132 led_counters[n] = fibonacci[pattern->duration_fib];
135 pwmleds_update_mode();
136 } else if (n < N_LEDS) {
137 gpio_set(n - 1, pattern->mode);
145 for (i = 0; i < N_LEDS; i++)
146 led_set_pattern(i, NULL);
148 led_set_pattern(N_ILLUM_LED, boot_pattern);
151 pattern_t *number_pattern(unsigned char num, unsigned char inv)
157 return pattern_invnum
158 + sizeof(pattern_invnum)/sizeof(pattern_t)
162 + sizeof(pattern_num)/sizeof(pattern_t)
167 static pattern_t *pattern_select(unsigned char n)
170 case 0: return pwmled_pattern_select();
171 case N_STATUS_LED: return status_led_pattern_select();
172 case N_ILLUM_LED: return illumination_led_pattern_select();
173 case N_LASER_LED: return laser_pattern_select();
174 default: return NULL;
178 void pattern_reload()
182 for (i = 0; i < N_LEDS; i++)
183 led_set_pattern(i, pattern_select(i));
186 static void inline pattern_finished(unsigned char n)
190 led_patterns[n] = NULL;
193 led_set_pattern(0, pattern_select(0));
194 } else if (n == N_STATUS_LED) {
195 if (!led_patterns[N_ILLUM_LED])
196 led_set_pattern(N_ILLUM_LED,
197 pattern_select(N_ILLUM_LED));
198 } else if (n == N_ILLUM_LED) {
199 if (!led_patterns[N_STATUS_LED])
200 led_set_pattern(N_STATUS_LED,
201 pattern_select(N_STATUS_LED));
203 led_set_pattern(n, pattern_select(n));
207 void patterns_next_tick()
211 for (i = 0; i < N_LEDS; i++) {
212 if (!led_patterns[i]) {
217 if (--led_counters[i] == 0) {
218 pattern_t *p = led_patterns[i];
220 if (p->duration_fib == 0) { // END
221 /* Keep the last state, wait for others */
225 led_set_pattern(i, p);