#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include "SevSeg.h"
#include <arduino-timer.h>
// Keypad defines.
const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] = {
{ '1', '2', '3'},
{ '4', '5', '6' },
{ '7', '8', '9' },
{ '*', '0', '#' }
};
uint8_t colPins[COLS] = { 31, 33, 35 };
uint8_t rowPins[ROWS] = { 23, 25, 27, 29 };
// Hardware defines.
LiquidCrystal_I2C LCD(0x27,20,4);
Keypad KEYPAD = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
SevSeg SEVSEG;
// Variables
auto timer = timer_create_default();
int LED_GREEN_PIN = 2;
int LED_RED_PIN = 3;
long DEFUSE_TIME = 0;
int LcdTextLength = 16;
String CODE = "";
String DEFUSE_CODE = "";
int MAX_CODE_LENGTH = 4;
int readDimPinsArray[] = {8,9,10,11};
byte digitPins[] = {32, 30, 28, 26};
byte segmentPins[] = {36, 37, 38, 39, 40, 41, 42};
bool resistorsOnSegments = false; // 'false' means resistors are on digit pins
byte hardwareConfig = COMMON_ANODE; // See README.md for options
// STATE
boolean SETUP_CODE_COMPLETE = false;
boolean SETUP_ARMED_COMPLETE = false;
boolean GAME_END = false;
boolean GAME_FINISHED = false;
boolean BOMB_IS_DEFUSED = false;
boolean BOMB_EXPLODED_OR_DEFUSED = false;
// Text
String TEXT_INPUT_SET_CODE = "SET CODE: ";
String TEXT_RESET_INPUT_CODE = "RESET INPUT...";
String TEXT_INPUT_CODE = "CODE: ";
String TEXT_BOMB_ARMING = "BOMB ARMING";
String TEXT_BOMB_ARMED = "BOMB ARMED";
String TEXT_BOMB_DEFUSED = "BOMB DEFUSED";
String TEXT_EXPLODE = "<<< BOOOOOOM >>> TERRORISTS WIN";
void setText(const String text="set text", boolean clear=true, int position=0, int line=2){
if(clear == true) {
LCD.clear();
LCD.setCursor(0, 0);
};
if(text.length() > LcdTextLength) {
int i = 0;
while (i <= text.length())
{
if(i == LcdTextLength) {
LCD.setCursor(0, 1);
}
LCD.print(text.charAt(i));
i++;
}
} else{
LCD.print(text);
}
}
void setup() {
Serial.begin(9600);
LCD.init();
LCD.backlight();
for (int pin : readDimPinsArray) {
pinMode(pin, INPUT);
if(digitalRead(pin) == HIGH) {
increasePlaytime();
}
}
SEVSEG.begin(hardwareConfig,4, digitPins, segmentPins, resistorsOnSegments, false, false, true);
SEVSEG.setBrightness(90);
pinMode(LED_GREEN_PIN, OUTPUT);
pinMode(LED_RED_PIN, OUTPUT);
pinMode(49, INPUT);
LCD.begin(16, 2);
setText(TEXT_INPUT_SET_CODE, false);
KEYPAD.addEventListener(keypadEvent); //add an event listener for this keypad
// Remove next line
setText(String(DEFUSE_TIME), false);
SEVSEG.setNumber(DEFUSE_TIME,0);
}
void setLedStatus(int pin, uint8_t status=LOW) {
digitalWrite(pin, status);
}
void timerDecrease() {
DEFUSE_TIME = DEFUSE_TIME - 1;
SEVSEG.setNumber(DEFUSE_TIME,0);
if(DEFUSE_TIME == 0){
BOMB_EXPLODED_OR_DEFUSED = true;
return false;
} else {
return true;
}
}
void increasePlaytime() {
DEFUSE_TIME = DEFUSE_TIME + 300;
}
void loop() {
char key = KEYPAD.getKey();
timer.tick();
SEVSEG.refreshDisplay();
// Bomb loop for game end.
if(SETUP_ARMED_COMPLETE == true && BOMB_EXPLODED_OR_DEFUSED == true && GAME_FINISHED == false) {
GAME_FINISHED = true;
timer.cancel();
KEYPAD.addEventListener(nullptr);
if(BOMB_IS_DEFUSED) {
setLedStatus(LED_RED_PIN, LOW);
setLedStatus(LED_GREEN_PIN);
setText(TEXT_BOMB_DEFUSED);
delay(10000);
setLedStatus(LED_GREEN_PIN, LOW);
} else {
setText(TEXT_EXPLODE);
}
}
}
void ledBlinkOnce(int pin, int blinkDelay=500) {
digitalWrite(pin, HIGH);
delay(blinkDelay);
digitalWrite(pin, LOW);
}
void setAndUpdateCode(String codeInput){
CODE = CODE + codeInput;
ledBlinkOnce(LED_GREEN_PIN);
if(CODE.length() == MAX_CODE_LENGTH ){
SETUP_CODE_COMPLETE = true;
setupDefuseStage();
}
}
void setAndUpdateDefuseCode(String codeInput){
DEFUSE_CODE = DEFUSE_CODE + codeInput;
ledBlinkOnce(LED_GREEN_PIN); // todo
if(DEFUSE_CODE == CODE ){
BOMB_IS_DEFUSED = true;
BOMB_EXPLODED_OR_DEFUSED = true;
}
}
void setupDefuseStage(){
int i = 0;
String dots = "";
while(i < 4) {
ledBlinkOnce(LED_RED_PIN);
setText(TEXT_BOMB_ARMING + dots);
i++;
dots.concat(".");
delay(2000);
}
setText(TEXT_BOMB_ARMED);
setLedStatus(LED_RED_PIN, HIGH);
KEYPAD.addEventListener(nullptr);
setupDefuseStageComplete();
}
void setupDefuseStageComplete () {
SETUP_ARMED_COMPLETE = true;
setText(TEXT_INPUT_CODE);
KEYPAD.addEventListener(keypadEventDefuse);
timer.every(1000, timerDecrease);
}
// Keypad for setup.
void keypadEvent(KeypadEvent key){
String keyInput = String(key);
Serial.println("test");
switch (KEYPAD.getState()){
case PRESSED:
setText(keyInput, false);
setAndUpdateCode(keyInput);
break;
case RELEASED:
switch (key){
}
break;
case HOLD:
switch (key){
}
break;
}
}
// Keypad for defuse.
void keypadEventDefuse(KeypadEvent key){
String keyInput = String(key);
switch (KEYPAD.getState()){
case PRESSED:
setText(keyInput, false);
setAndUpdateDefuseCode(keyInput);
break;
case RELEASED:
switch (key){
}
break;
case HOLD:
switch (key){
case '*':
setText(TEXT_RESET_INPUT_CODE);
DEFUSE_CODE = "";
delay(1000);
setText(TEXT_INPUT_CODE);
}
break;
}
}