12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241 |
- /*
- 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 - Left Player Display
- 3 - Right Player Display
- 4 - unused (RX for left display)
- 5 - unused (RX for right display)
- 13 - Left Ready Button
- 7 - Left Pressure Simulator
- 8 - Right Ready Button
- 9 - Buzzer (+)
- 10 - Right Pressure Simularor
- 11 - Left Player Light Tree (6 lights) (If WS2812B)
- 12 - Right Player Light Tree (6 lights)(If WS2812B)
- 30-39 - Colored LEDs
- Analog:
- 0 - Right Player Pressure Sensor
- 1 - Left Player Pressure Sensor
- 7 - Unused; Seeds RNG.
- Fred Damstra
- fred.damstra@gmail.com
- 2016-09-29 - Initial Draft
- Licensed under GPLv3: https://www.gnu.org/licenses/gpl.html
- */
- #include <SoftwareSerial.h>
- #include "Adafruit_NeoPixel.h"
- #include "WS2812_Definitions.h"
- #include <eRCaGuy_ButtonReader.h>
- /**********
- 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 = 5;
- /* 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 ledPinsLeft[] = {38, 36, 34, 32, 30};
- //const int ledPinsRight[] = {31, 33, 35, 37, 39};
- const int ledPinsRight[] = {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 = 500; /* 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 = 7; /* For when the FSRs aren't there */
- const int rightFSRSimPin = 10; /* For when the FSRs aren't there */
- /* 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 = 6;
- 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;
- Adafruit_NeoPixel rightTree = Adafruit_NeoPixel(LED_COUNT, ledPinRight, NEO_GRB + NEO_KHZ800);
- Adafruit_NeoPixel leftTree = Adafruit_NeoPixel(LED_COUNT, ledPinLeft, NEO_GRB + NEO_KHZ800);
- 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);
- eRCaGuy_ButtonReader rightFSRButton = eRCaGuy_ButtonReader(rightFSRSimPin);
- 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(9600); // Serial used for logging
- /* Buzzer Setup */
- pinMode(buzzerPin, OUTPUT);
- randomSeed(analogRead(randomPin));
- /* WS2812 LED Setup */
- rightTree.begin();
- leftTree.begin();
- /* 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();
- /* 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();
- 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);
- pinMode(rightFSR, INPUT);
- /* 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);
- longbeep(); delay(400);
- setLEDs(BLACK, BLACK, BLACK, YELLOW, BLACK);
- longbeep(); delay(400);
- setLEDs(BLACK, BLACK, YELLOW, BLACK, BLACK);
- longbeep(); delay(400);
- setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK);
- longbeep(); delay(400);
- setLEDs(RED, BLACK, BLACK, BLACK, BLACK);
- longbeep();
-
- /* Arbitrary delay before updating the 7-segments again */
- delay(1000);
-
- /* 7 Segment Display Continued */
- if(random(0, 1000) < 100) {
- leftClock=531;
- rightClock=8008;
- printClocks(leftClock, rightClock);
- } else {
- leftClock=1223;
- rightClock=2016;
- printClocks(leftClock,rightClock);
- }
- longbeep();
- /* Switches */
- pinMode(leftFSR, INPUT);
- pinMode(rightFSR, INPUT);
- /* start button */
- //pinMode(startButtonPin, INPUT_PULLUP);
- Serial.println("Setup complete.");
- }
- /* MAIN LOOP */
- void loop() {
- int8_t clearButtonAction;
- boolean clearButtonState;
- // put your main code here, to run repeatedly:
- easterEggSongCheck(); // Sometimes we play a song
- prettyLEDCheck();
- 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();
-
- /* If either coaster is open (no glass), continue on */
- if (leftSwitchOpen() || rightSwitchOpen()) {
- clearLEDs();
- if(!leftSwitchOpen()) {
- digitalWrite(ledPinsLeft[0], HIGH);
- } else if(!rightSwitchOpen()) {
- digitalWrite(ledPinsRight[0], HIGH);
- }
- delay(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 */
- delay(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 */
- mode = 1;
- } else {
- /* Random delay mode */
- setLEDs(RED, BLACK, BLACK, BLACK, YELLOW);
- 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();
- delay(startDelay);
- unsigned long start = millis();
- while (1) {
- shouldwebuzz();
-
- if (leftSwitchOpen_debounce(1) || rightSwitchOpen_debounce(1)) {
- /* FALSE START! */
- if (leftSwitchOpen_debounce(1)) {
- Serial.println("FALSE START: Player Left");
- 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 */
- return;
- } else if (rightSwitchOpen_debounce(1)) {
- Serial.println("FALSE START: Player Right");
- 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 */
- 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);
- beep();
- cstep = 0;
- }
- continue;
- case 1:
- if (cstep != 1) {
- Serial.println("Countdown ... 2");
- setLEDs(RED, BLACK, BLACK, YELLOW, BLACK);
- beep();
- cstep = 1;
- }
- continue;
- case 2:
- if (cstep != 2) {
- Serial.println("Countdown ... 1");
- setLEDs(RED, BLACK, YELLOW, BLACK, BLACK);
- beep();
- cstep = 2;
- }
- continue;
- case 3:
- Serial.println("Countdown ... GO!!!!!!!!");
- setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK);
- longbeep();
- race_loop();
- return;
- }
- } else {
- /* Silent start */
- if(millis() > (start + startDelay + randomAdditionalDelay)) {
- Serial.println("Random delay met... GO!!!!!!!!");
- setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK);
- longbeep();
- race_loop();
- return;
- }
- }
- delay(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);
- }
- beep_nonblock();
- } else if (leftOpen && !leftStarted) {
- Serial.print("Left cup lifted at ");
- Serial.println(millis() - start);
- leftStarted = 1;
- }
- 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);
- }
- beep_nonblock();
- } else if (rightOpen && !rightStarted) {
- Serial.print("Right cup lifted at ");
- Serial.println(millis() - start);
- rightStarted = 1;
- }
- /* 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!");
- 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) {
- 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()) {
- delay(100);
- }
- return;
- }
- lastloop = loopstart;
- }
- Serial.println("ERROR: Woah. Just Woah. How the fuck? 0x73184fcgukl");
- }
- /* Beep and buzz if those toggles are pressed */
- void shouldwebuzz() {
- if(digitalRead(buzzPin) == LOW) {
- 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) {
- /* 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;
- /* Sim Mode:
- leftFSRButton.readButton(&leftButtonAction, &leftButtonState);
- if(leftButtonState == false) { */
- /* Button is low, meaning it's pressed */
- /* return 0;
- }
- return 1;
- */
- int value = analogRead(leftFSR);
- if( value > leftFSRThreshold) {
- /* Pressed! */
- if(lastvalue < leftFSRThreshold) {
- Serial.print("Left pressed, pressure: ");
- Serial.println(value);
- }
- lastvalue = value;
- return 0;
- }
- if(lastvalue > leftFSRThreshold) {
- Serial.print("Left released, pressure: ");
- Serial.println(value);
- lastvalue = value;
- }
- return 1;
- }
- int rightSwitchOpen() {
- return rightSwitchOpen_debounce(0);
- }
- int rightSwitchOpen_debounce(int silent) {
- /* 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] = 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 value = analogRead(rightFSR);
- if( value > rightFSRThreshold) {
- /* Pressed! */
- if(lastvalue < rightFSRThreshold) {
- Serial.print("Right pressed, pressure: ");
- Serial.println(value);
- }
- lastvalue = value;
- return 0;
- }
- if(lastvalue > rightFSRThreshold) {
- Serial.print("Right released, pressure: ");
- Serial.println(value);
- lastvalue = value;
- }
- 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() {
- ws2812_ledsToRed();
- 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();
- rightTree.setPixelColor(0, RED);
- leftTree.setPixelColor(0, RED);
- rightTree.show();
- leftTree.show();
- }
- /* Clears all LEDs (for WS2812, except the top one) */
- void clearLEDs() {
- ws2812_clearLEDs();
- for(int i = 0; i < 5; i++) {
- digitalWrite(ledPinsLeft[i], LOW);
- digitalWrite(ledPinsRight[i], LOW);
- }
- }
- void ws2812_clearLEDs()
- {
- for (int i = 0; i < (LED_COUNT - 1); i++)
- {
- rightTree.setPixelColor(i, 0);
- leftTree.setPixelColor(i, 0);
- }
- rightTree.setPixelColor(LED_COUNT - 1, topColor);
- leftTree.setPixelColor(LED_COUNT - 1, topColor);
- rightTree.show();
- leftTree.show();
- }
- 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 ws2812_setLEDs(unsigned long redlight,
- unsigned long greenlight,
- unsigned long yellow3,
- unsigned long yellow2,
- unsigned long yellow1) {
- rightTree.setPixelColor(0, redlight);
- rightTree.setPixelColor(1, greenlight);
- rightTree.setPixelColor(2, yellow3);
- rightTree.setPixelColor(3, yellow2);
- rightTree.setPixelColor(4, yellow1);
- rightTree.setPixelColor(LED_COUNT - 1, topColor);
- leftTree.setPixelColor(0, redlight);
- leftTree.setPixelColor(1, greenlight);
- leftTree.setPixelColor(2, yellow3);
- leftTree.setPixelColor(3, yellow2);
- leftTree.setPixelColor(4, yellow1);
- leftTree.setPixelColor(LED_COUNT - 1, topColor);
- rightTree.show();
- leftTree.show();
- }
- void prettyLEDCheck() {
- /* Lets see if we should play a song */
- 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 using the ws2812's, you may want to turn this back on
- ws2812_prettyLED();
- */
- if(random(0, 1000) < 500) {
- prettyCircleLED();
- prettyCircleLED();
- // prettyCircleLED();
- } else {
- prettyBounceLED();
- prettyBounceLED();
- prettyBounceLED();
- }
- }
- void prettyCircleLED() {
- clearLEDs();
- for(int i = 4; i >= 0; i--) {
- shouldwebuzz();
- Serial.print("Pin: ");
- Serial.println(i);
- digitalWrite(ledPinsLeft[i], HIGH);
- delay(100);
- digitalWrite(ledPinsLeft[i], LOW);
- }
- for(int i = 0; i < 5; i++) {
- shouldwebuzz();
- 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();
- 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();
- digitalWrite(ledPinsLeft[i], HIGH);
- digitalWrite(ledPinsRight[i], HIGH);
- delay(100);
- digitalWrite(ledPinsLeft[i], LOW);
- digitalWrite(ledPinsRight[i], LOW);
- }
- }
- 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 - 1; i++)
- {
- clearLEDs();
- rightTree.setPixelColor(i, red, green, blue); // Set the bright middle eye
- leftTree.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)
- leftTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
- rightTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
- if (i - j <= LED_COUNT)
- leftTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
- rightTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
- }
- leftTree.show(); // Turn the LEDs on
- rightTree.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();
- leftTree.setPixelColor(i, red, green, blue);
- rightTree.setPixelColor(i, red, green, blue);
- for (int j = 1; j < 3; j++)
- {
- if (i - j >= 0)
- leftTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
- rightTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
- if (i - j <= LED_COUNT)
- leftTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
- rightTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
- }
- leftTree.show();
- rightTree.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) < 9) {
- playsong();
- } else {
- playsong2();
- }
- 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
- }
- }
|