keyboard stuff
1# Haptic Feedback
2
3## Haptic feedback rules.mk options
4
5The following options are currently available for haptic feedback in `rules.mk`:
6
7```make
8HAPTIC_ENABLE = yes
9
10HAPTIC_DRIVER = drv2605l
11# or
12HAPTIC_DRIVER = solenoid
13```
14
15The following `config.h` settings are available for all types of haptic feedback:
16
17| Settings | Default | Description |
18|--------------------------------------|---------------|---------------------------------------------------------------------------------------------------------------|
19|`HAPTIC_ENABLE_PIN` | *Not defined* |Configures a pin to enable a boost converter for some haptic solution, often used with solenoid drivers. |
20|`HAPTIC_ENABLE_PIN_ACTIVE_LOW` | *Not defined* |If defined then the haptic enable pin is active-low. |
21|`HAPTIC_ENABLE_STATUS_LED` | *Not defined* |Configures a pin to reflect the current enabled/disabled status of haptic feedback. |
22|`HAPTIC_ENABLE_STATUS_LED_ACTIVE_LOW` | *Not defined* |If defined then the haptic status led will be active-low. |
23|`HAPTIC_OFF_IN_LOW_POWER` | `0` |If set to `1`, haptic feedback is disabled before the device is configured, and while the device is suspended. |
24
25## Known Supported Hardware
26
27| Name | Description |
28|--------------------|-------------------------------------------------|
29| [LV061228B-L65-A](https://www.digikey.com/product-detail/en/jinlong-machinery-electronics-inc/LV061228B-L65-A/1670-1050-ND/7732325) | z-axis 2v LRA |
30| [Mini Motor Disc](https://www.adafruit.com/product/1201) | small 2-5v ERM |
31
32## Haptic Keycodes
33
34Not all keycodes below will work depending on which haptic mechanism you have chosen.
35
36| Key | Aliases | Description |
37|-----------------------------|---------|-------------------------------------------------------|
38|`QK_HAPTIC_ON` |`HF_ON` | Turn haptic feedback on |
39|`QK_HAPTIC_OFF` |`HF_OFF` | Turn haptic feedback off |
40|`QK_HAPTIC_TOGGLE` |`HF_TOGG`| Toggle haptic feedback on/off |
41|`QK_HAPTIC_RESET` |`HF_RST` | Reset haptic feedback config to default |
42|`QK_HAPTIC_FEEDBACK_TOGGLE` |`HF_FDBK`| Toggle feedback to occur on keypress, release or both |
43|`QK_HAPTIC_BUZZ_TOGGLE` |`HF_BUZZ`| Toggle solenoid buzz on/off |
44|`QK_HAPTIC_MODE_NEXT` |`HF_NEXT`| Go to next DRV2605L waveform |
45|`QK_HAPTIC_MODE_PREVIOUS` |`HF_PREV`| Go to previous DRV2605L waveform |
46|`QK_HAPTIC_CONTINUOUS_TOGGLE`|`HF_CONT`| Toggle continuous haptic mode on/off |
47|`QK_HAPTIC_CONTINUOUS_UP` |`HF_CONU`| Increase DRV2605L continuous haptic strength |
48|`QK_HAPTIC_CONTINUOUS_DOWN` |`HF_COND`| Decrease DRV2605L continuous haptic strength |
49|`QK_HAPTIC_DWELL_UP` |`HF_DWLU`| Increase Solenoid dwell time |
50|`QK_HAPTIC_DWELL_DOWN` |`HF_DWLD`| Decrease Solenoid dwell time |
51
52### Solenoids
53
54The solenoid code supports relay switches, and similar hardware, as well as solenoids.
55
56For a regular solenoid, you will need a build a circuit to drive the solenoid through a mosfet as most MCU will not be able to provide the current needed to drive the coil in the solenoid.
57
58[Wiring diagram provided by Adafruit](https://cdn-shop.adafruit.com/product-files/412/solenoid_driver.pdf)
59
60For relay switches, the hardware may already contain all of that ciruitry, and just require VCC, GND and a data pin.
61
62| Settings | Default | Description |
63|----------------------------|----------------------|--------------------------------------------------------------|
64|`SOLENOID_PIN` | *Not defined* |Configures the pin that the switch is connected to. |
65|`SOLENOID_PIN_ACTIVE_LOW` | *Not defined* |If defined then the switch trigger pin is active low. |
66|`SOLENOID_PINS` | *Not defined* |Configures an array of pins to be used for switch activation. |
67|`SOLENOID_PINS_ACTIVE_LOW` | *Not defined* |Allows you to specify how each pin is pulled for activation. |
68|`SOLENOID_RANDOM_FIRE` | *Not defined* |When there are multiple solenoids, will select a random one to fire.|
69|`SOLENOID_DEFAULT_DWELL` | `12` ms |Configures the default dwell time for the switch. |
70|`SOLENOID_MIN_DWELL` | `4` ms |Sets the lower limit for the dwell. |
71|`SOLENOID_MAX_DWELL` | `100` ms |Sets the upper limit for the dwell. |
72|`SOLENOID_DWELL_STEP_SIZE` | `1` ms |The step size to use when `HF_DWL*` keycodes are sent. |
73|`SOLENOID_DEFAULT_BUZZ` | `0` (disabled) |On `HF_RST` buzz is set "on" if this is "1" |
74|`SOLENOID_BUZZ_ACTUATED` | `SOLENOID_MIN_DWELL` |Actuated-time when the switch is in buzz mode. |
75|`SOLENOID_BUZZ_NONACTUATED` | `SOLENOID_MIN_DWELL` |Non-Actuated-time when the switch is in buzz mode. |
76
77* If solenoid buzz is off, then dwell time is how long the "plunger" stays activated. The dwell time changes how the solenoid sounds.
78* If solenoid buzz is on, then dwell time sets the length of the buzz, while `SOLENOID_BUZZ_ACTUATED` and `SOLENOID_BUZZ_NONACTUATED` set the (non-)actuation times within the buzz period.
79* With the current implementation, for any of the above time settings, the precision of these settings may be affected by how fast the keyboard is able to scan the matrix.
80 Therefore, if the keyboards scanning routine is slow, it may be preferable to set `SOLENOID_DWELL_STEP_SIZE` to a value slightly smaller than the time it takes to scan the keyboard.
81
82Beware that some pins may be powered during bootloader (ie. A13 on the STM32F303 chip) and will result in the solenoid kept in the on state through the whole flashing process. This may overheat and damage the solenoid. If you find that the pin the solenoid is connected to is triggering the solenoid during bootloader/DFU, select another pin.
83
84### DRV2605L
85
86DRV2605L is controlled over i2c protocol, and has to be connected to the SDA and SCL pins, these varies depending on the MCU in use.
87
88#### Feedback motor setup
89
90This driver supports 2 different feedback motors. Set the following in your `config.h` based on which motor you have selected.
91
92##### ERM
93
94Eccentric Rotating Mass vibration motors (ERM) is motor with a off-set weight attached so when drive signal is attached, the off-set weight spins and causes a sinusoidal wave that translate into vibrations.
95
96```c
97#define DRV2605L_FB_ERM_LRA 0
98#define DRV2605L_FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */
99#define DRV2605L_FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */
100
101/* Please refer to your datasheet for the optimal setting for your specific motor. */
102#define DRV2605L_RATED_VOLTAGE 3
103#define DRV2605L_V_PEAK 5
104```
105##### LRA
106
107Linear resonant actuators (LRA, also know as a linear vibrator) works different from a ERM. A LRA has a weight and magnet suspended by springs and a voice coil. When the drive signal is applied, the weight would be vibrate on a single axis (side to side or up and down). Since the weight is attached to a spring, there is a resonance effect at a specific frequency. This frequency is where the LRA will operate the most efficiently. Refer to the motor's datasheet for the recommended range for this frequency.
108
109```c
110#define DRV2605L_FB_ERM_LRA 1
111#define DRV2605L_FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */
112#define DRV2605L_FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */
113
114/* Please refer to your datasheet for the optimal setting for your specific motor. */
115#define DRV2605L_RATED_VOLTAGE 2
116#define DRV2605L_V_PEAK 2.8
117#define DRV2605L_V_RMS 2.0
118#define DRV2605L_V_PEAK 2.1
119#define DRV2605L_F_LRA 205 /* resonance freq */
120```
121
122#### DRV2605L waveform library
123
124DRV2605L comes with preloaded library of various waveform sequences that can be called and played. If writing a macro, these waveforms can be played using `drv2605l_pulse(*sequence name or number*)` after adding `#include "drv2605l.h"`.
125
126List of waveform sequences from the datasheet:
127
128|seq# | Sequence name |seq# | Sequence name |seq# |Sequence name |
129|-----|---------------------|-----|-----------------------------------|-----|--------------------------------------|
130| 1 | strong_click | 43 | lg_dblclick_med_60 | 85 | transition_rampup_med_smooth2 |
131| 2 | strong_click_60 | 44 | lg_dblsharp_tick | 86 | transition_rampup_short_smooth1 |
132| 3 | strong_click_30 | 45 | lg_dblsharp_tick_80 | 87 | transition_rampup_short_smooth2 |
133| 4 | sharp_click | 46 | lg_dblsharp_tick_60 | 88 | transition_rampup_long_sharp1 |
134| 5 | sharp_click_60 | 47 | buzz | 89 | transition_rampup_long_sharp2 |
135| 6 | sharp_click_30 | 48 | buzz_80 | 90 | transition_rampup_med_sharp1 |
136| 7 | soft_bump | 49 | buzz_60 | 91 | transition_rampup_med_sharp2 |
137| 8 | soft_bump_60 | 50 | buzz_40 | 92 | transition_rampup_short_sharp1 |
138| 9 | soft_bump_30 | 51 | buzz_20 | 93 | transition_rampup_short_sharp2 |
139| 10 | dbl_click | 52 | pulsing_strong | 94 | transition_rampdown_long_smooth1_50 |
140| 11 | dbl_click_60 | 53 | pulsing_strong_80 | 95 | transition_rampdown_long_smooth2_50 |
141| 12 | trp_click | 54 | pulsing_medium | 96 | transition_rampdown_med_smooth1_50 |
142| 13 | soft_fuzz | 55 | pulsing_medium_80 | 97 | transition_rampdown_med_smooth2_50 |
143| 14 | strong_buzz | 56 | pulsing_sharp | 98 | transition_rampdown_short_smooth1_50 |
144| 15 | alert_750ms | 57 | pulsing_sharp_80 | 99 | transition_rampdown_short_smooth2_50 |
145| 16 | alert_1000ms | 58 | transition_click | 100 | transition_rampdown_long_sharp1_50 |
146| 17 | strong_click1 | 59 | transition_click_80 | 101 | transition_rampdown_long_sharp2_50 |
147| 18 | strong_click2_80 | 60 | transition_click_60 | 102 | transition_rampdown_med_sharp1_50 |
148| 19 | strong_click3_60 | 61 | transition_click_40 | 103 | transition_rampdown_med_sharp2_50 |
149| 20 | strong_click4_30 | 62 | transition_click_20 | 104 | transition_rampdown_short_sharp1_50 |
150| 21 | medium_click1 | 63 | transition_click_10 | 105 | transition_rampdown_short_sharp2_50 |
151| 22 | medium_click2_80 | 64 | transition_hum | 106 | transition_rampup_long_smooth1_50 |
152| 23 | medium_click3_60 | 65 | transition_hum_80 | 107 | transition_rampup_long_smooth2_50 |
153| 24 | sharp_tick1 | 66 | transition_hum_60 | 108 | transition_rampup_med_smooth1_50 |
154| 25 | sharp_tick2_80 | 67 | transition_hum_40 | 109 | transition_rampup_med_smooth2_50 |
155| 26 | sharp_tick3_60 | 68 | transition_hum_20 | 110 | transition_rampup_short_smooth1_50 |
156| 27 | sh_dblclick_str | 69 | transition_hum_10 | 111 | transition_rampup_short_smooth2_50 |
157| 28 | sh_dblclick_str_80 | 70 | transition_rampdown_long_smooth1 | 112 | transition_rampup_long_sharp1_50 |
158| 29 | sh_dblclick_str_60 | 71 | transition_rampdown_long_smooth2 | 113 | transition_rampup_long_sharp2_50 |
159| 30 | sh_dblclick_str_30 | 72 | transition_rampdown_med_smooth1 | 114 | transition_rampup_med_sharp1_50 |
160| 31 | sh_dblclick_med | 73 | transition_rampdown_med_smooth2 | 115 | transition_rampup_med_sharp2_50 |
161| 32 | sh_dblclick_med_80 | 74 | transition_rampdown_short_smooth1 | 116 | transition_rampup_short_sharp1_50 |
162| 33 | sh_dblclick_med_60 | 75 | transition_rampdown_short_smooth2 | 117 | transition_rampup_short_sharp2_50 |
163| 34 | sh_dblsharp_tick | 76 | transition_rampdown_long_sharp1 | 118 | long_buzz_for_programmatic_stopping |
164| 35 | sh_dblsharp_tick_80 | 77 | transition_rampdown_long_sharp2 | 119 | smooth_hum1_50 |
165| 36 | sh_dblsharp_tick_60 | 78 | transition_rampdown_med_sharp1 | 120 | smooth_hum2_40 |
166| 37 | lg_dblclick_str | 79 | transition_rampdown_med_sharp2 | 121 | smooth_hum3_30 |
167| 38 | lg_dblclick_str_80 | 80 | transition_rampdown_short_sharp1 | 122 | smooth_hum4_20 |
168| 39 | lg_dblclick_str_60 | 81 | transition_rampdown_short_sharp2 | 123 | smooth_hum5_10 |
169| 40 | lg_dblclick_str_30 | 82 | transition_rampup_long_smooth1 | | |
170| 41 | lg_dblclick_med | 83 | transition_rampup_long_smooth2 | | |
171| 42 | lg_dblclick_med_80 | 84 | transition_rampup_med_smooth1 | | |
172### Optional DRV2605L defines
173
174```c
175#define DRV2605L_GREETING *sequence name or number*
176```
177If haptic feedback is enabled, the keyboard will vibrate to a specific sequence during startup. That can be selected using the following define:
178
179```c
180#define DRV2605L_DEFAULT_MODE *sequence name or number*
181```
182This will set what sequence `HF_RST` will set as the active mode. If not defined, mode will be set to 1 when `HF_RST` is pressed.
183
184### DRV2605L Continuous Haptic Mode
185
186This mode sets continuous haptic feedback with the option to increase or decrease strength.
187
188## Haptic Key Exclusion
189The Haptic Exclusion is implemented as `__attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record)` in haptic.c. This allows a re-definition at the required level with the specific requirement / exclusion.
190
191### NO_HAPTIC_MOD
192With the entry of `#define NO_HAPTIC_MOD` in config.h, the following keys will not trigger feedback:
193
194* Usual modifier keys such as Control/Shift/Alt/Gui (For example `KC_LCTL`)
195* `MO()` momentary keys. See also [Layers](../feature_layers).
196* `LM()` momentary keys with mod active.
197* `LT()` layer tap keys, when held to activate a layer. However when tapped, and the key is quickly released, and sends a keycode, haptic feedback is still triggered.
198* `TT()` layer tap toggle keys, when held to activate a layer. However when tapped `TAPPING_TOGGLE` times to permanently toggle the layer, on the last tap haptic feedback is still triggered.
199* `MT()` mod tap keys, when held to keep a usual modifier key pressed. However when tapped, and the key is quickly released, and sends a keycode, haptic feedback is still triggered. See also [Mod-Tap](../mod_tap).
200
201### NO_HAPTIC_ALPHA
202With the entry of `#define NO_HAPTIC_ALPHA` in config.h, none of the alpha keys (A ... Z) will trigger a feedback.
203
204### NO_HAPTIC_PUNCTUATION
205With the entry of `#define NO_HAPTIC_PUNCTUATION` in config.h, none of the following keys will trigger a feedback: Enter, ESC, Backspace, Space, Minus, Equal, Left Bracket, Right Bracket, Backslash, Non-US Hash, Semicolon, Quote, Grave, Comma, Slash, Dot, Non-US Backslash.
206
207### NO_HAPTIC_LOCKKEYS
208With the entry of `#define NO_HAPTIC_LOCKKEYS` in config.h, none of the following keys will trigger a feedback: Caps Lock, Scroll Lock, Num Lock.
209
210### NO_HAPTIC_NAV
211With the entry of `#define NO_HAPTIC_NAV` in config.h, none of the following keys will trigger a feedback: Print Screen, Pause, Insert, Delete, Page Down, Page Up, Left Arrow, Up Arrow, Right Arrow, Down Arrow, End, Home.
212
213### NO_HAPTIC_NUMERIC
214With the entry of `#define NO_HAPTIC_NUMERIC` in config.h, none of the following keys between 0 and 9 (KC_1 ... KC_0) will trigger a feedback.