aboutsummaryrefslogtreecommitdiff
path: root/puzzle/vault/main.cpp
blob: 2e4cafca0b628c373ec78b340fb6d926666c5d89 (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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#include <Arduino.h>
#include <TM1637Display.h>
#include "lib/pbdrv/pb-types.h"
#include "lib/pbdrv/pb-mod.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";
const uint8_t SEGMENT_MAP[] = {
    0b00111111, // 0
    0b00000110, // 1
    0b01011011, // 2
    0b01001111, // 3
    0b01100110, // 4
    0b01101101, // 5
    0b01111101, // 6
    0b00000111, // 7
    0b01111111, // 8
    0b01101111, // 9
    0b01110111, // A
    0b01111100, // B
    0b00111001, // C
    0b01011110, // D
    0b01111001, // E
    0b01110001  // F
    // Add other letters if needed
};

// This array of level codes matches the codes you might display per level.
const char* levelCodes[TOTAL_LEVELS] = {"A1", "B2", "D1", "C3", "A2"};


// Puzzle state
pb_global_state_t puzzleState = PB_GS_NOINIT;

TM1637Display display(CLK, DIO);

int currentLevel = 0;

void blink_display(int num) {
    if (num == 1) {
        // Display "1111" with leading zeros shown if necessary
        display.showNumberDecEx(1111, 0b11111111, true);
    } else if (num == 0) {
        // Display "0000" with leading zeros shown if necessary
        display.showNumberDecEx(0, 0b11111111, true);
    }
    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) {
                            pb_hook_mod_state_write(PB_GS_SOLVED);
                            Serial.println("Puzzle solved!");
                            display.showNumberDec(currentLevel + 1, true);
                            digitalWrite(SOLVED_PIN, HIGH);
                        }
                    } 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 display_code_for_level(int level) {
    char code[3] = {0}; // Temp storage for level code
    strncpy(code, levelCodes[level], 2); // Copy the level-specific code

    uint8_t segs[4] = {0}; // Segments to send to the display

    // Check if the first character is a letter and map it
    if (isalpha(code[0])) {
        if (code[0] >= 'A' && code[0] <= 'F') {
            segs[0] = SEGMENT_MAP[code[0] - 'A' + 10]; // Maps A-F to their segment patterns
        } else {
            // Handle unexpected characters or extend SEGMENT_MAP for more letters
            segs[0] = 0; // Display nothing for undefined letters
        }
    } else {
        // Assume it's a number and map directly
        segs[0] = SEGMENT_MAP[code[0] - '0'];
    }

    // Check if the second character is a digit and map it
    if (isdigit(code[1])) {
        segs[1] = SEGMENT_MAP[code[1] - '0'];
    } else {
        // Handle unexpected characters
        segs[1] = 0; // Display nothing for undefined digits
    }

    // Set only the first two segments, leave others blank
    display.setSegments(segs, 2, 0); // Display on leftmost two digits
}


pb_global_state_t pb_hook_mod_state_read() {
	return puzzleState;
}

void pb_hook_mod_state_write(pb_global_state_t state) {
	puzzleState = state;
}

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

void loop() {
    switch(puzzleState) {
        case PB_GS_PLAYING:
            display_code_for_level(currentLevel);
            check_button_press();
            delay(100);
            break;
        case PB_GS_SOLVED:
            Serial.println("STATE = PB_GS_SOLVED");
            display_final_code(bombCode);
            digitalWrite(SOLVED_PIN, HIGH);
            break;
        case PB_GS_NOINIT:
            Serial.println("STATE = PB_GS_NOINIT");
            blink_display(0);
            break;
        case PB_GS_IDLE:
            Serial.println("STATE = PB_GS_IDLE");
            blink_display(1);
            break;
    }
}