소스 검색

Haptic feedback generalized - DRV2605 and solenoids (#4939)

* initial work to add eeprom to haptic feedback and decouple the feedback process from keyboards

* Haptic feedback enhancements: on/off toggle working, feedback order working
todo:
-work on modes switching
-get modes switching to save to eeprom

* haptic enhancement - eeprom and modes added

* Added set and get functions for haptic feedback

* initial implementation of solenoids under haptic feedback

* changed eeprom to 32 bits to reserve blocks for future features

* start documentation of haptic feedback

* change keycode per comment from reviewers

* typo fixes

* added eeprom for solenoid configs

* added solenoid and docs

* Add/fix default parameters configs, improve docs

* more doc cleanup

* add in solenoid buzz toggle, clean up doc

* some fixes for error in compiling solenoid

* fix a chibios specific i2c read function and added one for AVR controllers in DRV2605L.c

* fixes for avr side issues

* update keymap

* fix keymap compile error

* fix bugs found during solenoid testing

* set pin that is not powered during bootloader

* added warning about certain pins on the MCU may trip solenoid during DFU/bootloader
ishtob 6 년 전
부모
커밋
2cee371bf1

+ 10 - 0
common_features.mk

@@ -246,11 +246,21 @@ endif
 
 ifeq ($(strip $(HAPTIC_ENABLE)), DRV2605L)
     COMMON_VPATH += $(DRIVER_PATH)/haptic
+    SRC += haptic.c
     SRC += DRV2605L.c
     SRC += i2c_master.c
+    OPT_DEFS += -DHAPTIC_ENABLE
     OPT_DEFS += -DDRV2605L
 endif
 
+ifeq ($(strip $(HAPTIC_ENABLE)), SOLENOID)
+    COMMON_VPATH += $(DRIVER_PATH)/haptic
+    SRC += haptic.c
+    SRC += solenoid.c
+    OPT_DEFS += -DHAPTIC_ENABLE
+    OPT_DEFS += -DSOLENOID_ENABLE
+endif
+
 ifeq ($(strip $(HD44780_ENABLE)), yes)
     SRC += drivers/avr/hd44780.c
     OPT_DEFS += -DHD44780_ENABLE

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 147 - 0
docs/feature_haptic_feedback.md


+ 12 - 12
drivers/haptic/DRV2605L.c

@@ -21,7 +21,7 @@
 #include <math.h>
 
 
-uint8_t DRV2605L_transfer_buffer[20];
+uint8_t DRV2605L_transfer_buffer[2];
 uint8_t DRV2605L_tx_register[0];
 uint8_t DRV2605L_read_buffer[0];
 uint8_t DRV2605L_read_register;
@@ -34,6 +34,11 @@ void DRV_write(uint8_t drv_register, uint8_t settings) {
 }
 
 uint8_t DRV_read(uint8_t regaddress) {
+#ifdef __AVR__
+  i2c_readReg(DRV2605L_BASE_ADDRESS << 1,
+    regaddress, DRV2605L_read_buffer, 1, 100);
+  DRV2605L_read_register = (uint8_t)DRV2605L_read_buffer[0];
+#else
   DRV2605L_tx_register[0] = regaddress;
   if (MSG_OK != i2c_transmit_receive(DRV2605L_BASE_ADDRESS << 1,
     DRV2605L_tx_register, 1,
@@ -42,14 +47,13 @@ uint8_t DRV_read(uint8_t regaddress) {
     printf("err reading reg \n");
   }
   DRV2605L_read_register = (uint8_t)DRV2605L_read_buffer[0];
+#endif
 return DRV2605L_read_register;
 }
 
 void DRV_init(void)
 {
   i2c_init();
-  i2c_start(DRV2605L_BASE_ADDRESS);
-
   /* 0x07 sets DRV2605 into calibration mode */
   DRV_write(DRV_MODE,0x07); 
 
@@ -104,21 +108,17 @@ void DRV_init(void)
     C4_SET.Bits.C4_AUTO_CAL_TIME = AUTO_CAL_TIME;
     DRV_write(DRV_CTRL_4, (uint8_t) C4_SET.Byte);
   DRV_write(DRV_LIB_SELECTION,LIB_SELECTION);
-  //start autocalibration
+
   DRV_write(DRV_GO, 0x01);
 
   /* 0x00 sets DRV2605 out of standby and to use internal trigger
    * 0x01 sets DRV2605 out of standby and to use external trigger */
   DRV_write(DRV_MODE,0x00); 
-  
-  /* 0x06: LRA library */
-  DRV_write(DRV_WAVEFORM_SEQ_1, 0x01);
-
-  /* 0xB9: LRA, 4x brake factor, medium gain, 7.5x back EMF
-   * 0x39: ERM, 4x brake factor, medium gain, 1.365x back EMF */
-  
-  /* TODO: setup auto-calibration as part of initiation */
 
+//Play greeting sequence
+  DRV_write(DRV_GO, 0x00);
+  DRV_write(DRV_WAVEFORM_SEQ_1, DRV_GREETING);
+  DRV_write(DRV_GO, 0x01);
 }
 
 void DRV_pulse(uint8_t sequence)

+ 18 - 8
drivers/haptic/DRV2605L.h

@@ -31,13 +31,6 @@
 #define FB_LOOPGAIN 1 /* For  Low:0, Medium:1, High:2, Very High:3 */
 #endif
 
-#ifndef RATED_VOLTAGE
-#define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */
-#ifndef V_PEAK
-#define V_PEAK 2.8
-#endif
-#endif
-
 /* LRA specific settings */
 #if FB_ERM_LRA == 1
 #ifndef V_RMS
@@ -49,6 +42,16 @@
 #ifndef F_LRA
 #define F_LRA 205
 #endif
+#ifndef RATED_VOLTAGE
+#define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */
+#endif
+#endif
+
+#ifndef RATED_VOLTAGE
+#define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */
+#endif
+#ifndef V_PEAK
+#define V_PEAK 2.8
 #endif
 
 /* Library Selection */
@@ -60,6 +63,13 @@
 #endif
 #endif
 
+#ifndef DRV_GREETING
+#define DRV_GREETING alert_750ms
+#endif
+#ifndef DRV_MODE_DEFAULT
+#define DRV_MODE_DEFAULT strong_click1
+#endif
+
 /* Control 1 register settings */
 #ifndef DRIVE_TIME
 #define DRIVE_TIME 25
@@ -162,7 +172,6 @@ void DRV_write(const uint8_t drv_register, const uint8_t settings);
 uint8_t DRV_read(const uint8_t regaddress);
 void DRV_pulse(const uint8_t sequence);
 
-
 typedef enum DRV_EFFECT{
   clear_sequence      = 0,
   strong_click 		    = 1,
@@ -288,6 +297,7 @@ typedef enum DRV_EFFECT{
   smooth_hum3_30 = 121,
   smooth_hum4_20 = 122,
   smooth_hum5_10 = 123,
+  drv_effect_max = 124,
 } DRV_EFFECT;
 
 /* Register bit array unions */

+ 248 - 0
drivers/haptic/haptic.c

@@ -0,0 +1,248 @@
+/* Copyright 2019 ishtob
+ * Driver for haptic feedback written for QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "haptic.h"
+#include "eeconfig.h"
+#include "progmem.h"
+#include "debug.h"
+#ifdef DRV2605L
+#include "DRV2605L.h"
+#endif
+#ifdef SOLENOID_ENABLE
+#include "solenoid.h"
+#endif
+
+haptic_config_t haptic_config;
+
+void haptic_init(void) {
+  debug_enable = 1; //Debug is ON!
+  if (!eeconfig_is_enabled()) {
+  	eeconfig_init();
+  }
+  haptic_config.raw = eeconfig_read_haptic();
+  if (haptic_config.mode < 1){
+  haptic_config.mode = 1;
+  }
+  if (!haptic_config.mode){
+  dprintf("No haptic config found in eeprom, setting default configs\n");
+  haptic_reset();
+  }
+  #ifdef SOLENOID_ENABLE
+    solenoid_setup();
+    dprintf("Solenoid driver initialized\n");
+  #endif
+  #ifdef DRV2605L
+    DRV_init();
+    dprintf("DRV2605 driver initialized\n");
+  #endif
+  eeconfig_debug_haptic();
+}
+
+void haptic_task(void) {
+  #ifdef SOLENOID_ENABLE
+  solenoid_check();
+  #endif
+}
+
+void eeconfig_debug_haptic(void) {
+  dprintf("haptic_config eprom\n");
+  dprintf("haptic_config.enable = %d\n", haptic_config.enable);
+  dprintf("haptic_config.mode = %d\n", haptic_config.mode);
+}
+
+void haptic_enable(void) {
+  haptic_config.enable = 1;
+  xprintf("haptic_config.enable = %u\n", haptic_config.enable);
+  eeconfig_update_haptic(haptic_config.raw);
+}
+
+void haptic_disable(void) {
+  haptic_config.enable = 0;
+  xprintf("haptic_config.enable = %u\n", haptic_config.enable);
+  eeconfig_update_haptic(haptic_config.raw);
+}
+
+void haptic_toggle(void) {
+if (haptic_config.enable) {
+  haptic_disable();
+  } else {
+  haptic_enable();
+  }
+  eeconfig_update_haptic(haptic_config.raw);
+}
+
+void haptic_feedback_toggle(void){
+ haptic_config.feedback++;
+  if (haptic_config.feedback >= HAPTIC_FEEDBACK_MAX)
+  haptic_config.feedback = KEY_PRESS;
+  xprintf("haptic_config.feedback = %u\n", !haptic_config.feedback);
+  eeconfig_update_haptic(haptic_config.raw);
+}
+
+void haptic_buzz_toggle(void) {
+  bool buzz_stat = !haptic_config.buzz;
+  haptic_config.buzz = buzz_stat;
+  haptic_set_buzz(buzz_stat);
+}
+
+void haptic_mode_increase(void) {
+  uint8_t mode = haptic_config.mode + 1;
+  #ifdef DRV2605L
+  if (haptic_config.mode >= drv_effect_max) {
+    mode = 1;
+  }
+  #endif
+    haptic_set_mode(mode);
+}
+
+void haptic_mode_decrease(void) {
+  uint8_t mode = haptic_config.mode -1;
+  #ifdef DRV2605L
+  if (haptic_config.mode < 1) {
+    mode = (drv_effect_max - 1);
+  }
+  #endif
+  haptic_set_mode(mode);
+}
+
+void haptic_dwell_increase(void) {
+  uint8_t dwell = haptic_config.dwell + 1;
+  #ifdef SOLENOID_ENABLE
+  if (haptic_config.dwell >= SOLENOID_MAX_DWELL) {
+    dwell = 1;
+  }
+  solenoid_set_dwell(dwell);
+  #endif
+  haptic_set_dwell(dwell);
+}
+
+void haptic_dwell_decrease(void) {
+  uint8_t dwell = haptic_config.dwell -1;
+  #ifdef SOLENOID_ENABLE
+  if (haptic_config.dwell < SOLENOID_MIN_DWELL) {
+    dwell = SOLENOID_MAX_DWELL;
+  }
+  solenoid_set_dwell(dwell);
+  #endif
+  haptic_set_dwell(dwell);
+}
+
+void haptic_reset(void){
+  haptic_config.enable = true;
+  uint8_t feedback = HAPTIC_FEEDBACK_DEFAULT;
+  haptic_config.feedback = feedback;
+  #ifdef DRV2605L
+    uint8_t mode = HAPTIC_MODE_DEFAULT;
+    haptic_config.mode = mode;
+  #endif
+  #ifdef SOLENOID_ENABLE
+    uint8_t dwell = SOLENOID_DEFAULT_DWELL;
+    haptic_config.dwell = dwell;
+  #endif
+  eeconfig_update_haptic(haptic_config.raw);
+  xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
+  xprintf("haptic_config.mode = %u\n", haptic_config.mode);
+}
+
+void haptic_set_feedback(uint8_t feedback) {
+  haptic_config.feedback = feedback;
+  eeconfig_update_haptic(haptic_config.raw);
+  xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
+}
+
+void haptic_set_mode(uint8_t mode) {
+  haptic_config.mode = mode;
+  eeconfig_update_haptic(haptic_config.raw);
+  xprintf("haptic_config.mode = %u\n", haptic_config.mode);
+}
+
+void haptic_set_buzz(uint8_t buzz) {
+  haptic_config.buzz = buzz;
+  eeconfig_update_haptic(haptic_config.raw);
+  xprintf("haptic_config.buzz = %u\n", haptic_config.buzz);
+}
+
+void haptic_set_dwell(uint8_t dwell) {
+  haptic_config.dwell = dwell;
+  eeconfig_update_haptic(haptic_config.raw);
+  xprintf("haptic_config.dwell = %u\n", haptic_config.dwell);
+}
+
+uint8_t haptic_get_mode(void) {
+  if (!haptic_config.enable){
+    return false;
+  }
+  return haptic_config.mode;
+}
+
+uint8_t haptic_get_feedback(void) {
+  if (!haptic_config.enable){
+    return false;
+  }
+  return haptic_config.feedback;
+}
+
+uint8_t haptic_get_dwell(void) {
+  if (!haptic_config.enable){
+    return false;
+  }
+  return haptic_config.dwell;
+}
+
+void haptic_play(void) {
+  #ifdef DRV2605L
+  uint8_t play_eff = 0;
+  play_eff = haptic_config.mode;
+  DRV_pulse(play_eff);
+  #endif
+  #ifdef SOLENOID_ENABLE
+  solenoid_fire();
+  #endif
+}
+
+bool process_haptic(uint16_t keycode, keyrecord_t *record) {
+    if (keycode == HPT_ON && record->event.pressed) { haptic_enable(); }
+    if (keycode == HPT_OFF && record->event.pressed) { haptic_disable(); }
+    if (keycode == HPT_TOG && record->event.pressed) { haptic_toggle(); }
+    if (keycode == HPT_RST && record->event.pressed) { haptic_reset(); }
+    if (keycode == HPT_FBK && record->event.pressed) { haptic_feedback_toggle(); }
+    if (keycode == HPT_BUZ && record->event.pressed) { haptic_buzz_toggle(); }
+    if (keycode == HPT_MODI && record->event.pressed) { haptic_mode_increase(); }
+    if (keycode == HPT_MODD && record->event.pressed) { haptic_mode_decrease(); }
+    if (keycode == HPT_DWLI && record->event.pressed) { haptic_dwell_increase(); }
+    if (keycode == HPT_DWLD && record->event.pressed) { haptic_dwell_decrease(); }
+  if (haptic_config.enable) {
+    if ( record->event.pressed ) {
+	// keypress
+      if (haptic_config.feedback < 2) {
+      haptic_play();
+      }
+    } else {
+    //keyrelease
+      if (haptic_config.feedback > 0) {
+      haptic_play();
+      } 
+    }
+  }
+  return true;
+}
+
+void haptic_shutdown(void) {
+  #ifdef SOLENOID_ENABLE
+  solenoid_shutdown();
+  #endif
+
+}

+ 82 - 0
drivers/haptic/haptic.h

@@ -0,0 +1,82 @@
+/* Copyright 2019 ishtob
+ * Driver for haptic feedback written for QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+#include <stdint.h>
+#include <stdbool.h>
+#include "quantum.h"
+#ifdef DRV2605L
+#include "DRV2605L.h"
+#endif
+
+
+#ifndef HAPTIC_FEEDBACK_DEFAULT
+#define HAPTIC_FEEDBACK_DEFAULT 0
+#endif
+#ifndef HAPTIC_MODE_DEFAULT
+#define HAPTIC_MODE_DEFAULT DRV_MODE_DEFAULT
+#endif
+
+/* EEPROM config settings */
+typedef union {
+  uint32_t raw;
+  struct {
+    bool     enable    :1;
+    uint8_t  feedback  :2;
+    uint8_t  mode      :7;
+    bool     buzz      :1;
+    uint8_t  dwell     :7;
+    uint16_t reserved  :16; 
+  };
+} haptic_config_t;
+
+typedef enum HAPTIC_FEEDBACK{
+  KEY_PRESS,
+  KEY_PRESS_RELEASE,
+  KEY_RELEASE,
+  HAPTIC_FEEDBACK_MAX,
+} HAPTIC_FEEDBACK;
+
+bool process_haptic(uint16_t keycode, keyrecord_t *record);
+void haptic_init(void);
+void haptic_task(void);
+void eeconfig_debug_haptic(void);
+void haptic_enable(void);
+void haptic_disable(void);
+void haptic_toggle(void);
+void haptic_feedback_toggle(void);
+void haptic_mode_increase(void);
+void haptic_mode_decrease(void);
+void haptic_mode(uint8_t mode);
+void haptic_reset(void);
+void haptic_set_feedback(uint8_t feedback);
+void haptic_set_mode(uint8_t mode);
+void haptic_set_dwell(uint8_t dwell);
+void haptic_set_buzz(uint8_t buzz);
+void haptic_buzz_toggle(void);
+uint8_t haptic_get_mode(void);
+uint8_t haptic_get_feedback(void);
+void haptic_dwell_increase(void);
+void haptic_dwell_decrease(void);
+
+void haptic_play(void);
+void haptic_shutdown(void);
+
+
+
+
+

+ 109 - 0
drivers/haptic/solenoid.c

@@ -0,0 +1,109 @@
+/* Copyright 2018 mtdjr - modified by ishtob
+ * Driver for solenoid written for QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <timer.h>
+#include "solenoid.h"
+#include "haptic.h"
+
+bool solenoid_on = false;
+bool solenoid_buzzing = false;
+uint16_t solenoid_start = 0;
+uint8_t solenoid_dwell = SOLENOID_DEFAULT_DWELL;
+
+extern haptic_config_t haptic_config;
+
+
+void solenoid_buzz_on(void) {
+  haptic_set_buzz(1);
+}
+
+void solenoid_buzz_off(void) {
+  haptic_set_buzz(0);
+}
+
+void solenoid_set_buzz(int buzz) {
+  haptic_set_buzz(buzz);
+}
+
+
+void solenoid_dwell_minus(uint8_t solenoid_dwell) {
+  if (solenoid_dwell > 0) solenoid_dwell--;
+}
+
+void solenoid_dwell_plus(uint8_t solenoid_dwell) {
+  if (solenoid_dwell < SOLENOID_MAX_DWELL) solenoid_dwell++;
+}
+
+void solenoid_set_dwell(uint8_t dwell) {
+  solenoid_dwell = dwell;
+}
+
+void solenoid_stop(void) {
+  writePinLow(SOLENOID_PIN);
+  solenoid_on = false;
+  solenoid_buzzing = false;
+}
+
+void solenoid_fire(void) {
+  if (!haptic_config.buzz && solenoid_on) return;
+  if (haptic_config.buzz && solenoid_buzzing) return;
+
+  solenoid_on = true;
+  solenoid_buzzing = true;
+  solenoid_start = timer_read();
+  writePinHigh(SOLENOID_PIN);
+}
+
+void solenoid_check(void) {
+  uint16_t elapsed = 0;
+
+  if (!solenoid_on) return;
+
+  elapsed = timer_elapsed(solenoid_start);
+
+  //Check if it's time to finish this solenoid click cycle
+  if (elapsed > solenoid_dwell) {
+    solenoid_stop();
+    return;
+  }
+
+  //Check whether to buzz the solenoid on and off
+  if (haptic_config.buzz) {
+    if (elapsed / SOLENOID_MIN_DWELL % 2 == 0){
+      if (!solenoid_buzzing) {
+        solenoid_buzzing = true;
+        writePinHigh(SOLENOID_PIN);
+      }
+    }
+    else {
+      if (solenoid_buzzing) {
+        solenoid_buzzing = false;
+        writePinLow(SOLENOID_PIN);
+      }
+    }
+  }
+}
+
+void solenoid_setup(void) {
+  setPinOutput(SOLENOID_PIN);
+  solenoid_fire();
+}
+
+void solenoid_shutdown(void) {
+  writePinLow(SOLENOID_PIN);
+
+}

+ 54 - 0
drivers/haptic/solenoid.h

@@ -0,0 +1,54 @@
+/* Copyright 2018 mtdjr - modified by ishtob
+ * Driver for solenoid written for QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#ifndef SOLENOID_DEFAULT_DWELL
+#define SOLENOID_DEFAULT_DWELL 12
+#endif
+
+#ifndef SOLENOID_MAX_DWELL
+#define SOLENOID_MAX_DWELL 100
+#endif
+
+#ifndef SOLENOID_MIN_DWELL
+#define SOLENOID_MIN_DWELL 4
+#endif
+
+#ifndef SOLENOID_ACTIVE
+#define SOLENOID_ACTIVE false
+#endif
+
+#ifndef SOLENOID_PIN
+#define SOLENOID_PIN F6
+#endif
+
+void solenoid_buzz_on(void);
+void solenoid_buzz_off(void);
+void solenoid_set_buzz(int buzz);
+
+void solenoid_dwell_minus(uint8_t solenoid_dwell);
+void solenoid_dwell_plus(uint8_t solenoid_dwell);
+void solenoid_set_dwell(uint8_t dwell);
+
+void solenoid_stop(void);
+void solenoid_fire(void);
+
+void solenoid_check(void);
+
+void solenoid_setup(void);
+void solenoid_shutdown(void);

+ 3 - 0
keyboards/hadron/ver3/config.h

@@ -192,4 +192,7 @@
 //#define DRIVER_LED_TOTAL RGBLED_NUM
 
 //#define RGB_MATRIX_KEYPRESSES
+
+#define SOLENOID_PIN A14
+
 #endif

+ 2 - 2
keyboards/hadron/ver3/keymaps/default/keymap.c

@@ -190,8 +190,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  * `--------------------------------------------------------------------------------------------------------'
  */
 [_ADJUST] = LAYOUT(
-  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12, \
-  RESET,   RGB_TOG, RGB_MOD, RGB_HUI, RGB_HUD, RGB_SAI, RGB_SAD, RGB_VAI, RGB_VAD, _______, _______, _______, _______, _______, KC_DEL, \
+  RESET,   HPT_TOG, HPT_FBK, HPT_MODI, HPT_MODD, HPT_RST , _______, _______, _______, _______, _______, _______, \
+  _______, RGB_TOG, RGB_MOD, RGB_HUI, RGB_HUD, RGB_SAI, RGB_SAD, RGB_VAI, RGB_VAD, _______, _______, _______, _______, _______, KC_DEL, \
   _______, _______, _______, AU_ON,   AU_OFF,  AG_NORM, _______, _______, _______, AG_SWAP, QWERTY,  COLEMAK, _______,  _______,  _______, \
   _______, MUV_DE,  MUV_IN,  MU_ON,   MU_OFF,  MI_ON,   MI_OFF, _______, _______, _______,  _______, BL_DEC,  BL_INC,  BL_STEP, BL_TOGG, \
   _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, CK_RST,  CK_DOWN, CK_UP,   CK_TOGG\

+ 1 - 1
keyboards/hadron/ver3/keymaps/ishtob/keymap.c

@@ -165,7 +165,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  * `--------------------------------------------------------------------------------------------------------'
  */
 [_ADJUST] = LAYOUT_wrapper(
-  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12, \
+  _______, HPT_TOG, HPT_FBK, HPT_MODI, HPT_MODD, HPT_RST, _______, _______, _______, _______, _______, _______, \
   RESET,   RGB_TOG, RGB_MOD, RGB_HUI, RGB_HUD, RGB_SAI, RGB_SAD, RGB_VAI, RGB_VAD, _______, _______, _______, _______, _______, KC_DEL, \
   _______, MAGIC_TOGGLE_NKRO, _______, AU_ON,   AU_OFF,  AG_NORM, _______, _______, _______, AG_SWAP, QWERTY,  COLEMAK, _______,  _______,  _______, \
   _______, MUV_DE,  MUV_IN,  MU_ON,   MU_OFF,  MI_ON,   MI_OFF, _______, _______, _______,  _______, BL_DEC,  BL_INC,  BL_STEP, BL_TOGG, \

+ 1 - 1
keyboards/hadron/ver3/rules.mk

@@ -52,6 +52,6 @@ NKRO_ENABLE = yes	    # USB Nkey Rollover
 CUSTOM_MATRIX = yes # Custom matrix file
 AUDIO_ENABLE = yes
 RGBLIGHT_ENABLE = no
-HAPTIC_ENABLE = DRV2605L
+HAPTIC_ENABLE += DRV2605L
 QWIIC_ENABLE += MICRO_OLED
 # SERIAL_LINK_ENABLE = yes

+ 1 - 9
keyboards/hadron/ver3/ver3.c

@@ -17,7 +17,7 @@
 #include "qwiic.h"
 #include "action_layer.h"
 #include "matrix.h"
-#include "DRV2605L.h"
+#include "haptic.h"
 
 #ifdef QWIIC_MICRO_OLED_ENABLE
 
@@ -167,20 +167,12 @@ void encoder_update_kb(uint8_t index, bool clockwise) {
 #endif
 
 void matrix_init_kb(void) {
-#ifdef DRV2605L
-  DRV_init();
-#endif
   queue_for_send = true;
 	matrix_init_user();
 }
             
 void matrix_scan_kb(void) {
-
 if (queue_for_send) {
-  #ifdef DRV2605L
-    DRV_EFFECT play_eff = strong_click; 
-    DRV_pulse(play_eff);
-  #endif
 #ifdef QWIIC_MICRO_OLED_ENABLE
    read_host_led_state();
    draw_ui();

+ 16 - 0
quantum/quantum.c

@@ -47,6 +47,9 @@ extern backlight_config_t backlight_config;
 #include "process_midi.h"
 #endif
 
+#ifdef HAPTIC_ENABLE
+    #include "haptic.h"
+#endif
 
 #ifdef ENCODER_ENABLE
 #include "encoder.h"
@@ -179,6 +182,9 @@ void reset_keyboard(void) {
   shutdown_user();
   wait_ms(250);
 #endif
+#ifdef HAPTIC_ENABLE
+  haptic_shutdown();
+#endif
 // this is also done later in bootloader.c - not sure if it's neccesary here
 #ifdef BOOTLOADER_CATERINA
   *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific
@@ -257,6 +263,9 @@ bool process_record_quantum(keyrecord_t *record) {
   #if defined(AUDIO_ENABLE) && defined(AUDIO_CLICKY)
     process_clicky(keycode, record) &&
   #endif //AUDIO_CLICKY
+  #ifdef HAPTIC_ENABLE
+    process_haptic(keycode, record) &&
+  #endif //HAPTIC_ENABLE
     process_record_kb(keycode, record) &&
   #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_KEYPRESSES)
     process_rgb_matrix(keycode, record) &&
@@ -1049,6 +1058,9 @@ void matrix_init_quantum() {
   #if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE) || defined(UCIS_ENABLE)
     unicode_input_mode_init();
   #endif
+  #ifdef HAPTIC_ENABLE
+    haptic_init();
+  #endif
   matrix_init_kb();
 }
 
@@ -1091,6 +1103,10 @@ void matrix_scan_quantum() {
     encoder_read();
   #endif
 
+  #ifdef HAPTIC_ENABLE
+    haptic_task();
+  #endif
+
   matrix_scan_kb();
 }
 #if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)

+ 4 - 0
quantum/quantum.h

@@ -139,6 +139,10 @@ extern uint32_t default_layer_state;
     #include "hd44780.h"
 #endif
 
+#ifdef HAPTIC_ENABLE
+    #include "haptic.h"
+#endif
+
 //Function substitutions to ease GPIO manipulation
 #ifdef __AVR__
     #define PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + (p >> PORT_SHIFTER) + offset)

+ 30 - 19
quantum/quantum_keycodes.h

@@ -446,25 +446,36 @@ enum quantum_keycodes {
     KC_LOCK,
 #endif
 
-#ifdef TERMINAL_ENABLE
-    TERM_ON,
-    TERM_OFF,
-#endif
-
-    EEPROM_RESET,
-
-    UNICODE_MODE_FORWARD,
-    UNICODE_MODE_REVERSE,
-
-    UNICODE_MODE_OSX,
-    UNICODE_MODE_LNX,
-    UNICODE_MODE_WIN,
-    UNICODE_MODE_BSD,
-    UNICODE_MODE_WINC,
-
-    // always leave at the end
-    SAFE_RANGE
-};
+    #ifdef TERMINAL_ENABLE
+        TERM_ON,
+        TERM_OFF,
+    #endif
+
+        EEPROM_RESET,
+
+        UNICODE_MODE_FORWARD,
+        UNICODE_MODE_REVERSE,
+
+        UNICODE_MODE_OSX,
+        UNICODE_MODE_LNX,
+        UNICODE_MODE_WIN,
+        UNICODE_MODE_BSD,
+        UNICODE_MODE_WINC,
+
+        HPT_ON,
+        HPT_OFF,
+        HPT_TOG,
+        HPT_RST,
+        HPT_FBK,
+        HPT_BUZ,
+        HPT_MODI,
+        HPT_MODD,
+        HPT_DWLI,
+        HPT_DWLD,
+
+        // always leave at the end
+        SAFE_RANGE
+    };
 
 // Ability to use mods in layouts
 #define LCTL(kc) (QK_LCTL | (kc))

+ 9 - 0
tmk_core/common/eeconfig.c

@@ -45,6 +45,7 @@ void eeconfig_init_quantum(void) {
   eeprom_update_byte(EECONFIG_AUDIO,             0xFF); // On by default
   eeprom_update_dword(EECONFIG_RGBLIGHT,      0);
   eeprom_update_byte(EECONFIG_STENOMODE,      0);
+  eeprom_update_dword(EECONFIG_HAPTIC,        0);
 
   eeconfig_init_kb();
 }
@@ -177,3 +178,11 @@ uint32_t eeconfig_read_user(void)      { return eeprom_read_dword(EECONFIG_USER)
 void eeconfig_update_user(uint32_t val) { eeprom_update_dword(EECONFIG_USER, val); }
 
 
+uint32_t eeconfig_read_haptic(void)      { return eeprom_read_dword(EECONFIG_HAPTIC); }
+/** \brief eeconfig update user
+ *
+ * FIXME: needs doc
+ */
+void eeconfig_update_haptic(uint32_t val) { eeprom_update_dword(EECONFIG_HAPTIC, val); }
+
+

+ 7 - 0
tmk_core/common/eeconfig.h

@@ -41,6 +41,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define EECONFIG_KEYBOARD                          (uint32_t *)15
 #define EECONFIG_USER                              (uint32_t *)19
 
+#define EECONFIG_HAPTIC                            (uint32_t*)24
+
 /* debug bit */
 #define EECONFIG_DEBUG_ENABLE                       (1<<0)
 #define EECONFIG_DEBUG_MATRIX                       (1<<1)
@@ -94,4 +96,9 @@ void eeconfig_update_kb(uint32_t val);
 uint32_t eeconfig_read_user(void);
 void eeconfig_update_user(uint32_t val);
 
+#ifdef HAPTIC_ENABLE
+uint32_t eeconfig_read_haptic(void);
+void eeconfig_update_haptic(uint32_t val);
+#endif
+
 #endif