]> www.fi.muni.cz Git - tinyboard.git/blob - projects/rgb-led-light/main.c
rgb-lights: new slow-changing mode
[tinyboard.git] / projects / rgb-led-light / main.c
1 #include <avr/io.h>
2 #include <util/delay.h>
3 #include <avr/interrupt.h>
4
5 #include "rgbstring.h"
6
7 // #define CHRISTMAS_TREE 1
8
9 #define rgb_return(r, g, b)     do { send_rgb((r), (g), (b)); return 1; } while(0)
10
11 #define VERT_SIZE 47
12
13 /* RNG from ADC noise */
14 static unsigned char rand_pool[8], rand_pool_off, prev_bit, rand_pool_out;
15
16 static void init_rng()
17 {
18         ADCSRA |= _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1); // enable, clk/64
19         ADMUX = _BV(REFS1) | _BV(MUX0) | _BV(MUX3); // 1.1V, PB5:PB5, gain 20
20         DIDR0 = _BV(ADC0D);
21         ADCSRA |= _BV(ADIE) | _BV(ADSC);
22         rand_pool_off = 0;
23         prev_bit = 0;
24 }
25
26 static unsigned char rand() {
27         unsigned char rv = 0;
28
29         rv = rand_pool[rand_pool_out];
30         rand_pool_out++;
31         if (rand_pool_out >= sizeof(rand_pool))
32                 rand_pool_out = 0;
33
34         return rv;
35 }
36
37 ISR(ADC_vect) {
38         ADCSRA |= _BV(ADSC);
39         if ((rand_pool_off & 1) == 0) { // first bit of the pair
40                 prev_bit = ADCW & 1;
41                 rand_pool_off++;
42         } else {
43                 unsigned char bit = ADCW & 1;
44                 if (bit == prev_bit) { // whitening fail: try again
45                         rand_pool_off--;
46                         return;
47                 }
48
49                 if (bit) {
50                         rand_pool[rand_pool_off >> 4]
51                                 ^= 1 << ((rand_pool_off >> 1) & 7);
52                 }
53
54                 rand_pool_off++;
55                 if (rand_pool_off >= 16*sizeof(rand_pool))
56                         rand_pool_off = 0;
57         }
58 }
59
60 static unsigned int slow_dim[] = {
61         255, 27, 7, 2,
62 };
63
64 static void fill_color(unsigned char r, unsigned char g, unsigned char b)
65 {
66         unsigned char i;
67
68         for (i = 0; i < STRIP_SIZE; i++)
69                 send_rgb(r, g, b);
70
71         end_frame();
72 }
73
74 unsigned int state;
75
76 static void do_buttons()
77 {
78         static uint8_t prev_buttons = _BV(PB0) | _BV(PB3) | _BV(PB4);
79         static uint16_t prev_len = 0;
80
81         uint8_t buttons = PINB & (_BV(PB0) | _BV(PB3) | _BV(PB4));
82
83         if (prev_buttons == buttons) {
84                 prev_len++;
85                 return;
86         }
87
88         // was change
89         if (prev_len < 3 || (buttons != (_BV(PB0) | _BV(PB3) | _BV(PB4)))) {
90                 prev_buttons = buttons;
91                 prev_len = 0;
92                 return;
93         }
94
95         if ((prev_buttons & _BV(PB0)) == 0) {
96                 if (state)
97                         state--;
98         } else if ((prev_buttons & _BV(PB3)) == 0) {
99                 if (state < 5)
100                         state++;
101         } else if ((prev_buttons & _BV(PB4)) == 0) {
102                 state = 1;
103         }
104
105         prev_buttons = buttons;
106         prev_len = 0;
107 }
108
109 #define LED_MAX (2*STRIP_SIZE/5)
110 #define N_COLORS 8
111 #define R_BIAS(x)       ((x) << 3)
112 #define G_BIAS(x)       ((x) >> 1)
113 #define B_BIAS(x)       ((x) << 1)
114
115 static void do_hue()
116 {
117         static unsigned char color, led_off;
118         static uint16_t jiffies;
119         unsigned char i, c0, l0;
120
121         if ((jiffies++ & 0x03f) == 0) {
122                 if (++led_off >= LED_MAX) {
123                         led_off = 0;
124                         color++;
125                         if (color >= 3*N_COLORS)
126                                 color = 0;
127                 }
128         }
129
130         l0 = led_off;
131         c0 = color;
132
133         for (i = 0; i < STRIP_SIZE; i++) {
134                 if (c0 < N_COLORS) {
135                         send_rgb(R_BIAS(N_COLORS-c0), G_BIAS(c0), 0);
136                 } else if (c0 < 2*N_COLORS) {
137                         send_rgb(0, G_BIAS(2*N_COLORS-c0), B_BIAS(c0-N_COLORS));
138                 } else {
139                         send_rgb(R_BIAS(c0-2*N_COLORS), 0, B_BIAS(3*N_COLORS-c0));
140                 }
141
142                 if (++l0 >= LED_MAX) {
143                         l0 = 0;
144                         c0++;
145                         if (c0 >= 3*N_COLORS)
146                                 c0 = 0;
147                 }
148         }
149         end_frame();
150 }
151
152 int main(void)
153 {
154
155         init_log();
156         init_rng();
157         init_serial();
158
159         _delay_ms(3000/8); // wait for a bit and then increase the CPU clock
160         CLKPR = _BV(CLKPCE);
161         CLKPR = 0;
162
163         PORTB |= _BV(PB0) | _BV(PB3) | _BV(PB4); // pull-ups for buttons
164
165         state = 2;
166
167         sei();
168
169         while (1) {
170                 unsigned char i;
171
172                 do_buttons();
173
174                 switch (state) {
175                 case 0:
176                         zero_frame();
177                         break;
178                 case 1:
179                         i = 0;
180                         while (i < STRIP_SIZE) {
181                                 send_rgb(4, 0, 0);
182                                 send_rgb(4, 1, 0);
183                                 send_rgb(0, 2, 0);
184                                 send_rgb(0, 1, 1);
185                                 send_rgb(0, 0, 2);
186                                 send_rgb(4, 0, 2);
187                                 i += 6;
188                         }
189                         end_frame();
190                         break;
191                 case 2:
192                         do_hue();
193                         break;
194                 case 3:
195                         fill_color(16, 4, 8);
196                         break;
197                 case 4:
198                         fill_color(96, 64, 64);
199                         break;
200                 case 5:
201                         fill_color(255, 255, 255);
202                         break;
203                 default:
204                         { unsigned char light;
205
206                         light = slow_dim[sizeof(slow_dim)/sizeof(slow_dim[0]) - state];
207                         fill_color(4*light, light, 2*light);
208                         }
209                         break;
210                 }
211         }
212 }
213