]> www.fi.muni.cz Git - tinyboard.git/blob - projects/rgb-led-string/main.c
rgb-led-string: christmas tree mode
[tinyboard.git] / projects / rgb-led-string / main.c
1 #include <avr/io.h>
2 #include <util/delay.h>
3 #include <avr/interrupt.h>
4
5 #include "rgbstring.h"
6
7 static unsigned char jiffies;
8
9 // #define CHRISTMAS_TREE 1
10
11 #define rgb_return(r, g, b)     do { send_rgb((r), (g), (b)); return 1; } while(0)
12
13 #define VERT_SIZE 47
14
15 /* RNG from ADC noise */
16 static unsigned char rand_pool[8], rand_pool_off, prev_bit, rand_pool_out;
17
18 static void init_rng()
19 {
20         ADCSRA |= _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1); // enable, clk/64
21         ADMUX = _BV(REFS1) | _BV(MUX0) | _BV(MUX3); // 1.1V, PB5:PB5, gain 20
22         DIDR0 = _BV(ADC0D);
23         ADCSRA |= _BV(ADIE) | _BV(ADSC);
24         rand_pool_off = 0;
25         prev_bit = 0;
26 }
27
28 static unsigned char rand() {
29         unsigned char rv = 0;
30
31         rv = rand_pool[rand_pool_out];
32         rand_pool_out++;
33         if (rand_pool_out >= sizeof(rand_pool))
34                 rand_pool_out = 0;
35
36         return rv;
37 }
38
39 ISR(ADC_vect) {
40         ADCSRA |= _BV(ADSC);
41         if ((rand_pool_off & 1) == 0) { // first bit of the pair
42                 prev_bit = ADCW & 1;
43                 rand_pool_off++;
44         } else {
45                 unsigned char bit = ADCW & 1;
46                 if (bit == prev_bit) { // whitening fail: try again
47                         rand_pool_off--;
48                         return;
49                 }
50
51                 if (bit) {
52                         rand_pool[rand_pool_off >> 4]
53                                 ^= 1 << ((rand_pool_off >> 1) & 7);
54                 }
55
56                 rand_pool_off++;
57                 if (rand_pool_off >= 16*sizeof(rand_pool))
58                         rand_pool_off = 0;
59         }
60 }
61
62 /* up and down running stars at the beginning/end of the strip */
63 static unsigned char updown_star, updown_star0, updown_down, updown_bright;
64
65 static void updown_star_init()
66 {
67         updown_star0 = 0;
68         updown_down = 1;
69 }
70
71 static void updown_star_frame()
72 {
73         if (updown_star0 == 0) {
74                 updown_star0 = STRIP_SIZE-VERT_SIZE-8;
75                 updown_down = 0;
76         } else if (updown_star0 == STRIP_SIZE + 8) {
77                 updown_star0 = VERT_SIZE+7;
78                 updown_down = 1;
79         } else if (updown_star0 <= VERT_SIZE + 8) {
80                 updown_star0--;
81         } else if (updown_star0 >= STRIP_SIZE-VERT_SIZE-8) {
82                 updown_star0++;
83         }
84
85         if (updown_down && updown_star0 < 8) {
86                 updown_star = 0;
87                 updown_bright = 1 << updown_star0;
88         } else if (updown_down) {
89                 updown_star = updown_star0 - 8;
90                 updown_bright = 128;
91         } else if (updown_star0 < STRIP_SIZE-VERT_SIZE) {
92                 updown_star = STRIP_SIZE-VERT_SIZE;
93                 updown_bright = 1 << (STRIP_SIZE-VERT_SIZE-updown_star0);
94         } else {
95                 updown_star = updown_star0;
96                 updown_bright = 1;
97         }
98 }
99
100 static unsigned char updown_star_pixel(unsigned char pos)
101 {
102         if (pos >= VERT_SIZE && pos < STRIP_SIZE-VERT_SIZE)
103                 return 0;
104
105         if (pos == updown_star) {
106                 send_rgb(updown_bright, updown_bright, updown_bright);
107                 if (updown_down) {
108                         updown_bright >>= 1;
109                         if (updown_bright)
110                                 updown_star++;
111                 } else {
112                         updown_bright <<= 1;
113                         if (updown_bright)
114                                 updown_star++;
115                 }
116                 return 1;
117         }
118
119         return 0;
120 }
121
122 /* down running stars at the beginning/end of the strip */
123 static unsigned char down_star, down_star0, down_bright;
124
125 static void down_star_init()
126 {
127         down_star0 = STRIP_SIZE;
128 }
129
130 static void down_star_frame()
131 {
132         if (down_star0 == 0) {
133                 down_star0 = STRIP_SIZE;
134         } else {
135                 down_star0--;
136         }
137
138         if (down_star0 < 8) {
139                 down_star = 0;
140                 down_bright = 1 << down_star0;
141         } else {
142                 down_star = down_star0;
143                 down_bright = 128;
144         }
145 }
146
147 static unsigned char down_star_pixel(unsigned char pos)
148 {
149         if (pos == down_star) {
150                 send_rgb(down_bright, down_bright, down_bright);
151                 down_bright >>= 1;
152                 if (down_bright)
153                         down_star++;
154                 return 1;
155         }
156
157         return 0;
158 }
159
160 /* middle stars */
161
162 static unsigned char midstar_pos0, midstar_pos, midstar_bright, midstar_color;
163
164 static void midstar_init()
165 {
166         midstar_pos0 = STRIP_SIZE/2;
167         midstar_color = 0;
168 }
169
170 static unsigned int slow_dim[] = {
171         255, 182, 130, 92, 66, 47, 33, 24, 17, 12, 8, 6, 4, 3, 2, 1,
172 };
173
174 static void midstar_frame()
175 {
176         unsigned char phase = (jiffies) & 0x1F;
177
178         midstar_bright = phase & 0x10 ? slow_dim[phase & 0x0F]
179                 : slow_dim[15-(phase & 0x0F)];
180
181         if (!phase) {
182                 unsigned char c = rand();
183 #ifdef CHRISTMAS_TREE
184                 midstar_pos0 = 2 + (c % (STRIP_SIZE - 4));
185 #else
186                 midstar_pos0 -= 2 + VERT_SIZE;
187                 midstar_pos0 += 16 + (c & 0x1F);
188                 midstar_pos0 &= 0x3F;
189                 midstar_pos0 += 2 + VERT_SIZE;
190 #endif
191                 midstar_color += 1 + (c & 0xC0 ? 0 : 1);
192         }
193
194         midstar_pos = midstar_pos0 - 2;
195 }
196
197 static unsigned char midstar_pixel(unsigned char pos)
198 {
199         unsigned char dim;
200
201         if (pos != midstar_pos)
202                 return 0;
203
204         if (pos > midstar_pos0) {
205                 dim = pos - midstar_pos0;
206                 if (dim < 2)
207                         midstar_pos++;
208         } else {
209                 dim = midstar_pos0 - pos;
210                 midstar_pos++;
211         }
212
213         dim = midstar_bright >> 2*dim;
214         if (dim >= 2) {
215                 switch (midstar_color & 0x7) {
216                 case 0: send_rgb(dim, 0, 0); break;         // red
217                 case 1: send_rgb(dim, dim, dim); break;     // white
218                 case 2: send_rgb(0, dim, 0); break;         // green
219                 case 3: send_rgb(dim, 0, dim); break;       // violet
220                 case 4: send_rgb(dim, dim >> 2, 0); break;  // yellow/orange
221                 case 5: send_rgb(0, dim, dim >> 2); break;  // cyan
222                 case 6: send_rgb(0, 0, dim); break;         // blue
223                 case 7: send_rgb(dim, dim, 0); break;       // yellow
224                 }
225
226                 return 1;
227         } else {
228                 return 0;
229         }
230 }
231
232 static void background(unsigned char pos)
233 {
234 #ifdef CHRISTMAS_TREE
235         switch ((pos >> 4) & 3) {
236         case 0: if (pos & 1) send_rgb(7, 0, 0); else send_rgb(0, 7, 0);
237                 break;
238         case 1: if (pos & 1) send_rgb(0, 0, 7); else send_rgb(7, 7, 7);
239                 break;
240         case 2: if (pos & 1) send_rgb(7, 0, 7); else send_rgb(0, 7, 5);
241                 break;
242         case 3: if (pos & 1) send_rgb(7, 5, 0); else send_rgb(7, 7, 7);
243                 break;
244         }
245 #else
246         send_rgb(0, 0, 7);
247 #endif
248 }
249
250 int main(void)
251 {
252         init_log();
253         init_rng();
254         init_serial();
255
256         _delay_ms(3000/8); // wait for a bit and then increase the CPU clock
257         CLKPR = _BV(CLKPCE);
258         CLKPR = 0;
259
260         sei();
261
262 #ifdef CHRISTMAS_TREE
263         down_star_init();
264 #else
265         updown_star_init();
266 #endif
267         midstar_init();
268
269         while (1) {
270                 unsigned char i;
271
272                 ++jiffies;
273
274 #ifdef CHRISTMAS_TREE
275                 down_star_frame();
276 #else
277                 updown_star_frame();
278 #endif
279                 midstar_frame();
280                 
281                 for (i = 0; i < STRIP_SIZE; i++) {
282 #ifdef CHRISTMAS_TREE
283                         if (down_star_pixel(i)) continue;
284 #else
285                         if (updown_star_pixel(i)) continue;
286 #endif
287                         if (midstar_pixel(i)) continue;
288                         background(i);
289                 }
290                 end_frame();
291                 _delay_ms(30);
292         }
293 }