/* Brainuino Aleph Copyright (C) 2011-2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "pinout.h" #include "game.h" #include "lcdprint.h" void ask(void); answer_t discuss(uint16_t); answer_t answer(uint8_t); void falseStart(uint8_t); void refresh(void); void printState(const char*); void printState(const __FlashStringHelper*); void printTime(void); void printPreciseTime(void); void readButton(void); void pinInit(void); void printGameType(void); void printPlayer(uint8_t); LiquidCrystal lcd(LCD4, LCD6, LCD11, LCD12, LCD13, LCD14); void setup() { lcd.begin(16, 2); pinInit(); time = 0; // TODO: the following settings should be readen from EEPROM gameType = SI; withFalseStart = false; timer1 = 5; timer2 = 5; preSignal = 0; } void loop() { buttonPressed = 0; startTime = 0; // timer = timer1; printGameType(); // ensure that stop button is released while (digitalRead(CONTROL2) == LOW) { delay(20); } ask(); } // ask() - wait until start button is pressed, then run timer // the question should be asked at this time void ask() { digitalWrite(GREENLAMP, LOW); digitalWrite(REDLAMP, LOW); #ifdef RUSSIAN printState(F("Задаётся вопрос ")); #else printState(F("Asking question ")); #endif while (true) { if (buttonPressed) { if (withFalseStart) { falseStart(buttonPressed); } else { answer(buttonPressed); } } if (digitalRead(CONTROL1) == LOW) { // start button is pressed if (discuss(timer1) == WRONG) { while (discuss(timer2) == WRONG) {} } return; } if (digitalRead(CONTROL2) == LOW) { // stop button is pressed return; } delay(100); } } // discuss() - start timer and wait for button being pressed // here teams can discuss question or single players think themselves answer_t discuss(uint16_t timer) { answer_t reply = NOREPLY; // is random delay needed here when playing with false starts? unsure... // reset timer or continue count if (timer > 0) { time = 0; startTime = millis(); } else { startTime = millis() - time; } // we need sound signal here only if we are playing with false starts // or am i wrong? if (withFalseStart) tone(SPEAKER, 3000, 1000); digitalWrite(GREENLAMP, HIGH); digitalWrite(REDLAMP, LOW); printGameType(); #ifdef RUSSIAN printState(F("Отсчёт: ")); #else printState(F("Count: ")); #endif while (!buttonPressed && time < (timer - preSignal) * 1000) { refresh(); delay(25); if (digitalRead(CONTROL2) == LOW) { tone(SPEAKER, 1500, 500); return reply; } } if (!buttonPressed) tone(SPEAKER, 2121, 1000); while (!buttonPressed && time < timer * 1000) { refresh(); delay(25); if (digitalRead(CONTROL2) == LOW) { tone(SPEAKER, 1784, 500); return reply; } } // the time is out or someone pressed a button... hmm... if (buttonPressed) { reply = answer(buttonPressed); } else { tone(SPEAKER, 3000, 1000); } if (reply != WRONG) { digitalWrite(GREENLAMP, LOW); digitalWrite(REDLAMP, LOW); startTime = 0; delay(1000); } return reply; } // answer() - wait while the answer is given // return answer correctness answer_t answer(uint8_t num) { digitalWrite(REDLAMP, HIGH); // if (timer2 > 0) // timer = timer2; printPlayer(num); #ifdef RUSSIAN printState(F("Ответ ")); #else printState(F("Answer ")); #endif printPreciseTime(); tone(SPEAKER, 2523, 1000); buttonPressed = 0; // a pause is needed to release start button, if it was not yet delay(2000); while (true) { // if start button was pressed if (digitalRead(CONTROL1) == LOW) { buttonPressed = 0; return WRONG; } // if stop button was pressed if (digitalRead(CONTROL2) == LOW) { buttonPressed = 0; return CORRECT; } delay(100); } } // falseStart() - display false start message void falseStart(uint8_t num) { tone(SPEAKER, 1784, 1000); digitalWrite(REDLAMP, HIGH); #ifdef RUSSIAN printState(F(" Фальстарт ")); #else printState(F(" False start ")); #endif printPlayer(num); delay(3000); digitalWrite(REDLAMP, LOW); return; } // refresh() - display current timer state void refresh() { time = millis() - startTime; printTime(); } // printState() - display string in the beginning of LCD second row void printState(const char *state) { lcd.setCursor(0, 1); uprint(state, &lcd); } // printState() variant getting strings stored in flash void printState(const __FlashStringHelper *state) { lcd.setCursor(0, 1); uprint(state, &lcd); } // printTime() - display time passed since timer was started void printTime() { char s[4]; lcd.setCursor(8, 1); itoa(time/1000, s, 10); uprint(s, &lcd); uprint(".", &lcd); itoa(time%1000/100, s, 10); uprint(s, &lcd); } // printPreciseTime() - display time passed since timer was started // or that it was not started yet void printPreciseTime() { char s[5]; uint16_t ms; lcd.setCursor(8, 1); if (startTime > 0) { // timer was started time = millis()-startTime; itoa(time/1000, s, 10); uprint(s, &lcd); uprint(".", &lcd); ms = time%1000; if (ms < 100) { uprint("0", &lcd); if (ms < 10) uprint("0", &lcd); } itoa(ms, s, 10); uprint(s, &lcd); } else { // timer was not started yet #ifdef RUSSIAN uprint(F("досрочно"), &lcd); #else uprint(F("prematur"), &lcd); #endif } } // readButton() - scan buttons void readButton() { if (buttonPressed > 0 || gameType == CHGK) return; if (digitalRead(BUTTON1) == LOW) { buttonPressed = 1; return; } if (digitalRead(BUTTON2) == LOW) { buttonPressed = 2; return; } if (digitalRead(BUTTON3) == LOW) { buttonPressed = 3; return; } if (digitalRead(BUTTON4) == LOW) { buttonPressed = 4; return; } } // pinInit() - Arduino I/O initialization, needed on startup only void pinInit() { digitalWrite(2, HIGH); digitalWrite(3, HIGH); digitalWrite(BUTTON1, HIGH); digitalWrite(BUTTON2, HIGH); digitalWrite(BUTTON3, HIGH); digitalWrite(BUTTON4, HIGH); digitalWrite(CONTROL1, HIGH); digitalWrite(CONTROL2, HIGH); digitalWrite(ENCPUSH, HIGH); pinMode(GREENLAMP, OUTPUT); pinMode(REDLAMP, OUTPUT); pinMode(SPEAKER, OUTPUT); attachInterrupt(0, readButton, FALLING); } // printGameType() - display game title on LCD void printGameType() { lcd.setCursor(0, 0); switch (gameType) { case BRAIN: #ifdef RUSSIAN uprint(F(" Брейн-ринг "), &lcd); #else uprint(F(" Brain-ring "), &lcd); #endif break; case SI: #ifdef RUSSIAN uprint(F(" Своя игра "), &lcd); #else uprint(F(" Jeopardy "), &lcd); #endif break; case CHGK: #ifdef RUSSIAN uprint(F("Что? Где? Когда?"), &lcd); #else uprint(F("What?Where?When?"), &lcd); #endif break; } } // printPlayer() - display number of player or team void printPlayer(uint8_t num) { char nums[2]; itoa(num, nums, 10); lcd.setCursor(0, 0); switch (gameType) { case BRAIN: #ifdef RUSSIAN uprint(F("Команда "), &lcd); uprint(nums, &lcd); uprint(F(" "), &lcd); #else uprint(F("Team "), &lcd); uprint(nums, &lcd); uprint(F(" "), &lcd); #endif break; case SI: #ifdef RUSSIAN uprint(F("Игрок "), &lcd); uprint(nums, &lcd); uprint(F(" "), &lcd); #else uprint(F("Player "), &lcd); uprint(nums, &lcd); uprint(F(" "), &lcd); #endif break; default: break; } buttonPressed = 0; }