#include #include #include #include "rgbstring.h" static unsigned char jiffies; // #define CHRISTMAS_TREE 1 #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) { init_log(); init_rng(); init_serial(); _delay_ms(3000/8); // wait for a bit and then increase the CPU clock CLKPR = _BV(CLKPCE); CLKPR = 0; sei(); #ifdef CHRISTMAS_TREE down_star_init(); #else updown_star_init(); #endif midstar_init(); while (1) { unsigned char i; ++jiffies; #ifdef CHRISTMAS_TREE down_star_frame(); #else updown_star_frame(); #endif midstar_frame(); for (i = 0; i < STRIP_SIZE; i++) { #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(30); } }