qmk_firmware

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

dip_switch.c (4841B)


      1 /*
      2  * Copyright 2018 Jack Humbert <jack.humb@gmail.com>
      3  * Copyright 2019 Drashna Jaelre (Christopher Courtney) <drashna@live.com>
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include <string.h> // for memcpy
     20 
     21 #include "dip_switch.h"
     22 
     23 #ifdef SPLIT_KEYBOARD
     24 #    include "split_common/split_util.h"
     25 #endif
     26 
     27 #if !defined(DIP_SWITCH_PINS) && !defined(DIP_SWITCH_MATRIX_GRID)
     28 #    error "Either DIP_SWITCH_PINS or DIP_SWITCH_MATRIX_GRID must be defined."
     29 #endif
     30 
     31 #if defined(DIP_SWITCH_PINS) && defined(DIP_SWITCH_MATRIX_GRID)
     32 #    error "Both DIP_SWITCH_PINS and DIP_SWITCH_MATRIX_GRID are defined."
     33 #endif
     34 
     35 #ifdef DIP_SWITCH_PINS
     36 static pin_t dip_switch_pad[] = DIP_SWITCH_PINS;
     37 #endif
     38 
     39 #ifdef DIP_SWITCH_MATRIX_GRID
     40 static matrix_intersection_t dip_switch_pad[] = DIP_SWITCH_MATRIX_GRID;
     41 extern bool                  peek_matrix(uint8_t row_index, uint8_t col_index, bool read_raw);
     42 static uint16_t              scan_count;
     43 #endif /* DIP_SWITCH_MATRIX_GRID */
     44 
     45 static bool dip_switch_state[NUM_DIP_SWITCHES]      = {0};
     46 static bool last_dip_switch_state[NUM_DIP_SWITCHES] = {0};
     47 
     48 __attribute__((weak)) bool dip_switch_update_user(uint8_t index, bool active) {
     49     return true;
     50 }
     51 
     52 __attribute__((weak)) bool dip_switch_update_kb(uint8_t index, bool active) {
     53     return dip_switch_update_user(index, active);
     54 }
     55 
     56 __attribute__((weak)) bool dip_switch_update_mask_user(uint32_t state) {
     57     return true;
     58 }
     59 
     60 __attribute__((weak)) bool dip_switch_update_mask_kb(uint32_t state) {
     61     return dip_switch_update_mask_user(state);
     62 }
     63 
     64 #ifdef DIP_SWITCH_MAP_ENABLE
     65 #    include "keymap_introspection.h"
     66 #    include "action.h"
     67 #    include "wait.h"
     68 
     69 #    ifndef DIP_SWITCH_MAP_KEY_DELAY
     70 #        define DIP_SWITCH_MAP_KEY_DELAY TAP_CODE_DELAY
     71 #    endif
     72 
     73 static void dip_switch_exec_mapping(uint8_t index, bool on) {
     74     // The delays below cater for Windows and its wonderful requirements.
     75     action_exec(on ? MAKE_DIPSWITCH_ON_EVENT(index, true) : MAKE_DIPSWITCH_OFF_EVENT(index, true));
     76 #    if DIP_SWITCH_MAP_KEY_DELAY > 0
     77     wait_ms(DIP_SWITCH_MAP_KEY_DELAY);
     78 #    endif // DIP_SWITCH_MAP_KEY_DELAY > 0
     79 
     80     action_exec(on ? MAKE_DIPSWITCH_ON_EVENT(index, false) : MAKE_DIPSWITCH_OFF_EVENT(index, false));
     81 #    if DIP_SWITCH_MAP_KEY_DELAY > 0
     82     wait_ms(DIP_SWITCH_MAP_KEY_DELAY);
     83 #    endif // DIP_SWITCH_MAP_KEY_DELAY > 0
     84 }
     85 #endif // DIP_SWITCH_MAP_ENABLE
     86 
     87 void dip_switch_init(void) {
     88 #ifdef DIP_SWITCH_PINS
     89 #    if defined(SPLIT_KEYBOARD) && defined(DIP_SWITCH_PINS_RIGHT)
     90     if (!isLeftHand) {
     91         const pin_t dip_switch_pad_right[] = DIP_SWITCH_PINS_RIGHT;
     92         for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
     93             dip_switch_pad[i] = dip_switch_pad_right[i];
     94         }
     95     }
     96 #    endif
     97     for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
     98         gpio_set_pin_input_high(dip_switch_pad[i]);
     99     }
    100     dip_switch_read(true);
    101 #endif
    102 #ifdef DIP_SWITCH_MATRIX_GRID
    103     scan_count = 0;
    104 #endif
    105 }
    106 
    107 void dip_switch_read(bool forced) {
    108     bool     has_dip_state_changed = false;
    109     uint32_t dip_switch_mask       = 0;
    110 
    111 #ifdef DIP_SWITCH_MATRIX_GRID
    112     bool read_raw = false;
    113 
    114     if (scan_count < 500) {
    115         scan_count++;
    116         if (scan_count == 10) {
    117             read_raw = true;
    118             forced   = true; /* First reading of the dip switch */
    119         } else {
    120             return;
    121         }
    122     }
    123 #endif
    124 
    125     for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
    126 #ifdef DIP_SWITCH_PINS
    127         dip_switch_state[i] = !gpio_read_pin(dip_switch_pad[i]);
    128 #endif
    129 #ifdef DIP_SWITCH_MATRIX_GRID
    130         dip_switch_state[i] = peek_matrix(dip_switch_pad[i].row, dip_switch_pad[i].col, read_raw);
    131 #endif
    132         dip_switch_mask |= dip_switch_state[i] << i;
    133         if (last_dip_switch_state[i] != dip_switch_state[i] || forced) {
    134             has_dip_state_changed = true;
    135 #ifndef DIP_SWITCH_MAP_ENABLE
    136             dip_switch_update_kb(i, dip_switch_state[i]);
    137 #else
    138             dip_switch_exec_mapping(i, dip_switch_state[i]);
    139 #endif
    140         }
    141     }
    142     if (has_dip_state_changed) {
    143 #ifndef DIP_SWITCH_MAP_ENABLE
    144         dip_switch_update_mask_kb(dip_switch_mask);
    145 #endif
    146         memcpy(last_dip_switch_state, dip_switch_state, sizeof(dip_switch_state));
    147     }
    148 }
    149 
    150 void dip_switch_task(void) {
    151     dip_switch_read(false);
    152 }