]> www.fi.muni.cz Git - bike-lights.git/blob - firmware/pattern.c
PWM LEDs driven by a single pattern
[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 static void led_set_mode(unsigned char n, unsigned char mode)
89 {
90         if (n == 0) {
91                 pwmled_set_mode(0, mode & 3);
92                 pwmled_set_mode(1, (mode >> 2) & 1);
93                 pwmled_set_mode(2, (mode >> 3) & 3);
94         } else if (n < N_LEDS) {
95                 gpio_set(n - 1, mode);
96         }
97 }
98
99 void led_set_pattern(unsigned char n, pattern_t *pattern)
100 {
101         if (!pattern)
102                 pattern = off_pattern;
103
104         led_patterns[n] = pattern;
105
106         led_counters[n] = fibonacci[pattern->duration_fib];
107
108         led_set_mode(n, pattern->mode);
109 }
110
111 void init_pattern()
112 {
113         unsigned char i;
114
115         for (i = 0; i < N_LEDS; i++)
116                 led_set_pattern(i, NULL);
117
118         led_set_pattern(N_ILLUM_LED, boot_pattern);
119 }
120
121 pattern_t *number_pattern(unsigned char num, unsigned char inv)
122 {
123         if (num >= 10)
124                 num = 10;
125
126         if (inv) {
127                 return pattern_invnum
128                         + sizeof(pattern_invnum)/sizeof(pattern_t)
129                         - 2 - 2*num;
130         } else {
131                 return pattern_num
132                         + sizeof(pattern_num)/sizeof(pattern_t)
133                         - 2 - 2*num;
134         }
135 }
136
137 static pattern_t *pattern_select(unsigned char n)
138 {
139         switch(n) {
140         case 0: return pwmled_pattern_select();
141         case N_STATUS_LED: return status_led_pattern_select();
142         case N_ILLUM_LED:  return illumination_led_pattern_select();
143         case N_LASER_LED:  return laser_pattern_select();
144         default: return NULL;
145         }
146 }
147
148 void pattern_reload()
149 {
150         unsigned char i;
151
152         for (i = 0; i < N_LEDS; i++)
153                 led_set_pattern(i, pattern_select(i));
154 }
155
156 static void inline pattern_finished(unsigned char n)
157 {
158         unsigned char i;
159
160         led_patterns[n] = NULL;
161
162         if (n == 0) {
163                 led_set_pattern(0, pattern_select(0));
164         } else if (n == N_STATUS_LED) {
165                 if (!led_patterns[N_ILLUM_LED])
166                         led_set_pattern(N_ILLUM_LED,
167                                 pattern_select(N_ILLUM_LED));
168         } else if (n == N_ILLUM_LED) {
169                 if (!led_patterns[N_STATUS_LED])
170                         led_set_pattern(N_STATUS_LED,
171                                 pattern_select(N_STATUS_LED));
172         } else {
173                 led_set_pattern(n, pattern_select(n));
174         }
175 }
176
177 void patterns_next_tick()
178 {
179         unsigned char i;
180
181         for (i = 0; i < N_LEDS; i++) {
182                 if (!led_patterns[i]) {
183                         pattern_finished(i);
184                         continue;
185                 }
186
187                 if (--led_counters[i] == 0) {
188                         pattern_t *p = led_patterns[i];
189                         p++;
190                         if (p->duration_fib == 0) { // END
191                                 /* Keep the last state, wait for others */
192                                 pattern_finished(i);
193                                 continue;
194                         }
195                         led_set_pattern(i, p);
196                 }
197
198         }
199 }
200