Last active
July 2, 2018 17:42
-
-
Save mpflaga/fe91612db2ed75d21489b2e17c08b387 to your computer and use it in GitHub Desktop.
IrMagicWandDuelNeoPixel- code for home made Magic Wand Kiosk receiver, using a Arduino with NeoPixels. It is an upgrade to TinyIRduel.ino
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* IrMagicWandDuelNeoPixel: IRrecvDump - dump details of IR codes with IRrecv | |
* https://gist.github.com/mpflaga/fe91612db2ed75d21489b2e17c08b387 | |
* IR detector/demodulator must be connected to the input RECV_PIN. | |
* IR Transmitter to JAM must be connected | |
* schematic https://drive.google.com/open?id=1Sr9TtA06r71xR5ZPSr_fqb461YxncRx6 | |
* Version 0.1 July, 2016 | |
* Author: 2016 Michael P. Flaga | |
* This is an alternative to the TinyIRduel.ino | |
*/ | |
#define LENGTH_OF_ARRAY(x) ((sizeof(x)/sizeof(x[0]))) | |
#include <avr/wdt.h> | |
#include <IRremote.h> // https://github.com/mpflaga/Arduino-IRremote.git | |
// This fork support MagiQuest Wand decoding. | |
// define pin locations | |
#define NEOPIXEL_PIN 6 | |
#define NEOPIXEL_LENGTH 24 | |
#define SHUTDOWNn_PIN 15 | |
#define BUZZER_PIN 9 | |
#define LED_PIN 13 // nothing there. | |
int LED_TX_PIN = 5; | |
int RECV_PIN = 2; | |
IRrecv irrecv(RECV_PIN); | |
decode_results results; | |
#include <Adafruit_NeoPixel.h> | |
#ifdef __AVR__ | |
#include <avr/power.h> | |
#endif | |
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NEOPIXEL_LENGTH, NEOPIXEL_PIN, NEO_RGB + NEO_KHZ400); | |
#include <EEPROM.h> | |
#define CONFIG_START 32 | |
#define CONFIG_VERSION "ls1" | |
//#define api_url_maxlen 40 | |
//#define api_fname_maxlen 40 | |
//#define token_id_maxlen 40 | |
typedef struct StoreStruct_t{ | |
uint8_t mute; | |
uint8_t team; | |
int32_t wandWinner; | |
int32_t wandLooser; | |
char version_of_program[4]; // it is the last variable of the | |
} StoreStruct_t; | |
StoreStruct_t EEPROM_configuration = {0}; | |
// intial state | |
uint32_t WandPreviousMillis = 0; | |
uint32_t WandIdleTimeOut = 1800000; | |
uint32_t idleBlinkPreviousMillis = 0; | |
uint32_t idleBlinkIdleTimeOut = 1000; | |
uint32_t currentMillis; | |
static const uint8_t twinkleColors[][3] PROGMEM = { | |
{255,255,255}, //White | |
{255,000,000}, //Red | |
{000,255,000}, //Green | |
{000,000,255}, //Blue | |
{255,255,000}, //Yellow | |
{126,255,000}, //LightGreen | |
{244,011,146}, //Magenta | |
{122,040,005}, //Brown | |
{181,074,143} //Purple | |
}; | |
void setup() { | |
// MCUSR = 0; // clear out any flags of prior resets. | |
// Continue to hold Power on. | |
pinMode(SHUTDOWNn_PIN, OUTPUT); | |
digitalWrite(SHUTDOWNn_PIN, HIGH); | |
pinMode(LED_PIN, OUTPUT); | |
digitalWrite(LED_PIN, HIGH); | |
// init the Serial Port for Debug | |
Serial.begin(115200); | |
// don't want for stand-a-lone operation, but good for serial debuging. | |
#if defined(__AVR_ATmega32U4__) | |
// while (!Serial); | |
#endif | |
Serial.println("starting..."); | |
loadConfig(); | |
// init the NeoPixel Strip | |
strip.begin(); | |
strip.show(); // Initialize all pixels to 'off' | |
// init the Buzzer. | |
pinMode(BUZZER_PIN, OUTPUT); | |
digitalWrite(BUZZER_PIN, LOW); | |
// Initial Boot Test Pattern of NeoPixels. | |
testRGB(); | |
// turn off the NeoPixel Strip | |
colorWipe(strip.Color(0, 0, 0), 25); // Off | |
// init the IR Reciever. | |
irrecv.enableIRIn(); // Start the receiver | |
randomSeed(analogRead(5)); | |
WandPreviousMillis = millis(); | |
// Get Stored Configuration | |
Serial.println("Initial State:"); | |
dumpInfo(); | |
beep(2, 125); | |
Serial.println("Main Loop is starting..."); | |
} // end setup() | |
void loop() { | |
currentMillis = millis(); | |
// Check for and decode and IR signals | |
if (irrecv.decode(&results)) { | |
dump(&results); | |
irrecv.resume(); // Receive the next value | |
} | |
// Blink the center NeoPixel and LED indicating it is ON | |
if ((currentMillis - idleBlinkPreviousMillis) > idleBlinkIdleTimeOut) { | |
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // toggle LED | |
Serial.print("."); // print idle | |
if (EEPROM_configuration.mute) { | |
strip.setPixelColor(0 ,Color(0, 0, (digitalRead(LED_PIN) ? (255/8) : 0))); | |
} | |
else { | |
strip.setPixelColor(0 ,Color(0, (digitalRead(LED_PIN) ? (255/8) : 0), 0)); | |
} | |
strip.show(); | |
idleBlinkPreviousMillis = currentMillis; | |
} | |
// Idle Power Off | |
if (digitalRead(SHUTDOWNn_PIN) == HIGH) { | |
if ((currentMillis - WandPreviousMillis) > WandIdleTimeOut) { | |
Serial.println("No Activity Time Out."); | |
beep(2,125); | |
digitalWrite(SHUTDOWNn_PIN, LOW); | |
// Good night. | |
} | |
} | |
if(Serial.available()) { | |
parse_menu(Serial.read()); // get command from serial input | |
} | |
} // loop() | |
void parse_menu(byte key_command) { | |
if(key_command == 'm') { | |
Serial.println(F("Mutting")); | |
toggleMute(); | |
} else if(key_command == '1') { | |
Serial.println(F("Player 1")); | |
setTeam(1); | |
} else if(key_command == '2') { | |
Serial.println(F("Player 2")); | |
setTeam(2); | |
} else if(key_command == 't') { | |
Serial.println(F("Test Pattern")); | |
testRGB(); | |
} else if(key_command == 'u') { | |
Serial.println(F("Unknown Pattern")); | |
unknown(); | |
} else if(key_command == 'l') { | |
Serial.println(F("Learning Mode")); | |
learnNewWands(&results); | |
} else if(key_command == 'i') { | |
Serial.println(F("Dump Information Status")); | |
dumpInfo(); | |
} else if(key_command == 'r') { | |
Serial.println(F("Resetting")); | |
wdt_enable(WDTO_120MS); // turn on the WatchDog and don't stroke it. | |
for(;;) { | |
// do nothing and wait for the eventual... | |
} | |
} | |
} | |
void dumpInfo() { | |
Serial.print("Strand Length = "); Serial.println(NEOPIXEL_LENGTH); | |
Serial.print("WandPreviousMillis = "); Serial.println(WandPreviousMillis); | |
Serial.print("WandIdleTimeOut = "); Serial.println(WandIdleTimeOut); | |
Serial.print("idleBlinkPreviousMillis = "); Serial.println(idleBlinkPreviousMillis); | |
Serial.print("idleBlinkIdleTimeOut = "); Serial.println(idleBlinkIdleTimeOut); | |
Serial.println("EEPROM Configuration:"); | |
Serial.print("MUTE = "); Serial.println(EEPROM_configuration.mute); | |
Serial.print("team = "); Serial.println(EEPROM_configuration.team); | |
Serial.print("wandWinner = 0x"); Serial.println(EEPROM_configuration.wandWinner, HEX); | |
Serial.print("wandLooser = 0x"); Serial.println(EEPROM_configuration.wandLooser, HEX); | |
Serial.print("version_of_program = "); Serial.println(EEPROM_configuration.version_of_program); | |
} | |
void learnNewWands(decode_results *results) { | |
uint32_t timeOut = 10000; | |
uint8_t r = pgm_read_byte_near ( &(twinkleColors[2][0]) ); | |
uint8_t g = pgm_read_byte_near ( &(twinkleColors[2][1]) ); | |
uint8_t b = pgm_read_byte_near ( &(twinkleColors[2][2]) ); | |
colorWipe(strip.Color(r, g, b), 25); // Red | |
irrecv.resume(); // Receive the next value | |
Serial.println("Waiting for New Winning Wand;"); | |
uint32_t endTime = millis() + timeOut; | |
while ((int32_t)(millis() - endTime) <= 0) { | |
if (irrecv.decode(results)) { | |
if (results->decode_type == MAGIQUEST) { | |
EEPROM_configuration.wandWinner = results->value; | |
Serial.print("Learned - wand_id=0x"); | |
Serial.println(EEPROM_configuration.wandWinner, HEX); | |
saveConfig(); | |
loadConfig(); | |
Serial.print("EE Read Back - wand_id=0x"); | |
Serial.println(EEPROM_configuration.wandWinner, HEX); | |
irrecv.resume(); // Receive the next value | |
break; | |
} | |
irrecv.resume(); // Receive the next value | |
} | |
} | |
if ((int32_t)(millis() - endTime) > 0) { | |
Serial.println("Timed Out"); | |
} | |
else { | |
Serial.println("Waiting for New Loosing Wand;"); | |
uint8_t r = pgm_read_byte_near ( &(twinkleColors[1][0]) ); | |
uint8_t g = pgm_read_byte_near ( &(twinkleColors[1][1]) ); | |
uint8_t b = pgm_read_byte_near ( &(twinkleColors[1][2]) ); | |
colorWipe(strip.Color(r, g, b), 25); // Red | |
uint32_t endTime = millis() + timeOut; | |
while ((int32_t)(millis() - endTime) <= 0) { | |
if (irrecv.decode(results)) { | |
if (results->decode_type == MAGIQUEST) { | |
EEPROM_configuration.wandLooser = results->value; | |
Serial.print("Learned - wand_id=0x"); | |
Serial.println(EEPROM_configuration.wandLooser, HEX); | |
saveConfig(); | |
loadConfig(); | |
Serial.print("EE Read Back - wand_id=0x"); | |
Serial.println(EEPROM_configuration.wandLooser, HEX); | |
irrecv.resume(); // Receive the next value | |
break; | |
} | |
irrecv.resume(); // Receive the next value | |
} | |
} | |
if ((int32_t)(millis() - endTime) > 0) { | |
Serial.println("Timed Out"); | |
} | |
else { | |
uint8_t r = pgm_read_byte_near ( &(twinkleColors[0][0]) ); | |
uint8_t g = pgm_read_byte_near ( &(twinkleColors[0][1]) ); | |
uint8_t b = pgm_read_byte_near ( &(twinkleColors[0][2]) ); | |
colorWipe(strip.Color(r, g, b), 25); // Red | |
} | |
} | |
colorWipe(strip.Color(0, 0, 0), 25); // Red | |
Serial.println("Ended waiting for New Wand;"); | |
} | |
void dump(decode_results *results) { | |
if (results->decode_type == MAGIQUEST) { | |
Serial.println(); | |
Serial.print("Decoded MAGIQUEST - Magnitude="); | |
Serial.print(results->magiquestMagnitude, HEX); | |
Serial.print(", wand_id=0x"); | |
Serial.print(results->value, HEX); | |
if (EEPROM_configuration.wandWinner == results->value) { | |
winner(); | |
} | |
else if (EEPROM_configuration.wandLooser == results->value) { | |
looser(); | |
} | |
else { | |
unknown(); | |
} | |
WandPreviousMillis = currentMillis; | |
} | |
else if (results->decode_type == MITSUBISHI) { | |
Serial.print("Decoded MITSUBISHI: 0x"); | |
Serial.print(results->value, HEX); | |
switch (results->value) { | |
case 0xE240: | |
Serial.println(" PWR"); | |
strip.setPixelColor(0 ,Color(255, 0, 0)); | |
strip.show(); | |
beep(2,125); | |
//delay(1000); | |
digitalWrite(SHUTDOWNn_PIN, !digitalRead(SHUTDOWNn_PIN)); | |
Serial.print("SHUTDOWNn_PIN="); | |
Serial.println(digitalRead(SHUTDOWNn_PIN)); | |
break; | |
case 0xE24C: | |
parse_menu("m"); | |
break; | |
case 0xE25C: | |
Serial.println(" AVTV"); | |
parse_menu("t"); | |
break; | |
case 0xE248: | |
Serial.println(" CH UP"); | |
break; | |
case 0xE250: | |
Serial.println(" CH DWN"); | |
break; | |
case 0xE254: | |
Serial.println(" LEFT"); | |
parse_menu("1"); | |
break; | |
case 0xE244: | |
Serial.println(" RIGHT"); | |
parse_menu("2"); | |
break; | |
default: | |
Serial.println(" UNKNOWN"); | |
break; | |
} | |
if (!EEPROM_configuration.mute) { | |
digitalWrite(BUZZER_PIN, HIGH); | |
delay(250); | |
digitalWrite(BUZZER_PIN, LOW); | |
} | |
} | |
WandPreviousMillis = currentMillis; | |
} // end dump() | |
void setTeam(uint8_t team) { | |
Serial.println(); | |
Serial.print("Team="); | |
Serial.println(EEPROM_configuration.team); | |
EEPROM_configuration.team = team; | |
saveConfig(); | |
loadConfig(); | |
Serial.print("Team="); | |
Serial.println(EEPROM_configuration.team); | |
colorWipe(strip.Color(0, 0, 255), 0); // Blue | |
delay(1000); | |
colorWipe(strip.Color(0, 0, 0), 0); // Off | |
blinkTeam(); | |
} | |
void testRGB() { | |
Serial.println(); | |
for(int test=0; test < LENGTH_OF_ARRAY(twinkleColors); test++) { | |
uint8_t r = pgm_read_byte_near ( &(twinkleColors[test][0]) ); | |
uint8_t g = pgm_read_byte_near ( &(twinkleColors[test][1]) ); | |
uint8_t b = pgm_read_byte_near ( &(twinkleColors[test][2]) ); | |
colorWipe(strip.Color(r, g, b), 10); // Red | |
Serial.print("Twinkle["); | |
Serial.print(test, DEC); | |
Serial.print("]=("); | |
Serial.print(r, DEC); | |
Serial.print(","); | |
Serial.print(g, DEC); | |
Serial.print(","); | |
Serial.print(b, DEC); | |
Serial.println(")"); | |
} | |
colorWipe(strip.Color(0, 0, 0), 25); // Off | |
} | |
void toggleMute() { | |
Serial.print(" MUTE="); | |
Serial.println(EEPROM_configuration.mute); | |
if (!EEPROM_configuration.mute) { | |
Serial.println(" Mute ON"); | |
EEPROM_configuration.mute = 1; | |
colorWipe(strip.Color(225, 0, 0), 15); // Red | |
} | |
else { | |
Serial.println(" Mute OFF"); | |
EEPROM_configuration.mute = 0; | |
colorWipe(strip.Color( 0,225, 0), 15); // Green | |
} | |
delay(250); | |
colorWipe(strip.Color( 0, 0, 0), 0); // Off | |
saveConfig(); | |
loadConfig(); | |
Serial.print("mute="); | |
Serial.println(EEPROM_configuration.mute); | |
beep(2, 125); | |
} | |
//// Wand Helpers | |
void winner() { | |
Serial.println(" Winner Wand"); | |
tone(LED_TX_PIN, 39000); | |
if (!EEPROM_configuration.mute) { | |
digitalWrite(BUZZER_PIN, HIGH); | |
} | |
for (int loops = 0; loops < 20; loops++) { | |
Serial.print(" pixelColor="); | |
for(int led=0; led < NEOPIXEL_LENGTH; led++) { | |
uint8_t pixelColor = random(1, LENGTH_OF_ARRAY(twinkleColors) - 1); | |
Serial.print(","); | |
Serial.print(pixelColor, DEC); | |
uint8_t r = pgm_read_byte_near ( &(twinkleColors[pixelColor][0]) ); | |
uint8_t g = pgm_read_byte_near ( &(twinkleColors[pixelColor][1]) ); | |
uint8_t b = pgm_read_byte_near ( &(twinkleColors[pixelColor][2]) ); | |
strip.setPixelColor(led,Color(r, g, b)); | |
} | |
strip.show(); | |
Serial.println(); | |
delay(100); | |
} | |
colorWipe(strip.Color(0, 0, 0), 0); // Off | |
noTone(LED_TX_PIN); | |
if (!EEPROM_configuration.mute) { | |
digitalWrite(BUZZER_PIN, LOW); | |
} | |
} // end winner() | |
void looser() { | |
Serial.println(" Looser Wand"); // Really just a Touch-Back | |
for (int loops = 0; loops < 5; loops++) { | |
colorWipe(strip.Color(255, 0, 0), 0); // Red | |
delay(100); | |
colorWipe(strip.Color( 0, 0, 0), 0); // Off | |
} | |
} // end looser() | |
void unknown() { | |
Serial.println("Uknown Wand"); | |
colorWipe(strip.Color( 0, 0, 0), 0); // Off | |
// Display a Question Mark | |
uint8_t r = pgm_read_byte_near ( &(twinkleColors[0][0]) ); | |
uint8_t g = pgm_read_byte_near ( &(twinkleColors[0][1]) ); | |
uint8_t b = pgm_read_byte_near ( &(twinkleColors[0][2]) ); | |
strip.setPixelColor( 3, r, g, b); | |
strip.setPixelColor( 9, r, g, b); | |
strip.setPixelColor(11, r, g, b); | |
strip.setPixelColor(15, r, g, b); | |
strip.setPixelColor(16, r, g, b); | |
strip.setPixelColor(17, r, g, b); | |
strip.setPixelColor(17, r, g, b); | |
// period is different color | |
r = pgm_read_byte_near ( &(twinkleColors[8][0]) ); | |
g = pgm_read_byte_near ( &(twinkleColors[8][1]) ); | |
b = pgm_read_byte_near ( &(twinkleColors[8][2]) ); | |
strip.setPixelColor(21, r, g, b); | |
strip.show(); | |
delay(1000); | |
colorWipe(strip.Color( 0, 0, 0), 0); // Off | |
} // end unknown() | |
//// NeoPixel Helpers | |
// Create a 24 bit color value from R,G,B | |
uint32_t Color(byte r, byte g, byte b) | |
{ | |
uint32_t c; | |
c = r; | |
c <<= 8; | |
c |= g; | |
c <<= 8; | |
c |= b; | |
return c; | |
} // end color() | |
// Fill the dots one after the other with a color | |
void colorWipe(uint32_t c, uint8_t wait) { | |
for(uint16_t i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, c); | |
strip.show(); | |
delay(wait); | |
} | |
} // end colorWipe() | |
void rainbow(uint8_t wait) { | |
uint16_t i, j; | |
for(j=0; j<256; j++) { | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, Wheel((i+j) & 255)); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
} // end rainbow() | |
// Slightly different, this makes the rainbow equally distributed throughout | |
void rainbowCycle(uint8_t wait) { | |
uint16_t i, j; | |
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel | |
for(i=0; i< strip.numPixels(); i++) { | |
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
} // end rainbowCycle() | |
//Theatre-style crawling lights. | |
void theaterChase(uint32_t c, uint8_t wait) { | |
for (int j=0; j<10; j++) { //do 10 cycles of chasing | |
for (int q=0; q < 3; q++) { | |
for (int i=0; i < strip.numPixels(); i=i+3) { | |
strip.setPixelColor(i+q, c); //turn every third pixel on | |
} | |
strip.show(); | |
delay(wait); | |
for (int i=0; i < strip.numPixels(); i=i+3) { | |
strip.setPixelColor(i+q, 0); //turn every third pixel off | |
} | |
} | |
} | |
} // end theaterChase() | |
//Theatre-style crawling lights with rainbow effect | |
void theaterChaseRainbow(uint8_t wait) { | |
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel | |
for (int q=0; q < 3; q++) { | |
for (int i=0; i < strip.numPixels(); i=i+3) { | |
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on | |
} | |
strip.show(); | |
delay(wait); | |
for (int i=0; i < strip.numPixels(); i=i+3) { | |
strip.setPixelColor(i+q, 0); //turn every third pixel off | |
} | |
} | |
} | |
} // end theaterChaseRainbow() | |
// Input a value 0 to 255 to get a color value. | |
// The colours are a transition r - g - b - back to r. | |
uint32_t Wheel(byte WheelPos) { | |
WheelPos = 255 - WheelPos; | |
if(WheelPos < 85) { | |
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); | |
} | |
if(WheelPos < 170) { | |
WheelPos -= 85; | |
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); | |
} | |
WheelPos -= 170; | |
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | |
} // end Wheel() | |
void blinkTeam() { | |
strip.setPixelColor((NEOPIXEL_LENGTH - EEPROM_configuration.team - 1) ,Color(255, 0, 0)); | |
strip.show(); | |
delay(1000); | |
strip.setPixelColor((NEOPIXEL_LENGTH - EEPROM_configuration.team - 1) ,Color( 0, 0, 0)); | |
} | |
void beep(int count, int wait) | |
{ | |
if (!EEPROM_configuration.mute) { | |
for (int j=0; j<count; j++) { | |
digitalWrite(BUZZER_PIN, HIGH); | |
delay(wait); | |
digitalWrite(BUZZER_PIN, LOW); | |
delay(wait); | |
} | |
} | |
} // end beep() | |
void loadConfig() { | |
// To make sure there are EEPROM_configuration, and they are YOURS! | |
// If nothing is found it will use the default EEPROM_configuration. | |
if ( //EEPROM.read(CONFIG_START + sizeof(EEPROM_configuration) - 1) == EEPROM_configuration.version_of_program[3] // this is '\0' | |
EEPROM.read(CONFIG_START + sizeof(EEPROM_configuration) - 2) == EEPROM_configuration.version_of_program[2] && | |
EEPROM.read(CONFIG_START + sizeof(EEPROM_configuration) - 3) == EEPROM_configuration.version_of_program[1] && | |
EEPROM.read(CONFIG_START + sizeof(EEPROM_configuration) - 4) == EEPROM_configuration.version_of_program[0]) { // reads EEPROM_configuration from EEPROM | |
Serial.println("EEPROM being loaded."); | |
for (unsigned int t=0; t<sizeof(EEPROM_configuration); t++) | |
*((char*)&EEPROM_configuration + t) = EEPROM.read(CONFIG_START + t); | |
} else { | |
// EEPROM_configuration aren't valid! will overwrite with default EEPROM_configuration | |
Serial.println("EEPROM being defaulted."); | |
saveConfig(); | |
} | |
} // end loadConfig() | |
void saveConfig() { | |
Serial.println("EEPROM being saved."); | |
for (unsigned int t=0; t<sizeof(EEPROM_configuration); t++) | |
{ // writes to EEPROM | |
EEPROM.write(CONFIG_START + t, *((char*)&EEPROM_configuration + t)); | |
// and verifies the data | |
if (EEPROM.read(CONFIG_START + t) != *((char*)&EEPROM_configuration + t)) { | |
// error writing to EEPROM | |
} | |
} | |
} // end saveConfig() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Excellent!