aboutsummaryrefslogtreecommitdiff
path: root/main/main.ino
blob: fcdf3e50f712dd3bf073c9da2d2159a9705d3ebb (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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#include "constants.h"

/** KB -> arduino pin mapping
 * 0  (1) ->  8 & 9
 * 1  (2) ->  8 & 7
 * 2  (3) ->  8 & 5
 * 3  (4) -> 12 & 9
 * 4  (5) -> 12 & 7
 * 5  (6) -> 12 & 5
 * 6  (7) ->  6 & 9
 * 7  (8) ->  6 & 7
 * 8  (9) ->  6 & 5
 * 9  (C) ->  4 & 9
 * 10 (0) ->  4 & 7
 * 11 (E) ->  4 & 5
 */

const int kb_rows[] = { KB_ROW_1, KB_ROW_2, KB_ROW_3, KB_ROW_4 };
const int kb_cols[] = { KB_COL_1, KB_COL_2, KB_COL_3 };

#define LED_R 0
#define LED_G 1
#define LED_Y 2

const int led_pinouts[] = { PINOUT_LED_R, PINOUT_LED_G, PINOUT_LED_Y };
unsigned long led_timings[] = { 0, 0, 0 };
bool led_status[] = { 0, 0, 0 };

unsigned char kb[12], kb_old[12];

unsigned char correct_code[MAX_CODE_LEN];
unsigned int correct_code_len = 4;

unsigned char code[MAX_CODE_LEN];
unsigned int codei = 0;

/** @brief informatie over toets die `void kb_onevent()` mee krijgt */
typedef struct {
	/** @brief kb[12] index van de toets */
	unsigned char key;
	/** @brief true als de toets wordt ingedrukt */
	bool down;
	/** @brief tijd van toetsaanslag */
	unsigned long timestamp;
} kb_event;

void setup() {
	// Start serial (vooral voor debugging)
	Serial.begin(SERIAL_BAUD);

	// keyboard kolommen als input
	pinMode(KB_COL_1, INPUT_PULLUP);
	pinMode(KB_COL_2, INPUT_PULLUP);
	pinMode(KB_COL_3, INPUT_PULLUP);

	// keyboard rijen als output
	pinMode(KB_ROW_1, OUTPUT);
	pinMode(KB_ROW_2, OUTPUT);
	pinMode(KB_ROW_3, OUTPUT);
	pinMode(KB_ROW_4, OUTPUT);

	// alle rijen moeten standaard HIGH zijn voor de scan
	digitalWrite(KB_ROW_1, HIGH);
	digitalWrite(KB_ROW_2, HIGH);
	digitalWrite(KB_ROW_3, HIGH);
	digitalWrite(KB_ROW_4, HIGH);

	// LED's
	pinMode(PINOUT_LED_G, OUTPUT);
	pinMode(PINOUT_LED_R, OUTPUT);
	pinMode(PINOUT_LED_Y, OUTPUT);

	// Overige outputs
	pinMode(PINOUT_RELAIS, OUTPUT);
	pinMode(PINOUT_BUZZ, OUTPUT);
}

/** @brief scan het toetsenbord en stop alles in `kb[12]` */
void kb_scan() {
	// kopieer kb naar kb_old
	memcpy(&kb_old, kb, sizeof(kb_old));

	// stel alle indices van kb_old in op 0
	memset(&kb, 0, sizeof(kb));

	for (int row = 0; row < 4; row++) {
		digitalWrite(kb_rows[row], LOW);

		for (int col = 0; col < 3; col++) {
			// index hack om 2d coordinaten in een 1d array op te slaan
			kb[3 * row + col] = !digitalRead(kb_cols[col]);
		}

		digitalWrite(kb_rows[row], HIGH);
	}
}

/** @brief debug functie die een getallen array als JSON print */
void debug_print_arr(unsigned char x[12]) {
	Serial.print("[");
	for(int i = 0; i < 12; i++) {
		Serial.print(x[i], DEC);
		if (i != 11) Serial.print(", ");
	}
	Serial.print("]\n");
}

/** @brief wordt uitgevoerd wanneer de verkeerde code is ingevoerd */
void wrong_code_routine() {
	tone(PINOUT_BUZZ, BUZZ_SAD);
	digitalWrite(PINOUT_LED_R, HIGH);

	delay(1e3); // shorthand voor 1000

	digitalWrite(PINOUT_LED_R, LOW);
	noTone(PINOUT_BUZZ);
}

/** @brief wordt uitgevoerd wanneer de juiste code is ingevoerd */
void unlock_routine() {
	tone(PINOUT_BUZZ, BUZZ_HAPPY);
	digitalWrite(PINOUT_RELAIS, HIGH);
	digitalWrite(PINOUT_LED_G, HIGH);

	delay(2e3);

	digitalWrite(PINOUT_LED_G, LOW);
	digitalWrite(PINOUT_RELAIS, LOW);
	noTone(PINOUT_BUZZ);
}

/** @brief wordt uitgevoerd wanneer "E" wordt ingedrukt */
void check_code() {
	bool correct = true;

	// check lengte
	if (codei != correct_code_len) return wrong_code_routine();

	for (int i = 0; i < correct_code_len; i++) {
		if (correct_code[i] == code[i]) continue;

		// dit voert alleen uit als een van
		// de getallen in code[] niet gelijk is aan correct_code[]
		correct = false;
		break;
	}
	
	// debug
	Serial.print(correct, DEC);

	// kijk mama zonder haakjes!
	if (correct)
		unlock_routine();
	else
		wrong_code_routine();
}

/**
 * @brief event handler voor het toetsenbord
 * (voert elke keer uit wanneer de toestand van een toets verandert)
 */
void kb_onevent(kb_event ev) {
	if (!ev.down) return; // alleen uit naar aan events boeien (voor nu)

	// korte pieptoon als een nummertoets of *clear* wordt ingedrukt
	if (ev.key != KB_KEY_E) tone(PINOUT_BUZZ, BUZZ_HAPPY, 200);

	switch (ev.key) {
		case KB_KEY_C: {
			// leeg code[]
			memset(&code, 0, MAX_CODE_LEN);
			codei = 0;

			break;
		}

		case KB_KEY_E: {
			check_code();

			break;
		}

		// Overige toetsen (nummers)
		default: {
			led_set_timeout(LED_Y, 200);

			// bereken getal op toets
			// (key + 1 voor alle toetsen behalve 0)
			int num = ev.key == 10 ? 0 : ev.key + 1;

			// voeg getal toe aan het einde van de code
			code[codei] = num;
			codei++;
		}
	}
}

/**
 * @brief voert `kb_onevent` uit
 * wanneer de toestand van een toets verandert
 */
void kb_event_gen() {
	for(int i = 0; i < 12; i++) {
		// ga door naar de volgende iteratie
		// als de toetsen niet veranderd zijn
		if (kb[i] == kb_old[i]) continue;

		// maak en vul struct met informatie
		kb_event event = {
			.key = (unsigned char) i,
			.down = kb[i],
			.timestamp = millis()
		};

		// voer on_event handler uit
		kb_onevent(event);
	}
}

/**
 * @brief zet een led aan voor `duration_millis` milliseconden (non-blocking)
 * @param led `LED_?` constante voor led kleur
 * @param duration_millis aantal milliseconden dat de led aan moet zijn
 */
void led_set_timeout(unsigned int led, unsigned long duration_millis) {
	led_timings[led] = millis() + duration_millis;
	led_status[led] = 1;
	digitalWrite(led_pinouts[led], HIGH);
}

/** @brief led update functie (voor event loop) */
void led_update() {
	unsigned long current_time = millis();

	for (int i = 0; i < 3; i++) {
		// negeer huidige led als die timer nog niet voorbij is
		if (led_timings[i] > current_time) continue;

		// negeer huidige led als die al uit is
		if (led_status[i] == 0) continue;

		// zet huidige led uit
		led_status[i] = 0;
		digitalWrite(led_pinouts[i], LOW);
	}
}

/** @brief arduino `loop` functie, wordt gebruikt als event loop */
void loop() {
	kb_scan();
	kb_event_gen();
	led_update();
}