]> www.fi.muni.cz Git - bike-lights.git/blob - firmware/pattern.c
Error flags, error reporting
[bike-lights.git] / firmware / pattern.c
1 #include <avr/io.h>
2 #include <stdlib.h> // for NULL
3
4 #include "lights.h"
5
6 static unsigned char led_counters[N_LEDS];
7 static pattern_t *led_patterns[N_LEDS];
8
9 static unsigned char fibonacci[8] = {
10         0, 1, 2, 3, 5, 8, 13, 21,
11 };
12
13 static pattern_t boot_pattern[] = {
14         { 1, D_5 },
15         { 0, D_5 },
16         { 1, D_3 },
17         { 0, D_3 },
18         { 1, D_2 },
19         { 0, D_2 },
20         { 1, D_1 },
21         { 0, D_1 },
22         { 1, D_1 },
23         { 0, D_1 },
24         { 1, D_1 },
25         { 0, D_1 },
26         { 1, D_1 },
27         { 0, D_1 },
28         { 1, D_8 },
29         { 0, D_8 },
30         PATTERN_END
31 };
32
33 static pattern_t pattern_num[] = {
34         { 0, D_5 },
35         { 1, D_1 }, /* 10 */
36         { 0, D_5 },
37         { 1, D_1 }, /*  9 */
38         { 0, D_5 },
39         { 1, D_1 }, /*  8 */
40         { 0, D_5 },
41         { 1, D_1 }, /*  7 */
42         { 0, D_5 },
43         { 1, D_1 }, /*  6 */
44         { 0, D_5 },
45         { 1, D_1 }, /*  5 */
46         { 0, D_5 },
47         { 1, D_1 }, /*  4 */
48         { 0, D_5 },
49         { 1, D_1 }, /*  3 */
50         { 0, D_5 },
51         { 1, D_1 }, /*  2 */
52         { 0, D_5 },
53         { 1, D_1 }, /*  1 */
54         { 0, D_13 },
55         PATTERN_END
56 };
57
58 static pattern_t pattern_invnum[] = {
59         { 1, D_5 },
60         { 0, D_1 }, /* 10 */
61         { 1, D_5 },
62         { 0, D_1 }, /*  9 */
63         { 1, D_5 },
64         { 0, D_1 }, /*  8 */
65         { 1, D_5 },
66         { 0, D_1 }, /*  7 */
67         { 1, D_5 },
68         { 0, D_1 }, /*  6 */
69         { 1, D_5 },
70         { 0, D_1 }, /*  5 */
71         { 1, D_5 },
72         { 0, D_1 }, /*  4 */
73         { 1, D_5 },
74         { 0, D_1 }, /*  3 */
75         { 1, D_5 },
76         { 0, D_1 }, /*  2 */
77         { 1, D_5 },
78         { 0, D_1 }, /*  1 */
79         { 1, D_13 },
80         PATTERN_END
81 };
82
83 pattern_t off_pattern[] = {
84         { 0, D_1 },
85         PATTERN_END
86 };
87
88 /*
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.
102  */
103 void pwmleds_update_mode()
104 {
105         unsigned char mode, mode0, mode1, mode2;
106
107         mode = led_patterns[0]->mode;
108
109         mode0 = mode & 3;
110         mode1 = (mode >> 2) & 1;
111         mode2 = (mode >> 3) & 3;
112
113         if (err_flags.braking && !err_flags.err_battery) {
114                 mode0 = 2;
115                 if (mode2 == 2)
116                         mode2 = 3;
117         }
118
119         pwmled_set_mode(0, mode0);
120         pwmled_set_mode(1, mode1);
121         pwmled_set_mode(2, mode2);
122 }
123
124 void led_set_pattern(unsigned char n, pattern_t *pattern)
125 {
126         if (!pattern)
127                 pattern = off_pattern;
128
129         led_patterns[n] = pattern;
130
131         led_counters[n] = fibonacci[pattern->duration_fib];
132
133         if (n == 0) {
134                 pwmleds_update_mode();
135         } else if (n < N_LEDS) {
136                 gpio_set(n - 1, pattern->mode);
137         }
138 }
139
140 void init_pattern()
141 {
142         unsigned char i;
143
144         for (i = 0; i < N_LEDS; i++)
145                 led_set_pattern(i, NULL);
146
147         led_set_pattern(N_ILLUM_LED, boot_pattern);
148 }
149
150 pattern_t *number_pattern(unsigned char num, unsigned char inv)
151 {
152         if (num >= 10)
153                 num = 10;
154
155         if (inv) {
156                 return pattern_invnum
157                         + sizeof(pattern_invnum)/sizeof(pattern_t)
158                         - 2 - 2*num;
159         } else {
160                 return pattern_num
161                         + sizeof(pattern_num)/sizeof(pattern_t)
162                         - 2 - 2*num;
163         }
164 }
165
166 static pattern_t *pattern_select(unsigned char n)
167 {
168         switch(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;
174         }
175 }
176
177 void pattern_reload()
178 {
179         unsigned char i;
180
181         for (i = 0; i < N_LEDS; i++)
182                 led_set_pattern(i, pattern_select(i));
183 }
184
185 static void inline pattern_finished(unsigned char n)
186 {
187         unsigned char i;
188
189         led_patterns[n] = NULL;
190
191         if (n == 0) {
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));
201         } else {
202                 led_set_pattern(n, pattern_select(n));
203         }
204 }
205
206 void patterns_next_tick()
207 {
208         unsigned char i;
209
210         for (i = 0; i < N_LEDS; i++) {
211                 if (!led_patterns[i]) {
212                         pattern_finished(i);
213                         continue;
214                 }
215
216                 if (--led_counters[i] == 0) {
217                         pattern_t *p = led_patterns[i];
218                         p++;
219                         if (p->duration_fib == 0) { // END
220                                 /* Keep the last state, wait for others */
221                                 pattern_finished(i);
222                                 continue;
223                         }
224                         led_set_pattern(i, p);
225                 }
226
227         }
228 }
229