rgb-led-string: christmas tree mode
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Mon, 23 Dec 2013 21:27:07 +0000 (22:27 +0100)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Mon, 23 Dec 2013 21:27:38 +0000 (22:27 +0100)
projects/rgb-led-string/main.c

index dc96861..bd92361 100644 (file)
 
 #include "rgbstring.h"
 
-unsigned char jiffies;
+static unsigned char jiffies;
 
-typedef struct {
-       unsigned char type : 4;
-       unsigned char order : 4;
-} pixel_t;
+// #define CHRISTMAS_TREE 1
 
-pixel_t pixels[STRIP_SIZE];
+#define rgb_return(r, g, b)    do { send_rgb((r), (g), (b)); return 1; } while(0)
 
+#define VERT_SIZE 47
+
+/* RNG from ADC noise */
+static unsigned char rand_pool[8], rand_pool_off, prev_bit, rand_pool_out;
+
+static void init_rng()
+{
+       ADCSRA |= _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1); // enable, clk/64
+       ADMUX = _BV(REFS1) | _BV(MUX0) | _BV(MUX3); // 1.1V, PB5:PB5, gain 20
+       DIDR0 = _BV(ADC0D);
+       ADCSRA |= _BV(ADIE) | _BV(ADSC);
+       rand_pool_off = 0;
+       prev_bit = 0;
+}
+
+static unsigned char rand() {
+       unsigned char rv = 0;
+
+       rv = rand_pool[rand_pool_out];
+       rand_pool_out++;
+       if (rand_pool_out >= sizeof(rand_pool))
+               rand_pool_out = 0;
+
+       return rv;
+}
+
+ISR(ADC_vect) {
+       ADCSRA |= _BV(ADSC);
+       if ((rand_pool_off & 1) == 0) { // first bit of the pair
+               prev_bit = ADCW & 1;
+               rand_pool_off++;
+       } else {
+               unsigned char bit = ADCW & 1;
+               if (bit == prev_bit) { // whitening fail: try again
+                       rand_pool_off--;
+                       return;
+               }
+
+               if (bit) {
+                       rand_pool[rand_pool_off >> 4]
+                               ^= 1 << ((rand_pool_off >> 1) & 7);
+               }
+
+               rand_pool_off++;
+               if (rand_pool_off >= 16*sizeof(rand_pool))
+                       rand_pool_off = 0;
+       }
+}
+
+/* up and down running stars at the beginning/end of the strip */
+static unsigned char updown_star, updown_star0, updown_down, updown_bright;
+
+static void updown_star_init()
+{
+       updown_star0 = 0;
+       updown_down = 1;
+}
+
+static void updown_star_frame()
+{
+       if (updown_star0 == 0) {
+               updown_star0 = STRIP_SIZE-VERT_SIZE-8;
+               updown_down = 0;
+       } else if (updown_star0 == STRIP_SIZE + 8) {
+               updown_star0 = VERT_SIZE+7;
+               updown_down = 1;
+       } else if (updown_star0 <= VERT_SIZE + 8) {
+               updown_star0--;
+       } else if (updown_star0 >= STRIP_SIZE-VERT_SIZE-8) {
+               updown_star0++;
+       }
+
+       if (updown_down && updown_star0 < 8) {
+               updown_star = 0;
+               updown_bright = 1 << updown_star0;
+       } else if (updown_down) {
+               updown_star = updown_star0 - 8;
+               updown_bright = 128;
+       } else if (updown_star0 < STRIP_SIZE-VERT_SIZE) {
+               updown_star = STRIP_SIZE-VERT_SIZE;
+               updown_bright = 1 << (STRIP_SIZE-VERT_SIZE-updown_star0);
+       } else {
+               updown_star = updown_star0;
+               updown_bright = 1;
+       }
+}
+
+static unsigned char updown_star_pixel(unsigned char pos)
+{
+       if (pos >= VERT_SIZE && pos < STRIP_SIZE-VERT_SIZE)
+               return 0;
+
+       if (pos == updown_star) {
+               send_rgb(updown_bright, updown_bright, updown_bright);
+               if (updown_down) {
+                       updown_bright >>= 1;
+                       if (updown_bright)
+                               updown_star++;
+               } else {
+                       updown_bright <<= 1;
+                       if (updown_bright)
+                               updown_star++;
+               }
+               return 1;
+       }
+
+       return 0;
+}
+
+/* down running stars at the beginning/end of the strip */
+static unsigned char down_star, down_star0, down_bright;
+
+static void down_star_init()
+{
+       down_star0 = STRIP_SIZE;
+}
+
+static void down_star_frame()
+{
+       if (down_star0 == 0) {
+               down_star0 = STRIP_SIZE;
+       } else {
+               down_star0--;
+       }
+
+       if (down_star0 < 8) {
+               down_star = 0;
+               down_bright = 1 << down_star0;
+       } else {
+               down_star = down_star0;
+               down_bright = 128;
+       }
+}
+
+static unsigned char down_star_pixel(unsigned char pos)
+{
+       if (pos == down_star) {
+               send_rgb(down_bright, down_bright, down_bright);
+               down_bright >>= 1;
+               if (down_bright)
+                       down_star++;
+               return 1;
+       }
+
+       return 0;
+}
+
+/* middle stars */
+
+static unsigned char midstar_pos0, midstar_pos, midstar_bright, midstar_color;
+
+static void midstar_init()
+{
+       midstar_pos0 = STRIP_SIZE/2;
+       midstar_color = 0;
+}
+
+static unsigned int slow_dim[] = {
+       255, 182, 130, 92, 66, 47, 33, 24, 17, 12, 8, 6, 4, 3, 2, 1,
+};
+
+static void midstar_frame()
+{
+       unsigned char phase = (jiffies) & 0x1F;
+
+       midstar_bright = phase & 0x10 ? slow_dim[phase & 0x0F]
+               : slow_dim[15-(phase & 0x0F)];
+
+       if (!phase) {
+               unsigned char c = rand();
+#ifdef CHRISTMAS_TREE
+               midstar_pos0 = 2 + (c % (STRIP_SIZE - 4));
+#else
+               midstar_pos0 -= 2 + VERT_SIZE;
+               midstar_pos0 += 16 + (c & 0x1F);
+               midstar_pos0 &= 0x3F;
+               midstar_pos0 += 2 + VERT_SIZE;
+#endif
+               midstar_color += 1 + (c & 0xC0 ? 0 : 1);
+       }
+
+       midstar_pos = midstar_pos0 - 2;
+}
+
+static unsigned char midstar_pixel(unsigned char pos)
+{
+       unsigned char dim;
+
+       if (pos != midstar_pos)
+               return 0;
+
+       if (pos > midstar_pos0) {
+               dim = pos - midstar_pos0;
+               if (dim < 2)
+                       midstar_pos++;
+       } else {
+               dim = midstar_pos0 - pos;
+               midstar_pos++;
+       }
+
+       dim = midstar_bright >> 2*dim;
+       if (dim >= 2) {
+               switch (midstar_color & 0x7) {
+               case 0: send_rgb(dim, 0, 0); break;         // red
+               case 1: send_rgb(dim, dim, dim); break;     // white
+               case 2: send_rgb(0, dim, 0); break;         // green
+               case 3: send_rgb(dim, 0, dim); break;       // violet
+               case 4: send_rgb(dim, dim >> 2, 0); break;  // yellow/orange
+               case 5: send_rgb(0, dim, dim >> 2); break;  // cyan
+               case 6: send_rgb(0, 0, dim); break;         // blue
+               case 7: send_rgb(dim, dim, 0); break;       // yellow
+               }
+
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+static void background(unsigned char pos)
+{
+#ifdef CHRISTMAS_TREE
+       switch ((pos >> 4) & 3) {
+       case 0: if (pos & 1) send_rgb(7, 0, 0); else send_rgb(0, 7, 0);
+               break;
+       case 1: if (pos & 1) send_rgb(0, 0, 7); else send_rgb(7, 7, 7);
+               break;
+       case 2: if (pos & 1) send_rgb(7, 0, 7); else send_rgb(0, 7, 5);
+               break;
+       case 3: if (pos & 1) send_rgb(7, 5, 0); else send_rgb(7, 7, 7);
+               break;
+       }
+#else
+       send_rgb(0, 0, 7);
+#endif
+}
 
 int main(void)
 {
-       unsigned char i, start, rgb, jiffies;
        init_log();
+       init_rng();
        init_serial();
 
-       _delay_ms(3000/8);
+       _delay_ms(3000/8); // wait for a bit and then increase the CPU clock
        CLKPR = _BV(CLKPCE);
        CLKPR = 0;
 
-       for (i = 0; i < STRIP_SIZE; i+= 23)
-               pixels[i].type = 2;
+       sei();
 
-       while (1) {
-               jiffies++;
-               if ((jiffies & 7) == 0) {
-                       pixels[start].type = 1;
-                       pixels[start].order = 14;
-               }
+#ifdef CHRISTMAS_TREE
+       down_star_init();
+#else
+       updown_star_init();
+#endif
+       midstar_init();
 
-               if ((jiffies & 7) == 3) {
-                       pixels[start].type = 2;
-                       pixels[start].order = 0;
-                       start += 19;
-               }
+       while (1) {
+               unsigned char i;
 
-               start += 63;
-               if (start >= STRIP_SIZE)
-                       start -= STRIP_SIZE;
+               ++jiffies;
 
+#ifdef CHRISTMAS_TREE
+               down_star_frame();
+#else
+               updown_star_frame();
+#endif
+               midstar_frame();
+               
                for (i = 0; i < STRIP_SIZE; i++) {
-                       unsigned char type = pixels[i].type;
-                       unsigned char order = pixels[i].order;
-
-                       switch (type) {
-                       case 0:
-                               send_rgb(0, 0, 4);
-                               break;
-                       case 1:
-                       case 3:
-                               send_rgb(
-                                       6+(1 << (order/2)),
-                                       6+(1 << (order/2)),
-                                       6+(1 << (order/2))
-                               );
-                               pixels[i].type = type == 3 ? 2 : 0;;
-                               if (order > 1 && i) {
-                                       pixels[i-1].type = pixels[i-1].type == 2 ? 3 : 1;
-                                       pixels[i-1].order = order-1;
-                               }
-                               break;
-                       case 2:
-                               if (order >= 8) {
-                                       send_rgb(1 << ((15-order) / 2), 0, 0);
-                               } else {
-                                       send_rgb(1 << (order/2), 0, 0);
-                               }
-                               if (++order >= 15)
-                                       pixels[i].type = 0;
-                               pixels[i].order = order;
-                               break;
-                       }
+#ifdef CHRISTMAS_TREE
+                       if (down_star_pixel(i)) continue;
+#else
+                       if (updown_star_pixel(i)) continue;
+#endif
+                       if (midstar_pixel(i)) continue;
+                       background(i);
                }
-
                end_frame();
-
-               _delay_ms(50);
-#if 0
-               log_byte(0xFa);
-               log_flush();
-#endif
+               _delay_ms(30);
        }
 }