Skip to content

Instantly share code, notes, and snippets.

@mpflaga
Last active July 2, 2018 17:42
Show Gist options
  • Save mpflaga/fe91612db2ed75d21489b2e17c08b387 to your computer and use it in GitHub Desktop.
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
/*
* 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()
@mellerbeck
Copy link

Excellent!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment