aboutsummaryrefslogtreecommitdiff
path: root/main/main.ino
blob: 67222ee3ee6b53f1e29b263bf4142ce9e91b1342 (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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#include "constants.h"

/** BN (KB) -> PIN & PIN
 * 1   (0)  ->  D8 & D9
 * 2   (1)  ->  D8 & D7
 * 3   (2)  ->  D8 & D5
 * 4   (3)  -> D12 & D9
 * 5   (4)  -> D12 & D7
 * 6   (5)  -> D12 & D5
 * 7   (6)  ->  D6 & D9
 * 8   (7)  ->  D6 & D7
 * 9   (8)  ->  D6 & D5
 * C   (9)  ->  D4 & D9
 * 0   (10) ->  D4 & D7
 * E   (11) ->  D4 & D5
 * SET (12) -> GND & A1
 */

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[3];
bool led_status[3];

#define KB_KEYCOUNT 13
unsigned long kb_timings[KB_KEYCOUNT];
unsigned char kb[KB_KEYCOUNT], kb_old[KB_KEYCOUNT];

bool set_mode = false;

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[] 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);

	// set knop (met externe pull-up)
	pinMode(PINOUT_SET, INPUT);

	// 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 de set knop */
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);
	}

	kb[KB_KEY_SET] = !digitalRead(PINOUT_SET);
}

// wat zou deze functie toch doen
void clear_code() {
	memset(&code, 0, MAX_CODE_LEN);
	codei = 0;
}

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

	delay(1e3); // shorthand voor 1000

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

	clear_code();
}

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

	delay(2e3);

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

	clear_code();
}

/** @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;
	}
	
	// kijk mama zonder haakjes!
	if (correct)
		correct_code_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)

	// zorgt ervoor dat je een toets niet vaker dan een periode van
	// KB_DEBOUNCE_DELAY kunt indrukken
	bool bounce = kb_timings[ev.key] + KB_DEBOUNCE_DELAY > millis();
	kb_timings[ev.key] = ev.timestamp;
	if (bounce) return;

	switch (ev.key) {
		case KB_KEY_C: {
			tone(PINOUT_BUZZ, BUZZ_CLEAR, 200);
			clear_code();

			break;
		}

		case KB_KEY_E: {
			if (!set_mode) {
				check_code();
			} else {
				// stel nieuwe code in (set mode aan)
				memcpy(&correct_code, code, sizeof(correct_code));
				correct_code_len = codei;
				clear_code();
				set_mode = false;
			}

			break;
		}

		case KB_KEY_SET: {
			clear_code();
			set_mode = true;

			break;
		}

		// Overige toetsen (nummers)
		default: {
			tone(PINOUT_BUZZ, BUZZ_NUM, 200);
			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++; //TODO: fix array out of bounds crash
		}
	}
}

/**
 * @brief voert `kb_onevent` uit
 * wanneer de toestand van een toets verandert
 */
void kb_event_gen() {
	for(int i = 0; i < KB_KEYCOUNT; 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();
}