From 76fb54403ccd3ebaf1ca49c5172335e3593c5c5c Mon Sep 17 00:00:00 2001 From: Purdea Andrei Date: Tue, 2 Nov 2021 07:54:29 +0200 Subject: [PATCH] haptic: Feature to disable it when usb port is not configured or suspended. (#12692) This also add support for specifying a LED pin to indicate haptic status, and also adds support for a haptic-enable pin, which is useful to turn off the boost converter on the solenoid driver. --- docs/feature_haptic_feedback.md | 11 +++++ drivers/haptic/solenoid.c | 16 +++++--- drivers/haptic/solenoid.h | 8 ++++ quantum/haptic.c | 51 ++++++++++++++++++++++-- quantum/haptic.h | 27 +++++++++++++ quantum/process_keycode/process_haptic.c | 3 +- tmk_core/protocol/usb_device_state.c | 10 ++++- 7 files changed, 115 insertions(+), 11 deletions(-) diff --git a/docs/feature_haptic_feedback.md b/docs/feature_haptic_feedback.md index 4054c5d9b7..159296a297 100644 --- a/docs/feature_haptic_feedback.md +++ b/docs/feature_haptic_feedback.md @@ -11,6 +11,16 @@ HAPTIC_DRIVER += DRV2605L HAPTIC_DRIVER += SOLENOID ``` +The following `config.h` settings are available for all types of haptic feedback: + +| Settings | Default | Description | +|--------------------------------------|---------------|---------------------------------------------------------------------------------------------------------------| +|`HAPTIC_ENABLE_PIN` | *Not defined* |Configures a pin to enable a boost converter for some haptic solution, often used with solenoid drivers. | +|`HAPTIC_ENABLE_PIN_ACTIVE_LOW` | *Not defined* |If defined then the haptic enable pin is active-low. | +|`HAPTIC_ENABLE_STATUS_LED` | *Not defined* |Configures a pin to reflect the current enabled/disabled status of haptic feedback. | +|`HAPTIC_ENABLE_STATUS_LED_ACTIVE_LOW` | *Not defined* |If defined then the haptic status led will be active-low. | +|`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. | + ## Known Supported Hardware | Name | Description | @@ -48,6 +58,7 @@ First you will need a build a circuit to drive the solenoid through a mosfet as | Settings | Default | Description | |----------------------------|----------------------|-------------------------------------------------------| |`SOLENOID_PIN` | *Not defined* |Configures the pin that the Solenoid is connected to. | +|`SOLENOID_PIN_ACTIVE_LOW` | *Not defined* |If defined then the solenoid trigger pin is active low.| |`SOLENOID_DEFAULT_DWELL` | `12` ms |Configures the default dwell time for the solenoid. | |`SOLENOID_MIN_DWELL` | `4` ms |Sets the lower limit for the dwell. | |`SOLENOID_MAX_DWELL` | `100` ms |Sets the upper limit for the dwell. | diff --git a/drivers/haptic/solenoid.c b/drivers/haptic/solenoid.c index 25cf344655..7a09940f78 100644 --- a/drivers/haptic/solenoid.c +++ b/drivers/haptic/solenoid.c @@ -19,6 +19,7 @@ #include "solenoid.h" #include "haptic.h" #include "gpio.h" +#include "usb_device_state.h" bool solenoid_on = false; bool solenoid_buzzing = false; @@ -36,7 +37,7 @@ void solenoid_set_buzz(int buzz) { haptic_set_buzz(buzz); } void solenoid_set_dwell(uint8_t dwell) { solenoid_dwell = dwell; } void solenoid_stop(void) { - writePinLow(SOLENOID_PIN); + SOLENOID_PIN_WRITE_INACTIVE(); solenoid_on = false; solenoid_buzzing = false; } @@ -48,7 +49,7 @@ void solenoid_fire(void) { solenoid_on = true; solenoid_buzzing = true; solenoid_start = timer_read(); - writePinHigh(SOLENOID_PIN); + SOLENOID_PIN_WRITE_ACTIVE(); } void solenoid_check(void) { @@ -69,20 +70,23 @@ void solenoid_check(void) { if ((elapsed % (SOLENOID_BUZZ_ACTUATED + SOLENOID_BUZZ_NONACTUATED)) < SOLENOID_BUZZ_ACTUATED) { if (!solenoid_buzzing) { solenoid_buzzing = true; - writePinHigh(SOLENOID_PIN); + SOLENOID_PIN_WRITE_ACTIVE(); } } else { if (solenoid_buzzing) { solenoid_buzzing = false; - writePinLow(SOLENOID_PIN); + SOLENOID_PIN_WRITE_INACTIVE(); } } } } void solenoid_setup(void) { + SOLENOID_PIN_WRITE_INACTIVE(); setPinOutput(SOLENOID_PIN); - solenoid_fire(); + if ((!HAPTIC_OFF_IN_LOW_POWER) || (usb_device_state == USB_DEVICE_STATE_CONFIGURED)) { + solenoid_fire(); + } } -void solenoid_shutdown(void) { writePinLow(SOLENOID_PIN); } +void solenoid_shutdown(void) { SOLENOID_PIN_WRITE_INACTIVE(); } diff --git a/drivers/haptic/solenoid.h b/drivers/haptic/solenoid.h index f2a3bc4c30..653148154f 100644 --- a/drivers/haptic/solenoid.h +++ b/drivers/haptic/solenoid.h @@ -49,6 +49,14 @@ # error SOLENOID_PIN not defined #endif +#ifdef SOLENOID_PIN_ACTIVE_LOW +# define SOLENOID_PIN_WRITE_ACTIVE() writePinLow(SOLENOID_PIN) +# define SOLENOID_PIN_WRITE_INACTIVE() writePinHigh(SOLENOID_PIN) +#else +# define SOLENOID_PIN_WRITE_ACTIVE() writePinHigh(SOLENOID_PIN) +# define SOLENOID_PIN_WRITE_INACTIVE() writePinLow(SOLENOID_PIN) +#endif + void solenoid_buzz_on(void); void solenoid_buzz_off(void); void solenoid_set_buzz(int buzz); diff --git a/quantum/haptic.c b/quantum/haptic.c index 65abcc15fa..f915acf946 100644 --- a/quantum/haptic.c +++ b/quantum/haptic.c @@ -17,6 +17,8 @@ #include "haptic.h" #include "eeconfig.h" #include "debug.h" +#include "usb_device_state.h" +#include "gpio.h" #ifdef DRV2605L # include "DRV2605L.h" #endif @@ -26,6 +28,29 @@ haptic_config_t haptic_config; +static void update_haptic_enable_gpios(void) { + if (haptic_config.enable && ((!HAPTIC_OFF_IN_LOW_POWER) || (usb_device_state == USB_DEVICE_STATE_CONFIGURED))) { +#if defined(HAPTIC_ENABLE_PIN) + HAPTIC_ENABLE_PIN_WRITE_ACTIVE(); +#endif +#if defined(HAPTIC_ENABLE_STATUS_LED) + HAPTIC_ENABLE_STATUS_LED_WRITE_ACTIVE(); +#endif + } else { +#if defined(HAPTIC_ENABLE_PIN) + HAPTIC_ENABLE_PIN_WRITE_INACTIVE(); +#endif +#if defined(HAPTIC_ENABLE_STATUS_LED) + HAPTIC_ENABLE_STATUS_LED_WRITE_INACTIVE(); +#endif + } +} + +static void set_haptic_config_enable(bool enabled) { + haptic_config.enable = enabled; + update_haptic_enable_gpios(); +} + void haptic_init(void) { if (!eeconfig_is_enabled()) { eeconfig_init(); @@ -44,6 +69,10 @@ void haptic_init(void) { // or the previous firmware didn't have solenoid enabled, // and the current one has solenoid enabled. haptic_reset(); + } else { + // Haptic configuration has been loaded through the "raw" union item. + // This is to execute any side effects of the configuration. + set_haptic_config_enable(haptic_config.enable); } #ifdef SOLENOID_ENABLE solenoid_setup(); @@ -54,6 +83,12 @@ void haptic_init(void) { dprintf("DRV2605 driver initialized\n"); #endif eeconfig_debug_haptic(); +#ifdef HAPTIC_ENABLE_PIN + setPinOutput(HAPTIC_ENABLE_PIN); +#endif +#ifdef HAPTIC_ENABLE_STATUS_LED + setPinOutput(HAPTIC_ENABLE_STATUS_LED); +#endif } void haptic_task(void) { @@ -69,13 +104,13 @@ void eeconfig_debug_haptic(void) { } void haptic_enable(void) { - haptic_config.enable = 1; + set_haptic_config_enable(true); xprintf("haptic_config.enable = %u\n", haptic_config.enable); eeconfig_update_haptic(haptic_config.raw); } void haptic_disable(void) { - haptic_config.enable = 0; + set_haptic_config_enable(false); xprintf("haptic_config.enable = %u\n", haptic_config.enable); eeconfig_update_haptic(haptic_config.raw); } @@ -157,7 +192,7 @@ void haptic_dwell_decrease(void) { } void haptic_reset(void) { - haptic_config.enable = true; + set_haptic_config_enable(true); uint8_t feedback = HAPTIC_FEEDBACK_DEFAULT; haptic_config.feedback = feedback; #ifdef DRV2605L @@ -293,3 +328,13 @@ void haptic_shutdown(void) { solenoid_shutdown(); #endif } + +void haptic_notify_usb_device_state_change(void) { + update_haptic_enable_gpios(); +#if defined(HAPTIC_ENABLE_PIN) + setPinOutput(HAPTIC_ENABLE_PIN); +#endif +#if defined(HAPTIC_ENABLE_STATUS_LED) + setPinOutput(HAPTIC_ENABLE_STATUS_LED); +#endif +} diff --git a/quantum/haptic.h b/quantum/haptic.h index fc7ca2f3e6..7d70a01333 100644 --- a/quantum/haptic.h +++ b/quantum/haptic.h @@ -75,3 +75,30 @@ void haptic_cont_decrease(void); void haptic_play(void); void haptic_shutdown(void); +void haptic_notify_usb_device_state_change(void); + +#ifdef HAPTIC_ENABLE_PIN_ACTIVE_LOW +# ifndef HAPTIC_ENABLE_PIN +# error HAPTIC_ENABLE_PIN not defined +# endif +# define HAPTIC_ENABLE_PIN_WRITE_ACTIVE() writePinLow(HAPTIC_ENABLE_PIN) +# define HAPTIC_ENABLE_PIN_WRITE_INACTIVE() writePinHigh(HAPTIC_ENABLE_PIN) +#else +# define HAPTIC_ENABLE_PIN_WRITE_ACTIVE() writePinHigh(HAPTIC_ENABLE_PIN) +# define HAPTIC_ENABLE_PIN_WRITE_INACTIVE() writePinLow(HAPTIC_ENABLE_PIN) +#endif + +#ifdef HAPTIC_ENABLE_STATUS_LED_ACTIVE_LOW +# ifndef HAPTIC_ENABLE_STATUS_LED +# error HAPTIC_ENABLE_STATUS_LED not defined +# endif +# define HAPTIC_ENABLE_STATUS_LED_WRITE_ACTIVE() writePinLow(HAPTIC_ENABLE_STATUS_LED) +# define HAPTIC_ENABLE_STATUS_LED_WRITE_INACTIVE() writePinHigh(HAPTIC_ENABLE_STATUS_LED) +#else +# define HAPTIC_ENABLE_STATUS_LED_WRITE_ACTIVE() writePinHigh(HAPTIC_ENABLE_STATUS_LED) +# define HAPTIC_ENABLE_STATUS_LED_WRITE_INACTIVE() writePinLow(HAPTIC_ENABLE_STATUS_LED) +#endif + +#ifndef HAPTIC_OFF_IN_LOW_POWER +# define HAPTIC_OFF_IN_LOW_POWER 0 +#endif diff --git a/quantum/process_keycode/process_haptic.c b/quantum/process_keycode/process_haptic.c index 1b9c2f24fa..466c8e5543 100644 --- a/quantum/process_keycode/process_haptic.c +++ b/quantum/process_keycode/process_haptic.c @@ -17,6 +17,7 @@ #include "process_haptic.h" #include "quantum_keycodes.h" #include "action_tapping.h" +#include "usb_device_state.h" __attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record) { switch (keycode) { @@ -131,7 +132,7 @@ bool process_haptic(uint16_t keycode, keyrecord_t *record) { } } - if (haptic_get_enable()) { + if (haptic_get_enable() && ((!HAPTIC_OFF_IN_LOW_POWER) || (usb_device_state == USB_DEVICE_STATE_CONFIGURED))) { if (record->event.pressed) { // keypress if (haptic_get_feedback() < 2 && get_haptic_enabled_key(keycode, record)) { diff --git a/tmk_core/protocol/usb_device_state.c b/tmk_core/protocol/usb_device_state.c index 5ccd309ec2..84f01943be 100644 --- a/tmk_core/protocol/usb_device_state.c +++ b/tmk_core/protocol/usb_device_state.c @@ -16,6 +16,9 @@ */ #include "usb_device_state.h" +#if defined(HAPTIC_ENABLE) +# include "haptic.h" +#endif enum usb_device_state usb_device_state = USB_DEVICE_STATE_NO_INIT; @@ -23,7 +26,12 @@ __attribute__((weak)) void notify_usb_device_state_change_kb(enum usb_device_sta __attribute__((weak)) void notify_usb_device_state_change_user(enum usb_device_state usb_device_state) {} -static void notify_usb_device_state_change(enum usb_device_state usb_device_state) { notify_usb_device_state_change_kb(usb_device_state); } +static void notify_usb_device_state_change(enum usb_device_state usb_device_state) { +#if defined(HAPTIC_ENABLE) && HAPTIC_OFF_IN_LOW_POWER + haptic_notify_usb_device_state_change(); +#endif + notify_usb_device_state_change_kb(usb_device_state); +} void usb_device_state_set_configuration(bool isConfigured, uint8_t configurationNumber) { usb_device_state = isConfigured ? USB_DEVICE_STATE_CONFIGURED : USB_DEVICE_STATE_INIT;