123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380 |
- /* 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 <SoftwareSerial.h>
- #include <WS2812_Definitions.h>
- #include <eRCaGuy_ButtonReader.h>
- #include <BackgroundRingClass.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 = 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();
- }
|