aboutsummaryrefslogtreecommitdiff
path: root/src/input.c
blob: db306ea41fad7b79777c426a95376ca008c1bfc0 (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
#include <hardware.h>
#include <tty.h>
#include <stdint.h>
#include <input.h>

enum encoder_state {
	START,
	CW_START,
	CW_NEXT,
	CW_FINAL,
	CCW_START,
	CCW_NEXT,
	CCW_FINAL,
	CW = 0x10,
	CCW = 0x20
};

/* State machine to keep track of encoder */
static const uint8_t encoder_table[7][4] = {
	/*              00        01         10         11*/
	[START]     = { START,    CCW_START, CW_START,  START       },
	[CCW_START] = { CCW_NEXT, CCW_START, START,     START       },
	[CCW_NEXT]  = { CCW_NEXT, CCW_START, CCW_FINAL, START       },
	[CCW_FINAL] = { CCW_NEXT, START,     CCW_FINAL, START | CCW },
	[CW_START]  = { CW_NEXT,  START,     CW_START,  START       },
	[CW_NEXT]   = { CW_NEXT,  CW_FINAL,  CW_START,  START       },
	[CW_FINAL]  = { CW_NEXT,  CW_FINAL,  START,     START | CW  }
};

struct fifo input_fifo = {0, 0, {0}};

void
input_event(void) __critical __interrupt(4)
{
	if ((port_b_data & 0x03) != 0x03) {
		// Encoder
		uint8_t state = START;
		uint8_t encoder;
		uint8_t next_state;

		do {
			encoder = port_b_data & 0x03;
			next_state = encoder_table[state][encoder];
			state = next_state & 0x0F;
		} while (state != START);

		if (next_state == CW || next_state == CCW)
			fifo_push(&input_fifo, next_state);
	} else if (port_b_data & 0x7C) {
		// Key pressed
		for (int i = 0; i < 5; i++) {
			uint8_t bit = 1 << (i + 2);
			uint8_t state = !(port_b_data & bit);

			if (state)
				fifo_push(&input_fifo, i);
		}
	}
}