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}