CiderRaceTrack.ino 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. /*
  2. Cider Drag Races
  3. A project to let two racers compete in drinking a glass of cider,
  4. complete with start button, weight activated drink coasters,
  5. a drag-strip "christmas tree", and buzzer.
  6. Along with a few easter eggs.
  7. Pin Assignments per Default Sketch:
  8. Digital:
  9. 2 - Left Player Display
  10. 3 - Right Player Display
  11. 4 - unused (RX for left display)
  12. 5 - unused (RX for right display)
  13. 13 - Left Ready Button
  14. 7 - Left Pressure Simulator
  15. 8 - Right Ready Button
  16. 9 - Buzzer (+)
  17. 10 - Right Pressure Simularor
  18. 11 - Left Player Light Tree (6 lights) (If WS2812B)
  19. 12 - Right Player Light Tree (6 lights)(If WS2812B)
  20. 30-39 - Colored LEDs
  21. Analog:
  22. 0 - Right Player Pressure Sensor
  23. 1 - Left Player Pressure Sensor
  24. 7 - Unused; Seeds RNG.
  25. Fred Damstra
  26. fred.damstra@gmail.com
  27. 2016-09-29 - Initial Draft
  28. Licensed under GPLv3: https://www.gnu.org/licenses/gpl.html
  29. */
  30. #include <SoftwareSerial.h>
  31. #include "Adafruit_NeoPixel.h"
  32. #include "WS2812_Definitions.h"
  33. #include <eRCaGuy_ButtonReader.h>
  34. /**********
  35. CONFIGURATION SECTION
  36. */
  37. /* Buzzer Setup:
  38. Wire ground to common ground, and positive to a PWM
  39. pin. In this example, pin 9.
  40. Lots of help for this example at
  41. https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer
  42. */
  43. const int debug = 0;
  44. const int buzzerPin = 9;
  45. const unsigned long songFrequency = 90000; // How frequently the song may play in seconds
  46. const float songProbability = 0.0; // Probability that the song will play during that frequency
  47. /* randomPin should be an unused analog pin for seeding the RNG */
  48. const int randomPin = 5;
  49. /* WS2812 Christmas Tree Setup:
  50. Two strips of 6 LEDs connected to 5V and Ground, plus the signal pin
  51. */
  52. const int ledPinRight = 12;
  53. const int ledPinLeft = 11;
  54. const int brightness = 255;
  55. /* Digital (old school) Christmas Tree Setup:
  56. Two strips of 6 LEDs connected to 5V and Ground, plus the signal pin
  57. */
  58. //const int ledPinsLeft[] = {30, 32, 34, 36, 38};
  59. const int ledPinsLeft[] = {38, 36, 34, 32, 30};
  60. //const int ledPinsRight[] = {31, 33, 35, 37, 39};
  61. const int ledPinsRight[] = {39, 37, 35, 33, 31};
  62. const unsigned long prettyLEDFrequency = 30; // How frequently something pretty happens on the LEDs
  63. const float prettyLEDProbability = 0.75; // Probability that the song will play during that frequency
  64. /* Christmas Tree */
  65. const unsigned long startDelay = 1000; /* How long to wait between hitting the start ubtton and starting */
  66. const unsigned long maxDelay = 5000; /* In non dragrace mode, how long might we wait *after* a guaranteed startDelay? */
  67. const unsigned long lightDelay = 500; /* How long to wait between lights during the countdown */
  68. const unsigned long topColor = PURPLE; /* Top LED is constant to show power */
  69. /* 7-Segment Display Setup
  70. Two 7 OpenSegment displays from SparkFun in serial mode.
  71. */
  72. const int leftDisplayTX = 2;
  73. const int rightDisplayTX = 3;
  74. const int leftDisplayRX = 4; /* Unused */
  75. const int rightDisplayRX = 5; /* Unused */
  76. /* Force Sensitive Resistor Switches (Analog inputs) */
  77. const int leftFSR = A7;
  78. const int rightFSR = A0;
  79. const int leftFSRThreshold = 10; /* > this number is closed */
  80. const int rightFSRThreshold = 10;
  81. const int leftFSRSimPin = 7; /* For when the FSRs aren't there */
  82. const int rightFSRSimPin = 10; /* For when the FSRs aren't there */
  83. /* Start Button */
  84. const int leftReadyButtonPin = 13;
  85. const int rightReadyButtonPin = 8;
  86. /* Difficulty */
  87. const int difficultyLeftPin = 46;
  88. const int difficultyRightPin = 47;
  89. /* Loop delays
  90. n.b. It occurs to me that unusual values for these variables /may/ upset
  91. the math on looping. Probably not, but if you run into problems, return
  92. these to original values of 100 and 25 respectively
  93. */
  94. const int mainDelay = 100; /* How long to sleep during the main loop */
  95. const int countdownDelay = 25; /* How long to sleep during the countdown loop */
  96. /* Special Functions */
  97. const int modePin = 51; /* Red */
  98. const int buzzPin = 52; /* Green */
  99. const int clearPin = 53; /* White */
  100. /***********
  101. Application Constants
  102. */
  103. const int LED_COUNT = 6;
  104. const unsigned int buzzerFrequency = 70;
  105. const int buzzerDuration = 1800;
  106. const unsigned int beepFrequency = 3700;
  107. const int beepDuration = 100;
  108. const int beepMultiplier = 3; /* long beep is this x as long a short beep */
  109. const unsigned long renegDelay = 500;
  110. const unsigned long debounceDelay = 250;
  111. /***********
  112. Application Variables
  113. */
  114. unsigned long lastSongCheck = 0;
  115. Adafruit_NeoPixel rightTree = Adafruit_NeoPixel(LED_COUNT, ledPinRight, NEO_GRB + NEO_KHZ800);
  116. Adafruit_NeoPixel leftTree = Adafruit_NeoPixel(LED_COUNT, ledPinLeft, NEO_GRB + NEO_KHZ800);
  117. SoftwareSerial leftDisplay(leftDisplayRX, leftDisplayTX);
  118. SoftwareSerial rightDisplay(rightDisplayRX, rightDisplayTX);
  119. eRCaGuy_ButtonReader leftReadyButton = eRCaGuy_ButtonReader(leftReadyButtonPin);
  120. eRCaGuy_ButtonReader rightReadyButton = eRCaGuy_ButtonReader(rightReadyButtonPin);
  121. eRCaGuy_ButtonReader leftFSRButton = eRCaGuy_ButtonReader(leftFSRSimPin);
  122. eRCaGuy_ButtonReader rightFSRButton = eRCaGuy_ButtonReader(rightFSRSimPin);
  123. eRCaGuy_ButtonReader clearToggle = eRCaGuy_ButtonReader(clearPin);
  124. /* Buzzer: Some constants for playing a song: */
  125. const int songLength = 18;
  126. char notes[] = "cdfda ag cdfdg gf ";
  127. int beats[] = {1, 1, 1, 1, 1, 1, 4, 4, 2, 1, 1, 1, 1, 1, 1, 4, 4, 2};
  128. const int tempo = 118;
  129. int songLength2 = 26;
  130. char notes2[] = "eeeeeeegcde fffffeeeeddedg";
  131. 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};
  132. const int tempo2 = 130;
  133. /* LEDs */
  134. unsigned long lastPrettyLEDCheck = 0;
  135. /* 7 Segment */
  136. long rightClock = 0;
  137. long leftClock = 0;
  138. #define APOSTROPHE 5
  139. #define COLON 4
  140. #define DECIMAL4 3
  141. #define DECIMAL3 2
  142. #define DECIMAL2 1
  143. #define DECIMAL1 0
  144. /***********
  145. Code
  146. */
  147. void setup() {
  148. Serial.begin(9600); // Serial used for logging
  149. /* Buzzer Setup */
  150. pinMode(buzzerPin, OUTPUT);
  151. randomSeed(analogRead(randomPin));
  152. /* WS2812 LED Setup */
  153. rightTree.begin();
  154. leftTree.begin();
  155. /* Digital LED Setup */
  156. for(int i = 0; i < 5; i++) {
  157. pinMode(ledPinsLeft[i], OUTPUT);
  158. digitalWrite(ledPinsLeft[i], LOW);
  159. pinMode(ledPinsRight[i], OUTPUT);
  160. digitalWrite(ledPinsRight[i], LOW);
  161. }
  162. /* clearLEDs(); */
  163. clearLEDs();
  164. /* 7 Segment Displays */
  165. leftDisplay.listen();
  166. leftDisplay.begin(9600);
  167. leftDisplay.write('v');
  168. leftDisplay.write(0x7A);
  169. leftDisplay.write((byte) brightness);
  170. rightDisplay.listen();
  171. rightDisplay.begin(9600);
  172. rightDisplay.write('v');
  173. rightDisplay.write(0x7A);
  174. rightDisplay.write((byte) brightness);
  175. longbeep();
  176. printClocks(1223,1996);
  177. /* Initialize our buttons */
  178. pinMode(leftReadyButtonPin, INPUT_PULLUP);
  179. pinMode(rightReadyButtonPin, INPUT_PULLUP);
  180. pinMode(leftFSRSimPin, INPUT_PULLUP);
  181. pinMode(rightFSRSimPin, INPUT_PULLUP);
  182. pinMode(leftFSR, INPUT);
  183. pinMode(rightFSR, INPUT);
  184. /* And our switches */
  185. pinMode(modePin, INPUT_PULLUP); /* Red */
  186. pinMode(clearPin, INPUT_PULLUP); /* Green */
  187. pinMode(buzzPin, INPUT_PULLUP); /* White */
  188. /* And our sliders */
  189. pinMode(difficultyLeftPin, INPUT_PULLUP); /* HIGH is normal difficulty */
  190. pinMode(difficultyRightPin, INPUT_PULLUP);
  191. /* Demo the Christmas Tree */
  192. setLEDs(BLACK, BLACK, BLACK, BLACK, YELLOW);
  193. longbeep(); delay(400);
  194. setLEDs(BLACK, BLACK, BLACK, YELLOW, BLACK);
  195. longbeep(); delay(400);
  196. setLEDs(BLACK, BLACK, YELLOW, BLACK, BLACK);
  197. longbeep(); delay(400);
  198. setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK);
  199. longbeep(); delay(400);
  200. setLEDs(RED, BLACK, BLACK, BLACK, BLACK);
  201. longbeep();
  202. /* Arbitrary delay before updating the 7-segments again */
  203. delay(1000);
  204. /* 7 Segment Display Continued */
  205. if(random(0, 1000) < 100) {
  206. leftClock=531;
  207. rightClock=8008;
  208. printClocks(leftClock, rightClock);
  209. } else {
  210. leftClock=1223;
  211. rightClock=2016;
  212. printClocks(leftClock,rightClock);
  213. }
  214. longbeep();
  215. /* Switches */
  216. pinMode(leftFSR, INPUT);
  217. pinMode(rightFSR, INPUT);
  218. /* start button */
  219. //pinMode(startButtonPin, INPUT_PULLUP);
  220. Serial.println("Setup complete.");
  221. }
  222. /* MAIN LOOP */
  223. void loop() {
  224. int8_t clearButtonAction;
  225. boolean clearButtonState;
  226. // put your main code here, to run repeatedly:
  227. easterEggSongCheck(); // Sometimes we play a song
  228. prettyLEDCheck();
  229. clearToggle.readButton(&clearButtonAction, &clearButtonState);
  230. if(clearButtonAction == 1) {
  231. Serial.println("clear action called");
  232. if(random(0, 1000) < 100) {
  233. leftClock=531;
  234. rightClock=8008;
  235. printClocks(leftClock, rightClock);
  236. } else {
  237. leftClock=0;
  238. rightClock=0;
  239. printClocks(leftClock,rightClock);
  240. }
  241. }
  242. printClocks(leftClock, rightClock);
  243. shouldwebuzz();
  244. /* If either coaster is open (no glass), continue on */
  245. if (leftSwitchOpen() || rightSwitchOpen()) {
  246. clearLEDs();
  247. if(!leftSwitchOpen()) {
  248. digitalWrite(ledPinsLeft[0], HIGH);
  249. } else if(!rightSwitchOpen()) {
  250. digitalWrite(ledPinsRight[0], HIGH);
  251. }
  252. delay(mainDelay);
  253. return; /* Can't continue in main loop */
  254. } else {
  255. /* Both are closed, race can begin */
  256. ledsToRed();
  257. if(millis() % 5000 == 0) {
  258. Serial.println("Waiting for start button to be pressed.");
  259. }
  260. if (startButtonPressed()) {
  261. countdown();
  262. /* We're back from a race */
  263. /* Reset easter eggs */
  264. lastSongCheck = lastPrettyLEDCheck = millis();
  265. startButtonPressed(); /* Clear out "stuck" state input */
  266. //return; /* no continue in main loop */
  267. }
  268. }
  269. /* Rest before looping again */
  270. delay(mainDelay);
  271. }
  272. void countdown(void) {
  273. unsigned long randomAdditionalDelay;
  274. int mode; /* 1 is drag race, 0 is randomness */
  275. int cstep = -1; /* Which step of the countdown are we on? */
  276. rightClock = leftClock = 0;
  277. if(digitalRead(modePin) == HIGH) {
  278. /* Drag race mode */
  279. mode = 1;
  280. } else {
  281. /* Random delay mode */
  282. setLEDs(RED, BLACK, BLACK, BLACK, YELLOW);
  283. randomAdditionalDelay = random(maxDelay);
  284. mode = 0;
  285. }
  286. if(mode) {
  287. Serial.print("Start button pressed. Beginning xmas tree in ");
  288. Serial.print(startDelay);
  289. Serial.println("ms");
  290. } else {
  291. Serial.print("Start button pressed. Skipping xmas tree. Beginning in ");
  292. Serial.print(startDelay + randomAdditionalDelay);
  293. Serial.println("ms.");
  294. }
  295. printClocks(leftClock, rightClock);
  296. startsong();
  297. delay(startDelay);
  298. unsigned long start = millis();
  299. while (1) {
  300. shouldwebuzz();
  301. if (leftSwitchOpen_debounce(1) || rightSwitchOpen_debounce(1)) {
  302. /* FALSE START! */
  303. if (leftSwitchOpen_debounce(1)) {
  304. Serial.println("FALSE START: Player Left");
  305. buzz_nonblock();
  306. leftClock = 9999;
  307. rightClock = 0;
  308. printClocks(leftClock, rightClock);
  309. for(int i = 0; i < 3; i++) {
  310. leftDisplay.listen();
  311. leftDisplay.write(0x7A);
  312. leftDisplay.write((byte) 0);
  313. delay(150);
  314. leftDisplay.listen();
  315. leftDisplay.write(0x7A);
  316. leftDisplay.write((byte) brightness);
  317. delay(150);
  318. }
  319. delay(buzzerDuration - 900); /* Rest for the remaining buzz */
  320. leftSwitchOpen_debounce(1);
  321. rightSwitchOpen_debounce(1); /* Get another reading just to clear things out */
  322. return;
  323. } else if (rightSwitchOpen_debounce(1)) {
  324. Serial.println("FALSE START: Player Right");
  325. buzz_nonblock();
  326. rightClock = 9999;
  327. leftClock = 0;
  328. printClocks(leftClock, rightClock);
  329. for(int i = 0; i < 3; i++) {
  330. rightDisplay.listen();
  331. rightDisplay.write(0x7A);
  332. rightDisplay.write((byte) 0);
  333. delay(150);
  334. rightDisplay.listen();
  335. rightDisplay.write(0x7A);
  336. rightDisplay.write((byte) 255);
  337. delay(150);
  338. }
  339. delay(buzzerDuration - 900); /* Rest for the remaining buzz */
  340. leftSwitchOpen_debounce(1);
  341. rightSwitchOpen_debounce(1); /* Get another reading just to clear things out */
  342. return;
  343. } else {
  344. /* WTF? Timing issue */
  345. Serial.println("WARNING: False start detected, but corrected?!");
  346. }
  347. }
  348. /* No false start */
  349. if(mode) {
  350. /* drag race! */
  351. switch ( (millis() - start) / lightDelay ) {
  352. case 0:
  353. if (cstep != 0) {
  354. Serial.println("Countdown ... 3");
  355. setLEDs(RED, BLACK, BLACK, BLACK, YELLOW);
  356. beep();
  357. cstep = 0;
  358. }
  359. continue;
  360. case 1:
  361. if (cstep != 1) {
  362. Serial.println("Countdown ... 2");
  363. setLEDs(RED, BLACK, BLACK, YELLOW, BLACK);
  364. beep();
  365. cstep = 1;
  366. }
  367. continue;
  368. case 2:
  369. if (cstep != 2) {
  370. Serial.println("Countdown ... 1");
  371. setLEDs(RED, BLACK, YELLOW, BLACK, BLACK);
  372. beep();
  373. cstep = 2;
  374. }
  375. continue;
  376. case 3:
  377. Serial.println("Countdown ... GO!!!!!!!!");
  378. setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK);
  379. longbeep();
  380. race_loop();
  381. return;
  382. }
  383. } else {
  384. /* Silent start */
  385. if(millis() > (start + startDelay + randomAdditionalDelay)) {
  386. Serial.println("Random delay met... GO!!!!!!!!");
  387. setLEDs(BLACK, GREEN, BLACK, BLACK, BLACK);
  388. longbeep();
  389. race_loop();
  390. return;
  391. }
  392. }
  393. delay(countdownDelay); /* Make the loop less aggressive */
  394. }
  395. Serial.println("Should never get here...");
  396. }
  397. void race_loop(void) {
  398. /* Race is on! */
  399. unsigned long start = millis();
  400. Serial.print("Race is ON at ");
  401. Serial.println(start);
  402. boolean handicap_left = false;
  403. boolean handicap_right = false;
  404. unsigned long timerLeft, timerRight;
  405. timerLeft = timerRight = 0;
  406. /* determine handicap settings */
  407. if(digitalRead(difficultyLeftPin) == 0) {
  408. handicap_left = true;
  409. }
  410. if(digitalRead(difficultyRightPin) == 0) {
  411. handicap_right = true;
  412. }
  413. /* Record whether the racer picked up his/her cup */
  414. int leftStarted = 0;
  415. int rightStarted = 0;
  416. unsigned long loopstart = millis();
  417. unsigned long lastloop = millis();
  418. unsigned long leftRenegBounce = 0;
  419. unsigned long rightRenegBounce = 0;
  420. while (1) {
  421. loopstart = millis();
  422. //Serial.print("Loop time with serial: ");
  423. //Serial.println(loopstart - lastloop);
  424. /* Check for winners */
  425. boolean leftOpen, rightOpen;
  426. leftOpen = rightOpen = false;
  427. /* Choose which one to read first randomly to offset any potential bias. I
  428. * find that the loop is generally less than 1ms, so this is probably unnecessary,
  429. * but it doesn't hurt.
  430. */
  431. if(random(0, 2)) {
  432. // Serial.print("Left first. Time = ");
  433. // Serial.println(millis());
  434. leftOpen = leftSwitchOpen();
  435. rightOpen = rightSwitchOpen();
  436. } else {
  437. // Serial.print("Right first. Time = ");
  438. // Serial.println(millis());
  439. rightOpen = rightSwitchOpen();
  440. leftOpen = leftSwitchOpen();
  441. }
  442. /* Check for finishers */
  443. if (!leftOpen && leftStarted && !timerLeft) {
  444. /* Finished */
  445. Serial.print("Left player finished at ");
  446. Serial.println(millis() - start);
  447. timerLeft = (millis() - start) / 10;
  448. if(handicap_left) {
  449. /* Handicapped player */
  450. timerLeft = timerLeft - (timerLeft >> 2);
  451. }
  452. beep_nonblock();
  453. } else if (leftOpen && !leftStarted) {
  454. Serial.print("Left cup lifted at ");
  455. Serial.println(millis() - start);
  456. leftStarted = 1;
  457. }
  458. if (!rightOpen && rightStarted && !timerRight) {
  459. /* Finished */
  460. Serial.print("Right player finished at ");
  461. Serial.println(millis() - start);
  462. timerRight = (millis() - start) / 10;
  463. if(handicap_right) {
  464. /* Handicapped player */
  465. timerRight = timerRight - (timerRight >> 2);
  466. }
  467. beep_nonblock();
  468. } else if (rightOpen && !rightStarted) {
  469. Serial.print("Right cup lifted at ");
  470. Serial.println(millis() - start);
  471. rightStarted = 1;
  472. }
  473. /* Check for renegers
  474. * Note to cheaters: too hard a hit can make the opponent's cup bounce.
  475. * However, we can't turn this off, because things bounce on removal.
  476. */
  477. if (leftSwitchOpen() && timerLeft) {
  478. /* Bullshit! */
  479. if(leftRenegBounce == 0) {
  480. leftRenegBounce = millis();
  481. } else if((millis() - leftRenegBounce) > renegDelay) {
  482. Serial.println("Left player RENEGS! This is bullshit!");
  483. timerLeft = 0;
  484. leftRenegBounce = 0;
  485. } else {
  486. Serial.print("Left reneg on delay: ");
  487. Serial.println(millis() - leftRenegBounce);
  488. }
  489. }
  490. if (rightSwitchOpen() && timerRight) {
  491. /* Bullshit! */
  492. if(rightRenegBounce == 0) {
  493. rightRenegBounce = millis();
  494. } else if((millis() - rightRenegBounce) > renegDelay) {
  495. Serial.println("Right player RENEGS! This is bullshit!");
  496. timerRight = 0;
  497. rightRenegBounce = 0;
  498. } else {
  499. Serial.print("Right reneg on delay: ");
  500. Serial.println(millis() - rightRenegBounce);
  501. }
  502. }
  503. /* If still a winner and not a reneger, I think we have a winner */
  504. if (timerLeft) {
  505. leftClock = timerLeft;
  506. } else {
  507. leftClock = (millis() - start) / 10;
  508. if(handicap_left) {
  509. /* Handicapped player */
  510. leftClock = leftClock - (leftClock >> 2);
  511. }
  512. }
  513. if (timerRight) {
  514. rightClock = timerRight;
  515. } else {
  516. rightClock = (millis() - start) / 10;
  517. if(handicap_right) {
  518. /* Handicapped player */
  519. rightClock = rightClock - (rightClock >> 2);
  520. }
  521. }
  522. /* Print the clocks */
  523. printClocks(leftClock, rightClock);
  524. if (timerRight && timerLeft) {
  525. /* Race is finished */
  526. ledsToRed();
  527. if(timerRight < timerLeft) {
  528. Serial.println("Right player WINS!");
  529. for(int i = 0; i < 3; i++) {
  530. rightDisplay.listen();
  531. rightDisplay.write(0x7A);
  532. rightDisplay.write((byte) 0);
  533. delay(150);
  534. beep();
  535. rightDisplay.listen();
  536. rightDisplay.write(0x7A);
  537. rightDisplay.write((byte) 255);
  538. delay(150);
  539. }
  540. } else if(timerLeft < timerRight) {
  541. for(int i = 0; i < 3; i++) {
  542. leftDisplay.listen();
  543. leftDisplay.write(0x7A);
  544. leftDisplay.write((byte) 0);
  545. delay(150);
  546. beep();
  547. leftDisplay.listen();
  548. leftDisplay.write(0x7A);
  549. leftDisplay.write((byte) 255);
  550. delay(150);
  551. }
  552. Serial.println("Left player WINS!");
  553. } else {
  554. Serial.println("TIE GAME!!!");
  555. }
  556. playWinner();
  557. /* Wait until start buttons are no longer pressed */
  558. while(startButtonPressed()) {
  559. delay(100);
  560. }
  561. return;
  562. }
  563. lastloop = loopstart;
  564. }
  565. Serial.println("ERROR: Woah. Just Woah. How the fuck? 0x73184fcgukl");
  566. }
  567. /* Beep and buzz if those toggles are pressed */
  568. void shouldwebuzz() {
  569. if(digitalRead(buzzPin) == LOW) {
  570. buzz_nonblock();
  571. }
  572. }
  573. /* Start button switch */
  574. int startButtonPressed() {
  575. int8_t leftButtonAction, rightButtonAction;
  576. boolean leftButtonState, rightButtonState;
  577. leftReadyButton.readButton(&leftButtonAction, &leftButtonState);
  578. rightReadyButton.readButton(&rightButtonAction, &rightButtonState);
  579. if(leftButtonState == false && rightButtonState == false) {
  580. Serial.println("Both ready buttons pressed.");
  581. return 1;
  582. } else {
  583. /* Serial.print("Left state: ");
  584. Serial.println(leftButtonState);
  585. Serial.print("Right state: ");
  586. Serial.println(rightButtonState);
  587. */
  588. return 0;
  589. }
  590. }
  591. /* FSR Functions */
  592. int leftSwitchOpen() {
  593. return leftSwitchOpen_debounce(0);
  594. }
  595. int leftSwitchOpen_debounce(int silent) {
  596. /* Not a standard debounce method. We're going to keep the last 16 values
  597. * and majority rules.
  598. */
  599. static int results[16] = {0,0,0,0,0,
  600. 0,0,0,0,0,
  601. 0,0,0,0,0,0};
  602. static int pointer = 0;
  603. results[pointer] = leftSwitchOpen(silent);
  604. pointer = (pointer + 1) % 16;
  605. int sum = 0;
  606. // Serial.print("Left array: [");
  607. for(int i = 0; i < 16; i++) {
  608. sum+=results[i];
  609. // Serial.print(results[i]);
  610. // Serial.print(",");
  611. }
  612. if(sum > 8) {
  613. // Serial.println("]; Returning 1");
  614. return 1;
  615. } else {
  616. // Serial.println("]; Returning 0");
  617. return 0;
  618. }
  619. }
  620. int leftSwitchOpen(int silent) {
  621. int8_t leftButtonAction;
  622. boolean leftButtonState;
  623. static int lastvalue = 0;
  624. /* Sim Mode:
  625. leftFSRButton.readButton(&leftButtonAction, &leftButtonState);
  626. if(leftButtonState == false) { */
  627. /* Button is low, meaning it's pressed */
  628. /* return 0;
  629. }
  630. return 1;
  631. */
  632. int value = analogRead(leftFSR);
  633. if( value > leftFSRThreshold) {
  634. /* Pressed! */
  635. if(lastvalue < leftFSRThreshold) {
  636. Serial.print("Left pressed, pressure: ");
  637. Serial.println(value);
  638. }
  639. lastvalue = value;
  640. return 0;
  641. }
  642. if(lastvalue > leftFSRThreshold) {
  643. Serial.print("Left released, pressure: ");
  644. Serial.println(value);
  645. lastvalue = value;
  646. }
  647. return 1;
  648. }
  649. int rightSwitchOpen() {
  650. return rightSwitchOpen_debounce(0);
  651. }
  652. int rightSwitchOpen_debounce(int silent) {
  653. /* Not a standard debounce method. We're going to keep the last 16 values
  654. * and majority rules.
  655. */
  656. static int results[16] = {0,0,0,0,0,
  657. 0,0,0,0,0,
  658. 0,0,0,0,0,0};
  659. static int pointer = 0;
  660. results[pointer] = rightSwitchOpen(silent);
  661. pointer = (pointer + 1) % 16;
  662. int sum = 0;
  663. // Serial.print("Right array: [");
  664. for(int i = 0; i < 16; i++) {
  665. sum+=results[i];
  666. // Serial.print(results[i]);
  667. // Serial.print(",");
  668. }
  669. if(sum > 8) {
  670. // Serial.println("]; Returning 1");
  671. return 1;
  672. } else {
  673. // Serial.println("]; Returning 0");
  674. return 0;
  675. }
  676. }
  677. int rightSwitchOpen(int silent) {
  678. int8_t rightButtonAction;
  679. boolean rightButtonState;
  680. static int lastvalue = 0;
  681. /*
  682. rightFSRButton.readButton(&rightButtonAction, &rightButtonState);
  683. if(rightButtonState == false) { */
  684. /*Button is low, meaning it's pressed */
  685. /* return 0;
  686. }
  687. return 1;
  688. */
  689. int value = analogRead(rightFSR);
  690. if( value > rightFSRThreshold) {
  691. /* Pressed! */
  692. if(lastvalue < rightFSRThreshold) {
  693. Serial.print("Right pressed, pressure: ");
  694. Serial.println(value);
  695. }
  696. lastvalue = value;
  697. return 0;
  698. }
  699. if(lastvalue > rightFSRThreshold) {
  700. Serial.print("Right released, pressure: ");
  701. Serial.println(value);
  702. lastvalue = value;
  703. }
  704. return 1;
  705. }
  706. int switchOpen(int pin, int threshold, int silent) {
  707. int fsrADC = analogRead(pin);
  708. #ifdef SIMULATION
  709. fsrADC = random(0, 1000);
  710. #endif
  711. if (fsrADC < threshold) {
  712. if (!silent) {
  713. Serial.print(fsrADC);
  714. Serial.println(" -- OPEN");
  715. }
  716. return 1;
  717. }
  718. if (!silent) {
  719. Serial.print(fsrADC);
  720. Serial.println(" -- CLOSED");
  721. }
  722. return 0;
  723. }
  724. /* 7-Segment Functions */
  725. void printClocks(unsigned long leftValue, unsigned long rightValue) {
  726. if (leftValue > 9999) {
  727. leftValue = 9999;
  728. }
  729. if (rightValue > 9999) {
  730. rightValue = 9999;
  731. }
  732. // Serial.print("Clocks: ");
  733. char tempstring[10];
  734. snprintf(tempstring, sizeof(tempstring), "%04lu", leftValue);
  735. leftDisplay.listen();
  736. leftDisplay.write(tempstring);
  737. // Serial.print(tempstring);
  738. snprintf(tempstring, sizeof(tempstring), "%04lu", rightValue);
  739. rightDisplay.listen();
  740. rightDisplay.write(tempstring);
  741. // Serial.print(" ");
  742. // Serial.println(tempstring);
  743. /* TUrn on decimal point */
  744. leftDisplay.listen();
  745. leftDisplay.write(0x77); /* Decimal, colon, and apostrophe command */
  746. leftDisplay.write(0b000010); /* Decimal 2 is second bit) */
  747. rightDisplay.listen();
  748. rightDisplay.write(0x77); /* Decimal, colon, and apostrophe command */
  749. rightDisplay.write(0b000010); /* Decimal 2 is second bit) */
  750. }
  751. /* LED Functions */
  752. void ledsToRed() {
  753. ws2812_ledsToRed();
  754. digitalWrite(ledPinsLeft[0], HIGH);
  755. digitalWrite(ledPinsRight[0], HIGH);
  756. for(int i=1; i<5; i++) {
  757. digitalWrite(ledPinsLeft[i], LOW);
  758. digitalWrite(ledPinsRight[i], LOW);
  759. }
  760. }
  761. // Sets red light on.
  762. void ws2812_ledsToRed() {
  763. clearLEDs();
  764. rightTree.setPixelColor(0, RED);
  765. leftTree.setPixelColor(0, RED);
  766. rightTree.show();
  767. leftTree.show();
  768. }
  769. /* Clears all LEDs (for WS2812, except the top one) */
  770. void clearLEDs() {
  771. ws2812_clearLEDs();
  772. for(int i = 0; i < 5; i++) {
  773. digitalWrite(ledPinsLeft[i], LOW);
  774. digitalWrite(ledPinsRight[i], LOW);
  775. }
  776. }
  777. void ws2812_clearLEDs()
  778. {
  779. for (int i = 0; i < (LED_COUNT - 1); i++)
  780. {
  781. rightTree.setPixelColor(i, 0);
  782. leftTree.setPixelColor(i, 0);
  783. }
  784. rightTree.setPixelColor(LED_COUNT - 1, topColor);
  785. leftTree.setPixelColor(LED_COUNT - 1, topColor);
  786. rightTree.show();
  787. leftTree.show();
  788. }
  789. void setLEDs(unsigned long redlight,
  790. unsigned long greenlight,
  791. unsigned long yellow3,
  792. unsigned long yellow2,
  793. unsigned long yellow1) {
  794. ws2812_setLEDs(redlight, greenlight, yellow3, yellow2, yellow1);
  795. /* If black, turn it off, otherwise turn it on */
  796. if(redlight == BLACK) {
  797. digitalWrite(ledPinsLeft[0], LOW);
  798. digitalWrite(ledPinsRight[0], LOW);
  799. } else {
  800. digitalWrite(ledPinsLeft[0], HIGH);
  801. digitalWrite(ledPinsRight[0], HIGH);
  802. }
  803. /* If black, turn it off, otherwise turn it on */
  804. if(greenlight == BLACK) {
  805. digitalWrite(ledPinsLeft[1], LOW);
  806. digitalWrite(ledPinsRight[1], LOW);
  807. } else {
  808. digitalWrite(ledPinsLeft[1], HIGH);
  809. digitalWrite(ledPinsRight[1], HIGH);
  810. }
  811. /* If black, turn it off, otherwise turn it on */
  812. if(yellow3 == BLACK) {
  813. digitalWrite(ledPinsLeft[2], LOW);
  814. digitalWrite(ledPinsRight[2], LOW);
  815. } else {
  816. digitalWrite(ledPinsLeft[2], HIGH);
  817. digitalWrite(ledPinsRight[2], HIGH);
  818. }
  819. /* If black, turn it off, otherwise turn it on */
  820. if(yellow2 == BLACK) {
  821. digitalWrite(ledPinsLeft[3], LOW);
  822. digitalWrite(ledPinsRight[3], LOW);
  823. } else {
  824. digitalWrite(ledPinsLeft[3], HIGH);
  825. digitalWrite(ledPinsRight[3], HIGH);
  826. }
  827. /* If black, turn it off, otherwise turn it on */
  828. if(yellow1 == BLACK) {
  829. digitalWrite(ledPinsLeft[4], LOW);
  830. digitalWrite(ledPinsRight[4], LOW);
  831. } else {
  832. digitalWrite(ledPinsLeft[4], HIGH);
  833. digitalWrite(ledPinsRight[4], HIGH);
  834. }
  835. }
  836. void ws2812_setLEDs(unsigned long redlight,
  837. unsigned long greenlight,
  838. unsigned long yellow3,
  839. unsigned long yellow2,
  840. unsigned long yellow1) {
  841. rightTree.setPixelColor(0, redlight);
  842. rightTree.setPixelColor(1, greenlight);
  843. rightTree.setPixelColor(2, yellow3);
  844. rightTree.setPixelColor(3, yellow2);
  845. rightTree.setPixelColor(4, yellow1);
  846. rightTree.setPixelColor(LED_COUNT - 1, topColor);
  847. leftTree.setPixelColor(0, redlight);
  848. leftTree.setPixelColor(1, greenlight);
  849. leftTree.setPixelColor(2, yellow3);
  850. leftTree.setPixelColor(3, yellow2);
  851. leftTree.setPixelColor(4, yellow1);
  852. leftTree.setPixelColor(LED_COUNT - 1, topColor);
  853. rightTree.show();
  854. leftTree.show();
  855. }
  856. void prettyLEDCheck() {
  857. /* Lets see if we should play a song */
  858. if ( (millis() - lastPrettyLEDCheck) > (prettyLEDFrequency * 1000) ) {
  859. lastPrettyLEDCheck = millis();
  860. if ( (random(0, 1000) < long(prettyLEDProbability * 1000.0)) ) {
  861. Serial.println("Pretty LED Approved");
  862. prettyLED();
  863. } else {
  864. Serial.println("Pretty lED probability check declined.");
  865. }
  866. }
  867. }
  868. void prettyLED() {
  869. /* if using the ws2812's, you may want to turn this back on
  870. ws2812_prettyLED();
  871. */
  872. if(random(0, 1000) < 500) {
  873. prettyCircleLED();
  874. prettyCircleLED();
  875. // prettyCircleLED();
  876. } else {
  877. prettyBounceLED();
  878. prettyBounceLED();
  879. prettyBounceLED();
  880. }
  881. }
  882. void prettyCircleLED() {
  883. clearLEDs();
  884. for(int i = 4; i >= 0; i--) {
  885. shouldwebuzz();
  886. Serial.print("Pin: ");
  887. Serial.println(i);
  888. digitalWrite(ledPinsLeft[i], HIGH);
  889. delay(100);
  890. digitalWrite(ledPinsLeft[i], LOW);
  891. }
  892. for(int i = 0; i < 5; i++) {
  893. shouldwebuzz();
  894. Serial.print("Pin: ");
  895. Serial.println(i);
  896. digitalWrite(ledPinsRight[i], HIGH);
  897. delay(100);
  898. digitalWrite(ledPinsRight[i], LOW);
  899. }
  900. }
  901. void prettyBounceLED() {
  902. clearLEDs();
  903. for(int i = 4; i >= 0; i--) {
  904. shouldwebuzz();
  905. digitalWrite(ledPinsLeft[i], HIGH);
  906. digitalWrite(ledPinsRight[i], HIGH);
  907. delay(100);
  908. digitalWrite(ledPinsLeft[i], LOW);
  909. digitalWrite(ledPinsRight[i], LOW);
  910. }
  911. for(int i = 1; i < 5; i++) {
  912. shouldwebuzz();
  913. digitalWrite(ledPinsLeft[i], HIGH);
  914. digitalWrite(ledPinsRight[i], HIGH);
  915. delay(100);
  916. digitalWrite(ledPinsLeft[i], LOW);
  917. digitalWrite(ledPinsRight[i], LOW);
  918. }
  919. }
  920. void ws2812_prettyLED() {
  921. /* Do something interesting */
  922. /* cylon(YELLOW, 500); */
  923. }
  924. // Implements a little larson "cylon" sanner.
  925. // This'll run one full cycle, down one way and back the other
  926. void ws2812_cylon(unsigned long color, unsigned long wait)
  927. {
  928. Serial.println("Cylons are attacking.");
  929. // weight determines how much lighter the outer "eye" colors are
  930. const byte weight = 4;
  931. // It'll be easier to decrement each of these colors individually
  932. // so we'll split them out of the 24-bit color value
  933. byte red = (color & 0xFF0000) >> 16;
  934. byte green = (color & 0x00FF00) >> 8;
  935. byte blue = (color & 0x0000FF);
  936. // Start at closest LED, and move to the outside
  937. for (int i = 0; i <= LED_COUNT - 1; i++)
  938. {
  939. clearLEDs();
  940. rightTree.setPixelColor(i, red, green, blue); // Set the bright middle eye
  941. leftTree.setPixelColor(i, red, green, blue); // Set the bright middle eye
  942. // Now set two eyes to each side to get progressively dimmer
  943. for (int j = 1; j < 3; j++)
  944. {
  945. if (i - j >= 0)
  946. leftTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
  947. rightTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
  948. if (i - j <= LED_COUNT)
  949. leftTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
  950. rightTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
  951. }
  952. leftTree.show(); // Turn the LEDs on
  953. rightTree.show(); // Turn the LEDs on
  954. delay(wait); // Delay for visibility
  955. }
  956. // Now we go back to where we came. Do the same thing.
  957. for (int i = LED_COUNT - 2; i >= 1; i--)
  958. {
  959. clearLEDs();
  960. leftTree.setPixelColor(i, red, green, blue);
  961. rightTree.setPixelColor(i, red, green, blue);
  962. for (int j = 1; j < 3; j++)
  963. {
  964. if (i - j >= 0)
  965. leftTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
  966. rightTree.setPixelColor(i - j, red / (weight * j), green / (weight * j), blue / (weight * j));
  967. if (i - j <= LED_COUNT)
  968. leftTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
  969. rightTree.setPixelColor(i + j, red / (weight * j), green / (weight * j), blue / (weight * j));
  970. }
  971. leftTree.show();
  972. rightTree.show();
  973. delay(wait);
  974. }
  975. }
  976. /* Song Easter Egg */
  977. void easterEggSongCheck() {
  978. /* Lets see if we should play a song */
  979. if ( (millis() - lastSongCheck) > (songFrequency * 1000) ) {
  980. lastSongCheck = millis();
  981. if ( (random(0, 1000) < long(songProbability * 1000.0)) ) {
  982. Serial.println("Song probability check approved. Never give up!");
  983. playsong();
  984. } else {
  985. Serial.println("Song probability check declined.");
  986. }
  987. }
  988. }
  989. int frequency(char note)
  990. {
  991. // This function takes a note character (a-g), and returns the
  992. // corresponding frequency in Hz for the tone() function.
  993. int i;
  994. const int numNotes = 8; // number of notes we're storing
  995. // The following arrays hold the note characters and their
  996. // corresponding frequencies. The last "C" note is uppercase
  997. // to separate it from the first lowercase "c". If you want to
  998. // add more notes, you'll need to use unique characters.
  999. // For the "char" (character) type, we put single characters
  1000. // in single quotes.
  1001. char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
  1002. int frequencies[] = {262, 294, 330, 349, 392, 440, 494, 523};
  1003. // Now we'll search through the letters in the array, and if
  1004. // we find it, we'll return the frequency for that note.
  1005. for (i = 0; i < numNotes; i++) // Step through the notes
  1006. {
  1007. if (names[i] == note) // Is this the one?
  1008. {
  1009. return (frequencies[i]); // Yes! Return the frequency
  1010. }
  1011. }
  1012. return (0); // We looked through everything and didn't find it,
  1013. // but we still need to return a value, so return 0.
  1014. }
  1015. void playWinner() {
  1016. /* TODO: Ideally, this is "Enjoy MonkeyBOX", but anything will do */
  1017. /* Also, ideally won't block */
  1018. if(random(0, 10) < 9) {
  1019. playsong();
  1020. } else {
  1021. playsong2();
  1022. }
  1023. Serial.println("Insert winner music here.");
  1024. }
  1025. void startsong() {
  1026. /* TODO: Make this something fancier */
  1027. beep();
  1028. delay(200);
  1029. beep();
  1030. delay(200);
  1031. beep();
  1032. delay(200);
  1033. }
  1034. void buzz() {
  1035. /* play a loud, annoying buzz */
  1036. Serial.println("*BUZZ*");
  1037. tone(buzzerPin, buzzerFrequency, buzzerDuration);
  1038. delay(buzzerDuration);
  1039. }
  1040. void buzz_nonblock() {
  1041. /* play a loud, annoying buzz */
  1042. Serial.println("*BUZZ*");
  1043. tone(buzzerPin, buzzerFrequency, buzzerDuration);
  1044. }
  1045. void beep() {
  1046. /* play a simple, pleasant beep */
  1047. Serial.println("*beep*");
  1048. tone(buzzerPin, beepFrequency, beepDuration);
  1049. delay(beepDuration);
  1050. }
  1051. void beep_nonblock() {
  1052. /* play a simple, pleasant beep, but don't wait for it to finish */
  1053. Serial.println("*beep* (but don't wait for it)");
  1054. tone(buzzerPin, beepFrequency, beepDuration);
  1055. }
  1056. void longbeep() {
  1057. /* play a simple, pleasant beep */
  1058. Serial.println("*beeeeeeeeeeeeeeeeeeeeeeeeeep*");
  1059. tone(buzzerPin, beepFrequency, beepDuration * beepMultiplier);
  1060. /* longbeep doesn't delay. Maybe that's inconsistent */
  1061. /* delay(beepDuration * beepMultiplier); */
  1062. }
  1063. void playsong() {
  1064. /* Plays a song.
  1065. Cut directly from the SparkFun tutorial at
  1066. https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer
  1067. */
  1068. int i, duration;
  1069. for (i = 0; i < songLength; i++) // step through the song arrays
  1070. {
  1071. duration = beats[i] * tempo; // length of note/rest in ms
  1072. if (notes[i] == ' ') // is this a rest?
  1073. {
  1074. delay(duration); // then pause for a moment
  1075. }
  1076. else // otherwise, play the note
  1077. {
  1078. tone(buzzerPin, frequency(notes[i]), duration);
  1079. delay(duration); // wait for tone to finish
  1080. }
  1081. delay(tempo / 10); // brief pause between notes
  1082. }
  1083. }
  1084. void playsong2() {
  1085. /* Plays a song.
  1086. Cut directly from the SparkFun tutorial at
  1087. https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer
  1088. */
  1089. int i, duration;
  1090. for (i = 0; i < songLength2; i++) // step through the song arrays
  1091. {
  1092. duration = beats2[i] * tempo2; // length of note/rest in ms
  1093. if (notes2[i] == ' ') // is this a rest?
  1094. {
  1095. delay(duration); // then pause for a moment
  1096. }
  1097. else // otherwise, play the note
  1098. {
  1099. tone(buzzerPin, frequency(notes2[i]), duration);
  1100. delay(duration); // wait for tone to finish
  1101. }
  1102. delay(tempo2 / 10); // brief pause between notes
  1103. }
  1104. }