/* This code is in all sorts of disarray. Trust nothing. */ /* Notably, the `ws2812_*` functions are unused, I think */ /* Cider Drag Races A project to let two racers compete in drinking a glass of cider, complete with start button, weight activated drink coasters, a drag-strip "christmas tree", and buzzer. Along with a few easter eggs. Pin Assignments per Default Sketch: Digital: 2 - Right Player Display 3 - Left Player Display 4 - unused (RX for right display) 5 - unused (RX for left display) A0 - Left Pressure Simulator 8 - Right Ready Button 9 - Buzzer (+) A7 - Right Pressure Simularor 11 - Left Player Light Ring 12 - Right Player Light Ring 13 - Left Ready Button 30-39 - Colored LEDs Analog: A0 - Left Player Pressure Sensor [Digital] A7 - Right Player Pressure Sensor [Digital] A5 - Unused; Seeds RNG. Fred Damstra fred.damstra@gmail.com 2016-09-29 - Initial Draft 2025-02-09 - Revised for mouse switches and LED rings Licensed under GPLv3: https://www.gnu.org/licenses/gpl.html */ #include #include #include #include /********** CONFIGURATION SECTION */ /* Buzzer Setup: Wire ground to common ground, and positive to a PWM pin. In this example, pin 9. Lots of help for this example at https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer */ const int debug = 0; const int buzzerPin = 9; const unsigned long songFrequency = 90000; // How frequently the song may play in seconds const float songProbability = 0.0; // Probability that the song will play during that frequency /* randomPin should be an unused analog pin for seeding the RNG */ const int randomPin = A5; /* WS2812 Christmas Tree Setup: Two strips of 6 LEDs connected to 5V and Ground, plus the signal pin */ const int ledPinRight = 12; const int ledPinLeft = 11; const int brightness = 255; /* Digital (old school) Christmas Tree Setup: Two strips of 6 LEDs connected to 5V and Ground, plus the signal pin */ //const int ledPinsLeft[] = {30, 32, 34, 36, 38}; const int ledPinsRight[] = {38, 36, 34, 32, 30}; //const int ledPinsRight[] = {31, 33, 35, 37, 39}; const int ledPinsLeft[] = {39, 37, 35, 33, 31}; const unsigned long prettyLEDFrequency = 30; // How frequently something pretty happens on the LEDs const float prettyLEDProbability = 0.75; // Probability that the song will play during that frequency /* Christmas Tree */ const unsigned long startDelay = 1000; /* How long to wait between hitting the start ubtton and starting */ const unsigned long maxDelay = 5000; /* In non dragrace mode, how long might we wait *after* a guaranteed startDelay? */ const unsigned long lightDelay = 600; /* How long to wait between lights during the countdown */ const unsigned long topColor = PURPLE; /* Top LED is constant to show power */ /* 7-Segment Display Setup Two 7 OpenSegment displays from SparkFun in serial mode. */ const int leftDisplayTX = 2; const int rightDisplayTX = 3; const int leftDisplayRX = 4; /* Unused */ const int rightDisplayRX = 5; /* Unused */ /* Force Sensitive Resistor Switches (Analog inputs) */ //const int leftFSR = A7; //const int rightFSR = A0; //const int leftFSRThreshold = 10; /* > this number is closed */ //const int rightFSRThreshold = 10; const int leftFSRSimPin = A7; const int rightFSRSimPin = A0; /* Start Button */ const int leftReadyButtonPin = 13; const int rightReadyButtonPin = 8; /* Difficulty */ //const int difficultyLeftPin = 46; //const int difficultyRightPin = 47; /* Loop delays n.b. It occurs to me that unusual values for these variables /may/ upset the math on looping. Probably not, but if you run into problems, return these to original values of 100 and 25 respectively */ const int mainDelay = 100; /* How long to sleep during the main loop */ const int countdownDelay = 25; /* How long to sleep during the countdown loop */ /* Special Functions */ const int modePin = 51; /* Red */ const int buzzPin = 52; /* Green */ const int clearPin = 53; /* White */ /*********** Application Constants */ const int LED_COUNT = 24; const unsigned int buzzerFrequency = 70; const int buzzerDuration = 1800; const unsigned int beepFrequency = 3700; const int beepDuration = 100; const int beepMultiplier = 3; /* long beep is this x as long a short beep */ const unsigned long renegDelay = 500; const unsigned long debounceDelay = 250; /*********** Application Variables */ unsigned long lastSongCheck = 0; BackgroundRingClass rightRing = BackgroundRingClass(LED_COUNT, ledPinRight); BackgroundRingClass leftRing = BackgroundRingClass(LED_COUNT, ledPinLeft); SoftwareSerial leftDisplay(leftDisplayRX, leftDisplayTX); SoftwareSerial rightDisplay(rightDisplayRX, rightDisplayTX); eRCaGuy_ButtonReader leftReadyButton = eRCaGuy_ButtonReader(leftReadyButtonPin); eRCaGuy_ButtonReader rightReadyButton = eRCaGuy_ButtonReader(rightReadyButtonPin); eRCaGuy_ButtonReader leftFSRButton = eRCaGuy_ButtonReader(leftFSRSimPin, 25); eRCaGuy_ButtonReader rightFSRButton = eRCaGuy_ButtonReader(rightFSRSimPin, 25); eRCaGuy_ButtonReader clearToggle = eRCaGuy_ButtonReader(clearPin); /* Buzzer: Some constants for playing a song: */ const int songLength = 18; char notes[] = "cdfda ag cdfdg gf "; int beats[] = {1, 1, 1, 1, 1, 1, 4, 4, 2, 1, 1, 1, 1, 1, 1, 4, 4, 2}; const int tempo = 118; int songLength2 = 26; char notes2[] = "eeeeeeegcde fffffeeeeddedg"; int beats2[] = { 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2}; const int tempo2 = 130; /* LEDs */ unsigned long lastPrettyLEDCheck = 0; /* 7 Segment */ long rightClock = 0; long leftClock = 0; #define APOSTROPHE 5 #define COLON 4 #define DECIMAL4 3 #define DECIMAL3 2 #define DECIMAL2 1 #define DECIMAL1 0 /*********** Code */ void setup() { Serial.begin(115200); // Serial used for logging /* Buzzer Setup */ pinMode(buzzerPin, OUTPUT); randomSeed(analogRead(randomPin)); /* Digital LED Setup */ for(int i = 0; i < 5; i++) { pinMode(ledPinsLeft[i], OUTPUT); digitalWrite(ledPinsLeft[i], LOW); pinMode(ledPinsRight[i], OUTPUT); digitalWrite(ledPinsRight[i], LOW); } /* clearLEDs(); */ clearLEDs(); rightRing.setColor(BLACK, 255, true); leftRing.setColor(BLACK, 255, true); /* 7 Segment Displays */ leftDisplay.listen(); leftDisplay.begin(9600); leftDisplay.write('v'); leftDisplay.write(0x7A); leftDisplay.write((byte) brightness); rightDisplay.listen(); rightDisplay.begin(9600); rightDisplay.write('v'); rightDisplay.write(0x7A); rightDisplay.write((byte) brightness); longbeep(); delay(400); printClocks(1223,1996); /* Initialize our buttons */ pinMode(leftReadyButtonPin, INPUT_PULLUP); pinMode(rightReadyButtonPin, INPUT_PULLUP); pinMode(leftFSRSimPin, INPUT_PULLUP); pinMode(rightFSRSimPin, INPUT_PULLUP); //pinMode(leftFSR, INPUT_PULLUP); //pinMode(rightFSR, INPUT_PULLUP); /* And our switches */ pinMode(modePin, INPUT_PULLUP); /* Red */ pinMode(clearPin, INPUT_PULLUP); /* Green */ pinMode(buzzPin, INPUT_PULLUP); /* White */ /* And our sliders */ //pinMode(difficultyLeftPin, INPUT_PULLUP); /* HIGH is normal difficulty */ //pinMode(difficultyRightPin, INPUT_PULLUP); /* Demo the Christmas Tree */ setLEDs(BLACK, BLACK, BLACK, BLACK, YELLOW); rightRing.init_pulse_and_beep(YELLOW, 80, 400, buzzerPin, beepFrequency, beepDuration); leftRing.init_pulse_and_beep(YELLOW, 80, 400, buzzerPin, 0, beepDuration); mydelay(400); setLEDs(BLACK, BLACK, BLACK, YELLOW, BLACK); rightRing.init_pulse_and_beep(YELLOW, 80, 400, buzzerPin, beepFrequency, beepDuration); leftRing.init_pulse_and_beep(YELLOW, 80, 400, buzzerPin, 0, beepDuration); mydelay(400); setLEDs(BLACK, BLACK, YELLOW, BLACK, BLACK); rightRing.init_pulse_and_beep(YELLOW, 80, 400, buzzerPin, beepFrequency, beepDuration); leftRing.init_pulse_and_beep(YELLOW, 80, 400, buzzerPin, 0, beepDuration); mydelay(400); delay(100); setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK); //rightRing.init_pulse_and_beep(DARKGREEN, 80, 1000, buzzerPin, beepFrequency, 300); //leftRing.init_pulse_and_beep(DARKGREEN, 80, 1000, buzzerPin, 0, 300); leftRing.init_solid(DARKGREEN, 80); rightRing.init_solid(DARKGREEN, 80); longbeep(); delay(1000); setLEDs(BLACK, BLACK, BLACK, BLACK, BLACK); rightRing.init_idle(); leftRing.init_idle(); //longbeep(); /* 7 Segment Display Continued */ int special_clocks = random(0, 1000); if(special_clocks < 100) { // BOOBIES! leftClock=531; rightClock=8008; printClocks(leftClock, rightClock); } else if(special_clocks < 200) { leftClock=1223; rightClock=2025; printClocks(leftClock,rightClock); } else { leftClock=1223; rightClock=2016; printClocks(leftClock,rightClock); } //longbeep(); /* start button */ //pinMode(startButtonPin, INPUT_PULLUP); Serial.println("Setup complete."); } void mydelay(int ms) { // things we do during delays unsigned long starttime = millis(); while(millis() - starttime < ms) { rightRing.tick(); leftRing.tick(); } } /* MAIN LOOP */ void loop() { int8_t clearButtonAction; boolean clearButtonState; // put your main code here, to run repeatedly: easterEggSongCheck(); // Sometimes we play a song prettyLEDCheck(); // Sometimes we do something pretty with LEDs //prettyRingCheck(); // Sometimes we do something pretty with the RGB LEDs leftRing.tick(); rightRing.tick(); clearToggle.readButton(&clearButtonAction, &clearButtonState); if(clearButtonAction == 1) { Serial.println("clear action called"); if(random(0, 1000) < 100) { leftClock=531; rightClock=8008; printClocks(leftClock, rightClock); } else { leftClock=0; rightClock=0; printClocks(leftClock,rightClock); } } printClocks(leftClock, rightClock); shouldwebuzz(true); // blocking buzz so we don't do LED stuff /* If either coaster is open (no glass), continue through the loop */ if (leftSwitchOpen() || rightSwitchOpen()) { clearLEDs(); if(!leftSwitchOpen()) { digitalWrite(ledPinsLeft[0], HIGH); leftRing.init_solid(RED, 80); } else if(leftRing.action == Solid) { leftRing.init_idle(); } if(!rightSwitchOpen()) { digitalWrite(ledPinsRight[0], HIGH); rightRing.init_solid(RED, 80); } else if(rightRing.action == Solid) { rightRing.init_idle(); } mydelay(mainDelay); return; /* Can't continue in main loop */ } else { /* Both are closed, race can begin */ ledsToRed(); if(millis() % 5000 == 0) { Serial.println("Waiting for start button to be pressed."); } if (startButtonPressed()) { countdown(); /* We're back from a race */ /* Reset easter eggs */ lastSongCheck = lastPrettyLEDCheck = millis(); startButtonPressed(); /* Clear out "stuck" state input */ //return; /* no continue in main loop */ } } /* Rest before looping again */ mydelay(mainDelay); } void countdown(void) { unsigned long randomAdditionalDelay; int mode; /* 1 is drag race, 0 is randomness */ int cstep = -1; /* Which step of the countdown are we on? */ rightClock = leftClock = 0; if(digitalRead(modePin) == HIGH) { /* Drag race mode */ leftRing.init_solid(YELLOW, 80); rightRing.init_solid(YELLOW, 80); mode = 1; } else { /* Random delay mode */ setLEDs(RED, BLACK, BLACK, BLACK, YELLOW); leftRing.init_solid(YELLOW, 80); rightRing.init_solid(YELLOW, 80); randomAdditionalDelay = random(maxDelay); mode = 0; } if(mode) { Serial.print("Start button pressed. Beginning xmas tree in "); Serial.print(startDelay); Serial.println("ms"); } else { Serial.print("Start button pressed. Skipping xmas tree. Beginning in "); Serial.print(startDelay + randomAdditionalDelay); Serial.println("ms."); } printClocks(leftClock, rightClock); startsong(); mydelay(startDelay); unsigned long start = millis(); while (1) { rightRing.tick(); leftRing.tick(); shouldwebuzz(false); if (leftSwitchOpen_debounce(1) || rightSwitchOpen_debounce(1)) { /* FALSE START! */ if (leftSwitchOpen_debounce(1)) { Serial.println("FALSE START: Player Left"); leftRing.init_solid(RED, 80); buzz_nonblock(); leftClock = 9999; rightClock = 0; printClocks(leftClock, rightClock); for(int i = 0; i < 3; i++) { leftDisplay.listen(); leftDisplay.write(0x7A); leftDisplay.write((byte) 0); delay(150); leftDisplay.listen(); leftDisplay.write(0x7A); leftDisplay.write((byte) brightness); delay(150); } delay(buzzerDuration - 900); /* Rest for the remaining buzz */ leftSwitchOpen_debounce(1); rightSwitchOpen_debounce(1); /* Get another reading just to clear things out */ leftRing.init_pulse(RED, 80, 1000); mydelay(1000); leftRing.init_pulse(RED, 80, 1000); mydelay(1000); leftRing.init_pulse(RED, 80, 1000); return; } else if (rightSwitchOpen_debounce(1)) { Serial.println("FALSE START: Player Right"); rightRing.init_solid(RED, 80); buzz_nonblock(); rightClock = 9999; leftClock = 0; printClocks(leftClock, rightClock); for(int i = 0; i < 3; i++) { rightDisplay.listen(); rightDisplay.write(0x7A); rightDisplay.write((byte) 0); delay(150); rightDisplay.listen(); rightDisplay.write(0x7A); rightDisplay.write((byte) 255); delay(150); } delay(buzzerDuration - 900); /* Rest for the remaining buzz */ leftSwitchOpen_debounce(1); rightSwitchOpen_debounce(1); /* Get another reading just to clear things out */ rightRing.init_pulse(RED, 80, 1000); mydelay(1000); rightRing.init_pulse(RED, 80, 1000); mydelay(1000); rightRing.init_pulse(RED, 80, 1000); return; } else { /* WTF? Timing issue */ Serial.println("WARNING: False start detected, but corrected?!"); } } /* No false start */ if(mode) { /* drag race! */ switch ( (millis() - start) / lightDelay ) { case 0: if (cstep != 0) { Serial.println("Countdown ... 3"); setLEDs(RED, BLACK, BLACK, BLACK, YELLOW); rightRing.init_pulse_and_beep(YELLOW, 80, lightDelay, buzzerPin, beepFrequency, beepDuration); leftRing.init_pulse_and_beep(YELLOW, 80, lightDelay, buzzerPin, 0, beepDuration); cstep = 0; } continue; case 1: if (cstep != 1) { Serial.println("Countdown ... 2"); setLEDs(RED, BLACK, BLACK, YELLOW, BLACK); rightRing.init_pulse_and_beep(YELLOW, 80, lightDelay, buzzerPin, beepFrequency, beepDuration); leftRing.init_pulse_and_beep(YELLOW, 80, lightDelay, buzzerPin, 0, beepDuration); cstep = 1; } continue; case 2: if (cstep != 2) { Serial.println("Countdown ... 1"); setLEDs(RED, BLACK, YELLOW, BLACK, BLACK); rightRing.init_pulse_and_beep(YELLOW, 80, lightDelay, buzzerPin, beepFrequency, beepDuration); leftRing.init_pulse_and_beep(YELLOW, 80, lightDelay, buzzerPin, 0, beepDuration); cstep = 2; } continue; case 3: Serial.println("Countdown ... GO!!!!!!!!"); setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK); leftRing.init_solid(GREEN, 80); rightRing.init_solid(GREEN, 80); mydelay(lightDelay/2); longbeep(); race_loop(); return; } } else { /* Silent start */ if(millis() > (start + startDelay + randomAdditionalDelay)) { Serial.println("Random delay met... GO!!!!!!!!"); setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK); leftRing.init_solid(GREEN, 80); rightRing.init_solid(GREEN, 80); longbeep(); race_loop(); return; } } mydelay(countdownDelay); /* Make the loop less aggressive */ } Serial.println("Should never get here..."); } void race_loop(void) { /* Race is on! */ unsigned long start = millis(); Serial.print("Race is ON at "); Serial.println(start); boolean handicap_left = false; boolean handicap_right = false; unsigned long timerLeft, timerRight; timerLeft = timerRight = 0; /* determine handicap settings */ //if(digitalRead(difficultyLeftPin) == 0) { // handicap_left = true; //} //if(digitalRead(difficultyRightPin) == 0) { // handicap_right = true; //} /* Record whether the racer picked up his/her cup */ int leftStarted = 0; int rightStarted = 0; unsigned long loopstart = millis(); unsigned long lastloop = millis(); unsigned long leftRenegBounce = 0; unsigned long rightRenegBounce = 0; while (1) { loopstart = millis(); //Serial.print("Loop time with serial: "); //Serial.println(loopstart - lastloop); /* Check for winners */ boolean leftOpen, rightOpen; leftOpen = rightOpen = false; /* Choose which one to read first randomly to offset any potential bias. I * find that the loop is generally less than 1ms, so this is probably unnecessary, * but it doesn't hurt. */ if(random(0, 2)) { // Serial.print("Left first. Time = "); // Serial.println(millis()); leftOpen = leftSwitchOpen(); rightOpen = rightSwitchOpen(); } else { // Serial.print("Right first. Time = "); // Serial.println(millis()); rightOpen = rightSwitchOpen(); leftOpen = leftSwitchOpen(); } /* Check for finishers */ if (!leftOpen && leftStarted && !timerLeft) { /* Finished */ Serial.print("Left player finished at "); Serial.println(millis() - start); timerLeft = (millis() - start) / 10; //if(handicap_left) { // /* Handicapped player */ // timerLeft = timerLeft - (timerLeft >> 2); //} leftRing.init_solid(ORANGE, 80); beep_nonblock(); } else if (leftOpen && !leftStarted) { Serial.print("Left cup lifted at "); Serial.println(millis() - start); leftStarted = 1; leftRing.init_solid(YELLOW, 80); } if (!rightOpen && rightStarted && !timerRight) { /* Finished */ Serial.print("Right player finished at "); Serial.println(millis() - start); timerRight = (millis() - start) / 10; //if(handicap_right) { // /* Handicapped player */ // timerRight = timerRight - (timerRight >> 2); //} rightRing.init_solid(ORANGE, 80); beep_nonblock(); } else if (rightOpen && !rightStarted) { Serial.print("Right cup lifted at "); Serial.println(millis() - start); rightStarted = 1; rightRing.init_solid(YELLOW, 80); } /* Check for renegers * Note to cheaters: too hard a hit can make the opponent's cup bounce. * However, we can't turn this off, because things bounce on removal. */ if (leftSwitchOpen() && timerLeft) { /* Bullshit! */ if(leftRenegBounce == 0) { leftRenegBounce = millis(); } else if((millis() - leftRenegBounce) > renegDelay) { Serial.println("Left player RENEGS! This is bullshit!"); timerLeft = 0; leftRenegBounce = 0; } else { Serial.print("Left reneg on delay: "); Serial.println(millis() - leftRenegBounce); } } if (rightSwitchOpen() && timerRight) { /* Bullshit! */ if(rightRenegBounce == 0) { rightRenegBounce = millis(); } else if((millis() - rightRenegBounce) > renegDelay) { Serial.println("Right player RENEGS! This is bullshit!"); timerRight = 0; rightRenegBounce = 0; } else { Serial.print("Right reneg on delay: "); Serial.println(millis() - rightRenegBounce); } } /* If still a winner and not a reneger, I think we have a winner */ if (timerLeft) { leftClock = timerLeft; } else { leftClock = (millis() - start) / 10; //if(handicap_left) { // /* Handicapped player */ // leftClock = leftClock - (leftClock >> 2); //} } if (timerRight) { rightClock = timerRight; } else { rightClock = (millis() - start) / 10; //if(handicap_right) { // /* Handicapped player */ // rightClock = rightClock - (rightClock >> 2); //} } /* Print the clocks */ printClocks(leftClock, rightClock); if (timerRight && timerLeft) { /* Race is finished */ ledsToRed(); if(timerRight < timerLeft) { Serial.println("Right player WINS!"); rightRing.init_solid(GREEN, 80); leftRing.init_solid(RED, 80); for(int i = 0; i < 3; i++) { rightDisplay.listen(); rightDisplay.write(0x7A); rightDisplay.write((byte) 0); delay(150); beep(); rightDisplay.listen(); rightDisplay.write(0x7A); rightDisplay.write((byte) 255); delay(150); } } else if(timerLeft < timerRight) { leftRing.init_solid(GREEN, 80); rightRing.init_solid(RED, 80); for(int i = 0; i < 3; i++) { leftDisplay.listen(); leftDisplay.write(0x7A); leftDisplay.write((byte) 0); delay(150); beep(); leftDisplay.listen(); leftDisplay.write(0x7A); leftDisplay.write((byte) 255); delay(150); } Serial.println("Left player WINS!"); } else { Serial.println("TIE GAME!!!"); } playWinner(); /* Wait until start buttons are no longer pressed */ while(startButtonPressed()) { mydelay(100); } return; } lastloop = loopstart; } Serial.println("ERROR: Woah. Just Woah. How the fuck? 0x73184fcgukl"); } /* Beep and buzz if those toggles are pressed */ void shouldwebuzz(bool block) { if(digitalRead(buzzPin) == LOW) { if(block) { buzz(); } else { buzz_nonblock(); } } } /* Start button switch */ int startButtonPressed() { int8_t leftButtonAction, rightButtonAction; boolean leftButtonState, rightButtonState; leftReadyButton.readButton(&leftButtonAction, &leftButtonState); rightReadyButton.readButton(&rightButtonAction, &rightButtonState); if(leftButtonState == false && rightButtonState == false) { Serial.println("Both ready buttons pressed."); return 1; } else { /* Serial.print("Left state: "); Serial.println(leftButtonState); Serial.print("Right state: "); Serial.println(rightButtonState); */ return 0; } } /* FSR Functions */ int leftSwitchOpen() { return leftSwitchOpen_debounce(0); } int leftSwitchOpen_debounce(int silent) { return leftSwitchOpen(silent); // Temporarily just ignoring everything /* Not a standard debounce method. We're going to keep the last 16 values * and majority rules. */ static int results[16] = {0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0}; static int pointer = 0; results[pointer] = leftSwitchOpen(silent); pointer = (pointer + 1) % 16; int sum = 0; // Serial.print("Left array: ["); for(int i = 0; i < 16; i++) { sum+=results[i]; // Serial.print(results[i]); // Serial.print(","); } if(sum > 8) { // Serial.println("]; Returning 1"); return 1; } else { // Serial.println("]; Returning 0"); return 0; } } int leftSwitchOpen(int silent) { int8_t leftButtonAction; boolean leftButtonState; static int lastvalue = 0; leftFSRButton.readButton(&leftButtonAction, &leftButtonState); if(leftButtonState == false) { /* Button is low, meaning it's pressed */ return 0; } return 1; } int rightSwitchOpen() { return rightSwitchOpen_debounce(0); } int rightSwitchOpen_debounce(int silent) { return rightSwitchOpen(silent); /* Not a standard debounce method. We're going to keep the last 16 values * and majority rules. */ // we are ignoring all this static int results[16] = {0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0}; static int pointer = 0; results[pointer] = rightSwitchOpen(silent); pointer = (pointer + 1) % 16; int sum = 0; // Serial.print("Right array: ["); for(int i = 0; i < 16; i++) { sum+=results[i]; // Serial.print(results[i]); // Serial.print(","); } if(sum > 8) { // Serial.println("]; Returning 1"); return 1; } else { // Serial.println("]; Returning 0"); return 0; } } int rightSwitchOpen(int silent) { int8_t rightButtonAction; boolean rightButtonState; static int lastvalue = 0; rightFSRButton.readButton(&rightButtonAction, &rightButtonState); if(rightButtonState == false) { /*Button is low, meaning it's pressed */ return 0; } return 1; } int switchOpen(int pin, int threshold, int silent) { int fsrADC = analogRead(pin); #ifdef SIMULATION fsrADC = random(0, 1000); #endif if (fsrADC < threshold) { if (!silent) { Serial.print(fsrADC); Serial.println(" -- OPEN"); } return 1; } if (!silent) { Serial.print(fsrADC); Serial.println(" -- CLOSED"); } return 0; } /* 7-Segment Functions */ void printClocks(unsigned long leftValue, unsigned long rightValue) { if (leftValue > 9999) { leftValue = 9999; } if (rightValue > 9999) { rightValue = 9999; } // Serial.print("Clocks: "); char tempstring[10]; snprintf(tempstring, sizeof(tempstring), "%04lu", leftValue); leftDisplay.listen(); leftDisplay.write(tempstring); // Serial.print(tempstring); snprintf(tempstring, sizeof(tempstring), "%04lu", rightValue); rightDisplay.listen(); rightDisplay.write(tempstring); // Serial.print(" "); // Serial.println(tempstring); /* TUrn on decimal point */ leftDisplay.listen(); leftDisplay.write(0x77); /* Decimal, colon, and apostrophe command */ leftDisplay.write(0b000010); /* Decimal 2 is second bit) */ rightDisplay.listen(); rightDisplay.write(0x77); /* Decimal, colon, and apostrophe command */ rightDisplay.write(0b000010); /* Decimal 2 is second bit) */ } /* LED Functions */ void ledsToRed() { leftRing.init_solid(RED, 80); rightRing.init_solid(RED, 80); digitalWrite(ledPinsLeft[0], HIGH); digitalWrite(ledPinsRight[0], HIGH); for(int i=1; i<5; i++) { digitalWrite(ledPinsLeft[i], LOW); digitalWrite(ledPinsRight[i], LOW); } } // Sets red light on. //void ws2812_ledsToRed() { // clearLEDs(); // rightRing.setPixelColor(0, RED); // leftRing.setPixelColor(0, RED); // rightRing.show(); // leftRing.show(); //} /* Clears all LEDs (for WS2812, except the top one) */ void clearLEDs() { for(int i = 0; i < 5; i++) { digitalWrite(ledPinsLeft[i], LOW); digitalWrite(ledPinsRight[i], LOW); } } void ws2812_clearLEDs() { //ring_setColor(rightRing, WHITE); //ring_setColor(leftRing, WHITE); } void setLEDs(unsigned long redlight, unsigned long greenlight, unsigned long yellow3, unsigned long yellow2, unsigned long yellow1) { //ws2812_setLEDs(redlight, greenlight, yellow3, yellow2, yellow1); /* If black, turn it off, otherwise turn it on */ if(redlight == BLACK) { digitalWrite(ledPinsLeft[0], LOW); digitalWrite(ledPinsRight[0], LOW); } else { digitalWrite(ledPinsLeft[0], HIGH); digitalWrite(ledPinsRight[0], HIGH); } /* If black, turn it off, otherwise turn it on */ if(greenlight == BLACK) { digitalWrite(ledPinsLeft[1], LOW); digitalWrite(ledPinsRight[1], LOW); } else { digitalWrite(ledPinsLeft[1], HIGH); digitalWrite(ledPinsRight[1], HIGH); } /* If black, turn it off, otherwise turn it on */ if(yellow3 == BLACK) { digitalWrite(ledPinsLeft[2], LOW); digitalWrite(ledPinsRight[2], LOW); } else { digitalWrite(ledPinsLeft[2], HIGH); digitalWrite(ledPinsRight[2], HIGH); } /* If black, turn it off, otherwise turn it on */ if(yellow2 == BLACK) { digitalWrite(ledPinsLeft[3], LOW); digitalWrite(ledPinsRight[3], LOW); } else { digitalWrite(ledPinsLeft[3], HIGH); digitalWrite(ledPinsRight[3], HIGH); } /* If black, turn it off, otherwise turn it on */ if(yellow1 == BLACK) { digitalWrite(ledPinsLeft[4], LOW); digitalWrite(ledPinsRight[4], LOW); } else { digitalWrite(ledPinsLeft[4], HIGH); digitalWrite(ledPinsRight[4], HIGH); } } void red_green_pulse() { // pulses one coaster red and the other green. leftRing.setBrightness(1); rightRing.setBrightness(1); if(random(0, 2)) { leftring_setColor(RED); } else { leftring_setColor(GREEN); } if(random(0, 2)) { rightring_setColor(RED); } else { rightring_setColor(GREEN); } for(int pulses=0; pulses < 3; pulses++) { Serial.println("Pulsing up."); for(int brightness=1; brightness <= 255; brightness++) { rightRing.setBrightness(brightness); leftRing.setBrightness(brightness); rightRing.show(); leftRing.show(); delay(1); } Serial.println("Pulsing down."); for(int brightness=255; brightness >= 1; brightness--) { rightRing.setBrightness(brightness); leftRing.setBrightness(brightness); rightRing.show(); leftRing.show(); delay(1); } } leftRing.setBrightness(255); rightRing.setBrightness(255); clearLEDs(); } void rings_setColor(unsigned long color) { for(uint8_t i=0; i< LED_COUNT; i++) { rightRing.setPixelColor(i, color); leftRing.setPixelColor(i, color); } rightRing.show(); leftRing.show(); } void leftring_setColor(unsigned long color) { for(uint8_t i=0; i< LED_COUNT; i++) { leftRing.setPixelColor(i, color); } leftRing.show(); } void rightring_setColor(unsigned long color) { for(uint8_t i=0; i< LED_COUNT; i++) { rightRing.setPixelColor(i, color); } rightRing.show(); } void ws2812_setLEDs(unsigned long redlight, unsigned long greenlight, unsigned long yellow3, unsigned long yellow2, unsigned long yellow1) { rightRing.setPixelColor(0, redlight); rightRing.setPixelColor(1, greenlight); rightRing.setPixelColor(2, yellow3); rightRing.setPixelColor(3, yellow2); rightRing.setPixelColor(4, yellow1); rightRing.setPixelColor(LED_COUNT, topColor); leftRing.setPixelColor(0, redlight); leftRing.setPixelColor(1, greenlight); leftRing.setPixelColor(2, yellow3); leftRing.setPixelColor(3, yellow2); leftRing.setPixelColor(4, yellow1); leftRing.setPixelColor(LED_COUNT, topColor); rightRing.show(); leftRing.show(); } void prettyLEDCheck() { /* Lets see if we should do pretty things with the regular LEDs */ if ( (millis() - lastPrettyLEDCheck) > (prettyLEDFrequency * 1000) ) { lastPrettyLEDCheck = millis(); if ( (random(0, 1000) < long(prettyLEDProbability * 1000.0)) ) { Serial.println("Pretty LED Approved"); prettyLED(); } else { Serial.println("Pretty lED probability check declined."); } } } void prettyLED() { if(random(0, 2) == 0) { // use the classic LEDs if(random(0, 1000) < 500) { prettyCircleLED(); prettyCircleLED(); // prettyCircleLED(); } else { prettyBounceLED(); prettyBounceLED(); prettyBounceLED(); } } else { // Use the RGB LEDs if(random(0, 10) != 0) { // 90% chance that both rings do the same thing int draw = leftRing.random_event(); rightRing.random_event(draw); } else { leftRing.random_event(); rightRing.random_event(); } } } void prettyCircleLED() { clearLEDs(); for(int i = 4; i >= 0; i--) { shouldwebuzz(true); Serial.print("Pin: "); Serial.println(i); digitalWrite(ledPinsLeft[i], HIGH); delay(100); digitalWrite(ledPinsLeft[i], LOW); } for(int i = 0; i < 5; i++) { shouldwebuzz(true); Serial.print("Pin: "); Serial.println(i); digitalWrite(ledPinsRight[i], HIGH); delay(100); digitalWrite(ledPinsRight[i], LOW); } } void prettyBounceLED() { clearLEDs(); for(int i = 4; i >= 0; i--) { shouldwebuzz(true); digitalWrite(ledPinsLeft[i], HIGH); digitalWrite(ledPinsRight[i], HIGH); delay(100); digitalWrite(ledPinsLeft[i], LOW); digitalWrite(ledPinsRight[i], LOW); } for(int i = 1; i < 5; i++) { shouldwebuzz(true); digitalWrite(ledPinsLeft[i], HIGH); digitalWrite(ledPinsRight[i], HIGH); delay(100); digitalWrite(ledPinsLeft[i], LOW); digitalWrite(ledPinsRight[i], LOW); } } void prettyRingCheck() { // this doesn't work static unsigned long last_random_check = millis(); if(leftRing.action == Idle && rightRing.action == Idle) { if(millis() - last_random_check > 1000) { // only check every 10 seconds if(random(0, 20) == 0) { // do we do anything? if(random(0, 10) != 0) { // 90% chance that both rings do the same thing int draw = leftRing.random_event(); rightRing.random_event(draw); } else { leftRing.random_event(); rightRing.random_event(); } } } last_random_check = millis(); } } void ws2812_prettyLED() { /* Do something interesting */ /* cylon(YELLOW, 500); */ } // Implements a little larson "cylon" sanner. // This'll run one full cycle, down one way and back the other void ws2812_cylon(unsigned long color, unsigned long wait) { Serial.println("Cylons are attacking."); // weight determines how much lighter the outer "eye" colors are const byte weight = 4; // It'll be easier to decrement each of these colors individually // so we'll split them out of the 24-bit color value byte red = (color & 0xFF0000) >> 16; byte green = (color & 0x00FF00) >> 8; byte blue = (color & 0x0000FF); // Start at closest LED, and move to the outside for (int i = 0; i < LED_COUNT; i++) { clearLEDs(); rightRing.setPixelColor(i, red, green, blue); // Set the bright middle eye leftRing.setPixelColor(i, red, green, blue); // Set the bright middle eye // Now set two eyes to each side to get progressively dimmer for (int j = 1; j < 3; j++) { if (i - j >= 0) leftRing.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j)); rightRing.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j)); if (i - j < LED_COUNT) leftRing.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j)); rightRing.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j)); } leftRing.show(); // Turn the LEDs on rightRing.show(); // Turn the LEDs on delay(wait); // Delay for visibility } // Now we go back to where we came. Do the same thing. for (int i = LED_COUNT - 2; i >= 1; i--) { clearLEDs(); leftRing.setPixelColor(i, red, green, blue); rightRing.setPixelColor(i, red, green, blue); for (int j = 1; j < 3; j++) { if (i - j >= 0) leftRing.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j)); rightRing.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j)); if (i - j < LED_COUNT) leftRing.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j)); rightRing.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j)); } leftRing.show(); rightRing.show(); delay(wait); } } /* Song Easter Egg */ void easterEggSongCheck() { /* Lets see if we should play a song */ if ( (millis() - lastSongCheck) > (songFrequency * 1000) ) { lastSongCheck = millis(); if ( (random(0, 1000) < long(songProbability * 1000.0)) ) { Serial.println("Song probability check approved. Never give up!"); playsong(); } else { Serial.println("Song probability check declined."); } } } int frequency(char note) { // This function takes a note character (a-g), and returns the // corresponding frequency in Hz for the tone() function. int i; const int numNotes = 8; // number of notes we're storing // The following arrays hold the note characters and their // corresponding frequencies. The last "C" note is uppercase // to separate it from the first lowercase "c". If you want to // add more notes, you'll need to use unique characters. // For the "char" (character) type, we put single characters // in single quotes. char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' }; int frequencies[] = {262, 294, 330, 349, 392, 440, 494, 523}; // Now we'll search through the letters in the array, and if // we find it, we'll return the frequency for that note. for (i = 0; i < numNotes; i++) // Step through the notes { if (names[i] == note) // Is this the one? { return (frequencies[i]); // Yes! Return the frequency } } return (0); // We looked through everything and didn't find it, // but we still need to return a value, so return 0. } void playWinner() { /* TODO: Ideally, this is "Enjoy MonkeyBOX", but anything will do */ /* Also, ideally won't block */ if(random(0, 10) == 0) { playsong2(); } else { playsong(); } Serial.println("Insert winner music here."); } void startsong() { /* TODO: Make this something fancier */ beep(); delay(200); beep(); delay(200); beep(); delay(200); } void buzz() { /* play a loud, annoying buzz */ Serial.println("*BUZZ*"); tone(buzzerPin, buzzerFrequency, buzzerDuration); delay(buzzerDuration); } void buzz_nonblock() { /* play a loud, annoying buzz */ Serial.println("*BUZZ*"); tone(buzzerPin, buzzerFrequency, buzzerDuration); } void beep() { /* play a simple, pleasant beep */ Serial.println("*beep*"); tone(buzzerPin, beepFrequency, beepDuration); delay(beepDuration); } void beep_nonblock() { /* play a simple, pleasant beep, but don't wait for it to finish */ Serial.println("*beep* (but don't wait for it)"); tone(buzzerPin, beepFrequency, beepDuration); } void longbeep() { /* play a simple, pleasant beep */ Serial.println("*beeeeeeeeeeeeeeeeeeeeeeeeeep*"); tone(buzzerPin, beepFrequency, beepDuration * beepMultiplier); /* longbeep doesn't delay. Maybe that's inconsistent */ /* delay(beepDuration * beepMultiplier); */ } void playsong() { /* Plays a song. Cut directly from the SparkFun tutorial at https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer */ int i, duration; for (i = 0; i < songLength; i++) // step through the song arrays { duration = beats[i] * tempo; // length of note/rest in ms if (notes[i] == ' ') // is this a rest? { delay(duration); // then pause for a moment } else // otherwise, play the note { tone(buzzerPin, frequency(notes[i]), duration); delay(duration); // wait for tone to finish } delay(tempo / 10); // brief pause between notes } } void playsong2() { /* Plays a song. Cut directly from the SparkFun tutorial at https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer */ int i, duration; for (i = 0; i < songLength2; i++) // step through the song arrays { duration = beats2[i] * tempo2; // length of note/rest in ms if (notes2[i] == ' ') // is this a rest? { delay(duration); // then pause for a moment } else // otherwise, play the note { tone(buzzerPin, frequency(notes2[i]), duration); delay(duration); // wait for tone to finish } delay(tempo2 / 10); // brief pause between notes } } /* Ring Functions */ void ring_setColor(Adafruit_NeoPixel& ring, unsigned long color) { for(int i=0; i < LED_COUNT; i++) { ring.setPixelColor(i, color); } ring.show(); }