#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <TM1637Display.h>
#include <Keypad.h>
// OLED Display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// TM1637 Display
#define CLK 18
#define DIO 5
TM1637Display tmDisplay(CLK, DIO);
// Keypad
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {12, 13, 14, 27};
byte colPins[COLS] = {26, 25, 33, 32};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// LED Pins
#define COUNTDOWN_LED 4
#define RGB_RED 16
#define RGB_GREEN 17
#define RGB_BLUE 23
// Buzzer
#define BUZZER_PIN 19
// Fili taglio
#define WIRE1_PIN 34
#define WIRE2_PIN 35
#define WIRE3_PIN 36
#define WIRE4_PIN 39
#define WIRE5_PIN 15
// Variabili
String disarmCode = "";
String inputCode = "";
int countdownMinutes = 0;
int countdownSeconds = 0;
unsigned long countdownTime = 0;
unsigned long previousMillis = 0;
bool countdownActive = false;
int wrongAttempts = 0;
int wireCutAttempts = 0;
bool bombDisarmed = false;
//int wireOrder[5] = {WIRE3_PIN, WIRE1_PIN, WIRE5_PIN, WIRE2_PIN, WIRE4_PIN};
int wireStep = 0;
// Prototipi
void setRGBColor(bool r, bool g, bool b);
void displayMessage(String riga1, String riga2);
void startCountdown();
void updateCountdown();
void triggerExplosion();
void disarmBomb();
void handleWrongAttempt();
void handleWireCut(bool correct);
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 fallita"));
for(;;);
}
display.clearDisplay();
display.display();
tmDisplay.setBrightness(0x0f);
tmDisplay.showNumberDec(0, true);
pinMode(COUNTDOWN_LED, OUTPUT);
pinMode(RGB_RED, OUTPUT);
pinMode(RGB_GREEN, OUTPUT);
pinMode(RGB_BLUE, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(WIRE1_PIN, INPUT_PULLUP);
pinMode(WIRE2_PIN, INPUT_PULLUP);
pinMode(WIRE3_PIN, INPUT_PULLUP);
pinMode(WIRE4_PIN, INPUT_PULLUP);
pinMode(WIRE5_PIN, INPUT_PULLUP);
// Modalità programmazione
setRGBColor(true, false, false); // Rosso
displayMessage("MODALITA' SETUP", "Inserisci CODICE:");
Serial.println("Modalità Setup inserisci CODE: ");
while(disarmCode.length() < 4) {
char key = keypad.getKey();
if(key) {
disarmCode += key;
displayMessage("CODICE:", String(disarmCode.length(), '*'));
Serial.print(key);
digitalWrite(RGB_BLUE, HIGH);
delay(100);
digitalWrite(RGB_BLUE, LOW);
}
}
Serial.println();
displayMessage("INSERISCI TEMPO", "(mmss es. 0300)");
Serial.println("Inserisci tempo (mmss es. 0300): ");
String timeInput = "";
while(timeInput.length() < 4) {
char key = keypad.getKey();
if(key) {
timeInput += key;
displayMessage("TEMPO:", timeInput);
Serial.print(key);
digitalWrite(RGB_BLUE, HIGH);
delay(100);
digitalWrite(RGB_BLUE, LOW);
}
}
Serial.println();
countdownMinutes = timeInput.substring(0,2).toInt();
countdownSeconds = timeInput.substring(2,4).toInt();
countdownTime = (countdownMinutes * 60 + countdownSeconds) * 1000;
displayMessage("SETUP COMPLETATO", "Premi # per avvio");
Serial.println("Setup completo premi # per avvio");
while (true) {
char key = keypad.getKey();
if (key == '#') {
// Aspetta che il tasto venga rilasciato
while (keypad.getKey() == '#');
delay(200); // Anti-rimbalzo
break;
Serial.println("# premuto");
}
}
displayMessage("INSERISCI CODICE", String(inputCode.length(), '*'));
// Svuota eventuali tasti residui
while (keypad.getKey()); // attende finché tutti i tasti sono rilasciati
setRGBColor(false, false, false); // Tutti spenti
startCountdown();
}
void loop() {
if(countdownActive && !bombDisarmed) {
updateCountdown();
char key = keypad.getKey();
if(key) {
inputCode += key;
displayMessage("INSERISCI CODICE", String(inputCode.length(), '*'));
Serial.println("Inserisci codice: " + inputCode);
digitalWrite(RGB_BLUE, HIGH);
delay(100);
digitalWrite(RGB_BLUE, LOW);
if(inputCode.length() == disarmCode.length()) {
if(inputCode == disarmCode) {
disarmBomb();
} else {
handleWrongAttempt();
}
inputCode = "";
}
}
// Controllo taglio fili
/*for (int i = 0; i < 5; i++) {
int pin = wireOrder[i];
if (digitalRead(pin) == LOW && wireStep == i) {
wireStep++;
delay(500);
if (wireStep == 5) {
disarmBomb();
}
} else if (digitalRead(pin) == LOW && wireStep != i) {
handleWireCut(false);
delay(500);
}
}*/
}
}
void setRGBColor(bool r, bool g, bool b) {
digitalWrite(RGB_RED, r);
digitalWrite(RGB_GREEN, g);
digitalWrite(RGB_BLUE, b);
}
void displayMessage(String riga1, String riga2) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println(riga1);
display.setCursor(0,10);
display.println(riga2);
display.display();
}
void startCountdown() {
countdownActive = true;
previousMillis = millis();
}
void updateCountdown() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
if(countdownTime >= 1000) {
countdownTime -= 1000;
int totalSeconds = countdownTime / 1000;
int minutes = totalSeconds / 60;
int seconds = totalSeconds % 60;
tmDisplay.showNumberDecEx(minutes * 100 + seconds, 0b01000000, true);
digitalWrite(COUNTDOWN_LED, !digitalRead(COUNTDOWN_LED));
tone(BUZZER_PIN, 1000, 100);
} else {
triggerExplosion();
}
}
}
void triggerExplosion() {
countdownActive = false;
displayMessage("!!! ESPLOSO !!!", "BOOM!!!");
Serial.println("!!! ESPLOSO !!!");
setRGBColor(true, false, false);
while(true) {
digitalWrite(BUZZER_PIN, HIGH);
delay(4000);
digitalWrite(BUZZER_PIN, LOW);
delay(500);
}
}
void disarmBomb() {
countdownActive = false;
bombDisarmed = true;
displayMessage("DISINNESCATA", "Complimenti!");
Serial.println("BOMBA DISINNESCATA");
setRGBColor(false, true, false);
tmDisplay.showNumberDec(0, true);
}
void handleWrongAttempt() {
wrongAttempts++;
if(wrongAttempts == 1) {
countdownTime /= 2;
displayMessage("Codice ERRATO!", "Tempo dimezzato");
Serial.println("Codice ERRATO!");
} else if(wrongAttempts == 2) {
countdownTime /= 3;
displayMessage("Errore 2x!", "Countdown x3");
} else {
triggerExplosion();
}
}
void handleWireCut(bool correct) {
wireCutAttempts++;
if(wireCutAttempts == 1) {
countdownTime /= 2;
displayMessage("Filo ERRATO!", "Tempo dimezzato");
Serial.println("Filo ERRATO!");
} else if(wireCutAttempts == 2) {
countdownTime /= 3;
displayMessage("Errore FILO!", "Countdown x3");
} else {
triggerExplosion();
}
}