summary refs log tree commit diff
path: root/drivers/haptic
diff options
context:
space:
mode:
authorDrashna Jaelre <drashna@live.com>2022-05-15 04:24:35 -0700
committerGitHub <noreply@github.com>2022-05-15 21:24:35 +1000
commitf090881aebbd7af74294b53fabdf55a35004f190 (patch)
tree53d786c3be9bf1b2823bdee7bf6a55686d8b1461 /drivers/haptic
parent4d107feca9621ee3f342507136b04f176e8f2320 (diff)
[Feature] Add support for multiple switchs/solenoids to Haptic Feedback engine (#15657)
Diffstat (limited to 'drivers/haptic')
-rw-r--r--drivers/haptic/solenoid.c155
-rw-r--r--drivers/haptic/solenoid.h26
2 files changed, 126 insertions, 55 deletions
diff --git a/drivers/haptic/solenoid.c b/drivers/haptic/solenoid.c
index 14d868bffe..637a77da3d 100644
--- a/drivers/haptic/solenoid.c
+++ b/drivers/haptic/solenoid.c
@@ -20,11 +20,22 @@
 #include "haptic.h"
 #include "gpio.h"
 #include "usb_device_state.h"
-
-bool     solenoid_on      = false;
-bool     solenoid_buzzing = false;
-uint16_t solenoid_start   = 0;
-uint8_t  solenoid_dwell   = SOLENOID_DEFAULT_DWELL;
+#include <stdlib.h>
+
+uint8_t      solenoid_dwell  = SOLENOID_DEFAULT_DWELL;
+static pin_t solenoid_pads[] = SOLENOID_PINS;
+#define NUMBER_OF_SOLENOIDS (sizeof(solenoid_pads) / sizeof(pin_t))
+bool     solenoid_on[NUMBER_OF_SOLENOIDS]      = {false};
+bool     solenoid_buzzing[NUMBER_OF_SOLENOIDS] = {false};
+uint16_t solenoid_start[NUMBER_OF_SOLENOIDS]   = {0};
+#ifdef SOLENOID_PIN_ACTIVE_LOW
+#    define low true
+#    define high false
+#else
+#    define low false
+#    define high true
+#endif
+static bool solenoid_active_state[NUMBER_OF_SOLENOIDS];
 
 extern haptic_config_t haptic_config;
 
@@ -36,7 +47,7 @@ void solenoid_buzz_off(void) {
     haptic_set_buzz(0);
 }
 
-void solenoid_set_buzz(int buzz) {
+void solenoid_set_buzz(uint8_t buzz) {
     haptic_set_buzz(buzz);
 }
 
@@ -44,59 +55,121 @@ void solenoid_set_dwell(uint8_t dwell) {
     solenoid_dwell = dwell;
 }
 
-void solenoid_stop(void) {
-    SOLENOID_PIN_WRITE_INACTIVE();
-    solenoid_on      = false;
-    solenoid_buzzing = false;
+/**
+ * @brief Stops a specific solenoid
+ *
+ * @param index select which solenoid to check/stop
+ */
+void solenoid_stop(uint8_t index) {
+    writePin(solenoid_pads[index], !solenoid_active_state[index]);
+    solenoid_on[index]      = false;
+    solenoid_buzzing[index] = false;
 }
 
-void solenoid_fire(void) {
-    if (!haptic_config.buzz && solenoid_on) return;
-    if (haptic_config.buzz && solenoid_buzzing) return;
+/**
+ * @brief Fires off a specific solenoid
+ *
+ * @param index Selects which solenoid to fire
+ */
+void solenoid_fire(uint8_t index) {
+    if (!haptic_config.buzz && solenoid_on[index]) return;
+    if (haptic_config.buzz && solenoid_buzzing[index]) return;
+
+    solenoid_on[index]      = true;
+    solenoid_buzzing[index] = true;
+    solenoid_start[index]   = timer_read();
+    writePin(solenoid_pads[index], solenoid_active_state[index]);
+}
 
-    solenoid_on      = true;
-    solenoid_buzzing = true;
-    solenoid_start   = timer_read();
-    SOLENOID_PIN_WRITE_ACTIVE();
+/**
+ * @brief Handles selecting a non-active solenoid, and firing it.
+ *
+ */
+void solenoid_fire_handler(void) {
+#ifndef SOLENOID_RANDOM_FIRE
+    if (NUMBER_OF_SOLENOIDS > 1) {
+        uint8_t i = rand() % NUMBER_OF_SOLENOIDS;
+        if (!solenoid_on[i]) {
+            solenoid_fire(i);
+        }
+    } else {
+        solenoid_fire(0);
+    }
+#else
+    for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
+        if (!solenoid_on[i]) {
+            solenoid_fire(i);
+            break;
+        }
+    }
+#endif
 }
 
+/**
+ * @brief Checks active solenoid to stop them, and to handle buzz mode
+ *
+ */
 void solenoid_check(void) {
-    uint16_t elapsed = 0;
+    uint16_t elapsed[NUMBER_OF_SOLENOIDS] = {0};
 
-    if (!solenoid_on) return;
+    for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
+        if (!solenoid_on[i]) continue;
 
-    elapsed = timer_elapsed(solenoid_start);
+        elapsed[i] = timer_elapsed(solenoid_start[i]);
 
-    // Check if it's time to finish this solenoid click cycle
-    if (elapsed > solenoid_dwell) {
-        solenoid_stop();
-        return;
-    }
+        // Check if it's time to finish this solenoid click cycle
+        if (elapsed[i] > solenoid_dwell) {
+            solenoid_stop(i);
+            continue;
+        }
 
-    // Check whether to buzz the solenoid on and off
-    if (haptic_config.buzz) {
-        if ((elapsed % (SOLENOID_BUZZ_ACTUATED + SOLENOID_BUZZ_NONACTUATED)) < SOLENOID_BUZZ_ACTUATED) {
-            if (!solenoid_buzzing) {
-                solenoid_buzzing = true;
-                SOLENOID_PIN_WRITE_ACTIVE();
-            }
-        } else {
-            if (solenoid_buzzing) {
-                solenoid_buzzing = false;
-                SOLENOID_PIN_WRITE_INACTIVE();
+        // Check whether to buzz the solenoid on and off
+        if (haptic_config.buzz) {
+            if ((elapsed[i] % (SOLENOID_BUZZ_ACTUATED + SOLENOID_BUZZ_NONACTUATED)) < SOLENOID_BUZZ_ACTUATED) {
+                if (!solenoid_buzzing[i]) {
+                    solenoid_buzzing[i] = true;
+                    writePin(solenoid_pads[i], solenoid_active_state[i]);
+                }
+            } else {
+                if (solenoid_buzzing[i]) {
+                    solenoid_buzzing[i] = false;
+                    writePin(solenoid_pads[i], !solenoid_active_state[i]);
+                }
             }
         }
     }
 }
 
+/**
+ * @brief Initial configuration for solenoids
+ *
+ */
 void solenoid_setup(void) {
-    SOLENOID_PIN_WRITE_INACTIVE();
-    setPinOutput(SOLENOID_PIN);
-    if ((!HAPTIC_OFF_IN_LOW_POWER) || (usb_device_state == USB_DEVICE_STATE_CONFIGURED)) {
-        solenoid_fire();
+#ifdef SOLENOID_PINS_ACTIVE_STATE
+    bool    state_temp[] = SOLENOID_PINS_ACTIVE_STATE;
+    uint8_t bound_check  = (sizeof(state_temp) / sizeof(bool));
+#endif
+
+    for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
+#ifdef SOLENOID_PINS_ACTIVE_STATE
+        solenoid_active_state[i] = (bound_check - i) ? state_temp[i] : high;
+#else
+        solenoid_active_state[i] = high;
+#endif
+        writePin(solenoid_pads[i], !solenoid_active_state[i]);
+        setPinOutput(solenoid_pads[i]);
+        if ((!HAPTIC_OFF_IN_LOW_POWER) || (usb_device_state == USB_DEVICE_STATE_CONFIGURED)) {
+            solenoid_fire(i);
+        }
     }
 }
 
+/**
+ * @brief stops solenoids prior to device reboot, to prevent them from being locked on
+ *
+ */
 void solenoid_shutdown(void) {
-    SOLENOID_PIN_WRITE_INACTIVE();
+    for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
+        writePin(solenoid_pads[i], !solenoid_active_state[i]);
+    }
 }
diff --git a/drivers/haptic/solenoid.h b/drivers/haptic/solenoid.h
index 653148154f..952f86e922 100644
--- a/drivers/haptic/solenoid.h
+++ b/drivers/haptic/solenoid.h
@@ -45,26 +45,24 @@
 #    define SOLENOID_BUZZ_NONACTUATED SOLENOID_MIN_DWELL
 #endif
 
-#ifndef SOLENOID_PIN
-#    error SOLENOID_PIN not defined
+#ifndef SOLENOID_PINS
+#    ifdef SOLENOID_PIN
+#        define SOLENOID_PINS \
+            { SOLENOID_PIN }
+#    else
+#        error SOLENOID_PINS array not defined
+#    endif
 #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 solenoidbuzz_on(void);
 void solenoid_buzz_off(void);
-void solenoid_set_buzz(int buzz);
+void solenoid_set_buzz(uint8_t buzz);
 
 void solenoid_set_dwell(uint8_t dwell);
 
-void solenoid_stop(void);
-void solenoid_fire(void);
+void solenoid_stop(uint8_t index);
+void solenoid_fire(uint8_t index);
+void solenoid_fire_handler(void);
 
 void solenoid_check(void);