haptic.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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 "progmem.h"
  20. #include "debug.h"
  21. #ifdef DRV2605L
  22. # include "DRV2605L.h"
  23. #endif
  24. #ifdef SOLENOID_ENABLE
  25. # include "solenoid.h"
  26. #endif
  27. haptic_config_t haptic_config;
  28. void haptic_init(void) {
  29. debug_enable = 1; // Debug is ON!
  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. void haptic_task(void) {
  59. #ifdef SOLENOID_ENABLE
  60. solenoid_check();
  61. #endif
  62. }
  63. void eeconfig_debug_haptic(void) {
  64. dprintf("haptic_config eprom\n");
  65. dprintf("haptic_config.enable = %d\n", haptic_config.enable);
  66. dprintf("haptic_config.mode = %d\n", haptic_config.mode);
  67. }
  68. void haptic_enable(void) {
  69. haptic_config.enable = 1;
  70. xprintf("haptic_config.enable = %u\n", haptic_config.enable);
  71. eeconfig_update_haptic(haptic_config.raw);
  72. }
  73. void haptic_disable(void) {
  74. haptic_config.enable = 0;
  75. xprintf("haptic_config.enable = %u\n", haptic_config.enable);
  76. eeconfig_update_haptic(haptic_config.raw);
  77. }
  78. void haptic_toggle(void) {
  79. if (haptic_config.enable) {
  80. haptic_disable();
  81. } else {
  82. haptic_enable();
  83. }
  84. eeconfig_update_haptic(haptic_config.raw);
  85. }
  86. void haptic_feedback_toggle(void) {
  87. haptic_config.feedback++;
  88. if (haptic_config.feedback >= HAPTIC_FEEDBACK_MAX) haptic_config.feedback = KEY_PRESS;
  89. xprintf("haptic_config.feedback = %u\n", !haptic_config.feedback);
  90. eeconfig_update_haptic(haptic_config.raw);
  91. }
  92. void haptic_buzz_toggle(void) {
  93. bool buzz_stat = !haptic_config.buzz;
  94. haptic_config.buzz = buzz_stat;
  95. haptic_set_buzz(buzz_stat);
  96. }
  97. void haptic_mode_increase(void) {
  98. uint8_t mode = haptic_config.mode + 1;
  99. #ifdef DRV2605L
  100. if (haptic_config.mode >= drv_effect_max) {
  101. mode = 1;
  102. }
  103. #endif
  104. haptic_set_mode(mode);
  105. }
  106. void haptic_mode_decrease(void) {
  107. uint8_t mode = haptic_config.mode - 1;
  108. #ifdef DRV2605L
  109. if (haptic_config.mode < 1) {
  110. mode = (drv_effect_max - 1);
  111. }
  112. #endif
  113. haptic_set_mode(mode);
  114. }
  115. void haptic_dwell_increase(void) {
  116. #ifdef SOLENOID_ENABLE
  117. int16_t next_dwell = ((int16_t)haptic_config.dwell) + SOLENOID_DWELL_STEP_SIZE;
  118. if (haptic_config.dwell >= SOLENOID_MAX_DWELL) {
  119. // if it's already at max, we wrap back to min
  120. next_dwell = SOLENOID_MIN_DWELL;
  121. } else if (next_dwell > SOLENOID_MAX_DWELL) {
  122. // if we overshoot the max, then cap at max
  123. next_dwell = SOLENOID_MAX_DWELL;
  124. }
  125. solenoid_set_dwell(next_dwell);
  126. #else
  127. int16_t next_dwell = ((int16_t)haptic_config.dwell) + 1;
  128. #endif
  129. haptic_set_dwell(next_dwell);
  130. }
  131. void haptic_dwell_decrease(void) {
  132. #ifdef SOLENOID_ENABLE
  133. int16_t next_dwell = ((int16_t)haptic_config.dwell) - SOLENOID_DWELL_STEP_SIZE;
  134. if (haptic_config.dwell <= SOLENOID_MIN_DWELL) {
  135. // if it's already at min, we wrap to max
  136. next_dwell = SOLENOID_MAX_DWELL;
  137. } else if (next_dwell < SOLENOID_MIN_DWELL) {
  138. // if we go below min, then we cap to min
  139. next_dwell = SOLENOID_MIN_DWELL;
  140. }
  141. solenoid_set_dwell(next_dwell);
  142. #else
  143. int16_t next_dwell = ((int16_t)haptic_config.dwell) - 1;
  144. #endif
  145. haptic_set_dwell(next_dwell);
  146. }
  147. void haptic_reset(void) {
  148. haptic_config.enable = true;
  149. uint8_t feedback = HAPTIC_FEEDBACK_DEFAULT;
  150. haptic_config.feedback = feedback;
  151. #ifdef DRV2605L
  152. uint8_t mode = HAPTIC_MODE_DEFAULT;
  153. haptic_config.mode = mode;
  154. #endif
  155. #ifdef SOLENOID_ENABLE
  156. uint8_t dwell = SOLENOID_DEFAULT_DWELL;
  157. haptic_config.dwell = dwell;
  158. haptic_config.buzz = SOLENOID_DEFAULT_BUZZ;
  159. solenoid_set_dwell(dwell);
  160. #else
  161. // This is to trigger haptic_reset again, if solenoid is enabled in the future.
  162. haptic_config.dwell = 0;
  163. haptic_config.buzz = 0;
  164. #endif
  165. eeconfig_update_haptic(haptic_config.raw);
  166. xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
  167. xprintf("haptic_config.mode = %u\n", haptic_config.mode);
  168. }
  169. void haptic_set_feedback(uint8_t feedback) {
  170. haptic_config.feedback = feedback;
  171. eeconfig_update_haptic(haptic_config.raw);
  172. xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
  173. }
  174. void haptic_set_mode(uint8_t mode) {
  175. haptic_config.mode = mode;
  176. eeconfig_update_haptic(haptic_config.raw);
  177. xprintf("haptic_config.mode = %u\n", haptic_config.mode);
  178. }
  179. void haptic_set_amplitude(uint8_t amp) {
  180. haptic_config.amplitude = amp;
  181. eeconfig_update_haptic(haptic_config.raw);
  182. xprintf("haptic_config.amplitude = %u\n", haptic_config.amplitude);
  183. #ifdef DRV2605L
  184. DRV_amplitude(amp);
  185. #endif
  186. }
  187. void haptic_set_buzz(uint8_t buzz) {
  188. haptic_config.buzz = buzz;
  189. eeconfig_update_haptic(haptic_config.raw);
  190. xprintf("haptic_config.buzz = %u\n", haptic_config.buzz);
  191. }
  192. void haptic_set_dwell(uint8_t dwell) {
  193. haptic_config.dwell = dwell;
  194. eeconfig_update_haptic(haptic_config.raw);
  195. xprintf("haptic_config.dwell = %u\n", haptic_config.dwell);
  196. }
  197. uint8_t haptic_get_mode(void) {
  198. if (!haptic_config.enable) {
  199. return false;
  200. }
  201. return haptic_config.mode;
  202. }
  203. uint8_t haptic_get_feedback(void) {
  204. if (!haptic_config.enable) {
  205. return false;
  206. }
  207. return haptic_config.feedback;
  208. }
  209. uint8_t haptic_get_dwell(void) {
  210. if (!haptic_config.enable) {
  211. return false;
  212. }
  213. return haptic_config.dwell;
  214. }
  215. void haptic_enable_continuous(void) {
  216. haptic_config.cont = 1;
  217. xprintf("haptic_config.cont = %u\n", haptic_config.cont);
  218. eeconfig_update_haptic(haptic_config.raw);
  219. #ifdef DRV2605L
  220. DRV_rtp_init();
  221. #endif
  222. }
  223. void haptic_disable_continuous(void) {
  224. haptic_config.cont = 0;
  225. xprintf("haptic_config.cont = %u\n", haptic_config.cont);
  226. eeconfig_update_haptic(haptic_config.raw);
  227. #ifdef DRV2605L
  228. DRV_write(DRV_MODE, 0x00);
  229. #endif
  230. }
  231. void haptic_toggle_continuous(void) {
  232. #ifdef DRV2605L
  233. if (haptic_config.cont) {
  234. haptic_disable_continuous();
  235. } else {
  236. haptic_enable_continuous();
  237. }
  238. eeconfig_update_haptic(haptic_config.raw);
  239. #endif
  240. }
  241. void haptic_cont_increase(void) {
  242. uint8_t amp = haptic_config.amplitude + 10;
  243. if (haptic_config.amplitude >= 120) {
  244. amp = 120;
  245. }
  246. haptic_set_amplitude(amp);
  247. }
  248. void haptic_cont_decrease(void) {
  249. uint8_t amp = haptic_config.amplitude - 10;
  250. if (haptic_config.amplitude < 20) {
  251. amp = 20;
  252. }
  253. haptic_set_amplitude(amp);
  254. }
  255. void haptic_play(void) {
  256. #ifdef DRV2605L
  257. uint8_t play_eff = 0;
  258. play_eff = haptic_config.mode;
  259. DRV_pulse(play_eff);
  260. #endif
  261. #ifdef SOLENOID_ENABLE
  262. solenoid_fire();
  263. #endif
  264. }
  265. __attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record) {
  266. switch(keycode) {
  267. # ifdef NO_HAPTIC_MOD
  268. case QK_MOD_TAP ... QK_MOD_TAP_MAX:
  269. if (record->tap.count == 0) return false;
  270. break;
  271. case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
  272. if (record->tap.count != TAPPING_TOGGLE) return false;
  273. break;
  274. case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
  275. if (record->tap.count == 0) return false;
  276. break;
  277. case KC_LCTRL ... KC_RGUI:
  278. case QK_MOMENTARY ... QK_MOMENTARY_MAX:
  279. # endif
  280. # ifdef NO_HAPTIC_FN
  281. case KC_FN0 ... KC_FN31:
  282. # endif
  283. # ifdef NO_HAPTIC_ALPHA
  284. case KC_A ... KC_Z:
  285. # endif
  286. # ifdef NO_HAPTIC_PUNCTUATION
  287. case KC_ENTER:
  288. case KC_ESCAPE:
  289. case KC_BSPACE:
  290. case KC_SPACE:
  291. case KC_MINUS:
  292. case KC_EQUAL:
  293. case KC_LBRACKET:
  294. case KC_RBRACKET:
  295. case KC_BSLASH:
  296. case KC_NONUS_HASH:
  297. case KC_SCOLON:
  298. case KC_QUOTE:
  299. case KC_GRAVE:
  300. case KC_COMMA:
  301. case KC_SLASH:
  302. case KC_DOT:
  303. case KC_NONUS_BSLASH:
  304. # endif
  305. # ifdef NO_HAPTIC_LOCKKEYS
  306. case KC_CAPSLOCK:
  307. case KC_SCROLLLOCK:
  308. case KC_NUMLOCK:
  309. # endif
  310. # ifdef NO_HAPTIC_NAV
  311. case KC_PSCREEN:
  312. case KC_PAUSE:
  313. case KC_INSERT:
  314. case KC_DELETE:
  315. case KC_PGDOWN:
  316. case KC_PGUP:
  317. case KC_LEFT:
  318. case KC_UP:
  319. case KC_RIGHT:
  320. case KC_DOWN:
  321. case KC_END:
  322. case KC_HOME:
  323. # endif
  324. # ifdef NO_HAPTIC_NUMERIC
  325. case KC_1 ... KC_0:
  326. # endif
  327. return false;
  328. }
  329. return true;
  330. }
  331. bool process_haptic(uint16_t keycode, keyrecord_t *record) {
  332. if (keycode == HPT_ON && record->event.pressed) {
  333. haptic_enable();
  334. }
  335. if (keycode == HPT_OFF && record->event.pressed) {
  336. haptic_disable();
  337. }
  338. if (keycode == HPT_TOG && record->event.pressed) {
  339. haptic_toggle();
  340. }
  341. if (keycode == HPT_RST && record->event.pressed) {
  342. haptic_reset();
  343. }
  344. if (keycode == HPT_FBK && record->event.pressed) {
  345. haptic_feedback_toggle();
  346. }
  347. if (keycode == HPT_BUZ && record->event.pressed) {
  348. haptic_buzz_toggle();
  349. }
  350. if (keycode == HPT_MODI && record->event.pressed) {
  351. haptic_mode_increase();
  352. }
  353. if (keycode == HPT_MODD && record->event.pressed) {
  354. haptic_mode_decrease();
  355. }
  356. if (keycode == HPT_DWLI && record->event.pressed) {
  357. haptic_dwell_increase();
  358. }
  359. if (keycode == HPT_DWLD && record->event.pressed) {
  360. haptic_dwell_decrease();
  361. }
  362. if (keycode == HPT_CONT && record->event.pressed) {
  363. haptic_toggle_continuous();
  364. }
  365. if (keycode == HPT_CONI && record->event.pressed) {
  366. haptic_cont_increase();
  367. }
  368. if (keycode == HPT_COND && record->event.pressed) {
  369. haptic_cont_decrease();
  370. }
  371. if (haptic_config.enable) {
  372. if (record->event.pressed) {
  373. // keypress
  374. if (haptic_config.feedback < 2 && get_haptic_enabled_key(keycode, record)) {
  375. haptic_play();
  376. }
  377. } else {
  378. // keyrelease
  379. if (haptic_config.feedback > 0 && get_haptic_enabled_key(keycode, record)) {
  380. haptic_play();
  381. }
  382. }
  383. }
  384. return true;
  385. }
  386. void haptic_shutdown(void) {
  387. #ifdef SOLENOID_ENABLE
  388. solenoid_shutdown();
  389. #endif
  390. }