Browse Source

Add custom encoders

pull/16852/head
Leah Post 2 years ago
parent
commit
c5536971f6
4 changed files with 138 additions and 46 deletions
  1. +9
    -0
      builddefs/common_features.mk
  2. +52
    -0
      docs/feature_encoders.md
  3. +47
    -26
      quantum/encoder.c
  4. +30
    -20
      quantum/encoder.h

+ 9
- 0
builddefs/common_features.mk View File

@ -589,6 +589,15 @@ ifneq ($(strip $(CUSTOM_MATRIX)), yes)
endif
endif
VALID_CUSTOM_ENCODER_TYPES:= yes no
CUSTOM_ENCODER ?= no
ifneq ($(strip $(CUSTOM_ENCODER)), no)
ifeq ($(filter $(CUSTOM_ENCODER),$(VALID_CUSTOM_MATRIX_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid CUSTOM_ENCODER,CUSTOM_ENCODER="$(CUSTOM_ENCODER)" is not a valid custom encoder type)
endif
OPT_DEFS += -DCUSTOM_ENCODER
endif
# Debounce Modules. Set DEBOUNCE_TYPE=custom if including one manually.
DEBOUNCE_TYPE ?= sym_defer_g
ifneq ($(strip $(DEBOUNCE_TYPE)), custom)


+ 52
- 0
docs/feature_encoders.md View File

@ -183,3 +183,55 @@ You could even support three encoders using only three pins (one per encoder) ho
#define ENCODERS_PAD_B { B2, B3, B3 }
```
Here rotating Encoder 0 `B1 B2` and Encoder 1 `B1 B3` could be interpreted as rotating Encoder 2 `B2 B3` or `B3 B2` depending on the timing. This may still be a useful configuration depending on your use case
## Custom encoders
Not everyone has encoders wired directly to the MCU. If yours are wired to external hardware (such as an I/O multiplexer), you can supplement the default encoder logic with your own.
Add a new file to your keyboard directory:
```
keyboards/<keyboard>/encoder.c
```
And to configure compilation for the new file, add this to your `rules.mk`:
```make
CUSTOM_ENCODER = yes
SRC += encoder.c
```
Implement the following functions in the `encoder.c` file in your keyboard folder:
```c
void encoder_init_pads(uint8_t count, bool pads[]) {
// TODO: initialize hardware here
// EXAMPLE:
// expanderSetInputHigh(ENCODER_PAD_1A);
// expanderSetInputHigh(ENCODER_PAD_1B);
// expanderSetInputHigh(ENCODER_PAD_2A);
// expanderSetInputHigh(ENCODER_PAD_2B);
// // make sure we start with a known value
// encoder_read_pads(pads);
}
void encoder_read_pads(uint8_t count, bool pads[]) {
// TODO: add encoder reading routine here
// EXAMPLE:
// pads[0] = expanderReadPin(ENCODER_PAD_1A);
// pads[1] = expanderReadPin(ENCODER_PAD_1B);
// pads[2] = expanderReadPin(ENCODER_PAD_2A);
// pads[3] = expanderReadPin(ENCODER_PAD_2B);
}
```
Finally, let QMK know how many encoders you want to use by adding this to your `config.h`:
```c
#define NUM_ENCODERS 2 // or any other number
```
Or for a split keyboard:
```c
#define NUM_ENCODERS_LEFT 2
#define NUM_ENCODERS_RIGHT 2
```

+ 47
- 26
quantum/encoder.c View File

@ -31,14 +31,15 @@
# define ENCODER_RESOLUTION 4
#endif
#if !defined(ENCODERS_PAD_A) || !defined(ENCODERS_PAD_B)
# error "No encoder pads defined by ENCODERS_PAD_A and ENCODERS_PAD_B"
#endif
extern volatile bool isLeftHand;
#ifndef CUSTOM_ENCODER
# if !defined(ENCODERS_PAD_A) || !defined(ENCODERS_PAD_B)
# error "No encoder pads defined by ENCODERS_PAD_A and ENCODERS_PAD_B"
# endif
static pin_t encoders_pad_a[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_A;
static pin_t encoders_pad_b[NUM_ENCODERS_MAX_PER_SIDE] = ENCODERS_PAD_B;
#endif // CUSTOM_ENCODER
extern volatile bool isLeftHand;
#ifdef ENCODER_RESOLUTIONS
static uint8_t encoder_resolutions[NUM_ENCODERS] = ENCODER_RESOLUTIONS;
@ -79,6 +80,39 @@ __attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) {
return encoder_update_user(index, clockwise);
}
void encoder_init_pads(uint8_t count, bool pads[]);
void encoder_read_pads(uint8_t count, bool pads[]);
#ifndef CUSTOM_ENCODER
void encoder_init_pads(uint8_t count, bool pads[]) {
# if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT)
if (!isLeftHand) {
const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT;
const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT;
for (uint8_t i = 0; i < count; i++) {
encoders_pad_a[i] = encoders_pad_a_right[i];
encoders_pad_b[i] = encoders_pad_b_right[i];
}
}
# endif // defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT)
for (int i = 0; i < count; i++) {
setPinInputHigh(encoders_pad_a[i]);
setPinInputHigh(encoders_pad_b[i]);
}
encoder_wait_pullup_charge();
encoder_read_pads(count, pads);
}
void encoder_read_pads(uint8_t count, bool pads[]) {
for (int i = 0; i < count; i++) {
pads[2 * i + 0] = readPin(encoders_pad_a[i]);
pads[2 * i + 1] = readPin(encoders_pad_b[i]);
}
}
#endif // CUSTOM_ENCODER
void encoder_init(void) {
#ifdef SPLIT_KEYBOARD
thisHand = isLeftHand ? 0 : NUM_ENCODERS_LEFT;
@ -105,18 +139,6 @@ void encoder_init(void) {
}
#endif
#if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT)
// Re-initialise the pads if it's the right-hand side
if (!isLeftHand) {
static const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT;
static const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT;
for (uint8_t i = 0; i < thisCount; i++) {
encoders_pad_a[i] = encoders_pad_a_right[i];
encoders_pad_b[i] = encoders_pad_b_right[i];
}
}
#endif // defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT)
// Encoder resolutions is handled purely master-side, so concatenate the two arrays
#if defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS)
# if defined(ENCODER_RESOLUTIONS_RIGHT)
@ -129,13 +151,10 @@ void encoder_init(void) {
}
#endif // defined(SPLIT_KEYBOARD) && defined(ENCODER_RESOLUTIONS)
for (uint8_t i = 0; i < thisCount; i++) {
setPinInputHigh(encoders_pad_a[i]);
setPinInputHigh(encoders_pad_b[i]);
}
encoder_wait_pullup_charge();
for (uint8_t i = 0; i < thisCount; i++) {
encoder_state[i] = (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1);
bool pads[NUM_ENCODERS_MAX_PER_SIDE * 2];
encoder_init_pads(thisCount, pads);
for (int i = 0; i < thisCount; i++) {
encoder_state[i] = (pads[2 * i + 0] << 0) | (pads[2 * i + 1] << 1);
}
}
@ -192,8 +211,10 @@ static bool encoder_update(uint8_t index, uint8_t state) {
bool encoder_read(void) {
bool changed = false;
bool pads[NUM_ENCODERS_MAX_PER_SIDE * 2];
encoder_read_pads(thisCount, pads);
for (uint8_t i = 0; i < thisCount; i++) {
uint8_t new_status = (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1);
uint8_t new_status = (pads[2 * i + 0] << 0) | (pads[2 * i + 1] << 1);
if ((encoder_state[i] & 0x3) != new_status) {
encoder_state[i] <<= 2;
encoder_state[i] |= new_status;


+ 30
- 20
quantum/encoder.h View File

@ -31,28 +31,38 @@ bool encoder_update_user(uint8_t index, bool clockwise);
void encoder_state_raw(uint8_t* slave_state);
void encoder_update_raw(uint8_t* slave_state);
# if defined(ENCODERS_PAD_A_RIGHT)
# define NUM_ENCODERS_LEFT (sizeof(((pin_t[])ENCODERS_PAD_A)) / sizeof(pin_t))
# define NUM_ENCODERS_RIGHT (sizeof(((pin_t[])ENCODERS_PAD_A_RIGHT)) / sizeof(pin_t))
# else
# define NUM_ENCODERS_LEFT (sizeof(((pin_t[])ENCODERS_PAD_A)) / sizeof(pin_t))
# define NUM_ENCODERS_RIGHT NUM_ENCODERS_LEFT
# endif
# define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT)
#else // SPLIT_KEYBOARD
# define NUM_ENCODERS (sizeof(((pin_t[])ENCODERS_PAD_A)) / sizeof(pin_t))
# define NUM_ENCODERS_LEFT NUM_ENCODERS
# define NUM_ENCODERS_RIGHT 0
#endif // SPLIT_KEYBOARD
#ifndef NUM_ENCODERS
# define NUM_ENCODERS 0
# define NUM_ENCODERS_LEFT 0
# define NUM_ENCODERS_RIGHT 0
#endif // NUM_ENCODERS
#ifndef CUSTOM_ENCODER
# define NUM_ENCODERS_LEFT (sizeof(((pin_t[])ENCODERS_PAD_A)) / sizeof(pin_t))
# ifdef SPLIT_KEYBOARD
# ifdef ENCODERS_PAD_A_RIGHT
# define NUM_ENCODERS_RIGHT (sizeof(((pin_t[])ENCODERS_PAD_A_RIGHT)) / sizeof(pin_t))
# else
# define NUM_ENCODERS_RIGHT NUM_ENCODERS_LEFT
# endif
# else // SPLIT_KEYBOARD
# define NUM_ENCODERS_RIGHT 0
# endif // SPLIT_KEYBOARD
# define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT)
#else // CUSTOM_ENCODER
# ifdef SPLIT_KEYBOARD
# ifndef NUM_ENCODERS_LEFT
# error NUM_ENCODERS_LEFT must be defined
# endif
# ifndef NUM_ENCODERS_RIGHT
# error NUM_ENCODERS_RIGHT must be defined
# endif
# define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT)
# else // SPLIT_KEYBOARD
# ifndef NUM_ENCODERS
# error NUM_ENCODERS must be defined
# else
# define NUM_ENCODERS_LEFT NUM_ENCODERS
# define NUM_ENCODERS_RIGHT 0
# endif
# endif // SPLIT_KEYBOARD
#endif // CUSTOM_ENCODER
#define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT)


Loading…
Cancel
Save