Source

Gameshow / gameshow.ino

Full commit
/** \file
 * Game show buzzer.
 *
 * two big buttons with adafruit pixel rings.
 * One small reset button.
 *
 * Attract mode.
 * When one of the big buttons is pushed, turn off all pixels in
 * the other button and just play a winning pattern.
 *
 * Since the colors are strong, use only red in the one and blue in the other.
 * Or white.
 */
#include "Adafruit_NeoPixel.h"
#include "sprite.h"


// two rings == 16 * 2 == 32 pixels
#define NUM_PIXELS 32
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, 13, NEO_GRB + NEO_KHZ800);
RGBPixel frame[NUM_PIXELS];

int pos0 = 0;
int pos1 = 16;
int mode = 0;
int cycle = 0;


void setup() {
  // port b is used for the buttons -- pull up and input on the two of them
  PORTB |= 0x7;
  DDRB |= 0x7;

  strip.begin();

  // Update the strip, to start they are all 'off'
  strip.show();
}


/** Mix one color with the other one that was there. */
static void
avg_color(
	int x,
	int r,
	int g,
	int b
)
{
	if (x < 0 || x >= NUM_PIXELS)
		return;
	RGBPixel * const p = &frame[x];

	r = (p->red*3 + r) / 4;
	g = (p->green*3 + g) / 4;
	b = (p->blue*3 + b) / 4;

	if (r < 0) r = 0; else if (r > 0xFF) r = 0xFF;
	if (g < 0) g = 0; else if (g > 0xFF) g = 0xFF;
	if (b < 0) b = 0; else if (b > 0xFF) b = 0xFF;

	p->red = r;
	p->green = g;
	p->blue = b;
}


void sparkle(int chance, int low, int num)
{
	if (random(chance) != 0)
		return;
	int x = random(num) + low;
	avg_color(x, 1000, 1000, 1000);
}


int draw_wave(int pos, int low, int num, int r, int g, int b)
{
    avg_color(pos, r, g, b);
    pos++;
    if (pos >= low + num)
	pos = low;
    return pos;
}


static void strobe(int low, int num)
{
	//sparkle(100, low, num);

	if (cycle > 0x30)
	{
		// we're done
	} else
	if ((cycle++ & 0xF) == 0)
	{
		for (int i=low; i < low + num ; i++)
			avg_color(i, 1000, 1000, 1000);
	} else
	{
		// fade out the current display
		for (int i=0; i < NUM_PIXELS ; i++)
			avg_color(i, 0, 0, 0);
	}
}


void loop() {
    const uint8_t buttons = (~PINB) & 0x7;

    // reset button always switches to mode 0
    if ((buttons & 1) != 0)
	mode = 0;

    if (mode == 0)
    {
	// fade out the current display
	for (int i=0; i < NUM_PIXELS ; i++)
		avg_color(i, 0, 0, 0);

	// attract
	pos0 = draw_wave(pos0, 0, 16, 1000, 0, 0);
	pos1 = draw_wave(pos1, 16, 16, 0, 0, 1000);
	sparkle(100, 0, NUM_PIXELS);
	cycle = 0;

	// check for a winner
	if (buttons == 0x2)
	{
		mode = 1;
	} else
	if (buttons == 0x4)
	{
		mode = 2;
	} else
	{
		// tie?
	}
    }

    if (mode == 1)
    {
	//player 1 won!
	strobe(0,16);
    } else
    if (mode == 2)
    {
	//player 2 won!
	strobe(16,16);
    }

    for (int i=0; i < NUM_PIXELS; i++)
    {
      RGBPixel * const p = &frame[i];
      strip.setPixelColor(i, p->red, p->green, p->blue);
    }

    strip.show();   // write all the pixels out
    delay(20);
}

#if 0
void rainbow(uint8_t wait) {
  int i, j;
   
  for (j=0; j < 256; j++) {     // 3 cycles of all 256 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel( (i + j) % 255));
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

// Slightly different, this one makes the rainbow wheel equally distributed 
// along the chain
void rainbowCycle(uint8_t wait) {
  int i, j;
  
  for (j=0; j < 256 * 5; j++) {     // 5 cycles of all 25 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      // tricky math! we use each pixel as a fraction of the full 96-color wheel
      // (thats the i / strip.numPixels() part)
      // Then add in j which makes the colors go around per pixel
      // the % 96 is to make the wheel cycle around
      strip.setPixelColor(i, Wheel( ((i * 256 / strip.numPixels()) + j) % 256) );
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

// fill the dots one after the other with said color
// good for testing purposes
void colorWipe(RGBPixel c, uint8_t wait) {
  int i;
  
  for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}
#endif

/* Helper functions */

// Create a 24 bit color value from R,G,B
RGBPixel Color(byte r, byte g, byte b)
{
  RGBPixel p;
  
  p.red = r;
  p.green = g;
  p.blue = b;
  
  return p;
}

//Input a value 0 to 255 to get a color value.
//The colours are a transition r - g -b - back to r
RGBPixel Wheel(byte WheelPos)
{
  if (WheelPos < 85) {
   return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
   WheelPos -= 85;
   return Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170; 
   return Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}