#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);
}
}