aboutsummaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/haptic.c295
-rw-r--r--quantum/haptic.h77
-rw-r--r--quantum/process_keycode/process_haptic.c147
-rw-r--r--quantum/process_keycode/process_haptic.h21
-rw-r--r--quantum/quantum.c4
-rw-r--r--quantum/quantum.h1
6 files changed, 543 insertions, 2 deletions
diff --git a/quantum/haptic.c b/quantum/haptic.c
new file mode 100644
index 000000000..65abcc15f
--- /dev/null
+++ b/quantum/haptic.c
@@ -0,0 +1,295 @@
1/* Copyright 2019 ishtob
2 * Driver for haptic feedback written for QMK
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#include "haptic.h"
18#include "eeconfig.h"
19#include "debug.h"
20#ifdef DRV2605L
21# include "DRV2605L.h"
22#endif
23#ifdef SOLENOID_ENABLE
24# include "solenoid.h"
25#endif
26
27haptic_config_t haptic_config;
28
29void haptic_init(void) {
30 if (!eeconfig_is_enabled()) {
31 eeconfig_init();
32 }
33 haptic_config.raw = eeconfig_read_haptic();
34#ifdef SOLENOID_ENABLE
35 solenoid_set_dwell(haptic_config.dwell);
36#endif
37 if ((haptic_config.raw == 0)
38#ifdef SOLENOID_ENABLE
39 || (haptic_config.dwell == 0)
40#endif
41 ) {
42 // this will be called, if the eeprom is not corrupt,
43 // but the previous firmware didn't have haptic enabled,
44 // or the previous firmware didn't have solenoid enabled,
45 // and the current one has solenoid enabled.
46 haptic_reset();
47 }
48#ifdef SOLENOID_ENABLE
49 solenoid_setup();
50 dprintf("Solenoid driver initialized\n");
51#endif
52#ifdef DRV2605L
53 DRV_init();
54 dprintf("DRV2605 driver initialized\n");
55#endif
56 eeconfig_debug_haptic();
57}
58
59void haptic_task(void) {
60#ifdef SOLENOID_ENABLE
61 solenoid_check();
62#endif
63}
64
65void eeconfig_debug_haptic(void) {
66 dprintf("haptic_config eeprom\n");
67 dprintf("haptic_config.enable = %d\n", haptic_config.enable);
68 dprintf("haptic_config.mode = %d\n", haptic_config.mode);
69}
70
71void haptic_enable(void) {
72 haptic_config.enable = 1;
73 xprintf("haptic_config.enable = %u\n", haptic_config.enable);
74 eeconfig_update_haptic(haptic_config.raw);
75}
76
77void haptic_disable(void) {
78 haptic_config.enable = 0;
79 xprintf("haptic_config.enable = %u\n", haptic_config.enable);
80 eeconfig_update_haptic(haptic_config.raw);
81}
82
83void haptic_toggle(void) {
84 if (haptic_config.enable) {
85 haptic_disable();
86 } else {
87 haptic_enable();
88 }
89 eeconfig_update_haptic(haptic_config.raw);
90}
91
92void haptic_feedback_toggle(void) {
93 haptic_config.feedback++;
94 if (haptic_config.feedback >= HAPTIC_FEEDBACK_MAX) haptic_config.feedback = KEY_PRESS;
95 xprintf("haptic_config.feedback = %u\n", !haptic_config.feedback);
96 eeconfig_update_haptic(haptic_config.raw);
97}
98
99void haptic_buzz_toggle(void) {
100 bool buzz_stat = !haptic_config.buzz;
101 haptic_config.buzz = buzz_stat;
102 haptic_set_buzz(buzz_stat);
103}
104
105void haptic_mode_increase(void) {
106 uint8_t mode = haptic_config.mode + 1;
107#ifdef DRV2605L
108 if (haptic_config.mode >= drv_effect_max) {
109 mode = 1;
110 }
111#endif
112 haptic_set_mode(mode);
113}
114
115void haptic_mode_decrease(void) {
116 uint8_t mode = haptic_config.mode - 1;
117#ifdef DRV2605L
118 if (haptic_config.mode < 1) {
119 mode = (drv_effect_max - 1);
120 }
121#endif
122 haptic_set_mode(mode);
123}
124
125void haptic_dwell_increase(void) {
126#ifdef SOLENOID_ENABLE
127 int16_t next_dwell = ((int16_t)haptic_config.dwell) + SOLENOID_DWELL_STEP_SIZE;
128 if (haptic_config.dwell >= SOLENOID_MAX_DWELL) {
129 // if it's already at max, we wrap back to min
130 next_dwell = SOLENOID_MIN_DWELL;
131 } else if (next_dwell > SOLENOID_MAX_DWELL) {
132 // if we overshoot the max, then cap at max
133 next_dwell = SOLENOID_MAX_DWELL;
134 }
135 solenoid_set_dwell(next_dwell);
136#else
137 int16_t next_dwell = ((int16_t)haptic_config.dwell) + 1;
138#endif
139 haptic_set_dwell(next_dwell);
140}
141
142void haptic_dwell_decrease(void) {
143#ifdef SOLENOID_ENABLE
144 int16_t next_dwell = ((int16_t)haptic_config.dwell) - SOLENOID_DWELL_STEP_SIZE;
145 if (haptic_config.dwell <= SOLENOID_MIN_DWELL) {
146 // if it's already at min, we wrap to max
147 next_dwell = SOLENOID_MAX_DWELL;
148 } else if (next_dwell < SOLENOID_MIN_DWELL) {
149 // if we go below min, then we cap to min
150 next_dwell = SOLENOID_MIN_DWELL;
151 }
152 solenoid_set_dwell(next_dwell);
153#else
154 int16_t next_dwell = ((int16_t)haptic_config.dwell) - 1;
155#endif
156 haptic_set_dwell(next_dwell);
157}
158
159void haptic_reset(void) {
160 haptic_config.enable = true;
161 uint8_t feedback = HAPTIC_FEEDBACK_DEFAULT;
162 haptic_config.feedback = feedback;
163#ifdef DRV2605L
164 uint8_t mode = HAPTIC_MODE_DEFAULT;
165 haptic_config.mode = mode;
166#endif
167#ifdef SOLENOID_ENABLE
168 uint8_t dwell = SOLENOID_DEFAULT_DWELL;
169 haptic_config.dwell = dwell;
170 haptic_config.buzz = SOLENOID_DEFAULT_BUZZ;
171 solenoid_set_dwell(dwell);
172#else
173 // This is to trigger haptic_reset again, if solenoid is enabled in the future.
174 haptic_config.dwell = 0;
175 haptic_config.buzz = 0;
176#endif
177 eeconfig_update_haptic(haptic_config.raw);
178 xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
179 xprintf("haptic_config.mode = %u\n", haptic_config.mode);
180}
181
182void haptic_set_feedback(uint8_t feedback) {
183 haptic_config.feedback = feedback;
184 eeconfig_update_haptic(haptic_config.raw);
185 xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
186}
187
188void haptic_set_mode(uint8_t mode) {
189 haptic_config.mode = mode;
190 eeconfig_update_haptic(haptic_config.raw);
191 xprintf("haptic_config.mode = %u\n", haptic_config.mode);
192}
193
194void haptic_set_amplitude(uint8_t amp) {
195 haptic_config.amplitude = amp;
196 eeconfig_update_haptic(haptic_config.raw);
197 xprintf("haptic_config.amplitude = %u\n", haptic_config.amplitude);
198#ifdef DRV2605L
199 DRV_amplitude(amp);
200#endif
201}
202
203void haptic_set_buzz(uint8_t buzz) {
204 haptic_config.buzz = buzz;
205 eeconfig_update_haptic(haptic_config.raw);
206 xprintf("haptic_config.buzz = %u\n", haptic_config.buzz);
207}
208
209void haptic_set_dwell(uint8_t dwell) {
210 haptic_config.dwell = dwell;
211 eeconfig_update_haptic(haptic_config.raw);
212 xprintf("haptic_config.dwell = %u\n", haptic_config.dwell);
213}
214
215uint8_t haptic_get_enable(void) { return haptic_config.enable; }
216
217uint8_t haptic_get_mode(void) {
218 if (!haptic_config.enable) {
219 return false;
220 }
221 return haptic_config.mode;
222}
223
224uint8_t haptic_get_feedback(void) {
225 if (!haptic_config.enable) {
226 return false;
227 }
228 return haptic_config.feedback;
229}
230
231uint8_t haptic_get_dwell(void) {
232 if (!haptic_config.enable) {
233 return false;
234 }
235 return haptic_config.dwell;
236}
237
238void haptic_enable_continuous(void) {
239 haptic_config.cont = 1;
240 xprintf("haptic_config.cont = %u\n", haptic_config.cont);
241 eeconfig_update_haptic(haptic_config.raw);
242#ifdef DRV2605L
243 DRV_rtp_init();
244#endif
245}
246
247void haptic_disable_continuous(void) {
248 haptic_config.cont = 0;
249 xprintf("haptic_config.cont = %u\n", haptic_config.cont);
250 eeconfig_update_haptic(haptic_config.raw);
251#ifdef DRV2605L
252 DRV_write(DRV_MODE, 0x00);
253#endif
254}
255
256void haptic_toggle_continuous(void) {
257 if (haptic_config.cont) {
258 haptic_disable_continuous();
259 } else {
260 haptic_enable_continuous();
261 }
262}
263
264void haptic_cont_increase(void) {
265 uint8_t amp = haptic_config.amplitude + 10;
266 if (haptic_config.amplitude >= 120) {
267 amp = 120;
268 }
269 haptic_set_amplitude(amp);
270}
271
272void haptic_cont_decrease(void) {
273 uint8_t amp = haptic_config.amplitude - 10;
274 if (haptic_config.amplitude < 20) {
275 amp = 20;
276 }
277 haptic_set_amplitude(amp);
278}
279
280void haptic_play(void) {
281#ifdef DRV2605L
282 uint8_t play_eff = 0;
283 play_eff = haptic_config.mode;
284 DRV_pulse(play_eff);
285#endif
286#ifdef SOLENOID_ENABLE
287 solenoid_fire();
288#endif
289}
290
291void haptic_shutdown(void) {
292#ifdef SOLENOID_ENABLE
293 solenoid_shutdown();
294#endif
295}
diff --git a/quantum/haptic.h b/quantum/haptic.h
new file mode 100644
index 000000000..fc7ca2f3e
--- /dev/null
+++ b/quantum/haptic.h
@@ -0,0 +1,77 @@
1/* Copyright 2019 ishtob
2 * Driver for haptic feedback written for QMK
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#pragma once
19#include <stdint.h>
20#include <stdbool.h>
21
22#ifndef HAPTIC_FEEDBACK_DEFAULT
23# define HAPTIC_FEEDBACK_DEFAULT 0
24#endif
25#ifndef HAPTIC_MODE_DEFAULT
26# define HAPTIC_MODE_DEFAULT DRV_MODE_DEFAULT
27#endif
28
29/* EEPROM config settings */
30typedef union {
31 uint32_t raw;
32 struct {
33 bool enable : 1;
34 uint8_t feedback : 2;
35 uint8_t mode : 7;
36 bool buzz : 1;
37 uint8_t dwell : 7;
38 bool cont : 1;
39 uint8_t amplitude : 8;
40 uint8_t reserved : 5;
41 };
42} haptic_config_t;
43
44typedef enum HAPTIC_FEEDBACK {
45 KEY_PRESS,
46 KEY_PRESS_RELEASE,
47 KEY_RELEASE,
48 HAPTIC_FEEDBACK_MAX,
49} HAPTIC_FEEDBACK;
50
51void haptic_init(void);
52void haptic_task(void);
53void eeconfig_debug_haptic(void);
54void haptic_enable(void);
55void haptic_disable(void);
56void haptic_toggle(void);
57void haptic_feedback_toggle(void);
58void haptic_mode_increase(void);
59void haptic_mode_decrease(void);
60void haptic_mode(uint8_t mode);
61void haptic_reset(void);
62void haptic_set_feedback(uint8_t feedback);
63void haptic_set_mode(uint8_t mode);
64void haptic_set_dwell(uint8_t dwell);
65void haptic_set_buzz(uint8_t buzz);
66void haptic_buzz_toggle(void);
67uint8_t haptic_get_enable(void);
68uint8_t haptic_get_mode(void);
69uint8_t haptic_get_feedback(void);
70void haptic_dwell_increase(void);
71void haptic_dwell_decrease(void);
72void haptic_toggle_continuous(void);
73void haptic_cont_increase(void);
74void haptic_cont_decrease(void);
75
76void haptic_play(void);
77void haptic_shutdown(void);
diff --git a/quantum/process_keycode/process_haptic.c b/quantum/process_keycode/process_haptic.c
new file mode 100644
index 000000000..29a4ffd10
--- /dev/null
+++ b/quantum/process_keycode/process_haptic.c
@@ -0,0 +1,147 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#include "haptic.h"
17#include "process_haptic.h"
18#include "quantum_keycodes.h"
19
20__attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record) {
21 switch (keycode) {
22#ifdef NO_HAPTIC_MOD
23 case QK_MOD_TAP ... QK_MOD_TAP_MAX:
24 if (record->tap.count == 0) return false;
25 break;
26 case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
27 if (record->tap.count != TAPPING_TOGGLE) return false;
28 break;
29 case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
30 if (record->tap.count == 0) return false;
31 break;
32 case KC_LCTRL ... KC_RGUI:
33 case QK_MOMENTARY ... QK_MOMENTARY_MAX:
34#endif
35#ifdef NO_HAPTIC_FN
36 case KC_FN0 ... KC_FN31:
37#endif
38#ifdef NO_HAPTIC_ALPHA
39 case KC_A ... KC_Z:
40#endif
41#ifdef NO_HAPTIC_PUNCTUATION
42 case KC_ENTER:
43 case KC_ESCAPE:
44 case KC_BSPACE:
45 case KC_SPACE:
46 case KC_MINUS:
47 case KC_EQUAL:
48 case KC_LBRACKET:
49 case KC_RBRACKET:
50 case KC_BSLASH:
51 case KC_NONUS_HASH:
52 case KC_SCOLON:
53 case KC_QUOTE:
54 case KC_GRAVE:
55 case KC_COMMA:
56 case KC_SLASH:
57 case KC_DOT:
58 case KC_NONUS_BSLASH:
59#endif
60#ifdef NO_HAPTIC_LOCKKEYS
61 case KC_CAPSLOCK:
62 case KC_SCROLLLOCK:
63 case KC_NUMLOCK:
64#endif
65#ifdef NO_HAPTIC_NAV
66 case KC_PSCREEN:
67 case KC_PAUSE:
68 case KC_INSERT:
69 case KC_DELETE:
70 case KC_PGDOWN:
71 case KC_PGUP:
72 case KC_LEFT:
73 case KC_UP:
74 case KC_RIGHT:
75 case KC_DOWN:
76 case KC_END:
77 case KC_HOME:
78#endif
79#ifdef NO_HAPTIC_NUMERIC
80 case KC_1 ... KC_0:
81#endif
82 return false;
83 }
84 return true;
85}
86
87bool process_haptic(uint16_t keycode, keyrecord_t *record) {
88 if (record->event.pressed) {
89 switch (keycode) {
90 case HPT_ON:
91 haptic_enable();
92 break;
93 case HPT_OFF:
94 haptic_disable();
95 break;
96 case HPT_TOG:
97 haptic_toggle();
98 break;
99 case HPT_RST:
100 haptic_reset();
101 break;
102 case HPT_FBK:
103 haptic_feedback_toggle();
104 break;
105 case HPT_BUZ:
106 haptic_buzz_toggle();
107 break;
108 case HPT_MODI:
109 haptic_mode_increase();
110 break;
111 case HPT_MODD:
112 haptic_mode_decrease();
113 break;
114 case HPT_DWLI:
115 haptic_dwell_increase();
116 break;
117 case HPT_DWLD:
118 haptic_dwell_decrease();
119 break;
120 case HPT_CONT:
121 haptic_toggle_continuous();
122 break;
123 case HPT_CONI:
124 haptic_cont_increase();
125 break;
126 case HPT_COND:
127 haptic_cont_decrease();
128 break;
129 }
130 }
131
132 if (haptic_get_enable()) {
133 if (record->event.pressed) {
134 // keypress
135 if (haptic_get_feedback() < 2 && get_haptic_enabled_key(keycode, record)) {
136 haptic_play();
137 }
138 } else {
139 // keyrelease
140 if (haptic_get_feedback() > 0 && get_haptic_enabled_key(keycode, record)) {
141 haptic_play();
142 }
143 }
144 }
145
146 return true;
147}
diff --git a/quantum/process_keycode/process_haptic.h b/quantum/process_keycode/process_haptic.h
new file mode 100644
index 000000000..6dbb0f014
--- /dev/null
+++ b/quantum/process_keycode/process_haptic.h
@@ -0,0 +1,21 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <stdbool.h>
19#include "action.h"
20
21bool process_haptic(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 56ceec5db..f430a521b 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -220,10 +220,10 @@ bool process_record_quantum(keyrecord_t *record) {
220#endif 220#endif
221#if defined(AUDIO_ENABLE) && defined(AUDIO_CLICKY) 221#if defined(AUDIO_ENABLE) && defined(AUDIO_CLICKY)
222 process_clicky(keycode, record) && 222 process_clicky(keycode, record) &&
223#endif // AUDIO_CLICKY 223#endif
224#ifdef HAPTIC_ENABLE 224#ifdef HAPTIC_ENABLE
225 process_haptic(keycode, record) && 225 process_haptic(keycode, record) &&
226#endif // HAPTIC_ENABLE 226#endif
227#if defined(VIA_ENABLE) 227#if defined(VIA_ENABLE)
228 process_record_via(keycode, record) && 228 process_record_via(keycode, record) &&
229#endif 229#endif
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 756a5603c..72970a649 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -161,6 +161,7 @@ extern layer_state_t layer_state;
161 161
162#ifdef HAPTIC_ENABLE 162#ifdef HAPTIC_ENABLE
163# include "haptic.h" 163# include "haptic.h"
164# include "process_haptic.h"
164#endif 165#endif
165 166
166#ifdef OLED_DRIVER_ENABLE 167#ifdef OLED_DRIVER_ENABLE