keyboard stuff
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add encoder abstraction. (#21548)

authored by

Nick Brassel and committed by
GitHub
9d9cdaaa 2eb9ff8e

+852 -642
+15
builddefs/common_features.mk
··· 886 886 endif 887 887 endif 888 888 889 + ENCODER_ENABLE ?= no 890 + ENCODER_DRIVER ?= quadrature 891 + VALID_ENCODER_DRIVER_TYPES := quadrature custom 889 892 ifeq ($(strip $(ENCODER_ENABLE)), yes) 893 + ifeq ($(filter $(ENCODER_DRIVER),$(VALID_ENCODER_DRIVER_TYPES)),) 894 + $(call CATASTROPHIC_ERROR,Invalid ENCODER_DRIVER,ENCODER_DRIVER="$(ENCODER_DRIVER)" is not a valid encoder driver) 895 + endif 890 896 SRC += $(QUANTUM_DIR)/encoder.c 891 897 OPT_DEFS += -DENCODER_ENABLE 898 + OPT_DEFS += -DENCODER_DRIVER_$(strip $(shell echo $(ENCODER_DRIVER) | tr '[:lower:]' '[:upper:]')) 899 + 900 + COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/encoder 901 + COMMON_VPATH += $(DRIVER_PATH)/encoder 902 + 903 + ifneq ($(strip $(ENCODER_DRIVER)), custom) 904 + SRC += encoder_$(strip $(ENCODER_DRIVER)).c 905 + endif 906 + 892 907 ifeq ($(strip $(ENCODER_MAP_ENABLE)), yes) 893 908 OPT_DEFS += -DENCODER_MAP_ENABLE 894 909 endif
+1
data/mappings/info_rules.hjson
··· 21 21 "DEBOUNCE_TYPE": {"info_key": "build.debounce_type"}, 22 22 "EEPROM_DRIVER": {"info_key": "eeprom.driver"}, 23 23 "ENCODER_ENABLE": {"info_key": "encoder.enabled", "value_type": "bool"}, 24 + "ENCODER_DRIVER": {"info_key": "encoder.driver"}, 24 25 "FIRMWARE_FORMAT": {"info_key": "build.firmware_format"}, 25 26 "KEYBOARD_SHARED_EP": {"info_key": "usb.shared_endpoint.keyboard", "value_type": "bool"}, 26 27 "LAYOUTS": {"info_key": "community_layouts", "value_type": "list"},
+4
data/schemas/keyboard.jsonschema
··· 6 6 "encoder_config": { 7 7 "type": "object", 8 8 "properties": { 9 + "driver": { 10 + "type": "string", 11 + "enum": ["quadrature", "custom"] 12 + }, 9 13 "rotary": { 10 14 "type": "array", 11 15 "items": {
+213
drivers/encoder/encoder_quadrature.c
··· 1 + // Copyright 2018 Jack Humbert <jack.humb@gmail.com> 2 + // Copyright 2018-2023 Nick Brassel (@tzarc) 3 + // SPDX-License-Identifier: GPL-2.0-or-later 4 + 5 + #include <stdint.h> 6 + #include "encoder.h" 7 + #include "gpio.h" 8 + #include "keyboard.h" 9 + #include "action.h" 10 + #include "keycodes.h" 11 + #include "wait.h" 12 + 13 + #ifdef SPLIT_KEYBOARD 14 + # include "split_util.h" 15 + #endif 16 + 17 + // for memcpy 18 + #include <string.h> 19 + 20 + #if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION) 21 + # define ENCODER_RESOLUTION 4 22 + #endif 23 + 24 + #undef ENCODER_DEFAULT_PIN_API_IMPL 25 + #if defined(ENCODERS_PAD_A) && defined(ENCODERS_PAD_B) 26 + // Inform the quadrature driver that it needs to implement pin init/read functions 27 + # define ENCODER_DEFAULT_PIN_API_IMPL 28 + #endif 29 + 30 + extern volatile bool isLeftHand; 31 + 32 + __attribute__((weak)) void encoder_quadrature_init_pin(uint8_t index, bool pad_b); 33 + __attribute__((weak)) uint8_t encoder_quadrature_read_pin(uint8_t index, bool pad_b); 34 + 35 + #ifdef ENCODER_DEFAULT_PIN_API_IMPL 36 + 37 + static pin_t encoders_pad_a[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_A; 38 + static pin_t encoders_pad_b[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_B; 39 + 40 + __attribute__((weak)) void encoder_wait_pullup_charge(void) { 41 + wait_us(100); 42 + } 43 + 44 + __attribute__((weak)) void encoder_quadrature_init_pin(uint8_t index, bool pad_b) { 45 + pin_t pin = pad_b ? encoders_pad_b[index] : encoders_pad_a[index]; 46 + if (pin != NO_PIN) { 47 + gpio_set_pin_input_high(pin); 48 + } 49 + } 50 + 51 + __attribute__((weak)) uint8_t encoder_quadrature_read_pin(uint8_t index, bool pad_b) { 52 + pin_t pin = pad_b ? encoders_pad_b[index] : encoders_pad_a[index]; 53 + if (pin != NO_PIN) { 54 + return gpio_read_pin(pin) ? 1 : 0; 55 + } 56 + return 0; 57 + } 58 + 59 + #endif // ENCODER_DEFAULT_PIN_API_IMPL 60 + 61 + #ifdef ENCODER_RESOLUTIONS 62 + static uint8_t encoder_resolutions[NUM_ENCODERS] = ENCODER_RESOLUTIONS; 63 + #endif 64 + 65 + #ifndef ENCODER_DIRECTION_FLIP 66 + # define ENCODER_CLOCKWISE true 67 + # define ENCODER_COUNTER_CLOCKWISE false 68 + #else 69 + # define ENCODER_CLOCKWISE false 70 + # define ENCODER_COUNTER_CLOCKWISE true 71 + #endif 72 + static int8_t encoder_LUT[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0}; 73 + 74 + static uint8_t encoder_state[NUM_ENCODERS] = {0}; 75 + static int8_t encoder_pulses[NUM_ENCODERS] = {0}; 76 + 77 + // encoder counts 78 + static uint8_t thisCount; 79 + #ifdef SPLIT_KEYBOARD 80 + // encoder offsets for each hand 81 + static uint8_t thisHand, thatHand; 82 + // encoder counts for each hand 83 + static uint8_t thatCount; 84 + #endif 85 + 86 + __attribute__((weak)) void encoder_quadrature_post_init_kb(void) { 87 + extern void encoder_quadrature_handle_read(uint8_t index, uint8_t pin_a_state, uint8_t pin_b_state); 88 + // Unused normally, but can be used for things like setting up pin-change interrupts in keyboard code. 89 + // During the interrupt, read the pins then call `encoder_handle_read()` with the pin states and it'll queue up an encoder event if needed. 90 + } 91 + 92 + void encoder_quadrature_post_init(void) { 93 + #ifdef ENCODER_DEFAULT_PIN_API_IMPL 94 + for (uint8_t i = 0; i < thisCount; i++) { 95 + encoder_quadrature_init_pin(i, false); 96 + encoder_quadrature_init_pin(i, true); 97 + } 98 + encoder_wait_pullup_charge(); 99 + for (uint8_t i = 0; i < thisCount; i++) { 100 + encoder_state[i] = (encoder_quadrature_read_pin(i, false) << 0) | (encoder_quadrature_read_pin(i, true) << 1); 101 + } 102 + #else 103 + memset(encoder_state, 0, sizeof(encoder_state)); 104 + #endif 105 + 106 + encoder_quadrature_post_init_kb(); 107 + } 108 + 109 + void encoder_driver_init(void) { 110 + #ifdef SPLIT_KEYBOARD 111 + thisHand = isLeftHand ? 0 : NUM_ENCODERS_LEFT; 112 + thatHand = NUM_ENCODERS_LEFT - thisHand; 113 + thisCount = isLeftHand ? NUM_ENCODERS_LEFT : NUM_ENCODERS_RIGHT; 114 + thatCount = isLeftHand ? NUM_ENCODERS_RIGHT : NUM_ENCODERS_LEFT; 115 + #else // SPLIT_KEYBOARD 116 + thisCount = NUM_ENCODERS; 117 + #endif 118 + 119 + #ifdef ENCODER_TESTS 120 + // Annoying that we have to clear out values during initialisation here, but 121 + // because all the arrays are static locals, rerunning tests in the same 122 + // executable doesn't reset any of these. Kinda crappy having test-only code 123 + // here, but it's the simplest solution. 124 + memset(encoder_state, 0, sizeof(encoder_state)); 125 + memset(encoder_pulses, 0, sizeof(encoder_pulses)); 126 + const pin_t encoders_pad_a_left[] = ENCODERS_PAD_A; 127 + const pin_t encoders_pad_b_left[] = ENCODERS_PAD_B; 128 + for (uint8_t i = 0; i < thisCount; i++) { 129 + encoders_pad_a[i] = encoders_pad_a_left[i]; 130 + encoders_pad_b[i] = encoders_pad_b_left[i]; 131 + } 132 + #endif 133 + 134 + #if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) 135 + // Re-initialise the pads if it's the right-hand side 136 + if (!isLeftHand) { 137 + const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT; 138 + const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT; 139 + for (uint8_t i = 0; i < thisCount; i++) { 140 + encoders_pad_a[i] = encoders_pad_a_right[i]; 141 + encoders_pad_b[i] = encoders_pad_b_right[i]; 142 + } 143 + } 144 + #endif // defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) 145 + 146 + // Encoder resolutions is defined differently in config.h, so concatenate 147 + #if defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS) 148 + # if defined(ENCODER_RESOLUTIONS_RIGHT) 149 + static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS_RIGHT; 150 + # else // defined(ENCODER_RESOLUTIONS_RIGHT) 151 + static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS; 152 + # endif // defined(ENCODER_RESOLUTIONS_RIGHT) 153 + for (uint8_t i = 0; i < NUM_ENCODERS_RIGHT; i++) { 154 + encoder_resolutions[NUM_ENCODERS_LEFT + i] = encoder_resolutions_right[i]; 155 + } 156 + #endif // defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS) 157 + 158 + encoder_quadrature_post_init(); 159 + } 160 + 161 + static void encoder_handle_state_change(uint8_t index, uint8_t state) { 162 + uint8_t i = index; 163 + 164 + #ifdef SPLIT_KEYBOARD 165 + index += thisHand; 166 + #endif 167 + 168 + #ifdef ENCODER_RESOLUTIONS 169 + const uint8_t resolution = encoder_resolutions[index]; 170 + #else 171 + const uint8_t resolution = ENCODER_RESOLUTION; 172 + #endif 173 + 174 + encoder_pulses[i] += encoder_LUT[state & 0xF]; 175 + 176 + #ifdef ENCODER_DEFAULT_POS 177 + if ((encoder_pulses[i] >= resolution) || (encoder_pulses[i] <= -resolution) || ((state & 0x3) == ENCODER_DEFAULT_POS)) { 178 + if (encoder_pulses[i] >= 1) { 179 + #else 180 + if (encoder_pulses[i] >= resolution) { 181 + #endif 182 + 183 + encoder_queue_event(index, ENCODER_COUNTER_CLOCKWISE); 184 + } 185 + 186 + #ifdef ENCODER_DEFAULT_POS 187 + if (encoder_pulses[i] <= -1) { 188 + #else 189 + if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise 190 + #endif 191 + encoder_queue_event(index, ENCODER_CLOCKWISE); 192 + } 193 + encoder_pulses[i] %= resolution; 194 + #ifdef ENCODER_DEFAULT_POS 195 + encoder_pulses[i] = 0; 196 + } 197 + #endif 198 + } 199 + 200 + void encoder_quadrature_handle_read(uint8_t index, uint8_t pin_a_state, uint8_t pin_b_state) { 201 + uint8_t state = pin_a_state | (pin_b_state << 1); 202 + if ((encoder_state[index] & 0x3) != state) { 203 + encoder_state[index] <<= 2; 204 + encoder_state[index] |= state; 205 + encoder_handle_state_change(index, encoder_state[index]); 206 + } 207 + } 208 + 209 + __attribute__((weak)) void encoder_driver_task(void) { 210 + for (uint8_t i = 0; i < thisCount; i++) { 211 + encoder_quadrature_handle_read(i, encoder_quadrature_read_pin(i, false), encoder_quadrature_read_pin(i, true)); 212 + } 213 + }
+4 -2
keyboards/mechwild/sugarglider/matrix.c
··· 50 50 //wait_us(100); 51 51 return; 52 52 } 53 - 53 + 54 54 if (row > 1) { 55 55 mcp23018_errors += !mcp23018_set_config(I2C_ADDR, mcp23018_PORTB, ALL_INPUT); 56 56 mcp23018_errors += !mcp23018_set_config(I2C_ADDR, mcp23018_PORTA, ~(row_pos[row])); ··· 87 87 bool changed = false; 88 88 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 89 89 changed |= read_cols_on_row(current_matrix, current_row); 90 + 90 91 #ifdef ENCODER_ENABLE 91 - encoder_read(); 92 + // Need to frequently read the encoder pins while scanning because the I/O expander takes a long time in comparison. 93 + encoder_driver_task(); 92 94 #endif 93 95 } 94 96 return changed;
-8
keyboards/pica40/rev2/post_rules.mk
··· 1 - # if ENCODER_ENABLE is set, add defines but avoid adding encoder.c as it's replaced by custom code in rev2.c 2 - ifeq ($(strip $(ENCODER_ENABLE)), yes) 3 - ENCODER_ENABLE := no 4 - OPT_DEFS += -DENCODER_ENABLE 5 - ifeq ($(strip $(ENCODER_MAP_ENABLE)), yes) 6 - OPT_DEFS += -DENCODER_MAP_ENABLE 7 - endif 8 - endif
+17 -81
keyboards/pica40/rev2/rev2.c
··· 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 4 4 #include "rev2.h" 5 + #include "gpio.h" 5 6 6 7 #ifdef ENCODER_ENABLE // code based on encoder.c 7 8 8 - static const pin_t encoders_pad_a[] = ENCODERS_PAD_A; 9 - static const pin_t encoders_pad_b[] = ENCODERS_PAD_B; 10 - 11 - static int8_t encoder_LUT[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0}; 12 - static uint8_t encoder_state = 3; 13 - static int8_t encoder_pulses = 0; 14 - static uint8_t encoder_value = 0; 15 - 16 - typedef struct encoder_sync_data { 17 - int value; 18 - } encoder_sync_data; 9 + #define ENCODER_PIN_A (((pin_t[])ENCODERS_PAD_A)[0]) 10 + #define ENCODER_PIN_B (((pin_t[])ENCODERS_PAD_B)[0]) 19 11 20 12 // custom handler that returns encoder B pin status from slave side 21 13 void encoder_sync_slave_handler(uint8_t in_buflen, const void *in_data, uint8_t out_buflen, void *out_data) { 22 - encoder_sync_data *data = (encoder_sync_data *)out_data; 23 - data->value = readPin(encoders_pad_b[0]); 24 - } 25 - 26 - __attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { 27 - return true; 14 + *(uint8_t *)out_data = readPin(ENCODER_PIN_B) ? 1 : 0; 28 15 } 29 16 30 - bool encoder_update_kb(uint8_t index, bool clockwise) { 31 - if (!encoder_update_user(index, clockwise)) return false; 32 - 33 - tap_code(clockwise ? KC_VOLU : KC_VOLD); 34 - 35 - return false; 36 - } 37 - 38 - #ifdef ENCODER_MAP_ENABLE 39 - static void encoder_exec_mapping(uint8_t index, bool clockwise) { 40 - action_exec(clockwise ? ENCODER_CW_EVENT(index, true) : ENCODER_CCW_EVENT(index, true)); 41 - wait_ms(ENCODER_MAP_KEY_DELAY); 42 - action_exec(clockwise ? ENCODER_CW_EVENT(index, false) : ENCODER_CCW_EVENT(index, false)); 43 - wait_ms(ENCODER_MAP_KEY_DELAY); 44 - } 45 - #endif // ENCODER_MAP_ENABLE 46 - 47 - void encoder_init(void) { 48 - setPinInputHigh(encoders_pad_a[0]); 49 - setPinInputHigh(encoders_pad_b[0]); 50 - wait_us(100); 51 - transaction_register_rpc(ENCODER_SYNC, encoder_sync_slave_handler); 52 - } 53 - 54 - bool encoder_read(void) { 55 - // ignore if running on slave side 56 - if (!is_keyboard_master()) return false; 57 - 58 - bool changed = false; 59 - encoder_sync_data data = {0}; 60 - // request pin B status from slave side 61 - if (transaction_rpc_recv(ENCODER_SYNC, sizeof(data), &data)) { 62 - uint8_t new_status = (readPin(encoders_pad_a[0]) << 0) | (data.value << 1); 63 - if ((encoder_state & 0x3) != new_status) { 64 - encoder_state <<= 2; 65 - encoder_state |= new_status; 66 - encoder_pulses += encoder_LUT[encoder_state & 0xF]; 17 + void encoder_quadrature_init_pin(uint8_t index, bool pad_b) {} 67 18 68 - if (encoder_pulses >= ENCODER_RESOLUTION) { 69 - encoder_value++; 70 - changed = true; 71 - #ifdef ENCODER_MAP_ENABLE 72 - encoder_exec_mapping(0, false); 73 - #else // ENCODER_MAP_ENABLE 74 - encoder_update_kb(0, false); 75 - #endif // ENCODER_MAP_ENABLE 76 - } 77 - 78 - if (encoder_pulses <= -ENCODER_RESOLUTION) { 79 - encoder_value--; 80 - changed = true; 81 - #ifdef ENCODER_MAP_ENABLE 82 - encoder_exec_mapping(0, true); 83 - #else // ENCODER_MAP_ENABLE 84 - encoder_update_kb(0, true); 85 - #endif // ENCODER_MAP_ENABLE 86 - } 87 - 88 - encoder_pulses %= ENCODER_RESOLUTION; 89 - } 19 + uint8_t encoder_quadrature_read_pin(uint8_t index, bool pad_b) { 20 + if(pad_b) { 21 + uint8_t data = 0; 22 + transaction_rpc_recv(ENCODER_SYNC, sizeof(data), &data); 23 + return data; 90 24 } 91 - return changed; 25 + return readPin(ENCODER_PIN_A) ? 1 : 0; 92 26 } 93 - 94 - // do not use standard split encoder transactions 95 - void encoder_state_raw(uint8_t *slave_state) {} 96 - void encoder_update_raw(uint8_t *slave_state) {} 97 27 98 28 #endif // ENCODER_ENABLE 99 29 ··· 124 54 125 55 void keyboard_post_init_kb(void) { 126 56 setPinOutput(PICA40_RGB_POWER_PIN); 57 + 58 + #ifdef ENCODER_ENABLE 59 + setPinInputHigh(ENCODER_PIN_A); 60 + setPinInputHigh(ENCODER_PIN_B); 61 + transaction_register_rpc(ENCODER_SYNC, encoder_sync_slave_handler); 62 + #endif // ENCODER_ENABLE 127 63 128 64 #ifdef PICA40_RGBLIGHT_TIMEOUT 129 65 idle_timer = timer_read();
+8 -1
keyboards/planck/rev7/info.json
··· 26 26 }, 27 27 "encoder": { 28 28 "rotary": [ 29 - {"pin_a": "B12", "pin_b": "B13"} 29 + {"pin_a": "B12", "pin_b": "B13"}, 30 + {"pin_a": "B12", "pin_b": "B13"}, 31 + {"pin_a": "B12", "pin_b": "B13"}, 32 + {"pin_a": "B12", "pin_b": "B13"}, 33 + {"pin_a": "B12", "pin_b": "B13"}, 34 + {"pin_a": "B12", "pin_b": "B13"}, 35 + {"pin_a": "B12", "pin_b": "B13"}, 36 + {"pin_a": "B12", "pin_b": "B13"} 30 37 ] 31 38 }, 32 39 "features": {
+11 -75
keyboards/planck/rev7/matrix.c
··· 32 32 #define STM32_IWDG_RL_MS(s) STM32_IWDG_RL_US(s * 1000.0) 33 33 #define STM32_IWDG_RL_S(s) STM32_IWDG_RL_US(s * 1000000.0) 34 34 35 - #if !defined(PLANCK_ENCODER_RESOLUTION) 36 - # define PLANCK_ENCODER_RESOLUTION 4 37 - #endif 38 - 39 35 #if !defined(PLANCK_WATCHDOG_TIMEOUT) 40 36 # define PLANCK_WATCHDOG_TIMEOUT 1.0 41 37 #endif 42 38 43 - #ifdef ENCODER_MAP_ENABLE 44 - #error "The encoder map feature is not currently supported by the Planck's encoder matrix" 45 - #endif 46 - 47 39 /* matrix state(1:on, 0:off) */ 48 40 static pin_t matrix_row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 49 41 static pin_t matrix_col_pins[MATRIX_COLS] = MATRIX_COL_PINS; 50 42 51 43 static matrix_row_t matrix_inverted[MATRIX_COLS]; 52 44 53 - #ifdef ENCODER_ENABLE 54 - int8_t encoder_LUT[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0}; 55 - uint8_t encoder_state[8] = {0}; 56 - int8_t encoder_pulses[8] = {0}; 57 - uint8_t encoder_value[8] = {0}; 58 - #endif 59 - 60 45 void matrix_init_custom(void) { 61 46 // actual matrix setup - cols 62 47 for (int i = 0; i < MATRIX_COLS; i++) { ··· 84 69 #endif 85 70 } 86 71 87 - #ifdef ENCODER_ENABLE 88 - bool encoder_update(uint8_t index, uint8_t state) { 89 - bool changed = false; 90 - uint8_t i = index; 91 - 92 - encoder_pulses[i] += encoder_LUT[state & 0xF]; 93 - 94 - if (encoder_pulses[i] >= PLANCK_ENCODER_RESOLUTION) { 95 - encoder_value[index]++; 96 - changed = true; 97 - encoder_update_kb(index, false); 98 - } 99 - if (encoder_pulses[i] <= -PLANCK_ENCODER_RESOLUTION) { 100 - encoder_value[index]--; 101 - changed = true; 102 - encoder_update_kb(index, true); 103 - } 104 - encoder_pulses[i] %= PLANCK_ENCODER_RESOLUTION; 105 - #ifdef ENCODER_DEFAULT_POS 106 - encoder_pulses[i] = 0; 107 - #endif 108 - return changed; 109 - } 110 - #endif 111 - 112 72 bool matrix_scan_custom(matrix_row_t current_matrix[]) { 113 73 #ifndef PLANCK_WATCHDOG_DISABLE 114 74 // reset watchdog ··· 149 109 changed |= old != current_matrix[row]; 150 110 } 151 111 152 - #ifdef ENCODER_ENABLE 153 - // encoder-matrix functionality 154 - 155 - // set up C/rows for encoder read 156 - for (int i = 0; i < MATRIX_ROWS; i++) { 157 - setPinOutput(matrix_row_pins[i]); 158 - writePinHigh(matrix_row_pins[i]); 159 - } 160 - 161 - // set up A & B for reading 162 - setPinInputHigh(B12); 163 - setPinInputHigh(B13); 112 + return changed; 113 + } 164 114 165 - for (int i = 0; i < MATRIX_ROWS; i++) { 166 - writePinLow(matrix_row_pins[i]); 167 - wait_us(10); 168 - uint8_t new_status = (palReadPad(GPIOB, 12) << 0) | (palReadPad(GPIOB, 13) << 1); 169 - if ((encoder_state[i] & 0x3) != new_status) { 170 - encoder_state[i] <<= 2; 171 - encoder_state[i] |= new_status; 172 - encoder_update(i, encoder_state[i]); 173 - } 174 - writePinHigh(matrix_row_pins[i]); 175 - } 176 - 177 - // revert A & B to matrix state 178 - setPinInputLow(B12); 179 - setPinInputLow(B13); 180 - 181 - // revert C/rows to matrix state 182 - for (int i = 0; i < MATRIX_ROWS; i++) { 183 - setPinInputLow(matrix_row_pins[i]); 184 - } 185 - #endif 186 - 187 - return changed; 115 + uint8_t encoder_quadrature_read_pin(uint8_t index, bool pad_b) { 116 + pin_t pin = pad_b ? B13: B12; 117 + setPinInputHigh(pin); 118 + writePinLow(matrix_row_pins[index]); 119 + wait_us(10); 120 + uint8_t ret = readPin(pin) ? 1 : 0; 121 + setPinInputLow(matrix_row_pins[index]); 122 + setPinInputLow(pin); 123 + return ret; 188 124 }
+3
keyboards/ploopyco/mouse/config.h
··· 32 32 33 33 /* PMW33XX Settings */ 34 34 #define PMW33XX_CS_PIN B0 35 + 36 + /* Custom encoder needs to specify just how many encoders we have */ 37 + #define NUM_ENCODERS 1
+6
keyboards/ploopyco/mouse/info.json
··· 31 31 ["D4", "D2", "E6", "B6", "D7", "C6", "C7", "B7"] 32 32 ] 33 33 }, 34 + "features": { 35 + "encoder": true 36 + }, 37 + "encoder": { 38 + "driver": "custom" 39 + }, 34 40 "layouts": { 35 41 "LAYOUT": { 36 42 "layout": [
+9 -11
keyboards/ploopyco/mouse/mouse.c
··· 66 66 bool debug_encoder = false; 67 67 bool is_drag_scroll = false; 68 68 69 - __attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { return true; } 70 - 71 69 bool encoder_update_kb(uint8_t index, bool clockwise) { 72 70 if (!encoder_update_user(index, clockwise)) { 73 71 return false; ··· 83 81 return true; 84 82 } 85 83 86 - void process_wheel(void) { 84 + void encoder_driver_init(void) { 85 + setPinInput(OPT_ENC1); 86 + setPinInput(OPT_ENC2); 87 + 88 + opt_encoder_init(); 89 + } 90 + 91 + void encoder_driver_task(void) { 87 92 // Lovingly ripped from the Ploopy Source 88 93 89 94 // If the mouse wheel was just released, do not scroll. ··· 111 116 int dir = opt_encoder_handler(p1, p2); 112 117 113 118 if (dir == 0) return; 114 - encoder_update_kb(0, dir > 0); 119 + encoder_queue_event(0, dir == 1); 115 120 } 116 121 117 122 report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { 118 - process_wheel(); 119 - 120 123 if (is_drag_scroll) { 121 124 mouse_report.h = mouse_report.x; 122 125 #ifdef PLOOPY_DRAGSCROLL_INVERT ··· 177 180 // debug_mouse = true; 178 181 // debug_encoder = true; 179 182 180 - setPinInput(OPT_ENC1); 181 - setPinInput(OPT_ENC2); 182 - 183 183 /* Ground all output pins connected to ground. This provides additional 184 184 * pathways to ground. If you're messing with this, know this: driving ANY 185 185 * of these pins high will cause a short. On the MCU. Ka-blooey. ··· 204 204 205 205 void pointing_device_init_kb(void) { 206 206 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); 207 - // initialize the scroll wheel's optical encoder 208 - opt_encoder_init(); 209 207 } 210 208 211 209 void eeconfig_init_kb(void) {
-3
keyboards/ploopyco/mouse/rules.mk
··· 16 16 POINTING_DEVICE_DRIVER = pmw3360 17 17 MOUSEKEY_ENABLE = yes # Mouse keys 18 18 19 - ENCODER_ENABLE := no 20 - OPTS_DEF += -DENCODER_ENABLE 21 - 22 19 ANALOG_DRIVER_REQUIRED = yes 23 20 24 21 SRC += opt_encoder.c
+3
keyboards/ploopyco/trackball/config.h
··· 31 31 /* PMW33XX Settings */ 32 32 #define PMW33XX_CS_PIN B0 33 33 #define POINTING_DEVICE_INVERT_Y 34 + 35 + /* Custom encoder needs to specify just how many encoders we have */ 36 + #define NUM_ENCODERS 1
+6
keyboards/ploopyco/trackball/info.json
··· 12 12 "bootmagic": { 13 13 "matrix": [0, 3] 14 14 }, 15 + "features": { 16 + "encoder": true 17 + }, 18 + "encoder": { 19 + "driver": "custom" 20 + }, 15 21 "layouts": { 16 22 "LAYOUT": { 17 23 "layout": [
-3
keyboards/ploopyco/trackball/rules.mk
··· 16 16 POINTING_DEVICE_DRIVER = pmw3360 17 17 MOUSEKEY_ENABLE = yes # Mouse keys 18 18 19 - ENCODER_ENABLE := no 20 - OPTS_DEF += -DENCODER_ENABLE 21 - 22 19 ANALOG_DRIVER_REQUIRED = yes 23 20 24 21 SRC += opt_encoder.c
+10 -10
keyboards/ploopyco/trackball/trackball.c
··· 66 66 bool debug_encoder = false; 67 67 bool is_drag_scroll = false; 68 68 69 - __attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { return true; } 70 - 71 69 bool encoder_update_kb(uint8_t index, bool clockwise) { 72 70 if (!encoder_update_user(index, clockwise)) { 73 71 return false; ··· 83 81 return true; 84 82 } 85 83 86 - void process_wheel(void) { 84 + 85 + void encoder_driver_init(void) { 86 + setPinInput(OPT_ENC1); 87 + setPinInput(OPT_ENC2); 88 + 89 + opt_encoder_init(); 90 + } 91 + 92 + void encoder_driver_task(void) { 87 93 // TODO: Replace this with interrupt driven code, polling is S L O W 88 94 // Lovingly ripped from the Ploopy Source 89 95 ··· 112 118 int dir = opt_encoder_handler(p1, p2); 113 119 114 120 if (dir == 0) return; 115 - encoder_update_kb(0, dir > 0); 121 + encoder_queue_event(0, dir == 1); 116 122 } 117 123 118 124 report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { 119 - process_wheel(); 120 125 121 126 if (is_drag_scroll) { 122 127 #ifdef PLOOPY_DRAGSCROLL_H_INVERT ··· 189 194 // debug_mouse = true; 190 195 // debug_encoder = true; 191 196 192 - setPinInput(OPT_ENC1); 193 - setPinInput(OPT_ENC2); 194 - 195 197 /* Ground all output pins connected to ground. This provides additional 196 198 * pathways to ground. If you're messing with this, know this: driving ANY 197 199 * of these pins high will cause a short. On the MCU. Ka-blooey. ··· 216 218 217 219 void pointing_device_init_kb(void) { 218 220 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); 219 - // initialize the scroll wheel's optical encoder 220 - opt_encoder_init(); 221 221 } 222 222 223 223 void eeconfig_init_kb(void) {
+3
keyboards/ploopyco/trackball_mini/config.h
··· 32 32 #define ADNS5050_CS_PIN B4 33 33 34 34 #define POINTING_DEVICE_ROTATION_270 35 + 36 + /* Custom encoder needs to specify just how many encoders we have */ 37 + #define NUM_ENCODERS 1
+6
keyboards/ploopyco/trackball_mini/info.json
··· 14 14 }, 15 15 "processor": "atmega32u4", 16 16 "bootloader": "atmel-dfu", 17 + "features": { 18 + "encoder": true 19 + }, 20 + "encoder": { 21 + "driver": "custom" 22 + }, 17 23 "layouts": { 18 24 "LAYOUT": { 19 25 "layout": [
-3
keyboards/ploopyco/trackball_mini/rules.mk
··· 13 13 POINTING_DEVICE_DRIVER = adns5050 14 14 MOUSEKEY_ENABLE = yes # Mouse keys 15 15 16 - ENCODER_ENABLE := no 17 - OPTS_DEF += -DENCODER_ENABLE 18 - 19 16 ANALOG_DRIVER_REQUIRED = yes 20 17 21 18 SRC += opt_encoder.c
+9 -11
keyboards/ploopyco/trackball_mini/trackball_mini.c
··· 74 74 bool debug_encoder = false; 75 75 bool is_drag_scroll = false; 76 76 77 - __attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { return true; } 78 - 79 77 bool encoder_update_kb(uint8_t index, bool clockwise) { 80 78 if (!encoder_update_user(index, clockwise)) { 81 79 return false; ··· 91 89 return true; 92 90 } 93 91 94 - void process_wheel(void) { 92 + void encoder_driver_init(void) { 93 + setPinInput(OPT_ENC1); 94 + setPinInput(OPT_ENC2); 95 + 96 + opt_encoder_init(); 97 + } 98 + 99 + void encoder_driver_task(void) { 95 100 uint16_t p1 = adc_read(OPT_ENC1_MUX); 96 101 uint16_t p2 = adc_read(OPT_ENC2_MUX); 97 102 ··· 113 118 } 114 119 115 120 if (dir == 0) return; 116 - encoder_update_kb(0, dir > 0); 121 + encoder_queue_event(0, dir == 1); 117 122 118 123 lastScroll = timer_read(); 119 124 } 120 125 121 126 void pointing_device_init_kb(void) { 122 - opt_encoder_init(); 123 - 124 127 // set the DPI. 125 128 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); 126 129 } 127 130 128 131 report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { 129 - process_wheel(); 130 - 131 132 if (is_drag_scroll) { 132 133 mouse_report.h = mouse_report.x; 133 134 #ifdef PLOOPY_DRAGSCROLL_INVERT ··· 179 180 // debug_matrix = true; 180 181 // debug_mouse = true; 181 182 // debug_encoder = true; 182 - 183 - setPinInput(OPT_ENC1); 184 - setPinInput(OPT_ENC2); 185 183 186 184 /* Ground all output pins connected to ground. This provides additional 187 185 * pathways to ground. If you're messing with this, know this: driving ANY
+3
keyboards/ploopyco/trackball_thumb/config.h
··· 31 31 32 32 /* PMW3360 Settings */ 33 33 #define POINTING_DEVICE_CS_PIN B0 34 + 35 + /* Custom encoder needs to specify just how many encoders we have */ 36 + #define NUM_ENCODERS 1
+4 -1
keyboards/ploopyco/trackball_thumb/info.json
··· 18 18 "mousekey": true, 19 19 "nkro": true, 20 20 "pointing_device": true, 21 - "encoder": false 21 + "encoder": true 22 + }, 23 + "encoder": { 24 + "driver": "custom" 22 25 }, 23 26 "layouts": { 24 27 "LAYOUT": {
-4
keyboards/ploopyco/trackball_thumb/post_rules.mk
··· 1 - # Force encoder to be disabled 2 - # But enable the defines for it 3 - ENCODER_ENABLE := no 4 - OPT_DEFS += -DENCODER_ENABLE
+8 -12
keyboards/ploopyco/trackball_thumb/trackball_thumb.c
··· 17 17 */ 18 18 19 19 #include "trackball_thumb.h" 20 + #include "encoder.h" 20 21 21 22 #ifndef OPT_DEBOUNCE 22 23 # define OPT_DEBOUNCE 5 // (ms) Time between scroll events ··· 57 58 bool debug_encoder = false; 58 59 bool is_drag_scroll = false; 59 60 60 - // require, since core encoder.c (where is is normally defined isn't present 61 - __attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { return true; } 62 - 63 61 bool encoder_update_kb(uint8_t index, bool clockwise) { 64 62 if (!encoder_update_user(index, clockwise)) { 65 63 return false; ··· 75 73 return true; 76 74 } 77 75 78 - void encoder_init(void) { opt_encoder_init(); } 76 + void encoder_driver_init(void) { opt_encoder_init(); } 79 77 80 - bool encoder_read(void) { 78 + void encoder_driver_task(void) { 81 79 // Lovingly ripped from the Ploopy Source 82 80 83 81 // If the mouse wheel was just released, do not scroll. 84 82 if (timer_elapsed(last_mid_click) < SCROLL_BUTT_DEBOUNCE) { 85 - return false; 83 + return; 86 84 } 87 85 88 86 // Limit the number of scrolls per unit time. 89 87 if (timer_elapsed(last_scroll) < OPT_DEBOUNCE) { 90 - return false; 88 + return; 91 89 } 92 90 93 91 // Don't scroll if the middle button is depressed. 94 92 if (is_scroll_clicked) { 95 93 #ifndef IGNORE_SCROLL_CLICK 96 - return false; 94 + return; 97 95 #endif 98 96 } 99 97 ··· 104 102 105 103 int dir = opt_encoder_handler(p1, p2); 106 104 107 - if (dir == 0) return false; 108 - ; 109 - encoder_update_kb(0, dir == 1); 110 - return true; 105 + if (dir == 0) return; 106 + encoder_queue_event(0, dir == 1); 111 107 } 112 108 113 109 report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
-3
keyboards/ploopyco/trackball_thumb/trackball_thumb.h
··· 28 28 #define OPT_ENC1_MUX 4 29 29 #define OPT_ENC2_MUX 0 30 30 31 - bool encoder_update_kb(uint8_t index, bool clockwise); 32 - bool encoder_update_user(uint8_t index, bool clockwise); 33 - 34 31 typedef union { 35 32 uint32_t raw; 36 33 struct {
+88 -248
quantum/encoder.c
··· 1 - /* 2 - * Copyright 2018 Jack Humbert <jack.humb@gmail.com> 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 - */ 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 + // SPDX-License-Identifier: GPL-2.0-or-later 17 3 18 - #include "encoder.h" 19 - #include "keyboard.h" 4 + #include <string.h> 20 5 #include "action.h" 21 - #include "keycodes.h" 6 + #include "encoder.h" 22 7 #include "wait.h" 23 8 24 - #ifdef SPLIT_KEYBOARD 25 - # include "split_util.h" 26 - #endif 27 - 28 - // for memcpy 29 - #include <string.h> 30 - 31 9 #ifndef ENCODER_MAP_KEY_DELAY 32 - # include "action.h" 33 10 # define ENCODER_MAP_KEY_DELAY TAP_CODE_DELAY 34 11 #endif 35 12 36 - #if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION) 37 - # define ENCODER_RESOLUTION 4 38 - #endif 13 + __attribute__((weak)) bool should_process_encoder(void) { 14 + return is_keyboard_master(); 15 + } 39 16 40 - #if !defined(ENCODERS_PAD_A) || !defined(ENCODERS_PAD_B) 41 - # error "No encoder pads defined by ENCODERS_PAD_A and ENCODERS_PAD_B" 42 - #endif 17 + static encoder_events_t encoder_events; 43 18 44 - extern volatile bool isLeftHand; 19 + void encoder_init(void) { 20 + memset(&encoder_events, 0, sizeof(encoder_events)); 21 + encoder_driver_init(); 22 + } 45 23 46 - static pin_t encoders_pad_a[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_A; 47 - static pin_t encoders_pad_b[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_B; 24 + static bool encoder_handle_queue(void) { 25 + bool changed = false; 26 + while (encoder_events.tail != encoder_events.head) { 27 + encoder_event_t event = encoder_events.queue[encoder_events.tail]; 28 + encoder_events.tail = (encoder_events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 48 29 49 - #ifdef ENCODER_RESOLUTIONS 50 - static uint8_t encoder_resolutions[NUM_ENCODERS] = ENCODER_RESOLUTIONS; 51 - #endif 30 + #ifdef ENCODER_MAP_ENABLE 52 31 53 - #ifndef ENCODER_DIRECTION_FLIP 54 - # define ENCODER_CLOCKWISE true 55 - # define ENCODER_COUNTER_CLOCKWISE false 56 - #else 57 - # define ENCODER_CLOCKWISE false 58 - # define ENCODER_COUNTER_CLOCKWISE true 59 - #endif 60 - static int8_t encoder_LUT[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0}; 32 + // The delays below cater for Windows and its wonderful requirements. 33 + action_exec(event.clockwise ? MAKE_ENCODER_CW_EVENT(event.index, true) : MAKE_ENCODER_CCW_EVENT(event.index, true)); 34 + # if ENCODER_MAP_KEY_DELAY > 0 35 + wait_ms(ENCODER_MAP_KEY_DELAY); 36 + # endif // ENCODER_MAP_KEY_DELAY > 0 37 + 38 + action_exec(event.clockwise ? MAKE_ENCODER_CW_EVENT(event.index, false) : MAKE_ENCODER_CCW_EVENT(event.index, false)); 39 + # if ENCODER_MAP_KEY_DELAY > 0 40 + wait_ms(ENCODER_MAP_KEY_DELAY); 41 + # endif // ENCODER_MAP_KEY_DELAY > 0 42 + 43 + #else // ENCODER_MAP_ENABLE 61 44 62 - static uint8_t encoder_state[NUM_ENCODERS] = {0}; 63 - static int8_t encoder_pulses[NUM_ENCODERS] = {0}; 45 + encoder_update_kb(event.index, event.clockwise ? true : false); 46 + 47 + #endif // ENCODER_MAP_ENABLE 64 48 65 - // encoder counts 66 - static uint8_t thisCount; 49 + changed = true; 50 + } 51 + return changed; 52 + } 53 + 54 + bool encoder_task(void) { 55 + bool changed = false; 56 + 67 57 #ifdef SPLIT_KEYBOARD 68 - // encoder offsets for each hand 69 - static uint8_t thisHand, thatHand; 70 - // encoder counts for each hand 71 - static uint8_t thatCount; 72 - #endif 58 + // Attempt to process existing encoder events in case split handling has already enqueued events 59 + if (should_process_encoder()) { 60 + changed |= encoder_handle_queue(); 61 + } 62 + #endif // SPLIT_KEYBOARD 73 63 74 - static uint8_t encoder_value[NUM_ENCODERS] = {0}; 64 + // Let the encoder driver produce events 65 + encoder_driver_task(); 75 66 76 - __attribute__((weak)) void encoder_wait_pullup_charge(void) { 77 - wait_us(100); 67 + // Process any events that were enqueued 68 + if (should_process_encoder()) { 69 + changed |= encoder_handle_queue(); 70 + } 71 + 72 + return changed; 78 73 } 79 74 75 + bool encoder_queue_event(uint8_t index, bool clockwise) { 76 + // Drop out if we're full 77 + if ((encoder_events.head + 1) % MAX_QUEUED_ENCODER_EVENTS == encoder_events.tail) { 78 + return false; 79 + } 80 + 81 + // Append the event 82 + encoder_event_t new_event = {.index = index, .clockwise = clockwise ? 1 : 0}; 83 + encoder_events.queue[encoder_events.head] = new_event; 84 + 85 + // Increment the head index 86 + encoder_events.head = (encoder_events.head + 1) % MAX_QUEUED_ENCODER_EVENTS; 87 + 88 + return true; 89 + } 90 + 91 + void encoder_retrieve_events(encoder_events_t *events) { 92 + memcpy(events, &encoder_events, sizeof(encoder_events)); 93 + } 94 + 95 + #ifdef SPLIT_KEYBOARD 96 + void encoder_set_tail_index(uint8_t tail_index) { 97 + encoder_events.tail = tail_index; 98 + } 99 + 100 + void encoder_handle_slave_events(encoder_events_t *events) { 101 + while (events->tail != events->head) { 102 + encoder_event_t event = events->queue[events->tail]; 103 + events->tail = (events->tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 104 + encoder_queue_event(event.index, event.clockwise ? true : false); 105 + } 106 + } 107 + #endif // SPLIT_KEYBOARD 108 + 80 109 __attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { 81 110 return true; 82 111 } ··· 106 135 #endif // ENCODER_TESTS 107 136 return res; 108 137 } 109 - 110 - __attribute__((weak)) bool should_process_encoder(void) { 111 - return is_keyboard_master(); 112 - } 113 - 114 - void encoder_init(void) { 115 - #ifdef SPLIT_KEYBOARD 116 - thisHand = isLeftHand ? 0 : NUM_ENCODERS_LEFT; 117 - thatHand = NUM_ENCODERS_LEFT - thisHand; 118 - thisCount = isLeftHand ? NUM_ENCODERS_LEFT : NUM_ENCODERS_RIGHT; 119 - thatCount = isLeftHand ? NUM_ENCODERS_RIGHT : NUM_ENCODERS_LEFT; 120 - #else // SPLIT_KEYBOARD 121 - thisCount = NUM_ENCODERS; 122 - #endif 123 - 124 - #ifdef ENCODER_TESTS 125 - // Annoying that we have to clear out values during initialisation here, but 126 - // because all the arrays are static locals, rerunning tests in the same 127 - // executable doesn't reset any of these. Kinda crappy having test-only code 128 - // here, but it's the simplest solution. 129 - memset(encoder_value, 0, sizeof(encoder_value)); 130 - memset(encoder_state, 0, sizeof(encoder_state)); 131 - memset(encoder_pulses, 0, sizeof(encoder_pulses)); 132 - static const pin_t encoders_pad_a_left[] = ENCODERS_PAD_A; 133 - static const pin_t encoders_pad_b_left[] = ENCODERS_PAD_B; 134 - for (uint8_t i = 0; i < thisCount; i++) { 135 - encoders_pad_a[i] = encoders_pad_a_left[i]; 136 - encoders_pad_b[i] = encoders_pad_b_left[i]; 137 - } 138 - #endif 139 - 140 - #if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) 141 - // Re-initialise the pads if it's the right-hand side 142 - if (!isLeftHand) { 143 - static const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT; 144 - static const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT; 145 - for (uint8_t i = 0; i < thisCount; i++) { 146 - encoders_pad_a[i] = encoders_pad_a_right[i]; 147 - encoders_pad_b[i] = encoders_pad_b_right[i]; 148 - } 149 - } 150 - #endif // defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT) 151 - 152 - // Encoder resolutions is handled purely master-side, so concatenate the two arrays 153 - #if defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS) 154 - # if defined(ENCODER_RESOLUTIONS_RIGHT) 155 - static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS_RIGHT; 156 - # else // defined(ENCODER_RESOLUTIONS_RIGHT) 157 - static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS; 158 - # endif // defined(ENCODER_RESOLUTIONS_RIGHT) 159 - for (uint8_t i = 0; i < NUM_ENCODERS_RIGHT; i++) { 160 - encoder_resolutions[NUM_ENCODERS_LEFT + i] = encoder_resolutions_right[i]; 161 - } 162 - #endif // defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS) 163 - 164 - for (uint8_t i = 0; i < thisCount; i++) { 165 - gpio_set_pin_input_high(encoders_pad_a[i]); 166 - gpio_set_pin_input_high(encoders_pad_b[i]); 167 - } 168 - encoder_wait_pullup_charge(); 169 - for (uint8_t i = 0; i < thisCount; i++) { 170 - encoder_state[i] = (gpio_read_pin(encoders_pad_a[i]) << 0) | (gpio_read_pin(encoders_pad_b[i]) << 1); 171 - } 172 - } 173 - 174 - #ifdef ENCODER_MAP_ENABLE 175 - static void encoder_exec_mapping(uint8_t index, bool clockwise) { 176 - // The delays below cater for Windows and its wonderful requirements. 177 - action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, true) : MAKE_ENCODER_CCW_EVENT(index, true)); 178 - # if ENCODER_MAP_KEY_DELAY > 0 179 - wait_ms(ENCODER_MAP_KEY_DELAY); 180 - # endif // ENCODER_MAP_KEY_DELAY > 0 181 - 182 - action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, false) : MAKE_ENCODER_CCW_EVENT(index, false)); 183 - # if ENCODER_MAP_KEY_DELAY > 0 184 - wait_ms(ENCODER_MAP_KEY_DELAY); 185 - # endif // ENCODER_MAP_KEY_DELAY > 0 186 - } 187 - #endif // ENCODER_MAP_ENABLE 188 - 189 - static bool encoder_update(uint8_t index, uint8_t state) { 190 - bool changed = false; 191 - uint8_t i = index; 192 - 193 - #ifdef ENCODER_RESOLUTIONS 194 - const uint8_t resolution = encoder_resolutions[i]; 195 - #else 196 - const uint8_t resolution = ENCODER_RESOLUTION; 197 - #endif 198 - 199 - #ifdef SPLIT_KEYBOARD 200 - index += thisHand; 201 - #endif 202 - encoder_pulses[i] += encoder_LUT[state & 0xF]; 203 - 204 - #ifdef ENCODER_DEFAULT_POS 205 - if ((encoder_pulses[i] >= resolution) || (encoder_pulses[i] <= -resolution) || ((state & 0x3) == ENCODER_DEFAULT_POS)) { 206 - if (encoder_pulses[i] >= 1) { 207 - #else 208 - if (encoder_pulses[i] >= resolution) { 209 - #endif 210 - 211 - encoder_value[index]++; 212 - changed = true; 213 - #ifdef SPLIT_KEYBOARD 214 - if (should_process_encoder()) 215 - #endif // SPLIT_KEYBOARD 216 - #ifdef ENCODER_MAP_ENABLE 217 - encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE); 218 - #else // ENCODER_MAP_ENABLE 219 - encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); 220 - #endif // ENCODER_MAP_ENABLE 221 - } 222 - 223 - #ifdef ENCODER_DEFAULT_POS 224 - if (encoder_pulses[i] <= -1) { 225 - #else 226 - if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise 227 - #endif 228 - encoder_value[index]--; 229 - changed = true; 230 - #ifdef SPLIT_KEYBOARD 231 - if (should_process_encoder()) 232 - #endif // SPLIT_KEYBOARD 233 - #ifdef ENCODER_MAP_ENABLE 234 - encoder_exec_mapping(index, ENCODER_CLOCKWISE); 235 - #else // ENCODER_MAP_ENABLE 236 - encoder_update_kb(index, ENCODER_CLOCKWISE); 237 - #endif // ENCODER_MAP_ENABLE 238 - } 239 - encoder_pulses[i] %= resolution; 240 - #ifdef ENCODER_DEFAULT_POS 241 - encoder_pulses[i] = 0; 242 - } 243 - #endif 244 - return changed; 245 - } 246 - 247 - bool encoder_read(void) { 248 - bool changed = false; 249 - for (uint8_t i = 0; i < thisCount; i++) { 250 - uint8_t new_status = (gpio_read_pin(encoders_pad_a[i]) << 0) | (gpio_read_pin(encoders_pad_b[i]) << 1); 251 - if ((encoder_state[i] & 0x3) != new_status) { 252 - encoder_state[i] <<= 2; 253 - encoder_state[i] |= new_status; 254 - changed |= encoder_update(i, encoder_state[i]); 255 - } 256 - } 257 - return changed; 258 - } 259 - 260 - #ifdef SPLIT_KEYBOARD 261 - void last_encoder_activity_trigger(void); 262 - 263 - void encoder_state_raw(uint8_t *slave_state) { 264 - memcpy(slave_state, &encoder_value[thisHand], sizeof(uint8_t) * thisCount); 265 - } 266 - 267 - void encoder_update_raw(uint8_t *slave_state) { 268 - bool changed = false; 269 - for (uint8_t i = 0; i < thatCount; i++) { // Note inverted logic -- we want the opposite side 270 - const uint8_t index = i + thatHand; 271 - int8_t delta = slave_state[i] - encoder_value[index]; 272 - while (delta > 0) { 273 - delta--; 274 - encoder_value[index]++; 275 - changed = true; 276 - # ifdef ENCODER_MAP_ENABLE 277 - encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE); 278 - # else // ENCODER_MAP_ENABLE 279 - encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); 280 - # endif // ENCODER_MAP_ENABLE 281 - } 282 - while (delta < 0) { 283 - delta++; 284 - encoder_value[index]--; 285 - changed = true; 286 - # ifdef ENCODER_MAP_ENABLE 287 - encoder_exec_mapping(index, ENCODER_CLOCKWISE); 288 - # else // ENCODER_MAP_ENABLE 289 - encoder_update_kb(index, ENCODER_CLOCKWISE); 290 - # endif // ENCODER_MAP_ENABLE 291 - } 292 - } 293 - 294 - // Update the last encoder input time -- handled external to encoder_read() when we're running a split 295 - if (changed) last_encoder_activity_trigger(); 296 - } 297 - #endif
+71 -28
quantum/encoder.h
··· 22 22 #include "gpio.h" 23 23 #include "util.h" 24 24 25 + #ifdef ENCODER_ENABLE 26 + 27 + __attribute__((weak)) bool should_process_encoder(void); 28 + 25 29 void encoder_init(void); 26 - bool encoder_read(void); 30 + bool encoder_task(void); 31 + bool encoder_queue_event(uint8_t index, bool clockwise); 27 32 28 33 bool encoder_update_kb(uint8_t index, bool clockwise); 29 34 bool encoder_update_user(uint8_t index, bool clockwise); 30 35 31 - #ifdef SPLIT_KEYBOARD 36 + # ifdef SPLIT_KEYBOARD 32 37 33 - void encoder_state_raw(uint8_t* slave_state); 34 - void encoder_update_raw(uint8_t* slave_state); 38 + # if defined(ENCODERS_PAD_A_RIGHT) 39 + # ifndef NUM_ENCODERS_LEFT 40 + # define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A)) 41 + # endif 42 + # ifndef NUM_ENCODERS_RIGHT 43 + # define NUM_ENCODERS_RIGHT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A_RIGHT)) 44 + # endif 45 + # else 46 + # ifndef NUM_ENCODERS_LEFT 47 + # define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A)) 48 + # endif 49 + # ifndef NUM_ENCODERS_RIGHT 50 + # define NUM_ENCODERS_RIGHT NUM_ENCODERS_LEFT 51 + # endif 52 + # endif 53 + # ifndef NUM_ENCODERS 54 + # define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT) 55 + # endif 35 56 36 - # if defined(ENCODERS_PAD_A_RIGHT) 37 - # define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A)) 38 - # define NUM_ENCODERS_RIGHT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A_RIGHT)) 39 - # else 40 - # define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A)) 41 - # define NUM_ENCODERS_RIGHT NUM_ENCODERS_LEFT 42 - # endif 43 - # define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT) 57 + # else // SPLIT_KEYBOARD 58 + 59 + # ifndef NUM_ENCODERS 60 + # define NUM_ENCODERS ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A)) 61 + # endif 62 + # define NUM_ENCODERS_LEFT NUM_ENCODERS 63 + # define NUM_ENCODERS_RIGHT 0 64 + 65 + # endif // SPLIT_KEYBOARD 66 + 67 + # ifndef NUM_ENCODERS 68 + # define NUM_ENCODERS 0 69 + # define NUM_ENCODERS_LEFT 0 70 + # define NUM_ENCODERS_RIGHT 0 71 + # endif // NUM_ENCODERS 72 + 73 + # define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT) 44 74 45 - #else // SPLIT_KEYBOARD 75 + # ifndef MAX_QUEUED_ENCODER_EVENTS 76 + # define MAX_QUEUED_ENCODER_EVENTS MAX(4, ((NUM_ENCODERS_MAX_PER_SIDE) + 1)) 77 + # endif // MAX_QUEUED_ENCODER_EVENTS 46 78 47 - # define NUM_ENCODERS ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A)) 48 - # define NUM_ENCODERS_LEFT NUM_ENCODERS 49 - # define NUM_ENCODERS_RIGHT 0 79 + typedef struct encoder_event_t { 80 + uint8_t index : 7; 81 + uint8_t clockwise : 1; 82 + } encoder_event_t; 50 83 51 - #endif // SPLIT_KEYBOARD 84 + typedef struct encoder_events_t { 85 + uint8_t head; 86 + uint8_t tail; 87 + encoder_event_t queue[MAX_QUEUED_ENCODER_EVENTS]; 88 + } encoder_events_t; 52 89 53 - #ifndef NUM_ENCODERS 54 - # define NUM_ENCODERS 0 55 - # define NUM_ENCODERS_LEFT 0 56 - # define NUM_ENCODERS_RIGHT 0 57 - #endif // NUM_ENCODERS 90 + // Get the current queued events 91 + void encoder_retrieve_events(encoder_events_t *events); 58 92 59 - #define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT) 93 + # ifdef SPLIT_KEYBOARD 94 + void encoder_set_tail_index(uint8_t tail_index); 95 + void encoder_handle_slave_events(encoder_events_t *events); 96 + # endif // SPLIT_KEYBOARD 60 97 61 - #ifdef ENCODER_MAP_ENABLE 62 - # define NUM_DIRECTIONS 2 63 - # define ENCODER_CCW_CW(ccw, cw) \ 64 - { (cw), (ccw) } 98 + # ifdef ENCODER_MAP_ENABLE 99 + # define NUM_DIRECTIONS 2 100 + # define ENCODER_CCW_CW(ccw, cw) \ 101 + { (cw), (ccw) } 65 102 extern const uint16_t encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS]; 66 - #endif // ENCODER_MAP_ENABLE 103 + # endif // ENCODER_MAP_ENABLE 104 + 105 + // "Custom encoder lite" support 106 + void encoder_driver_init(void); 107 + void encoder_driver_task(void); 108 + 109 + #endif // ENCODER_ENABLE
+6
quantum/encoder/tests/config_encoder_common.h
··· 1 + // Copyright 2023 Nick Brassel (@tzarc) 2 + // SPDX-License-Identifier: GPL-2.0-or-later 3 + #pragma once 4 + 5 + // Override the one in quantum/util because it doesn't like working on x64 builds. 6 + #define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0]))
+2 -1
quantum/encoder/tests/config_mock.h
··· 1 - // Copyright 2022 Nick Brassel (@tzarc) 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 #pragma once 4 + #include "config_encoder_common.h" 4 5 5 6 #define MATRIX_ROWS 1 6 7 #define MATRIX_COLS 1
+2 -1
quantum/encoder/tests/config_mock_split_left_eq_right.h
··· 1 - // Copyright 2022 Nick Brassel (@tzarc) 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 #pragma once 4 + #include "config_encoder_common.h" 4 5 5 6 #define MATRIX_ROWS 1 6 7 #define MATRIX_COLS 1
+2 -1
quantum/encoder/tests/config_mock_split_left_gt_right.h
··· 1 - // Copyright 2022 Nick Brassel (@tzarc) 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 #pragma once 4 + #include "config_encoder_common.h" 4 5 5 6 #define MATRIX_ROWS 1 6 7 #define MATRIX_COLS 1
+2 -1
quantum/encoder/tests/config_mock_split_left_lt_right.h
··· 1 - // Copyright 2022 Nick Brassel (@tzarc) 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 #pragma once 4 + #include "config_encoder_common.h" 4 5 5 6 #define MATRIX_ROWS 1 6 7 #define MATRIX_COLS 1
+2 -1
quantum/encoder/tests/config_mock_split_no_left.h
··· 1 - // Copyright 2022 Nick Brassel (@tzarc) 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 #pragma once 4 + #include "config_encoder_common.h" 4 5 5 6 #define MATRIX_ROWS 1 6 7 #define MATRIX_COLS 1
+2 -1
quantum/encoder/tests/config_mock_split_no_right.h
··· 1 - // Copyright 2022 Nick Brassel (@tzarc) 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 #pragma once 4 + #include "config_encoder_common.h" 4 5 5 6 #define MATRIX_ROWS 1 6 7 #define MATRIX_COLS 1
+2 -1
quantum/encoder/tests/config_mock_split_role.h
··· 1 - // Copyright 2022 Nick Brassel (@tzarc) 1 + // Copyright 2022-2023 Nick Brassel (@tzarc) 2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 #pragma once 4 + #include "config_encoder_common.h" 4 5 5 6 #define MATRIX_ROWS 1 6 7 #define MATRIX_COLS 1
+1 -1
quantum/encoder/tests/encoder_tests.cpp
··· 41 41 42 42 bool setAndRead(pin_t pin, bool val) { 43 43 setPin(pin, val); 44 - return encoder_read(); 44 + return encoder_task(); 45 45 } 46 46 47 47 class EncoderTest : public ::testing::Test {};
+74 -17
quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp
··· 33 33 uint8_t updates_array_idx = 0; 34 34 update updates[32]; 35 35 36 + bool isMaster; 36 37 bool isLeftHand; 38 + 39 + extern "C" { 40 + bool is_keyboard_master(void) { 41 + return isMaster; 42 + } 37 43 38 44 bool encoder_update_kb(uint8_t index, bool clockwise) { 39 - if (!isLeftHand) { 45 + if (!is_keyboard_master()) { 40 46 // this method has no effect on slave half 41 - printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC"); 47 + printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC"); 42 48 return true; 43 49 } 44 50 updates[updates_array_idx % 32] = {index, clockwise}; 45 51 updates_array_idx++; 46 52 return true; 47 53 } 54 + }; 48 55 49 56 bool setAndRead(pin_t pin, bool val) { 50 57 setPin(pin, val); 51 - return encoder_read(); 58 + return encoder_task(); 52 59 } 53 60 54 61 class EncoderSplitTestLeftEqRight : public ::testing::Test { ··· 63 70 }; 64 71 65 72 TEST_F(EncoderSplitTestLeftEqRight, TestInitLeft) { 73 + isMaster = true; 66 74 isLeftHand = true; 67 75 encoder_init(); 68 76 EXPECT_EQ(pinIsInputHigh[0], true); ··· 77 85 } 78 86 79 87 TEST_F(EncoderSplitTestLeftEqRight, TestInitRight) { 88 + isMaster = true; 80 89 isLeftHand = false; 81 90 encoder_init(); 82 91 EXPECT_EQ(pinIsInputHigh[0], false); ··· 90 99 EXPECT_EQ(updates_array_idx, 0); // no updates received 91 100 } 92 101 93 - TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeft) { 102 + TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeftMaster) { 103 + isMaster = true; 94 104 isLeftHand = true; 95 105 encoder_init(); 96 106 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. ··· 102 112 EXPECT_EQ(updates_array_idx, 1); // one update received 103 113 EXPECT_EQ(updates[0].index, 0); 104 114 EXPECT_EQ(updates[0].clockwise, true); 115 + 116 + int events_queued = 0; 117 + encoder_events_t events; 118 + encoder_retrieve_events(&events); 119 + while (events.tail != events.head) { 120 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 121 + ++events_queued; 122 + } 123 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 105 124 } 106 125 107 - TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightSent) { 126 + TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightMaster) { 127 + isMaster = true; 108 128 isLeftHand = false; 109 129 encoder_init(); 110 130 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. ··· 113 133 setAndRead(6, true); 114 134 setAndRead(7, true); 115 135 116 - uint8_t slave_state[32] = {0}; 117 - encoder_state_raw(slave_state); 136 + EXPECT_EQ(updates_array_idx, 1); // one update received 137 + EXPECT_EQ(updates[0].index, 3); 138 + EXPECT_EQ(updates[0].clockwise, true); 118 139 119 - EXPECT_EQ(slave_state[0], 0); 120 - EXPECT_EQ(slave_state[1], 0xFF); 140 + int events_queued = 0; 141 + encoder_events_t events; 142 + encoder_retrieve_events(&events); 143 + while (events.tail != events.head) { 144 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 145 + ++events_queued; 146 + } 147 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 121 148 } 122 149 123 - TEST_F(EncoderSplitTestLeftEqRight, TestMultipleEncodersRightReceived) { 150 + TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeftSlave) { 151 + isMaster = false; 124 152 isLeftHand = true; 125 153 encoder_init(); 154 + // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 155 + setAndRead(0, false); 156 + setAndRead(1, false); 157 + setAndRead(0, true); 158 + setAndRead(1, true); 126 159 127 - uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder CW 128 - encoder_update_raw(slave_state); 160 + EXPECT_EQ(updates_array_idx, 0); // no updates received 161 + 162 + int events_queued = 0; 163 + encoder_events_t events; 164 + encoder_retrieve_events(&events); 165 + while (events.tail != events.head) { 166 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 167 + ++events_queued; 168 + } 169 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 170 + } 171 + 172 + TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightSlave) { 173 + isMaster = false; 174 + isLeftHand = false; 175 + encoder_init(); 176 + // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 177 + setAndRead(6, false); 178 + setAndRead(7, false); 179 + setAndRead(6, true); 180 + setAndRead(7, true); 129 181 130 - EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side 131 - EXPECT_EQ(updates[0].index, 2); 132 - EXPECT_EQ(updates[0].clockwise, false); 133 - EXPECT_EQ(updates[1].index, 3); 134 - EXPECT_EQ(updates[1].clockwise, true); 182 + EXPECT_EQ(updates_array_idx, 0); // no updates received 183 + 184 + int events_queued = 0; 185 + encoder_events_t events; 186 + encoder_retrieve_events(&events); 187 + while (events.tail != events.head) { 188 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 189 + ++events_queued; 190 + } 191 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 135 192 }
+72 -17
quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp
··· 33 33 uint8_t updates_array_idx = 0; 34 34 update updates[32]; 35 35 36 + bool isMaster; 36 37 bool isLeftHand; 37 38 39 + extern "C" { 40 + bool is_keyboard_master(void) { 41 + return isMaster; 42 + } 43 + 38 44 bool encoder_update_kb(uint8_t index, bool clockwise) { 39 - if (!isLeftHand) { 45 + if (!is_keyboard_master()) { 40 46 // this method has no effect on slave half 41 - printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC"); 47 + printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC"); 42 48 return true; 43 49 } 44 50 updates[updates_array_idx % 32] = {index, clockwise}; 45 51 updates_array_idx++; 46 52 return true; 47 53 } 54 + }; 48 55 49 56 bool setAndRead(pin_t pin, bool val) { 50 57 setPin(pin, val); 51 - return encoder_read(); 58 + return encoder_task(); 52 59 } 53 60 54 61 class EncoderSplitTestLeftGreaterThanRight : public ::testing::Test { ··· 94 101 EXPECT_EQ(updates_array_idx, 0); // no updates received 95 102 } 96 103 97 - TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeft) { 104 + TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeftMaster) { 105 + isMaster = true; 98 106 isLeftHand = true; 99 107 encoder_init(); 100 108 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. ··· 106 114 EXPECT_EQ(updates_array_idx, 1); // one update received 107 115 EXPECT_EQ(updates[0].index, 0); 108 116 EXPECT_EQ(updates[0].clockwise, true); 117 + 118 + int events_queued = 0; 119 + encoder_events_t events; 120 + encoder_retrieve_events(&events); 121 + while (events.tail != events.head) { 122 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 123 + ++events_queued; 124 + } 125 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 109 126 } 110 127 111 - TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightSent) { 128 + TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightMaster) { 129 + isMaster = true; 112 130 isLeftHand = false; 113 131 encoder_init(); 114 132 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. ··· 117 135 setAndRead(6, true); 118 136 setAndRead(7, true); 119 137 120 - uint8_t slave_state[32] = {0}; 121 - encoder_state_raw(slave_state); 138 + EXPECT_EQ(updates_array_idx, 1); // one update received 139 + EXPECT_EQ(updates[0].index, 3); 140 + EXPECT_EQ(updates[0].clockwise, true); 122 141 123 - EXPECT_EQ(slave_state[0], 0xFF); 124 - EXPECT_EQ(slave_state[1], 0); 142 + int events_queued = 0; 143 + encoder_events_t events; 144 + encoder_retrieve_events(&events); 145 + while (events.tail != events.head) { 146 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 147 + ++events_queued; 148 + } 149 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 125 150 } 126 151 127 - TEST_F(EncoderSplitTestLeftGreaterThanRight, TestMultipleEncodersRightReceived) { 152 + TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeftSlave) { 153 + isMaster = false; 128 154 isLeftHand = true; 129 155 encoder_init(); 156 + // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 157 + setAndRead(0, false); 158 + setAndRead(1, false); 159 + setAndRead(0, true); 160 + setAndRead(1, true); 130 161 131 - uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW 132 - encoder_update_raw(slave_state); 162 + EXPECT_EQ(updates_array_idx, 0); // no updates received 133 163 134 - EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side 135 - EXPECT_EQ(updates[0].index, 3); 136 - EXPECT_EQ(updates[0].clockwise, false); 137 - EXPECT_EQ(updates[1].index, 4); 138 - EXPECT_EQ(updates[1].clockwise, true); 164 + int events_queued = 0; 165 + encoder_events_t events; 166 + encoder_retrieve_events(&events); 167 + while (events.tail != events.head) { 168 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 169 + ++events_queued; 170 + } 171 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 172 + } 173 + 174 + TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightSlave) { 175 + isMaster = false; 176 + isLeftHand = false; 177 + encoder_init(); 178 + // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 179 + setAndRead(6, false); 180 + setAndRead(7, false); 181 + setAndRead(6, true); 182 + setAndRead(7, true); 183 + 184 + EXPECT_EQ(updates_array_idx, 0); // no updates received 185 + 186 + int events_queued = 0; 187 + encoder_events_t events; 188 + encoder_retrieve_events(&events); 189 + while (events.tail != events.head) { 190 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 191 + ++events_queued; 192 + } 193 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 139 194 }
+72 -17
quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp
··· 33 33 uint8_t updates_array_idx = 0; 34 34 update updates[32]; 35 35 36 + bool isMaster; 36 37 bool isLeftHand; 37 38 39 + extern "C" { 40 + bool is_keyboard_master(void) { 41 + return isMaster; 42 + } 43 + 38 44 bool encoder_update_kb(uint8_t index, bool clockwise) { 39 - if (!isLeftHand) { 45 + if (!is_keyboard_master()) { 40 46 // this method has no effect on slave half 41 - printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC"); 47 + printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC"); 42 48 return true; 43 49 } 44 50 updates[updates_array_idx % 32] = {index, clockwise}; 45 51 updates_array_idx++; 46 52 return true; 47 53 } 54 + }; 48 55 49 56 bool setAndRead(pin_t pin, bool val) { 50 57 setPin(pin, val); 51 - return encoder_read(); 58 + return encoder_task(); 52 59 } 53 60 54 61 class EncoderSplitTestLeftLessThanRight : public ::testing::Test { ··· 94 101 EXPECT_EQ(updates_array_idx, 0); // no updates received 95 102 } 96 103 97 - TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeft) { 104 + TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeftMaster) { 105 + isMaster = true; 98 106 isLeftHand = true; 99 107 encoder_init(); 100 108 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. ··· 106 114 EXPECT_EQ(updates_array_idx, 1); // one update received 107 115 EXPECT_EQ(updates[0].index, 0); 108 116 EXPECT_EQ(updates[0].clockwise, true); 117 + 118 + int events_queued = 0; 119 + encoder_events_t events; 120 + encoder_retrieve_events(&events); 121 + while (events.tail != events.head) { 122 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 123 + ++events_queued; 124 + } 125 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 109 126 } 110 127 111 - TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightSent) { 128 + TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightMaster) { 129 + isMaster = true; 112 130 isLeftHand = false; 113 131 encoder_init(); 114 132 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. ··· 117 135 setAndRead(6, true); 118 136 setAndRead(7, true); 119 137 120 - uint8_t slave_state[32] = {0}; 121 - encoder_state_raw(slave_state); 138 + EXPECT_EQ(updates_array_idx, 1); // one update received 139 + EXPECT_EQ(updates[0].index, 3); 140 + EXPECT_EQ(updates[0].clockwise, true); 122 141 123 - EXPECT_EQ(slave_state[0], 0); 124 - EXPECT_EQ(slave_state[1], 0xFF); 142 + int events_queued = 0; 143 + encoder_events_t events; 144 + encoder_retrieve_events(&events); 145 + while (events.tail != events.head) { 146 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 147 + ++events_queued; 148 + } 149 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 125 150 } 126 151 127 - TEST_F(EncoderSplitTestLeftLessThanRight, TestMultipleEncodersRightReceived) { 152 + TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeftSlave) { 153 + isMaster = false; 128 154 isLeftHand = true; 129 155 encoder_init(); 156 + // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 157 + setAndRead(0, false); 158 + setAndRead(1, false); 159 + setAndRead(0, true); 160 + setAndRead(1, true); 130 161 131 - uint8_t slave_state[32] = {1, 0, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW 132 - encoder_update_raw(slave_state); 162 + EXPECT_EQ(updates_array_idx, 0); // no updates received 133 163 134 - EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side 135 - EXPECT_EQ(updates[0].index, 2); 136 - EXPECT_EQ(updates[0].clockwise, false); 137 - EXPECT_EQ(updates[1].index, 4); 138 - EXPECT_EQ(updates[1].clockwise, true); 164 + int events_queued = 0; 165 + encoder_events_t events; 166 + encoder_retrieve_events(&events); 167 + while (events.tail != events.head) { 168 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 169 + ++events_queued; 170 + } 171 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 172 + } 173 + 174 + TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightSlave) { 175 + isMaster = false; 176 + isLeftHand = false; 177 + encoder_init(); 178 + // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 179 + setAndRead(6, false); 180 + setAndRead(7, false); 181 + setAndRead(6, true); 182 + setAndRead(7, true); 183 + 184 + EXPECT_EQ(updates_array_idx, 0); // no updates received 185 + 186 + int events_queued = 0; 187 + encoder_events_t events; 188 + encoder_retrieve_events(&events); 189 + while (events.tail != events.head) { 190 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 191 + ++events_queued; 192 + } 193 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 139 194 }
+40 -29
quantum/encoder/tests/encoder_tests_split_no_left.cpp
··· 33 33 uint8_t updates_array_idx = 0; 34 34 update updates[32]; 35 35 36 + bool isMaster; 36 37 bool isLeftHand; 37 38 39 + extern "C" { 40 + bool is_keyboard_master(void) { 41 + return isMaster; 42 + } 43 + 38 44 bool encoder_update_kb(uint8_t index, bool clockwise) { 39 - if (!isLeftHand) { 45 + if (!is_keyboard_master()) { 40 46 // this method has no effect on slave half 41 - printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC"); 47 + printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC"); 42 48 return true; 43 49 } 44 50 updates[updates_array_idx % 32] = {index, clockwise}; 45 51 updates_array_idx++; 46 52 return true; 47 53 } 54 + }; 48 55 49 56 bool setAndRead(pin_t pin, bool val) { 50 57 setPin(pin, val); 51 - return encoder_read(); 58 + return encoder_task(); 52 59 } 53 60 54 61 class EncoderSplitTestNoLeft : public ::testing::Test { ··· 82 89 EXPECT_EQ(updates_array_idx, 0); // no updates received 83 90 } 84 91 85 - TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseLeft) { 86 - isLeftHand = true; 92 + TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseLeftMaster) { 93 + isMaster = true; 94 + isLeftHand = false; 87 95 encoder_init(); 88 96 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 89 - setAndRead(0, false); 90 - setAndRead(1, false); 91 - setAndRead(0, true); 92 - setAndRead(1, true); 97 + setAndRead(2, false); 98 + setAndRead(3, false); 99 + setAndRead(2, true); 100 + setAndRead(3, true); 101 + 102 + EXPECT_EQ(updates_array_idx, 1); // one update received 103 + EXPECT_EQ(updates[0].index, 1); 104 + EXPECT_EQ(updates[0].clockwise, true); 93 105 94 - EXPECT_EQ(updates_array_idx, 0); // no updates received 106 + int events_queued = 0; 107 + encoder_events_t events; 108 + encoder_retrieve_events(&events); 109 + while (events.tail != events.head) { 110 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 111 + ++events_queued; 112 + } 113 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 95 114 } 96 115 97 - TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseRightSent) { 116 + TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseRightSlave) { 117 + isMaster = false; 98 118 isLeftHand = false; 99 119 encoder_init(); 100 120 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. ··· 103 123 setAndRead(2, true); 104 124 setAndRead(3, true); 105 125 106 - uint8_t slave_state[32] = {0}; 107 - encoder_state_raw(slave_state); 108 - 109 - EXPECT_EQ(slave_state[0], 0); 110 - EXPECT_EQ(slave_state[1], 0xFF); 111 - } 112 - 113 - TEST_F(EncoderSplitTestNoLeft, TestMultipleEncodersRightReceived) { 114 - isLeftHand = true; 115 - encoder_init(); 126 + EXPECT_EQ(updates_array_idx, 0); // no updates received 116 127 117 - uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW 118 - encoder_update_raw(slave_state); 119 - 120 - EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side 121 - EXPECT_EQ(updates[0].index, 0); 122 - EXPECT_EQ(updates[0].clockwise, false); 123 - EXPECT_EQ(updates[1].index, 1); 124 - EXPECT_EQ(updates[1].clockwise, true); 128 + int events_queued = 0; 129 + encoder_events_t events; 130 + encoder_retrieve_events(&events); 131 + while (events.tail != events.head) { 132 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 133 + ++events_queued; 134 + } 135 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 125 136 }
+42 -24
quantum/encoder/tests/encoder_tests_split_no_right.cpp
··· 33 33 uint8_t updates_array_idx = 0; 34 34 update updates[32]; 35 35 36 + bool isMaster; 36 37 bool isLeftHand; 37 38 39 + extern "C" { 40 + bool is_keyboard_master(void) { 41 + return isMaster; 42 + } 43 + 38 44 bool encoder_update_kb(uint8_t index, bool clockwise) { 39 - if (!isLeftHand) { 45 + if (!is_keyboard_master()) { 40 46 // this method has no effect on slave half 41 - printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC"); 47 + printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC"); 42 48 return true; 43 49 } 44 50 updates[updates_array_idx % 32] = {index, clockwise}; 45 51 updates_array_idx++; 46 52 return true; 47 53 } 54 + }; 48 55 49 56 bool setAndRead(pin_t pin, bool val) { 50 57 setPin(pin, val); 51 - return encoder_read(); 58 + return encoder_task(); 52 59 } 53 60 54 61 class EncoderSplitTestNoRight : public ::testing::Test { ··· 82 89 EXPECT_EQ(updates_array_idx, 0); // no updates received 83 90 } 84 91 85 - TEST_F(EncoderSplitTestNoRight, TestOneClockwiseLeft) { 92 + TEST_F(EncoderSplitTestNoRight, TestOneClockwiseLeftMaster) { 93 + isMaster = true; 86 94 isLeftHand = true; 87 95 encoder_init(); 88 96 // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 89 - setAndRead(0, false); 90 - setAndRead(1, false); 91 - setAndRead(0, true); 92 - setAndRead(1, true); 97 + setAndRead(2, false); 98 + setAndRead(3, false); 99 + setAndRead(2, true); 100 + setAndRead(3, true); 93 101 94 - EXPECT_EQ(updates_array_idx, 1); // one updates received 95 - EXPECT_EQ(updates[0].index, 0); 102 + EXPECT_EQ(updates_array_idx, 1); // one update received 103 + EXPECT_EQ(updates[0].index, 1); 96 104 EXPECT_EQ(updates[0].clockwise, true); 97 - } 98 - 99 - TEST_F(EncoderSplitTestNoRight, TestOneClockwiseRightSent) { 100 - isLeftHand = false; 101 - encoder_init(); 102 105 103 - uint8_t slave_state[32] = {0xAA, 0xAA}; 104 - encoder_state_raw(slave_state); 105 - 106 - EXPECT_EQ(slave_state[0], 0xAA); 107 - EXPECT_EQ(slave_state[1], 0xAA); 106 + int events_queued = 0; 107 + encoder_events_t events; 108 + encoder_retrieve_events(&events); 109 + while (events.tail != events.head) { 110 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 111 + ++events_queued; 112 + } 113 + EXPECT_EQ(events_queued, 0); // No events should be queued on master 108 114 } 109 115 110 - TEST_F(EncoderSplitTestNoRight, TestMultipleEncodersRightReceived) { 116 + TEST_F(EncoderSplitTestNoRight, TestOneClockwiseRightSlave) { 117 + isMaster = false; 111 118 isLeftHand = true; 112 119 encoder_init(); 120 + // send 4 pulses. with resolution 4, that's one step and we should get 1 update. 121 + setAndRead(2, false); 122 + setAndRead(3, false); 123 + setAndRead(2, true); 124 + setAndRead(3, true); 113 125 114 - uint8_t slave_state[32] = {1, 0xFF}; // These values would trigger updates if there were encoders on the other side 115 - encoder_update_raw(slave_state); 126 + EXPECT_EQ(updates_array_idx, 0); // no updates received 116 127 117 - EXPECT_EQ(updates_array_idx, 0); // no updates received -- no right-hand encoders 128 + int events_queued = 0; 129 + encoder_events_t events; 130 + encoder_retrieve_events(&events); 131 + while (events.tail != events.head) { 132 + events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 133 + ++events_queued; 134 + } 135 + EXPECT_EQ(events_queued, 1); // One event should be queued on slave 118 136 }
+1 -7
quantum/encoder/tests/encoder_tests_split_role.cpp
··· 50 50 51 51 bool setAndRead(pin_t pin, bool val) { 52 52 setPin(pin, val); 53 - return encoder_read(); 53 + return encoder_task(); 54 54 } 55 55 56 56 class EncoderSplitTestRole : public ::testing::Test { ··· 87 87 setAndRead(6, true); 88 88 setAndRead(7, true); 89 89 90 - uint8_t slave_state[32] = {0}; 91 - encoder_state_raw(slave_state); 92 - 93 90 EXPECT_EQ(num_updates, 1); // one update received 94 91 } 95 92 ··· 115 112 setAndRead(7, false); 116 113 setAndRead(6, true); 117 114 setAndRead(7, true); 118 - 119 - uint8_t slave_state[32] = {0}; 120 - encoder_state_raw(slave_state); 121 115 122 116 EXPECT_EQ(num_updates, 0); // zero updates received 123 117 }
-4
quantum/encoder/tests/mock_split.c
··· 36 36 } 37 37 38 38 void last_encoder_activity_trigger(void) {} 39 - 40 - __attribute__((weak)) bool is_keyboard_master(void) { 41 - return true; 42 - }
-3
quantum/encoder/tests/mock_split.h
··· 22 22 #define SPLIT_KEYBOARD 23 23 typedef uint8_t pin_t; 24 24 25 - void encoder_state_raw(uint8_t* slave_state); 26 - void encoder_update_raw(uint8_t* slave_state); 27 - 28 25 extern bool pins[]; 29 26 extern bool pinIsInputHigh[]; 30 27
+7
quantum/encoder/tests/rules.mk
··· 3 3 4 4 encoder_SRC := \ 5 5 platforms/test/timer.c \ 6 + drivers/encoder/encoder_quadrature.c \ 6 7 $(QUANTUM_PATH)/encoder/tests/mock.c \ 7 8 $(QUANTUM_PATH)/encoder/tests/encoder_tests.cpp \ 8 9 $(QUANTUM_PATH)/encoder.c ··· 13 14 14 15 encoder_split_left_eq_right_SRC := \ 15 16 platforms/test/timer.c \ 17 + drivers/encoder/encoder_quadrature.c \ 16 18 $(QUANTUM_PATH)/encoder/tests/mock_split.c \ 17 19 $(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_eq_right.cpp \ 18 20 $(QUANTUM_PATH)/encoder.c ··· 23 25 24 26 encoder_split_left_gt_right_SRC := \ 25 27 platforms/test/timer.c \ 28 + drivers/encoder/encoder_quadrature.c \ 26 29 $(QUANTUM_PATH)/encoder/tests/mock_split.c \ 27 30 $(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_gt_right.cpp \ 28 31 $(QUANTUM_PATH)/encoder.c ··· 33 36 34 37 encoder_split_left_lt_right_SRC := \ 35 38 platforms/test/timer.c \ 39 + drivers/encoder/encoder_quadrature.c \ 36 40 $(QUANTUM_PATH)/encoder/tests/mock_split.c \ 37 41 $(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_lt_right.cpp \ 38 42 $(QUANTUM_PATH)/encoder.c ··· 43 47 44 48 encoder_split_no_left_SRC := \ 45 49 platforms/test/timer.c \ 50 + drivers/encoder/encoder_quadrature.c \ 46 51 $(QUANTUM_PATH)/encoder/tests/mock_split.c \ 47 52 $(QUANTUM_PATH)/encoder/tests/encoder_tests_split_no_left.cpp \ 48 53 $(QUANTUM_PATH)/encoder.c ··· 53 58 54 59 encoder_split_no_right_SRC := \ 55 60 platforms/test/timer.c \ 61 + drivers/encoder/encoder_quadrature.c \ 56 62 $(QUANTUM_PATH)/encoder/tests/mock_split.c \ 57 63 $(QUANTUM_PATH)/encoder/tests/encoder_tests_split_no_right.cpp \ 58 64 $(QUANTUM_PATH)/encoder.c ··· 63 69 64 70 encoder_split_role_SRC := \ 65 71 platforms/test/timer.c \ 72 + drivers/encoder/encoder_quadrature.c \ 66 73 $(QUANTUM_PATH)/encoder/tests/mock_split.c \ 67 74 $(QUANTUM_PATH)/encoder/tests/encoder_tests_split_role.cpp \ 68 75 $(QUANTUM_PATH)/encoder.c
+1 -1
quantum/keyboard.c
··· 689 689 #endif 690 690 691 691 #ifdef ENCODER_ENABLE 692 - if (encoder_read()) { 692 + if (encoder_task()) { 693 693 last_encoder_activity_trigger(); 694 694 activity_has_occurred = true; 695 695 }
+1
quantum/split_common/transaction_id_define.h
··· 31 31 #ifdef ENCODER_ENABLE 32 32 GET_ENCODERS_CHECKSUM, 33 33 GET_ENCODERS_DATA, 34 + PUT_ENCODER_TAIL, 34 35 #endif // ENCODER_ENABLE 35 36 36 37 #ifndef DISABLE_SYNC_TIMER
+17 -9
quantum/split_common/transactions.c
··· 234 234 #ifdef ENCODER_ENABLE 235 235 236 236 static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 237 - static uint32_t last_update = 0; 238 - uint8_t temp_state[NUM_ENCODERS_MAX_PER_SIDE]; 237 + static uint32_t last_update = 0; 238 + encoder_events_t temp_events; 239 239 240 - bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, temp_state, split_shmem->encoders.state, sizeof(temp_state)); 241 - if (okay) encoder_update_raw(temp_state); 240 + bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, &temp_events, &split_shmem->encoders.events, sizeof(temp_events)); 241 + if (okay) { 242 + encoder_handle_slave_events(&split_shmem->encoders.events); 243 + transport_write(PUT_ENCODER_TAIL, &split_shmem->encoders.events.tail, sizeof(split_shmem->encoders.events.tail)); 244 + split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events)); 245 + } 242 246 return okay; 243 247 } 244 248 245 249 static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 246 - uint8_t encoder_state[NUM_ENCODERS_MAX_PER_SIDE]; 247 - encoder_state_raw(encoder_state); 248 250 // Always prepare the encoder state for read. 249 - memcpy(split_shmem->encoders.state, encoder_state, sizeof(encoder_state)); 251 + encoder_retrieve_events(&split_shmem->encoders.events); 250 252 // Now update the checksum given that the encoders has been written to 251 - split_shmem->encoders.checksum = crc8(encoder_state, sizeof(encoder_state)); 253 + split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events)); 254 + } 255 + 256 + static void encoder_handlers_slave_reset(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) { 257 + uint8_t tail_index = *(uint8_t *)initiator2target_buffer; 258 + encoder_set_tail_index(tail_index); 252 259 } 253 260 254 261 // clang-format off ··· 256 263 # define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(encoder) 257 264 # define TRANSACTIONS_ENCODERS_REGISTRATIONS \ 258 265 [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \ 259 - [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.state), 266 + [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.events), \ 267 + [PUT_ENCODER_TAIL] = trans_initiator2target_initializer_cb(encoders.events.tail, encoder_handlers_slave_reset), 260 268 // clang-format on 261 269 262 270 #else // ENCODER_ENABLE
+2 -2
quantum/split_common/transport.h
··· 65 65 66 66 #ifdef ENCODER_ENABLE 67 67 typedef struct _split_slave_encoder_sync_t { 68 - uint8_t checksum; 69 - uint8_t state[NUM_ENCODERS_MAX_PER_SIDE]; 68 + uint8_t checksum; 69 + encoder_events_t events; 70 70 } split_slave_encoder_sync_t; 71 71 #endif // ENCODER_ENABLE 72 72