qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

solenoid.c (5009B)


      1 /* Copyright 2018 mtdjr - modified by ishtob
      2  * Driver for solenoid 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 
     18 #include "timer.h"
     19 #include "solenoid.h"
     20 #include "haptic.h"
     21 #include "gpio.h"
     22 #include "usb_device_state.h"
     23 #include "util.h"
     24 #include <stdlib.h>
     25 
     26 static pin_t solenoid_pads[] = SOLENOID_PINS;
     27 #define NUMBER_OF_SOLENOIDS ARRAY_SIZE(solenoid_pads)
     28 bool     solenoid_on[NUMBER_OF_SOLENOIDS]      = {false};
     29 bool     solenoid_buzzing[NUMBER_OF_SOLENOIDS] = {false};
     30 uint16_t solenoid_start[NUMBER_OF_SOLENOIDS]   = {0};
     31 #ifdef SOLENOID_PIN_ACTIVE_LOW
     32 #    define low true
     33 #    define high false
     34 #else
     35 #    define low false
     36 #    define high true
     37 #endif
     38 static bool solenoid_active_state[NUMBER_OF_SOLENOIDS];
     39 
     40 extern haptic_config_t haptic_config;
     41 
     42 void solenoid_buzz_on(void) {
     43     haptic_set_buzz(1);
     44 }
     45 
     46 void solenoid_buzz_off(void) {
     47     haptic_set_buzz(0);
     48 }
     49 
     50 void solenoid_set_buzz(uint8_t buzz) {
     51     haptic_set_buzz(buzz);
     52 }
     53 
     54 void solenoid_set_dwell(uint8_t dwell) {
     55     haptic_set_dwell(dwell);
     56 }
     57 
     58 /**
     59  * @brief Stops a specific solenoid
     60  *
     61  * @param index select which solenoid to check/stop
     62  */
     63 void solenoid_stop(uint8_t index) {
     64     gpio_write_pin(solenoid_pads[index], !solenoid_active_state[index]);
     65     solenoid_on[index]      = false;
     66     solenoid_buzzing[index] = false;
     67 }
     68 
     69 /**
     70  * @brief Fires off a specific solenoid
     71  *
     72  * @param index Selects which solenoid to fire
     73  */
     74 void solenoid_fire(uint8_t index) {
     75     if (!haptic_config.buzz && solenoid_on[index]) return;
     76     if (haptic_config.buzz && solenoid_buzzing[index]) return;
     77 
     78     solenoid_on[index]      = true;
     79     solenoid_buzzing[index] = true;
     80     solenoid_start[index]   = timer_read();
     81     gpio_write_pin(solenoid_pads[index], solenoid_active_state[index]);
     82 }
     83 
     84 /**
     85  * @brief Handles selecting a non-active solenoid, and firing it.
     86  *
     87  */
     88 void solenoid_fire_handler(void) {
     89 #ifndef SOLENOID_RANDOM_FIRE
     90     if (NUMBER_OF_SOLENOIDS > 1) {
     91         uint8_t i = rand() % NUMBER_OF_SOLENOIDS;
     92         if (!solenoid_on[i]) {
     93             solenoid_fire(i);
     94         }
     95     } else {
     96         solenoid_fire(0);
     97     }
     98 #else
     99     for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
    100         if (!solenoid_on[i]) {
    101             solenoid_fire(i);
    102             break;
    103         }
    104     }
    105 #endif
    106 }
    107 
    108 /**
    109  * @brief Checks active solenoid to stop them, and to handle buzz mode
    110  *
    111  */
    112 void solenoid_check(void) {
    113     uint16_t elapsed[NUMBER_OF_SOLENOIDS] = {0};
    114 
    115     for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
    116         if (!solenoid_on[i]) continue;
    117 
    118         elapsed[i] = timer_elapsed(solenoid_start[i]);
    119 
    120         // Check if it's time to finish this solenoid click cycle
    121         if (elapsed[i] > haptic_config.dwell) {
    122             solenoid_stop(i);
    123             continue;
    124         }
    125 
    126         // Check whether to buzz the solenoid on and off
    127         if (haptic_config.buzz) {
    128             if ((elapsed[i] % (SOLENOID_BUZZ_ACTUATED + SOLENOID_BUZZ_NONACTUATED)) < SOLENOID_BUZZ_ACTUATED) {
    129                 if (!solenoid_buzzing[i]) {
    130                     solenoid_buzzing[i] = true;
    131                     gpio_write_pin(solenoid_pads[i], solenoid_active_state[i]);
    132                 }
    133             } else {
    134                 if (solenoid_buzzing[i]) {
    135                     solenoid_buzzing[i] = false;
    136                     gpio_write_pin(solenoid_pads[i], !solenoid_active_state[i]);
    137                 }
    138             }
    139         }
    140     }
    141 }
    142 
    143 /**
    144  * @brief Initial configuration for solenoids
    145  *
    146  */
    147 void solenoid_setup(void) {
    148 #ifdef SOLENOID_PINS_ACTIVE_STATE
    149     bool    state_temp[] = SOLENOID_PINS_ACTIVE_STATE;
    150     uint8_t bound_check  = ARRAY_SIZE(state_temp);
    151 #endif
    152 
    153     for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
    154 #ifdef SOLENOID_PINS_ACTIVE_STATE
    155         solenoid_active_state[i] = (bound_check - i) ? state_temp[i] : high;
    156 #else
    157         solenoid_active_state[i] = high;
    158 #endif
    159         gpio_write_pin(solenoid_pads[i], !solenoid_active_state[i]);
    160         gpio_set_pin_output(solenoid_pads[i]);
    161         if ((!HAPTIC_OFF_IN_LOW_POWER) || (usb_device_state_get_configure_state() == USB_DEVICE_STATE_CONFIGURED)) {
    162             solenoid_fire(i);
    163         }
    164     }
    165 }
    166 
    167 /**
    168  * @brief stops solenoids prior to device reboot, to prevent them from being locked on
    169  *
    170  */
    171 void solenoid_shutdown(void) {
    172     for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) {
    173         gpio_write_pin(solenoid_pads[i], !solenoid_active_state[i]);
    174     }
    175 }