Created
August 29, 2012 16:31
-
-
Save zuk/3515280 to your computer and use it in GitHub Desktop.
rock_paper_awesome
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #define SERIAL_BAUDRATE 9600 | |
| #define MILLISECONDS_PER_FRAME 30 | |
| // the pins that control the brightness of RED, GREEN, and BLUE LEDs respectively | |
| #define R 9 | |
| #define G 10 | |
| #define B 11 | |
| // pins that receive input for ROCK, PAPER, and SCISSOR | |
| #define PIN_ROCK 3 | |
| #define PIN_PAPER 4 | |
| #define PIN_SCISSORS 5 | |
| // PROTOCOL | |
| // >> incoming messages from node over serialport | |
| #define PROT_ONLINE '@' // you are now online | |
| #define PROT_OFFLINE '#' // you are now offline | |
| #define PROT_NEW_GAME 'N' // sent by node to indicate that we're starting a new game | |
| #define PROT_THEY_CHOSE_ROCK 'R' | |
| #define PROT_THEY_CHOSE_PAPER 'P' | |
| #define PROT_THEY_CHOSE_SCISSORS 'S' | |
| #define PROT_WAITING_FOR_YOU ':' | |
| #define PROT_WAITING_FOR_THEM ';' | |
| #define PROT_YOU_WON '+' | |
| #define PROT_YOU_LOST '-' | |
| #define PROT_TIE '=' | |
| // << outgoing messages to node over serialport | |
| #define PROT_ARDUINO_READY '~' // sent to daemon to signal that the arduino is ready | |
| #define PROT_YOU_CHOSE_ROCK 'r' | |
| #define PROT_YOU_CHOSE_PAPER 'p' | |
| #define PROT_YOU_CHOSE_SCISSORS 's' | |
| #define PROT_READY_FOR_NEW_GAME 'n' // sent to daemon to signal that the arduino is ready for a new game | |
| // states | |
| #define STATE_OFFLINE 0 | |
| #define STATE_WAITING_FOR_EITHER_CHOICE 1 | |
| #define STATE_WAITING_FOR_YOUR_CHOICE 2 | |
| #define STATE_WAITING_FOR_THEIR_CHOICE 3 | |
| #define STATE_WAITING_FOR_GAME_OVER_CONFIRMATION 4 | |
| // LED modes | |
| #define LED_MODE_STEADY 0 | |
| #define LED_MODE_FADE 1 | |
| #define LED_MODE_BLINK 2 | |
| #define LED_MODE_PULSATE 3 | |
| char state = STATE_OFFLINE; | |
| char yourChoice = NULL; | |
| char theirChoice = NULL; | |
| // set to true once the choice has been reset -- used to prevent double-triggering when button is held down | |
| bool choiceWasReset = false; | |
| long frameCount = 0; | |
| byte cR, cG, cB; // current values of the red, green, and blue LEDs | |
| byte tR, tG, tB; // target values of the LEDs (when fading/blinking/pulsating) | |
| int rR, rG, rB = 0; // rate at which the LEDs should change per frame (has different meaning for fading, pulsating, and blinking) | |
| byte mR, mG, mB = LED_MODE_STEADY; // the current mode for each LED (steady, fading, blinking, pulsating, etc.) | |
| void setup() { | |
| pinMode(R, OUTPUT); | |
| pinMode(G, OUTPUT); | |
| pinMode(B, OUTPUT); | |
| digitalWrite(PIN_ROCK, LOW); | |
| digitalWrite(PIN_PAPER, LOW); | |
| digitalWrite(PIN_SCISSORS, LOW); | |
| pinMode(PIN_ROCK, INPUT); | |
| pinMode(PIN_PAPER, INPUT); | |
| pinMode(PIN_SCISSORS, INPUT); | |
| setRGB(0,0,0); | |
| Serial.begin(SERIAL_BAUDRATE); | |
| Serial.print(PROT_ARDUINO_READY); // tell the daemon that we're ready | |
| } | |
| void loop() { | |
| if (millis() % MILLISECONDS_PER_FRAME == 0) { | |
| rgbFrame(); | |
| frameCount++; | |
| // TODO: use interrupt timer for this instead | |
| // (see http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/ | |
| // and http://www.arduino.cc/playground/code/timer1) | |
| } | |
| if (state == STATE_WAITING_FOR_EITHER_CHOICE || state == STATE_WAITING_FOR_YOUR_CHOICE) { | |
| if (digitalRead(PIN_ROCK) == HIGH) | |
| youChose(PROT_YOU_CHOSE_ROCK); | |
| else if (digitalRead(PIN_PAPER) == HIGH) | |
| youChose(PROT_YOU_CHOSE_PAPER); | |
| else if (digitalRead(PIN_SCISSORS) == HIGH) | |
| youChose(PROT_YOU_CHOSE_SCISSORS); | |
| } else if (state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION) { | |
| if (digitalRead(PIN_ROCK) == LOW && yourChoice == PROT_YOU_CHOSE_ROCK | |
| || digitalRead(PIN_PAPER) == LOW && yourChoice == PROT_YOU_CHOSE_PAPER | |
| || digitalRead(PIN_SCISSORS) == LOW && yourChoice == PROT_YOU_CHOSE_SCISSORS) { | |
| choiceWasReset = true; | |
| } | |
| if (choiceWasReset && (digitalRead(PIN_ROCK) == HIGH || digitalRead(PIN_PAPER) == HIGH || digitalRead(PIN_SCISSORS))) { | |
| choiceWasReset = false; | |
| readyForNewGame(); | |
| } | |
| } | |
| if (Serial.available() > 0) { | |
| in(Serial.read()); | |
| } | |
| } | |
| // called for each incoming character from the serialport | |
| void in(char c) { | |
| switch (c) { | |
| case PROT_ONLINE: | |
| online(); | |
| break; | |
| case PROT_OFFLINE: | |
| offline(); | |
| break; | |
| case PROT_THEY_CHOSE_ROCK: | |
| case PROT_THEY_CHOSE_PAPER: | |
| case PROT_THEY_CHOSE_SCISSORS: | |
| theyChose(c); | |
| break; | |
| case PROT_WAITING_FOR_YOU: | |
| waitingForYou(); | |
| break; | |
| case PROT_WAITING_FOR_THEM: | |
| waitingForThem(); | |
| break; | |
| case PROT_YOU_WON: | |
| youWin(); | |
| break; | |
| case PROT_YOU_LOST: | |
| youLose(); | |
| break; | |
| case PROT_TIE: | |
| tie(); | |
| break; | |
| case PROT_NEW_GAME: | |
| tie(); | |
| break; | |
| } | |
| } | |
| // called when online | |
| void online() { | |
| pulsate(25, 150, &tG, &rG, &mG); | |
| state = STATE_WAITING_FOR_EITHER_CHOICE; | |
| } | |
| // called when offline | |
| void offline() { | |
| pulsate(20, 150, &tR, &rR, &mR); | |
| state = STATE_OFFLINE; | |
| } | |
| // called when you chose rock, paper, or scissors | |
| void youChose(char choice) { | |
| yourChoice = choice; | |
| switch(choice) { | |
| case PROT_YOU_CHOSE_ROCK: | |
| setR(255); | |
| break; | |
| case PROT_YOU_CHOSE_PAPER: | |
| setG(255); | |
| break; | |
| case PROT_YOU_CHOSE_SCISSORS: | |
| setB(255); | |
| break; | |
| } | |
| Serial.print(choice); | |
| } | |
| // called when they chose rock, paper, or scissors | |
| void theyChose(char choice) { | |
| theirChoice = choice; | |
| } | |
| // called when waiting for you to make a choice | |
| void waitingForYou() { | |
| setG(0); | |
| blink(255, 10, &tG, &rG, &mG); | |
| } | |
| // called when waiting for them to make a choice | |
| void waitingForThem() { | |
| setB(0); | |
| pulsate(255, 250, &tB, &rB, &mB); | |
| } | |
| void youWin() { | |
| pulsate(255, 5, &tG, &rG, &mG); | |
| state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION; | |
| } | |
| void youLose() { | |
| pulsate(255, 5, &tR, &rR, &mR); | |
| state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION; | |
| } | |
| void tie() { | |
| pulsate(100, 5, &tG, &rG, &mG); | |
| pulsate(100, 5, &tR, &rR, &mR); | |
| state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION; | |
| } | |
| void readyForNewGame() { | |
| Serial.print(PROT_READY_FOR_NEW_GAME); | |
| } | |
| void newGame() { | |
| theirChoice = NULL; | |
| yourChoice = NULL; | |
| state = STATE_WAITING_FOR_EITHER_CHOICE; | |
| // TODO: do some blinky stuff here | |
| //delay(2000); // wait 2 seconds before listening for other signals... otherwise we might catch a button held down too long | |
| } | |
| // called whenever a "frame" for red, green, and blue leds should be rendered | |
| void rgbFrame() { | |
| char state[32]; | |
| sprintf(state, "c:%02x%02x%02x t:%02x%02x%02x r:%02x%02x%02x m:%02x%02x%02x", // current target rate mode | |
| cR, cG, cB, tR, tG, tB, rR, rG, rB, mR, mG, mB); | |
| Serial.println(state); | |
| frame(R, &cR, &tR, &rR, &mR); | |
| frame(G, &cG, &tG, &rG, &mG); | |
| frame(B, &cB, &tB, &rB, &mB); | |
| } | |
| // called to render a frame for any one of the leds | |
| // led: the LED pin we're rendering a frame for | |
| // *current: reference to a c_ variable | |
| // *target: reference to a t_ variable | |
| // *rate: reference to a r_ variable | |
| // *mode: reference to a m_ variable | |
| void frame(int led, byte *current, byte *target, int *rate, byte *mode) { | |
| switch (*mode) { | |
| case LED_MODE_STEADY: | |
| if (*current != *target) | |
| *current = *target; | |
| break; | |
| case LED_MODE_BLINK: | |
| if ((frameCount % (*rate * 2)) > *rate) | |
| *current = *target; | |
| else | |
| *current = 0; | |
| analogWrite(led, *current); | |
| break; | |
| case LED_MODE_FADE: | |
| if (*current == *target) | |
| return; | |
| else if (*current < *target) | |
| *current = ((*current + *rate) > *target) ? *target : *current + *rate; | |
| else if (*current > *target) | |
| *current = ((*current - *rate) < *target) ? *target : *current - *rate; | |
| analogWrite(led, convertRGBval(*current)); | |
| break; | |
| case LED_MODE_PULSATE: | |
| float val = (frameCount % *rate) / (float) *rate; | |
| *current = (*target / 2) + ((*target / 2.0) * sin(val * 2.0 * PI)); | |
| analogWrite(led, convertRGBval(*current)); | |
| break; | |
| } | |
| } | |
| // does any necessary transformation from a LED value to the value that should be written to the pin (using analogWrite) | |
| byte convertRGBval(byte val) { | |
| // due to the way my LEDs are wired, my pin values are inverted, so for me 0 == maximum, 255 == minimum | |
| // get rid of the "255-" for yours to revert to normal usage | |
| return 255-val; | |
| } | |
| // immediatley set the RED led to the given brightness; sets the mode to LED_MODE_STEADY | |
| void setR(byte val) { | |
| analogWrite(R, convertRGBval(val)); | |
| cR = val; | |
| tR = val; | |
| mR = LED_MODE_STEADY; | |
| } | |
| // immediatley set the GREEN led to the given brightness; sets the mode to LED_MODE_STEADY | |
| void setG(byte val) { | |
| analogWrite(G, convertRGBval(val)); | |
| cG = val; | |
| tG = val; | |
| mG = LED_MODE_STEADY; | |
| } | |
| // immediatley set the BLUE led to the given brightness; sets the mode to LED_MODE_STEADY | |
| void setB(byte val) { | |
| analogWrite(B, convertRGBval(val)); | |
| cB = val; | |
| tB = val; | |
| mB = LED_MODE_STEADY; | |
| } | |
| // immediatley set the RED, GREEN, and BLUE leds to the given brightness; sets their modes to LED_MODE_STEADY | |
| void setRGB(byte r, byte g, byte b) { | |
| setR(r); setG(g); setB(b); | |
| } | |
| // fade the given pin to the given value at the specified rate | |
| // to: value that we should fade towards | |
| // rate: rate that we should fade at (higher rate means faster fade) | |
| // *t: reference to the t_ variable for the LED we want to fade | |
| // *r: reference to the r_ variable for the LED we want to fade | |
| // *m: reference to the m_ variable for the LED we want to fdae | |
| void fade(byte to, int rate, byte *t, int *r, byte *m) { | |
| *t = to; | |
| *r = rate; | |
| *m = LED_MODE_FADE; | |
| } | |
| // pulsate the given pin at the specified rate | |
| // max: the maximum brightness for the pulse (minimum is always 0) | |
| // period: the speed at which we should pulsate (higher period means slower pulse) | |
| // *t: reference to the t_ variable for the LED we want to pulsate | |
| // *r: reference to the r_ variable for the LED we want to pulsate | |
| // *m: reference to the m_ variable for the LED we want to pulsate | |
| void pulsate(byte max, int rate, byte *t, int *r, byte *m) { | |
| *t = max; | |
| *r = rate; | |
| *m = LED_MODE_PULSATE; | |
| } | |
| // blink the given pin tat the specified rate | |
| // max: the maximum brightness -- i.e. the "on" value ("off" value is always 0) | |
| // rate: rate that we should blink at (higher rate means faster blinking) | |
| // *t: reference to the t_ variable for the LED we want to blink | |
| // *r: reference to the r_ variable for the LED we want to blink | |
| // *m: reference to the m_ variable for the LED we want to blink | |
| void blink(byte max, int rate, byte *t, int *r, byte *m) { | |
| *t = max; | |
| *r = rate; | |
| *m = LED_MODE_BLINK; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment