//##########################################################################################################################################################################################################################
//### Initialize
//##########################################################################################################################################################################################################################
//MODULE 1 - TIMER
//#############################################################################################################
#include <TM1637Display.h>
#include "pitches.h"
// Pins
#define mod1mod6CLK_PIN 3
#define mod1mod6DIO_PIN 2
TM1637Display mod1Display(mod1mod6CLK_PIN, mod1mod6DIO_PIN);
const int mod1LedPins[] = {4, 5}; // Pins for Strike LEDs
const int mod1ButtonPin = 53; // Pin for error button TESTING
#define mod1SpeakerPin 51
// Timer
const unsigned long mod1CountdownTime = 60; // 5 minutes in seconds
unsigned long mod1StartTime;
unsigned long mod1CurrentTime;
unsigned long mod1ElapsedTime;
//Strikes
int mod1StrikeCount = 0;
//MODULE 2 - WIRES
//#############################################################################################################
const int mod2analogPins[6] = {A1, A2, A3, A4, A5, A6};
const int mod2ledPin = LED_BUILTIN;
const int mod2threshold = 1000; //Threshold to determine if wire is disconnected
// Define constants for wire colors
const int mod2RED = 0;
const int mod2BLUE = 1;
const int mod2WHITE = 2;
const int mod2YELLOW = 3;
const int mod2BLACK = 4;
const int mod2UNKNOWN = 5;
// Define expected analog value ranges for each color with tolerance
const int mod2RED_MIN = 85, mod2RED_MAX = 103;
const int mod2BLUE_MIN = 169, mod2BLUE_MAX = 199;
const int mod2WHITE_MIN = 304, mod2WHITE_MAX = 349;
const int mod2YELLOW_MIN = 485, mod2YELLOW_MAX = 536;
const int mod2BLACK_MIN = 686, mod2BLACK_MAX = 772;
int mod2wireColors[6];
int mod2numberOfWires;
int mod2correctWire = -1;
//MODULE 6 - NEEDY - KNOBS
//#############################################################################################################
//#include <TM1637Display.h> // added in module 1
#include <Adafruit_NeoPixel.h>
// Define pins for WS2812 LED ring
#define mod6LED_PIN 50
#define mod6LED_COUNT 12
// Define pins for 4-digit display
#define mod6CLK_PIN 46
#define mod6DIO_PIN 47
// Create objects for 4-digit display and LED ring
TM1637Display mod6display(mod6CLK_PIN, mod6DIO_PIN);
Adafruit_NeoPixel mod6strip(mod6LED_COUNT, mod6LED_PIN, NEO_GRB + NEO_KHZ800);
// Variables for countdown timer
unsigned long mod6countdownTime;
unsigned long mod6startTime;
bool mod6timerRunning = false;
const int mod6minTimer = 30;
const int mod6maxTimer = 60;
int mod6chosenLedConfig[0][0];
int mod6chosenDirection;
int mod6chosenDirectionPattern;
// LED configurations for rotary encoder positions
// Each pair of configurations corresponds to one of the four positions (up, right, down, left)
const int mod6ledConfigurations[4][2][12] = {
{{0,0,1,0,1,1,1,1,1,1,0,1}, {1,0,1,0,1,0,0,1,1,0,1,1}}, // UP (Example configurations)
{{1,0,1,1,1,1,1,1,1,0,1,0}, {1,0,1,1,0,0,1,1,1,0,1,0}}, // RIGHT
{{0,1,1,0,0,1,1,1,1,1,0,1}, {1,0,1,0,1,0,0,1,0,0,0,1}}, // DOWN
{{0,0,0,0,1,0,1,0,0,1,1,1}, {0,0,0,0,1,0,0,0,0,1,1,0}} // LEFT
};
int mod6configuration[12] = {};
// Position labels
const char* mod6positionLabels[4] = {"UP", "RIGHT", "DOWN", "LEFT"};
//##########################################################################################################################################################################################################################
//### SETUP
//##########################################################################################################################################################################################################################
void setup() {
Serial.begin(9600);
//MODULE 1 - TIMER
mod1Display.setBrightness(7); // Set the brightness of the mod6display (0-7)
mod1Display.clear(); // Clear the display
mod1StartTime = millis(); // Record the starting time
for (int i = 0; i < 2; i++) {
pinMode(mod1LedPins[i], OUTPUT);
}
pinMode(mod1ButtonPin, INPUT_PULLUP);
//MODULE 2 - WIRES
// Initialize wire pins as inputs
pinMode(mod2ledPin, OUTPUT);
// Read initial wire colors
mod2numberOfWires = 0;
for (int mod2i = 0; mod2i < 6; mod2i++) {
int mod2value = analogRead(mod2analogPins[mod2i]);
Serial.print(mod2value);
Serial.print(": ");
if (mod2value < mod2threshold) {
mod2wireColors[mod2numberOfWires] = mod2getColor(mod2value);
Serial.print("Wire ");
Serial.print(mod2numberOfWires);
Serial.print(" color: ");
Serial.println(mod2wireColors[mod2numberOfWires]);
mod2numberOfWires++;
}
}
// Determine which wire to cut
mod2determineCorrectWire();
Serial.print("Number of wires: ");
Serial.println(mod2numberOfWires);
Serial.print("Correct wire to cut: ");
Serial.println(mod2correctWire);
//MODULE 6 - NEEDY - KNOBS
}
//##########################################################################################################################################################################################################################
//### FUNCTIONS
//##########################################################################################################################################################################################################################
//#############################################################################################################
//### MODULE 1 - TIMER
//#############################################################################################################
void mod1UpdateElapsedTime() {
mod1CurrentTime = millis();
mod1ElapsedTime = (mod1CurrentTime - mod1StartTime) / 1000;
}
void mod1HandleCountdown() {
if (mod1ElapsedTime <= mod1CountdownTime) {
unsigned long mod1RemainingTime = mod1CountdownTime - mod1ElapsedTime;
mod1DisplayRemainingTime(mod1RemainingTime);
if (mod1RemainingTime == 0) {
mod1StartBlinking();
}
}
}
void mod1DisplayRemainingTime(unsigned long mod1RemainingTime) {
unsigned int minutes = mod1RemainingTime / 60;
unsigned int seconds = mod1RemainingTime % 60;
mod1Display.showNumberDecEx(minutes * 100 + seconds, 0b01000000, true);
}
void mod1StartBlinking() {
for (int i = 0; i < 10; i++) {
mod1Display.showNumberDecEx(0, 0b01000000, true);
delay(250);
mod1Display.clear();
delay(250);
tone(mod1SpeakerPin, NOTE_E4);
delay(10);
noTone(mod1SpeakerPin);
delay(10);
}
mod1ResetGame();
}
void mod1CheckButtonPress() {
if (digitalRead(mod1ButtonPin) == LOW) {
mod1StrikeCount++;
Serial.println("Strike added!");
mod1UpdateStrikes();
}
}
void mod1AddStrike() {
mod1StrikeCount++;
Serial.println("Strike added!");
mod1UpdateStrikes();
}
void mod1Beep(int times) {
for (int i = 0; i < times; i++) {
tone(mod1SpeakerPin, NOTE_E4);
delay(10);
noTone(mod1SpeakerPin);
delay(10);
}
}
void mod1UpdateStrikes() {
if (mod1StrikeCount >= 3) {
mod1Beep(5);
Serial.println("BOOOOM!");
mod1ResetGame();
} else if (mod1StrikeCount == 2) {
mod1Beep(2);
} else if (mod1StrikeCount == 1) {
mod1Beep(1);
}
for (int i = 0; i < 2; i++) {
digitalWrite(mod1LedPins[i], i < mod1StrikeCount ? HIGH : LOW);
}
}
void mod1ResetGame(){
delay(5000);
mod1StrikeCount = 0;
for (int i = 0; i < 2; i++) {
digitalWrite(mod1LedPins[i], LOW);
}
mod1StartTime = millis();
Serial.println("RESET");
}
//#############################################################################################################
//### MODULE 2 - WIRES
//#############################################################################################################
// Function to map analog values to wire colors
int mod2getColor(int mod2analogValue) {
if (mod2analogValue >= mod2RED_MIN && mod2analogValue <= mod2RED_MAX) return mod2RED;
else if (mod2analogValue >= mod2BLUE_MIN && mod2analogValue <= mod2BLUE_MAX) return mod2BLUE;
else if (mod2analogValue >= mod2WHITE_MIN && mod2analogValue <= mod2WHITE_MAX) return mod2WHITE;
else if (mod2analogValue >= mod2YELLOW_MIN && mod2analogValue <= mod2YELLOW_MAX) return mod2YELLOW;
else if (mod2analogValue >= mod2BLACK_MIN && mod2analogValue <= mod2BLACK_MAX) return mod2BLACK;
else return mod2UNKNOWN;
}
// Function to find the correct wire to cut based on the given rules
void mod2determineCorrectWire() {
int mod2redCount = 0, mod2blueCount = 0, mod2yellowCount = 0, mod2whiteCount = 0, mod2blackCount = 0;
for (int mod2i = 0; mod2i < mod2numberOfWires; mod2i++) {
switch (mod2wireColors[mod2i]) {
case mod2RED: mod2redCount++; break;
case mod2BLUE: mod2blueCount++; break;
case mod2WHITE: mod2whiteCount++; break;
case mod2YELLOW: mod2yellowCount++; break;
case mod2BLACK: mod2blackCount++; break;
default: break;
}
}
// Serial number's last digit (for simplicity, we'll use a fixed value)
int mod2serialLastDigit = 3; // Example serial number's last digit
if (mod2numberOfWires == 3) {
if (mod2redCount == 0) mod2correctWire = 1;
else if (mod2wireColors[2] == mod2WHITE) mod2correctWire = 2;
else if (mod2blueCount > 1) mod2correctWire = 2; // Last blue wire
else mod2correctWire = 2;
}
else if (mod2numberOfWires == 4) {
if (mod2redCount > 1 && mod2serialLastDigit % 2 != 0) mod2correctWire = 3; // Last red wire
else if (mod2wireColors[3] == mod2YELLOW && mod2redCount == 0) mod2correctWire = 0;
else if (mod2blueCount == 1) mod2correctWire = 0;
else if (mod2yellowCount > 1) mod2correctWire = 3;
else mod2correctWire = 1;
}
else if (mod2numberOfWires == 5) {
if (mod2wireColors[4] == mod2BLACK && mod2serialLastDigit % 2 != 0) mod2correctWire = 3;
else if (mod2redCount == 1 && mod2yellowCount > 1) mod2correctWire = 0;
else if (mod2blackCount == 0) mod2correctWire = 1;
else mod2correctWire = 0;
}
else if (mod2numberOfWires == 6) {
if (mod2yellowCount == 0 && mod2serialLastDigit % 2 != 0) mod2correctWire = 2;
else if (mod2yellowCount == 1 && mod2whiteCount > 1) mod2correctWire = 3;
else if (mod2redCount == 0) mod2correctWire = 5;
else mod2correctWire = 3;
}
}
//#############################################################################################################
//### MODULE 6 - NEEDY - KNOBS
//#############################################################################################################
void mod6startGame() {
// Initialize 4-digit display and LED ring
mod6display.setBrightness(0x0f);
mod6strip.begin();
mod6strip.show();
// Seed random number generator
randomSeed(analogRead(A0));
// Start random countdown timer between 30 seconds and 2 minutes
mod6countdownTime = random(mod6minTimer, mod6maxTimer);
mod6startTime = millis();
mod6timerRunning = true;
// Set initial LED mod6configuration
mod6chosenDirection = random(0,4);
mod6chosenDirectionPattern = random(0,2);
Serial.print("Selected config: ");
for (int i = 0; i < 12; i++) {
Serial.print(mod6ledConfigurations[mod6chosenDirection][mod6chosenDirectionPattern][i]);
}
Serial.print(" Orientation: ");
Serial.print(mod6positionLabels[mod6chosenDirection]);
Serial.println();
mod6setLEDConfiguration();
}
// Function to display time on 4-digit display
void mod6displayTime(int seconds) {
int minutes = seconds / 60;
int remainingSeconds = seconds % 60;
mod6display.showNumberDecEx(minutes * 100 + remainingSeconds, 0b01000000, true);
}
// Function to set LED mod6configuration based on current rotary encoder position
void mod6setLEDConfiguration() {
for (int i = 0; i < 12; i++) {
mod6configuration[i] = mod6ledConfigurations[mod6chosenDirection][mod6chosenDirectionPattern][i];
if (mod6configuration[i] == 1) {
mod6strip.setPixelColor(i, mod6strip.Color(255, 255, 255)); // White color
} else {
mod6strip.setPixelColor(i, mod6strip.Color(0, 0, 0)); // Off
}
}
mod6strip.show();
}
//##########################################################################################################################################################################################################################
//### Loop
//##########################################################################################################################################################################################################################
void loop() {
//MODULE 1 - TIMER
//#############################################################################################################
mod1UpdateElapsedTime();
mod1HandleCountdown();
mod1CheckButtonPress();
//MODULE 2 - WIRES
//#############################################################################################################
// Monitor for disconnection of the correct wire
if (mod2correctWire != -1) {
int mod2value = analogRead(mod2analogPins[mod2correctWire]);
if (mod2value > mod2threshold) {
digitalWrite(mod2ledPin, HIGH); // Turn on LED if correct wire is disconnected
} else {
digitalWrite(mod2ledPin, LOW); // Turn off LED otherwise
}
}
delay(100);
//MODULE 6 - NEEDY - KNOBS
//#############################################################################################################
if (mod6timerRunning) {
unsigned long currentTime = millis();
unsigned long elapsedTime = (currentTime - mod6startTime) / 1000;
if (elapsedTime >= mod6countdownTime) {
mod6timerRunning = false;
// Get current and required positions
uint8_t currentPosition = mod6positionLabels[mod6chosenDirection];
// Debug messages
Serial.print("Current Position: ");
Serial.println(mod6positionLabels[currentPosition]);
Serial.print("Required Position: ");
Serial.println(mod6positionLabels[mod6chosenDirection]);
// Check if rotary encoder is in the correct position
if (currentPosition == mod6positionLabels[mod6chosenDirection]) {
// Correct position
mod6display.showNumberDecEx(8888, 0b01000000, true); // Display success indicator (e.g., 8888)
Serial.println("Correct Position!");
} else {
// Incorrect position
mod6display.showNumberDecEx(1111, 0b01000000, true); // Display failure indicator (e.g., 1111)
Serial.println("Incorrect Position!");
mod1AddStrike();
}
} else {
// Update countdown display
mod6displayTime(mod6countdownTime - elapsedTime);
}
} else {
int randomStart = random(0,10000);
delay(100);
Serial.println(randomStart);
if (randomStart == 0) {
mod6startGame();
}
}
}
Loading
grove-oled-sh1107
grove-oled-sh1107