-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinput.c
More file actions
146 lines (119 loc) · 4.61 KB
/
Copy pathinput.c
File metadata and controls
146 lines (119 loc) · 4.61 KB
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
// input.c — see input.h for the module overview.
#include "input.h"
#include <avr/io.h>
#define DEBOUNCE_MS 5u
// TODO: confirm this direction-to-pin mapping matches the silkscreen /
// physical D-pad wiring on the PCB -- the spec lists the four pins but not
// which is which.
typedef struct {
volatile uint8_t *pinReg;
uint8_t bit;
} ButtonPin;
static const ButtonPin s_pins[BUTTON_COUNT] = {
{ &PIND, PD6 }, // BUTTON_UP
{ &PIND, PD3 }, // BUTTON_DOWN
{ &PIND, PD4 }, // BUTTON_LEFT
{ &PIND, PD5 }, // BUTTON_RIGHT
{ &PIND, PD2 }, // BUTTON_START
{ &PIND, PD0 }, // BUTTON_SELECT
{ &PIND, PD1 }, // BUTTON_HOME
};
static bool s_debounced[BUTTON_COUNT];
static bool s_prevDebounced[BUTTON_COUNT];
static bool s_rawLast[BUTTON_COUNT];
static uint32_t s_lastChangeMs[BUTTON_COUNT];
static uint32_t s_holdStartMs[BUTTON_COUNT];
static uint32_t s_lastRepeatMs[BUTTON_COUNT];
void inputInit(void) {
// Configure PD0-PD6 as inputs
DDRD &= (uint8_t)~((1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5) | (1 << PD6));
// Enable internal pull-ups for PD0-PD6
PORTD |= (uint8_t)((1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5) | (1 << PD6));
for (uint8_t i = 0; i < BUTTON_COUNT; i++) {
s_debounced[i] = true; // idle high == not pressed (active-low)
s_prevDebounced[i] = true;
s_rawLast[i] = true;
s_lastChangeMs[i] = 0;
}
// Configure ADC for the joystick (PC4 = X, PC5 = Y)
// AVCC with external capacitor at AREF pin
// Enable ADC, set prescaler to 128 (20MHz / 128 = ~156kHz, optimal for 10-bit)
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}
static uint16_t ReadADC(uint8_t channel) {
// Select ADC channel (0-7)
ADMUX = (1 << REFS0) | (channel & 0x07);
// Dummy conversion to allow the S&H capacitor to charge
// when switching channels. This fixes cross-talk and erratic values.
ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC));
// Actual conversion
ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC));
return ADC;
}
static uint16_t s_joyX = 512;
static uint16_t s_joyY = 512;
void inputUpdate(uint32_t nowMs) {
// Read the joystick analog axes (0-1023, midpoint ~512)
s_joyX = ReadADC(4); // PC4
s_joyY = ReadADC(5); // PC5
for (uint8_t i = 0; i < BUTTON_COUNT; i++) {
bool raw = (*s_pins[i].pinReg & (1 << s_pins[i].bit)) != 0;
// Map joystick analog deflections to D-Pad button presses (active low)
uint16_t jY = inputGetJoystickY();
uint16_t jX = inputGetJoystickX();
static bool s_joyUp, s_joyDown, s_joyLeft, s_joyRight;
if (jY < 200) s_joyUp = true; else if (jY > 400) s_joyUp = false;
if (jY > 800) s_joyDown = true; else if (jY < 600) s_joyDown = false;
if (jX < 200) s_joyLeft = true; else if (jX > 400) s_joyLeft = false;
if (jX > 800) s_joyRight = true; else if (jX < 600) s_joyRight = false;
if (i == BUTTON_UP && s_joyUp) raw = false;
if (i == BUTTON_DOWN && s_joyDown) raw = false;
if (i == BUTTON_LEFT && s_joyLeft) raw = false;
if (i == BUTTON_RIGHT && s_joyRight) raw = false;
if (raw != s_rawLast[i]) {
s_rawLast[i] = raw;
s_lastChangeMs[i] = nowMs;
}
s_prevDebounced[i] = s_debounced[i];
if ((nowMs - s_lastChangeMs[i]) >= DEBOUNCE_MS) {
s_debounced[i] = raw;
}
if (s_prevDebounced[i] && !s_debounced[i]) {
s_holdStartMs[i] = nowMs;
s_lastRepeatMs[i] = nowMs;
}
}
}
uint16_t inputGetJoystickX(void) {
return 1023 - s_joyX;
}
uint16_t inputGetJoystickY(void) {
return 1023 - s_joyY;
}
bool inputIsHeld(ButtonId btn) {
return !s_debounced[btn]; // active-low
}
bool inputWasPressed(ButtonId btn) {
return s_prevDebounced[btn] && !s_debounced[btn];
}
bool inputWasReleased(ButtonId btn) {
return !s_prevDebounced[btn] && s_debounced[btn];
}
#include "system.h"
bool inputIsRepeated(ButtonId btn) {
if (inputWasPressed(btn)) {
return true;
}
if (inputIsHeld(btn)) {
uint32_t nowMs = systemGetTimeMs();
if (nowMs - s_holdStartMs[btn] > 400) {
if (nowMs - s_lastRepeatMs[btn] > 100) {
s_lastRepeatMs[btn] = nowMs;
return true;
}
}
}
return false;
}