From 5013d75921e37f1df3034f0d2ed39ddecb718d67 Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Mon, 23 Dec 2013 22:27:07 +0100 Subject: [PATCH] rgb-led-string: christmas tree mode --- projects/rgb-led-string/main.c | 328 ++++++++++++++++++++++++++------- 1 file changed, 266 insertions(+), 62 deletions(-) diff --git a/projects/rgb-led-string/main.c b/projects/rgb-led-string/main.c index dc96861..bd92361 100644 --- a/projects/rgb-led-string/main.c +++ b/projects/rgb-led-string/main.c @@ -4,86 +4,290 @@ #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); } } -- 2.39.3