aboutsummaryrefslogtreecommitdiff
path: root/main/main.ino
blob: d4b765b7c3f4351e67be06eaab4b153f82c914d8 (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
255
#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
 */

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

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

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[] = { 0, 0, 0, 0 };
unsigned char code[MAX_CODE_LEN];
unsigned int codei = 0;

typedef struct {
	unsigned char key;
	bool down;
	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 functie die uitgevoerd wordt als
 * 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 functie die uitgevoerd wordt als
 * 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 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: {
			Serial.println("C");
			// TODO: kijk of sizeof() werkt voor arrays
			memset(&code, 0, sizeof(code));
			codei = 0;

			break;
		}

		case KB_KEY_E: {
			Serial.println("E");
			//TODO: array length
			int correct_code_len = 3;
			bool correct = true;

			if (codei != correct_code_len) break;
			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();

			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++;

			Serial.print("adding ");
			Serial.print(num, DEC);
			Serial.print(" to code\n");
		}
	}
}

/**
 * @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();
}