aboutsummaryrefslogtreecommitdiff
path: root/puzzle/vault/main.cpp
blob: 76e5f659bc1b2e7925703f8642e163b3dbea07bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <Arduino.h>
#include <Wire.h>
#include <TM1637Display.h>

#define TOTAL_LEVELS 5
#define ROWS 4
#define COLS 3
#define CLK 2
#define DIO 3
#define SOLVED_PIN 53
#define I2C_MODULE_ADDRESS 0x08  // Address of the puzzle module
#define HANDSHAKE_RECEIVED {0x70, 0x75, 0x7a, 0x62, 0x75, 0x73}   // Magic command for the handshake
#define HANDSHAKE_SEND {0x67, 0x61, 0x6d, 0x69, 0x6e, 0x67}      // Magic command for the handshake
#define REQUEST_STATE_CMD 0x53  // 'S' to request the game state

const int ROW_PINS[ROWS] = {7, 6, 5, 4};
const int COL_PINS[COLS] = {10, 9, 8};
const char* validButtons[TOTAL_LEVELS] = {"A2", "B1", "D3", "C2", "C3"};
const char bombCode[] = "1234";

TM1637Display display(CLK, DIO);

typedef enum {
    STATE_UNINITIALIZED = 0x00,
    STATE_RESET = 0x01,
    STATE_PLAYING = 0x02,
    STATE_SOLVED = 0x03,
    STATE_ERROR = 0x04
} PuzzleState;

PuzzleState puzzleState = STATE_UNINITIALIZED;
int currentLevel = 0;

void requestEvent() {
    if (puzzleState == STATE_PLAYING) {
        uint8_t responseData[] = HANDSHAKE_SEND;
        Wire.write(responseData, sizeof(responseData));
        Serial.println("Handshake response sent.");
    }
}

void blink_display(char num) {
    while(puzzleState == STATE_UNINITIALIZED || puzzleState == STATE_ERROR) {
        display.showNumberDecEx(0, 0b11111111, true); // Display "0000" with all digits on
        delay(500);
        display.clear();
        delay(500);
    }
}

void display_final_code(const char* code) {
    uint8_t segs[4] = {0, 0, 0, 0}; 
    int numDigits = strlen(code);   
    numDigits = numDigits > 4 ? 4 : numDigits; 

    for (int i = 0; i < numDigits; i++) {
        segs[i] = display.encodeDigit(code[i] - '0');
    }

    display.setSegments(segs, numDigits, 0);
}

void check_button_press() {
    for (int col = 0; col < COLS; col++) {
        digitalWrite(COL_PINS[col], LOW);
        for (int row = 0; row < ROWS; row++) {
            if (digitalRead(ROW_PINS[row]) == LOW) {
                delay(50);
                if (digitalRead(ROW_PINS[row]) == LOW) {
                    char keyPress[3] = {'A' + row, '1' + col, '\0'};
                    Serial.print("Keypress detected: ");
                    Serial.println(keyPress);
                    if (strcmp(keyPress, validButtons[currentLevel]) == 0) {
                        currentLevel++;
                        if (currentLevel >= TOTAL_LEVELS) {
                            puzzleState = STATE_SOLVED;
                            Serial.println("Puzzle solved!");
                            display.showNumberDec(currentLevel + 1, true);
                            digitalWrite(SOLVED_PIN, HIGH);
                        } else {
                            puzzleState = STATE_PLAYING;
                        }
                    } else {
                        currentLevel = 0;
                    }
                    while (digitalRead(ROW_PINS[row]) == LOW) {} // Ensure button release
                }
            }
        }
        digitalWrite(COL_PINS[col], HIGH);
    }
}

void initialize_system() {
    for (int i = 0; i < ROWS; i++) {
        pinMode(ROW_PINS[i], INPUT_PULLUP);
    }
    for (int i = 0; i < COLS; i++) {
        pinMode(COL_PINS[i], OUTPUT);
        digitalWrite(COL_PINS[i], HIGH);
    }
    Serial.println("GPIO and display initialized.");
}

void receiveEvent(int howMany) {
    if (howMany == 6) {
        uint8_t expectedBytes[] = HANDSHAKE_RECEIVED;
        uint8_t receivedBytes[6];
        bool match = true;

        for (int i = 0; i < 6; i++) {
            receivedBytes[i] = Wire.read();
            if (receivedBytes[i] != expectedBytes[i]) {
                match = false;
                break;
            }
        }

        if (match) {
            Serial.println("Correct handshake data received.");
            puzzleState = STATE_PLAYING;
            initialize_system();
        } else {
            Serial.println("Incorrect handshake data received.");
            puzzleState = STATE_ERROR;
        }
    } else {
        Serial.print("Received wrong number of bytes: ");
        Serial.println(howMany);
        puzzleState = STATE_ERROR;
    }
}


void setup() {
    Serial.begin(115200);
    pinMode(SOLVED_PIN, OUTPUT);
    digitalWrite(SOLVED_PIN, LOW);
    display.setBrightness(0x0f);

    Wire.begin(I2C_MODULE_ADDRESS);
    Wire.onRequest(requestEvent);
    Wire.onReceive(receiveEvent);

    // Initialize display with blinking zeros to indicate no connection or initialization state
    blink_display('0');
}

void loop() {
    switch(puzzleState) {
        case STATE_PLAYING:
            check_button_press();
            delay(100);
            break;
        case STATE_SOLVED:
            display_final_code(bombCode);
            digitalWrite(SOLVED_PIN, HIGH);
            Serial.println("Final display shown. Puzzle complete.");
            break;
        case STATE_ERROR:
        case STATE_UNINITIALIZED:
            blink_display('0');
            break;
    }
}