Parent directory

dip_switch.c

4819 bytes
  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
 36static pin_t dip_switch_pad[] = DIP_SWITCH_PINS;
 37#endif
 38
 39#ifdef DIP_SWITCH_MATRIX_GRID
 40static matrix_intersection_t dip_switch_pad[] = DIP_SWITCH_MATRIX_GRID;
 41extern bool                  peek_matrix(uint8_t row_index, uint8_t col_index, bool read_raw);
 42static uint16_t              scan_count;
 43#endif /* DIP_SWITCH_MATRIX_GRID */
 44
 45static bool dip_switch_state[NUM_DIP_SWITCHES]      = {0};
 46static 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
 68#    ifndef DIP_SWITCH_MAP_KEY_DELAY
 69#        define DIP_SWITCH_MAP_KEY_DELAY TAP_CODE_DELAY
 70#    endif
 71
 72static void dip_switch_exec_mapping(uint8_t index, bool on) {
 73    // The delays below cater for Windows and its wonderful requirements.
 74    action_exec(on ? MAKE_DIPSWITCH_ON_EVENT(index, true) : MAKE_DIPSWITCH_OFF_EVENT(index, true));
 75#    if DIP_SWITCH_MAP_KEY_DELAY > 0
 76    wait_ms(DIP_SWITCH_MAP_KEY_DELAY);
 77#    endif // DIP_SWITCH_MAP_KEY_DELAY > 0
 78
 79    action_exec(on ? MAKE_DIPSWITCH_ON_EVENT(index, false) : MAKE_DIPSWITCH_OFF_EVENT(index, false));
 80#    if DIP_SWITCH_MAP_KEY_DELAY > 0
 81    wait_ms(DIP_SWITCH_MAP_KEY_DELAY);
 82#    endif // DIP_SWITCH_MAP_KEY_DELAY > 0
 83}
 84#endif // DIP_SWITCH_MAP_ENABLE
 85
 86void dip_switch_init(void) {
 87#ifdef DIP_SWITCH_PINS
 88#    if defined(SPLIT_KEYBOARD) && defined(DIP_SWITCH_PINS_RIGHT)
 89    if (!isLeftHand) {
 90        const pin_t dip_switch_pad_right[] = DIP_SWITCH_PINS_RIGHT;
 91        for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
 92            dip_switch_pad[i] = dip_switch_pad_right[i];
 93        }
 94    }
 95#    endif
 96    for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
 97        gpio_set_pin_input_high(dip_switch_pad[i]);
 98    }
 99    dip_switch_read(true);
100#endif
101#ifdef DIP_SWITCH_MATRIX_GRID
102    scan_count = 0;
103#endif
104}
105
106void dip_switch_read(bool forced) {
107    bool     has_dip_state_changed = false;
108    uint32_t dip_switch_mask       = 0;
109
110#ifdef DIP_SWITCH_MATRIX_GRID
111    bool read_raw = false;
112
113    if (scan_count < 500) {
114        scan_count++;
115        if (scan_count == 10) {
116            read_raw = true;
117            forced   = true; /* First reading of the dip switch */
118        } else {
119            return;
120        }
121    }
122#endif
123
124    for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
125#ifdef DIP_SWITCH_PINS
126        dip_switch_state[i] = !gpio_read_pin(dip_switch_pad[i]);
127#endif
128#ifdef DIP_SWITCH_MATRIX_GRID
129        dip_switch_state[i] = peek_matrix(dip_switch_pad[i].row, dip_switch_pad[i].col, read_raw);
130#endif
131        dip_switch_mask |= dip_switch_state[i] << i;
132        if (last_dip_switch_state[i] != dip_switch_state[i] || forced) {
133            has_dip_state_changed = true;
134#ifndef DIP_SWITCH_MAP_ENABLE
135            dip_switch_update_kb(i, dip_switch_state[i]);
136#else
137            dip_switch_exec_mapping(i, dip_switch_state[i]);
138#endif
139        }
140    }
141    if (has_dip_state_changed) {
142#ifndef DIP_SWITCH_MAP_ENABLE
143        dip_switch_update_mask_kb(dip_switch_mask);
144#endif
145        memcpy(last_dip_switch_state, dip_switch_state, sizeof(dip_switch_state));
146    }
147}
148
149void dip_switch_task(void) {
150    dip_switch_read(false);
151}