-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathButtonBox.ino
More file actions
297 lines (214 loc) · 7.29 KB
/
ButtonBox.ino
File metadata and controls
297 lines (214 loc) · 7.29 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
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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
// /*https://github.com/MHeironimus/ArduinoJoystickLibrary*/
// /*https://github.com/dmadison/HID_Buttons*/
#ifndef TEENSYDUINO
#include <Joystick.h> // Use MHeironimus's Joystick library
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
2, 0, // Button Count, Hat Switch Count
true, true, true, // No X, Y, or Z axes
true, true, true, // No Rx, Ry, or Rz
false, false, // No rudder or throttle
false, false, false); // No accelerator, brake, or steering
#endif
#include <HID_Buttons.h> // Must import AFTER Joystick.h
#define POTI_1_PIN A0
#define POTI_2_PIN A1
#define SWITCH_MUTE 14
// #define BUTTON_MODE GENERIC_BUTTON // replaces generic button with mode toggle (not reported to OS anymore)
#define GENERIC_BUTTON 16
// rgb led uses pwm pins
#define RGB_RED 3
#define RGB_BLUE 5
#define RGB_GREEN 6
#define POTI_1_LED 7
#define POTI_2_LED 8
#define SWITCH_MUTE_LED 9
#define POT_0DB_DEADZONE_PCT 6
#define POT_0DB (uint16_t)(1023*0.75)
// 10/1024 is a deadzone of 0.9%, low enough
#define POT_JITTER_DEADZONE_ABS 10
JoystickButton muteButton(0);
JoystickButton genericButton(1);
void set_rgb_led(int r, int g, int b);
void setup() {
pinMode(POTI_1_PIN, INPUT);
pinMode(POTI_2_PIN, INPUT);
pinMode(SWITCH_MUTE, INPUT_PULLUP);
pinMode(GENERIC_BUTTON, INPUT_PULLUP);
pinMode(RGB_RED, OUTPUT);
pinMode(RGB_BLUE, OUTPUT);
pinMode(RGB_GREEN, OUTPUT);
// init as led off
set_rgb_led(0, 0, 0);
pinMode(POTI_1_LED, OUTPUT);
pinMode(POTI_2_LED, OUTPUT);
pinMode(SWITCH_MUTE_LED, OUTPUT);
Joystick.begin();
}
void loop() {
// limit update rate of oled
static uint32_t last_update_ms = millis();
static uint8_t is_update = 0;
static uint8_t mode = 0;
// keep last state to trigger oled update
static uint16_t pot1_last = 0, pot2_last = 0;
static uint8_t mic_active_last = 0;
static uint8_t mode_pressed_last = 0;
uint16_t pot1, pot2;
uint8_t mic_active;
uint8_t generic_pressed;
uint32_t current_time_ms;
/**************************************/
/* read signals */
/**************************************/
// range goes [0,1024], but wiring is inverted
pot1 = 1024 - analogRead(POTI_1_PIN);
pot2 = 1024 - analogRead(POTI_2_PIN);
// pull up resistor -> invert
mic_active = !digitalRead(SWITCH_MUTE);
generic_pressed = !digitalRead(GENERIC_BUTTON);
/**************************************/
/* process signal input */
/**************************************/
// 0 position of poti is at 3/4
// => add artificial deadzone at 768 +- 10%
uint16_t lower_deadzone = POT_0DB - (POT_0DB * POT_0DB_DEADZONE_PCT / 100);
uint16_t upper_deadzone = POT_0DB + (POT_0DB * POT_0DB_DEADZONE_PCT / 100);
if(pot1 >= lower_deadzone && pot1 <= upper_deadzone){
pot1 = POT_0DB;
}
if(pot2 >= lower_deadzone && pot2 <= upper_deadzone){
pot2 = POT_0DB;
}
/**************************************/
/* update last state/update flag */
/**************************************/
// whenever a value changed
// refresh the last_update timestamp
if(mic_active == mic_active_last &&\
(pot1 <= (pot1_last + POT_JITTER_DEADZONE_ABS) && pot1 >= (pot1_last - POT_JITTER_DEADZONE_ABS)) &&\
(pot2 <= (pot2_last + POT_JITTER_DEADZONE_ABS) && pot2 >= (pot2_last - POT_JITTER_DEADZONE_ABS))){
// eliminate the jitter
// IMPORTANT: if the deadzone is 10, a change by 9 is ignored
// however, two consecutive changes of 6 each, are counted as 12 at the second iteration
// this prevents 'sticking' of the poti when moving it slowly
pot1 = pot1_last;
pot2 = pot2_last;
}
else{
last_update_ms = millis();
pot1_last = pot1;
pot2_last = pot2;
mic_active_last = mic_active;
is_update = 1;
}
/**************************************/
/* publish to computer */
/**************************************/
// mode based button mappings
switch(mode){
case 0:
Joystick.setXAxis(pot1);
Joystick.setYAxis(pot2);
break;
case 1:
Joystick.setZAxis(pot1);
Joystick.setRxAxis(pot2);
break;
case 2:
Joystick.setRyAxis(pot1);
Joystick.setRzAxis(pot2);
break;
}
#ifndef BUTTON_MODE
genericButton.set(generic_pressed);
#endif
// universal button mappings
muteButton.set(mic_active);
/**************************************/
/* update UI */
/**************************************/
current_time_ms = millis();
if((current_time_ms - last_update_ms) > 10000){
set_rgb_led(0,0,0);
digitalWrite(SWITCH_MUTE_LED, LOW);
digitalWrite(POTI_1_LED, LOW);
digitalWrite(POTI_2_LED, LOW);
}
else{
#ifdef BUTTON_MODE
switch(mode){
case 0:
set_rgb_led(1, 0, 0);
break;
case 1:
set_rgb_led(0, 1, 0);
break;
case 2:
set_rgb_led(0, 0, 1);
break;
}
#else
if(generic_pressed){
set_rgb_led(1,0,0);
}
else{
set_rgb_led(0,0,0);
}
#endif
// update leds based on settings
if(mic_active){
digitalWrite(SWITCH_MUTE_LED, HIGH);
}
else{
digitalWrite(SWITCH_MUTE_LED, LOW);
}
if(pot1 == POT_0DB){
digitalWrite(POTI_1_LED, HIGH);
}
else{
digitalWrite(POTI_1_LED, LOW);
}
if(pot2 == POT_0DB){
digitalWrite(POTI_2_LED, HIGH);
}
else{
digitalWrite(POTI_2_LED, LOW);
}
}
/**************************************/
/* handle mode switch */
/**************************************/
#ifdef BUTTON_MODE
// toggle mode switch, force update oled in any case
if(mode_pressed_last != mode_pressed && mode_pressed){
mode = mode == 2 ? 0 : mode + 1;
delay(150); // de-bounce
// this counts as update aswell
last_update_ms = millis();
}
// update last-state vars
mode_pressed_last = mode_pressed;
#endif
}
void set_rgb_led(int r, int g, int b){
// common anode turns led off when HIGH
// currently only binary addressing is used
if(r){
digitalWrite(RGB_RED, LOW);
}
else{
digitalWrite(RGB_RED, HIGH);
}
if(g){
digitalWrite(RGB_GREEN, LOW);
}
else{
digitalWrite(RGB_GREEN, HIGH);
}
if(b){
digitalWrite(RGB_BLUE, LOW);
}
else{
digitalWrite(RGB_BLUE, HIGH);
}
}