summaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/action.c4
-rw-r--r--quantum/audio/audio.c37
-rw-r--r--quantum/audio/audio.h3
-rw-r--r--quantum/backlight/backlight.c21
-rw-r--r--quantum/backlight/backlight.h2
-rw-r--r--quantum/backlight/backlight_driver_common.c10
-rw-r--r--quantum/bootmagic/bootmagic.c (renamed from quantum/bootmagic/bootmagic_lite.c)54
-rw-r--r--quantum/bootmagic/bootmagic.h22
-rw-r--r--quantum/bootmagic/bootmagic_lite.h25
-rw-r--r--quantum/bootmagic/magic.c54
-rw-r--r--quantum/bootmagic/magic.h18
-rw-r--r--quantum/dip_switch.c61
-rw-r--r--quantum/dip_switch.h27
-rw-r--r--quantum/eeconfig.c2
-rw-r--r--quantum/encoder.c336
-rw-r--r--quantum/encoder.h99
-rw-r--r--quantum/encoder/tests/config_encoder_common.h6
-rw-r--r--quantum/encoder/tests/config_mock.h3
-rw-r--r--quantum/encoder/tests/config_mock_split_left_eq_right.h3
-rw-r--r--quantum/encoder/tests/config_mock_split_left_gt_right.h3
-rw-r--r--quantum/encoder/tests/config_mock_split_left_lt_right.h3
-rw-r--r--quantum/encoder/tests/config_mock_split_no_left.h3
-rw-r--r--quantum/encoder/tests/config_mock_split_no_right.h3
-rw-r--r--quantum/encoder/tests/config_mock_split_role.h3
-rw-r--r--quantum/encoder/tests/encoder_tests.cpp2
-rw-r--r--quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp91
-rw-r--r--quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp89
-rw-r--r--quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp89
-rw-r--r--quantum/encoder/tests/encoder_tests_split_no_left.cpp69
-rw-r--r--quantum/encoder/tests/encoder_tests_split_no_right.cpp66
-rw-r--r--quantum/encoder/tests/encoder_tests_split_role.cpp8
-rw-r--r--quantum/encoder/tests/mock.c4
-rw-r--r--quantum/encoder/tests/mock.h8
-rw-r--r--quantum/encoder/tests/mock_split.c8
-rw-r--r--quantum/encoder/tests/mock_split.h11
-rw-r--r--quantum/encoder/tests/rules.mk7
-rw-r--r--quantum/haptic.c8
-rw-r--r--quantum/haptic.h16
-rw-r--r--quantum/joystick.c101
-rw-r--r--quantum/joystick.h30
-rw-r--r--quantum/keyboard.c72
-rw-r--r--quantum/keyboard.h13
-rw-r--r--quantum/keycode_config.c2
-rw-r--r--quantum/keymap_common.c12
-rw-r--r--quantum/keymap_extras/keymap_canadian_french.h122
-rw-r--r--quantum/keymap_extras/keymap_spanish_latin_america.h105
-rw-r--r--quantum/keymap_extras/sendstring_canadian_french.h120
-rw-r--r--quantum/keymap_extras/sendstring_spanish_latin_america.h120
-rw-r--r--quantum/keymap_introspection.c18
-rw-r--r--quantum/keymap_introspection.h12
-rw-r--r--quantum/led.c34
-rw-r--r--quantum/led_matrix/led_matrix.c43
-rw-r--r--quantum/led_matrix/led_matrix.h45
-rw-r--r--quantum/led_matrix/led_matrix_drivers.c44
-rw-r--r--quantum/led_matrix/led_matrix_drivers.h46
-rw-r--r--quantum/logging/debug.h120
-rw-r--r--quantum/logging/print.h36
-rw-r--r--quantum/matrix.c14
-rw-r--r--quantum/os_detection.c148
-rw-r--r--quantum/os_detection.h12
-rw-r--r--quantum/os_detection/tests/os_detection.cpp231
-rw-r--r--quantum/os_detection/tests/rules.mk4
-rw-r--r--quantum/painter/qp.h6
-rw-r--r--quantum/painter/qp_draw.h5
-rw-r--r--quantum/painter/qp_draw_codec.c40
-rw-r--r--quantum/painter/qp_draw_image.c29
-rw-r--r--quantum/painter/qp_draw_text.c11
-rw-r--r--quantum/painter/qp_internal.c1
-rw-r--r--quantum/painter/rules.mk12
-rw-r--r--quantum/pointing_device/pointing_device.c19
-rw-r--r--quantum/pointing_device/pointing_device_auto_mouse.c15
-rw-r--r--quantum/pointing_device/pointing_device_auto_mouse.h10
-rw-r--r--quantum/process_keycode/process_caps_word.c4
-rw-r--r--quantum/process_keycode/process_midi.c23
-rw-r--r--quantum/process_keycode/process_space_cadet.c6
-rw-r--r--quantum/process_keycode/process_space_cadet.h1
-rw-r--r--quantum/process_keycode/process_steno.c3
-rw-r--r--quantum/process_keycode/process_tap_dance.c6
-rw-r--r--quantum/process_keycode/process_tap_dance.h4
-rw-r--r--quantum/quantum.h9
-rw-r--r--quantum/quantum_keycodes.h4
-rw-r--r--quantum/rgb_matrix/animations/solid_reactive_anim.h2
-rw-r--r--quantum/rgb_matrix/rgb_matrix.c29
-rw-r--r--quantum/rgb_matrix/rgb_matrix.h40
-rw-r--r--quantum/rgb_matrix/rgb_matrix_drivers.c52
-rw-r--r--quantum/rgb_matrix/rgb_matrix_drivers.h49
-rw-r--r--quantum/rgblight/rgblight.c71
-rw-r--r--quantum/rgblight/rgblight.h9
-rw-r--r--quantum/rgblight/rgblight_drivers.c20
-rw-r--r--quantum/rgblight/rgblight_drivers.h13
-rw-r--r--quantum/send_string/send_string.c36
-rw-r--r--quantum/send_string/send_string.h14
-rw-r--r--quantum/split_common/split_util.c22
-rw-r--r--quantum/split_common/transaction_id_define.h1
-rw-r--r--quantum/split_common/transactions.c26
-rw-r--r--quantum/split_common/transport.c6
-rw-r--r--quantum/split_common/transport.h4
97 files changed, 2212 insertions, 1172 deletions
diff --git a/quantum/action.c b/quantum/action.c
index 29822c39e9..8dae32b2cb 100644
--- a/quantum/action.c
+++ b/quantum/action.c
@@ -1011,9 +1011,7 @@ __attribute__((weak)) void unregister_code(uint8_t code) {
*/
__attribute__((weak)) void tap_code_delay(uint8_t code, uint16_t delay) {
register_code(code);
- for (uint16_t i = delay; i > 0; i--) {
- wait_ms(1);
- }
+ wait_ms(delay);
unregister_code(code);
}
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
index 28c8267517..c1a1500493 100644
--- a/quantum/audio/audio.c
+++ b/quantum/audio/audio.c
@@ -17,6 +17,7 @@
#include "audio.h"
#include "eeconfig.h"
#include "timer.h"
+#include "debug.h"
#include "wait.h"
#include "util.h"
@@ -62,6 +63,13 @@
* the internal state of the audio system does its calculations with the later - ms
*/
+#ifndef AUDIO_DEFAULT_ON
+# define AUDIO_DEFAULT_ON true
+#endif
+#ifndef AUDIO_DEFAULT_CLICKY_ON
+# define AUDIO_DEFAULT_CLICKY_ON true
+#endif
+
#ifndef AUDIO_TONE_STACKSIZE
# define AUDIO_TONE_STACKSIZE 8
#endif
@@ -117,32 +125,31 @@ void eeconfig_update_audio_current(void) {
eeconfig_update_audio(audio_config.raw);
}
+void eeconfig_update_audio_default(void) {
+ audio_config.valid = true;
+ audio_config.enable = AUDIO_DEFAULT_ON;
+ audio_config.clicky_enable = AUDIO_DEFAULT_CLICKY_ON;
+ eeconfig_update_audio(audio_config.raw);
+}
+
void audio_init(void) {
if (audio_initialized) {
return;
}
- // Check EEPROM
-#ifdef EEPROM_ENABLE
- if (!eeconfig_is_enabled()) {
- eeconfig_init();
- }
audio_config.raw = eeconfig_read_audio();
-#else // EEPROM settings
- audio_config.enable = true;
-# ifdef AUDIO_CLICKY_ON
- audio_config.clicky_enable = true;
-# endif
-#endif // EEPROM settings
+ if (!audio_config.valid) {
+ dprintf("audio_init audio_config.valid = 0. Write default values to EEPROM.\n");
+ eeconfig_update_audio_default();
+ }
for (uint8_t i = 0; i < AUDIO_TONE_STACKSIZE; i++) {
tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
}
- if (!audio_initialized) {
- audio_driver_initialize();
- audio_initialized = true;
- }
+ audio_driver_initialize();
+ audio_initialized = true;
+
stop_all_notes();
#ifndef AUDIO_INIT_DELAY
audio_startup();
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
index a4a908b43c..eb0bedc6f9 100644
--- a/quantum/audio/audio.h
+++ b/quantum/audio/audio.h
@@ -33,7 +33,8 @@ typedef union {
struct {
bool enable : 1;
bool clicky_enable : 1;
- uint8_t level : 6;
+ bool valid : 1;
+ uint8_t reserved : 5;
};
} audio_config_t;
diff --git a/quantum/backlight/backlight.c b/quantum/backlight/backlight.c
index e89b34696c..eb64dd71e8 100644
--- a/quantum/backlight/backlight.c
+++ b/quantum/backlight/backlight.c
@@ -42,20 +42,26 @@ backlight_config_t backlight_config;
static uint8_t breathing_period = BREATHING_PERIOD;
#endif
+static void backlight_check_config(void) {
+ /* Add some out of bound checks for backlight config */
+
+ if (backlight_config.level > BACKLIGHT_LEVELS) {
+ backlight_config.level = BACKLIGHT_LEVELS;
+ }
+}
+
/** \brief Backlight initialization
*
* FIXME: needs doc
*/
void backlight_init(void) {
- /* check signature */
- if (!eeconfig_is_enabled()) {
- eeconfig_init();
- eeconfig_update_backlight_default();
- }
backlight_config.raw = eeconfig_read_backlight();
- if (backlight_config.level > BACKLIGHT_LEVELS) {
- backlight_config.level = BACKLIGHT_LEVELS;
+ if (!backlight_config.valid) {
+ dprintf("backlight_init backlight_config.valid = 0. Write default values to EEPROM.\n");
+ eeconfig_update_backlight_default();
}
+ backlight_check_config();
+
backlight_set(backlight_config.enable ? backlight_config.level : 0);
}
@@ -183,6 +189,7 @@ void eeconfig_update_backlight_current(void) {
}
void eeconfig_update_backlight_default(void) {
+ backlight_config.valid = true;
backlight_config.enable = BACKLIGHT_DEFAULT_ON;
backlight_config.breathing = BACKLIGHT_DEFAULT_BREATHING;
backlight_config.level = BACKLIGHT_DEFAULT_LEVEL;
diff --git a/quantum/backlight/backlight.h b/quantum/backlight/backlight.h
index 85812bff3a..c34fb5858d 100644
--- a/quantum/backlight/backlight.h
+++ b/quantum/backlight/backlight.h
@@ -39,7 +39,7 @@ typedef union {
struct {
bool enable : 1;
bool breathing : 1;
- uint8_t reserved : 1; // Reserved for possible future backlight modes
+ bool valid : 1;
uint8_t level : 5;
};
} backlight_config_t;
diff --git a/quantum/backlight/backlight_driver_common.c b/quantum/backlight/backlight_driver_common.c
index 8c3fe461d7..fb2770ee3c 100644
--- a/quantum/backlight/backlight_driver_common.c
+++ b/quantum/backlight/backlight_driver_common.c
@@ -26,23 +26,23 @@ static const pin_t backlight_pin = BACKLIGHT_PIN;
static inline void backlight_on(pin_t backlight_pin) {
#if BACKLIGHT_ON_STATE == 0
- writePinLow(backlight_pin);
+ gpio_write_pin_low(backlight_pin);
#else
- writePinHigh(backlight_pin);
+ gpio_write_pin_high(backlight_pin);
#endif
}
static inline void backlight_off(pin_t backlight_pin) {
#if BACKLIGHT_ON_STATE == 0
- writePinHigh(backlight_pin);
+ gpio_write_pin_high(backlight_pin);
#else
- writePinLow(backlight_pin);
+ gpio_write_pin_low(backlight_pin);
#endif
}
void backlight_pins_init(void) {
// Setup backlight pin as output and output to off state.
- FOR_EACH_LED(setPinOutput(backlight_pin); backlight_off(backlight_pin);)
+ FOR_EACH_LED(gpio_set_pin_output(backlight_pin); backlight_off(backlight_pin);)
}
void backlight_pins_on(void) {
diff --git a/quantum/bootmagic/bootmagic_lite.c b/quantum/bootmagic/bootmagic.c
index efce6bfd12..419ec5229e 100644
--- a/quantum/bootmagic/bootmagic_lite.c
+++ b/quantum/bootmagic/bootmagic.c
@@ -20,44 +20,54 @@
#include "eeconfig.h"
#include "bootloader.h"
+#ifndef BOOTMAGIC_DEBOUNCE
+# if defined(DEBOUNCE) && DEBOUNCE > 0
+# define BOOTMAGIC_DEBOUNCE (DEBOUNCE * 2)
+# else
+# define BOOTMAGIC_DEBOUNCE 30
+# endif
+#endif
+
/** \brief Reset eeprom
*
* ...just incase someone wants to only change the eeprom behaviour
*/
-__attribute__((weak)) void bootmagic_lite_reset_eeprom(void) {
+__attribute__((weak)) void bootmagic_reset_eeprom(void) {
eeconfig_disable();
}
-/** \brief The lite version of TMK's bootmagic based on Wilba.
- *
- * 100% less potential for accidentally making the keyboard do stupid things.
+/** \brief Decide reboot based on current matrix state
*/
-__attribute__((weak)) void bootmagic_lite(void) {
- // We need multiple scans because debouncing can't be turned off.
- matrix_scan();
-#if defined(DEBOUNCE) && DEBOUNCE > 0
- wait_ms(DEBOUNCE * 2);
-#else
- wait_ms(30);
-#endif
- matrix_scan();
-
+__attribute__((weak)) bool bootmagic_should_reset(void) {
// If the configured key (commonly Esc) is held down on power up,
// reset the EEPROM valid state and jump to bootloader.
// This isn't very generalized, but we need something that doesn't
// rely on user's keymaps in firmware or EEPROM.
- uint8_t row = BOOTMAGIC_LITE_ROW;
- uint8_t col = BOOTMAGIC_LITE_COLUMN;
+ uint8_t row = BOOTMAGIC_ROW;
+ uint8_t col = BOOTMAGIC_COLUMN;
-#if defined(SPLIT_KEYBOARD) && defined(BOOTMAGIC_LITE_ROW_RIGHT) && defined(BOOTMAGIC_LITE_COLUMN_RIGHT)
+#if defined(SPLIT_KEYBOARD) && defined(BOOTMAGIC_ROW_RIGHT) && defined(BOOTMAGIC_COLUMN_RIGHT)
if (!is_keyboard_left()) {
- row = BOOTMAGIC_LITE_ROW_RIGHT;
- col = BOOTMAGIC_LITE_COLUMN_RIGHT;
+ row = BOOTMAGIC_ROW_RIGHT;
+ col = BOOTMAGIC_COLUMN_RIGHT;
}
#endif
- if (matrix_get_row(row) & (1 << col)) {
- bootmagic_lite_reset_eeprom();
+ return matrix_get_row(row) & (1 << col);
+}
+
+/** \brief The abridged version of TMK's bootmagic based on Wilba.
+ *
+ * 100% less potential for accidentally making the keyboard do stupid things.
+ */
+__attribute__((weak)) void bootmagic_scan(void) {
+ // We need multiple scans because debouncing can't be turned off.
+ matrix_scan();
+ wait_ms(BOOTMAGIC_DEBOUNCE);
+ matrix_scan();
+
+ if (bootmagic_should_reset()) {
+ bootmagic_reset_eeprom();
// Jump to bootloader.
bootloader_jump();
@@ -65,5 +75,5 @@ __attribute__((weak)) void bootmagic_lite(void) {
}
void bootmagic(void) {
- bootmagic_lite();
+ bootmagic_scan();
}
diff --git a/quantum/bootmagic/bootmagic.h b/quantum/bootmagic/bootmagic.h
index db826025ce..ee6fb49748 100644
--- a/quantum/bootmagic/bootmagic.h
+++ b/quantum/bootmagic/bootmagic.h
@@ -15,8 +15,26 @@
*/
#pragma once
-#if defined(BOOTMAGIC_LITE)
-# include "bootmagic_lite.h"
+// ======== DEPRECATED DEFINES - DO NOT USE ========
+#ifdef BOOTMAGIC_LITE_ROW
+# define BOOTMAGIC_ROW BOOTMAGIC_LITE_ROW
+#endif
+#ifdef BOOTMAGIC_LITE_COLUMN
+# define BOOTMAGIC_COLUMN BOOTMAGIC_LITE_COLUMN
+#endif
+#ifdef BOOTMAGIC_LITE_ROW_RIGHT
+# define BOOTMAGIC_ROW_RIGHT BOOTMAGIC_LITE_ROW_RIGHT
+#endif
+#ifdef BOOTMAGIC_LITE_COLUMN_RIGHT
+# define BOOTMAGIC_COLUMN_RIGHT BOOTMAGIC_LITE_COLUMN_RIGHT
+#endif
+// ========
+
+#ifndef BOOTMAGIC_COLUMN
+# define BOOTMAGIC_COLUMN 0
+#endif
+#ifndef BOOTMAGIC_ROW
+# define BOOTMAGIC_ROW 0
#endif
void bootmagic(void);
diff --git a/quantum/bootmagic/bootmagic_lite.h b/quantum/bootmagic/bootmagic_lite.h
deleted file mode 100644
index 17777e6b4a..0000000000
--- a/quantum/bootmagic/bootmagic_lite.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Copyright 2021 QMK
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#pragma once
-
-#ifndef BOOTMAGIC_LITE_COLUMN
-# define BOOTMAGIC_LITE_COLUMN 0
-#endif
-#ifndef BOOTMAGIC_LITE_ROW
-# define BOOTMAGIC_LITE_ROW 0
-#endif
-
-void bootmagic_lite(void);
diff --git a/quantum/bootmagic/magic.c b/quantum/bootmagic/magic.c
deleted file mode 100644
index d68df3fa58..0000000000
--- a/quantum/bootmagic/magic.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright 2021 QMK
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#include <stdint.h>
-#include <stdbool.h>
-#include "wait.h"
-#include "matrix.h"
-#include "bootloader.h"
-#include "debug.h"
-#include "keycode_config.h"
-#include "host.h"
-#include "action_layer.h"
-#include "eeconfig.h"
-#include "bootmagic.h"
-
-keymap_config_t keymap_config;
-
-__attribute__((weak)) void bootmagic(void) {}
-
-/** \brief Magic
- *
- * FIXME: Needs doc
- */
-void magic(void) {
- /* check signature */
- if (!eeconfig_is_enabled()) {
- eeconfig_init();
- }
-
- /* init globals */
- debug_config.raw = eeconfig_read_debug();
- keymap_config.raw = eeconfig_read_keymap();
-
- bootmagic();
-
- /* read here just incase bootmagic process changed its value */
- layer_state_t default_layer = (layer_state_t)eeconfig_read_default_layer();
- default_layer_set(default_layer);
-
- /* Also initialize layer state to trigger callback functions for layer_state */
- layer_state_set_kb((layer_state_t)layer_state);
-}
diff --git a/quantum/bootmagic/magic.h b/quantum/bootmagic/magic.h
deleted file mode 100644
index 2c3969b85c..0000000000
--- a/quantum/bootmagic/magic.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2021 QMK
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#pragma once
-
-void magic(void);
diff --git a/quantum/dip_switch.c b/quantum/dip_switch.c
index 6e254578d1..69cf665291 100644
--- a/quantum/dip_switch.c
+++ b/quantum/dip_switch.c
@@ -19,8 +19,6 @@
#include <string.h> // for memcpy
#include "dip_switch.h"
-#include "gpio.h"
-#include "util.h"
#ifdef SPLIT_KEYBOARD
# include "split_common/split_util.h"
@@ -35,24 +33,17 @@
#endif
#ifdef DIP_SWITCH_PINS
-# define NUMBER_OF_DIP_SWITCHES (ARRAY_SIZE(dip_switch_pad))
static pin_t dip_switch_pad[] = DIP_SWITCH_PINS;
#endif
#ifdef DIP_SWITCH_MATRIX_GRID
-typedef struct matrix_index_t {
- uint8_t row;
- uint8_t col;
-} matrix_index_t;
-
-# define NUMBER_OF_DIP_SWITCHES (ARRAY_SIZE(dip_switch_pad))
-static matrix_index_t dip_switch_pad[] = DIP_SWITCH_MATRIX_GRID;
-extern bool peek_matrix(uint8_t row_index, uint8_t col_index, bool read_raw);
-static uint16_t scan_count;
+static matrix_intersection_t dip_switch_pad[] = DIP_SWITCH_MATRIX_GRID;
+extern bool peek_matrix(uint8_t row_index, uint8_t col_index, bool read_raw);
+static uint16_t scan_count;
#endif /* DIP_SWITCH_MATRIX_GRID */
-static bool dip_switch_state[NUMBER_OF_DIP_SWITCHES] = {0};
-static bool last_dip_switch_state[NUMBER_OF_DIP_SWITCHES] = {0};
+static bool dip_switch_state[NUM_DIP_SWITCHES] = {0};
+static bool last_dip_switch_state[NUM_DIP_SWITCHES] = {0};
__attribute__((weak)) bool dip_switch_update_user(uint8_t index, bool active) {
return true;
@@ -70,18 +61,40 @@ __attribute__((weak)) bool dip_switch_update_mask_kb(uint32_t state) {
return dip_switch_update_mask_user(state);
}
+#ifdef DIP_SWITCH_MAP_ENABLE
+# include "keymap_introspection.h"
+# include "action.h"
+
+# ifndef DIP_SWITCH_MAP_KEY_DELAY
+# define DIP_SWITCH_MAP_KEY_DELAY TAP_CODE_DELAY
+# endif
+
+static void dip_switch_exec_mapping(uint8_t index, bool on) {
+ // The delays below cater for Windows and its wonderful requirements.
+ action_exec(on ? MAKE_DIPSWITCH_ON_EVENT(index, true) : MAKE_DIPSWITCH_OFF_EVENT(index, true));
+# if DIP_SWITCH_MAP_KEY_DELAY > 0
+ wait_ms(DIP_SWITCH_MAP_KEY_DELAY);
+# endif // DIP_SWITCH_MAP_KEY_DELAY > 0
+
+ action_exec(on ? MAKE_DIPSWITCH_ON_EVENT(index, false) : MAKE_DIPSWITCH_OFF_EVENT(index, false));
+# if DIP_SWITCH_MAP_KEY_DELAY > 0
+ wait_ms(DIP_SWITCH_MAP_KEY_DELAY);
+# endif // DIP_SWITCH_MAP_KEY_DELAY > 0
+}
+#endif // DIP_SWITCH_MAP_ENABLE
+
void dip_switch_init(void) {
#ifdef DIP_SWITCH_PINS
# if defined(SPLIT_KEYBOARD) && defined(DIP_SWITCH_PINS_RIGHT)
if (!isLeftHand) {
const pin_t dip_switch_pad_right[] = DIP_SWITCH_PINS_RIGHT;
- for (uint8_t i = 0; i < NUMBER_OF_DIP_SWITCHES; i++) {
+ for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
dip_switch_pad[i] = dip_switch_pad_right[i];
}
}
# endif
- for (uint8_t i = 0; i < NUMBER_OF_DIP_SWITCHES; i++) {
- setPinInputHigh(dip_switch_pad[i]);
+ for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
+ gpio_set_pin_input_high(dip_switch_pad[i]);
}
dip_switch_read(true);
#endif
@@ -108,9 +121,9 @@ void dip_switch_read(bool forced) {
}
#endif
- for (uint8_t i = 0; i < NUMBER_OF_DIP_SWITCHES; i++) {
+ for (uint8_t i = 0; i < NUM_DIP_SWITCHES; i++) {
#ifdef DIP_SWITCH_PINS
- dip_switch_state[i] = !readPin(dip_switch_pad[i]);
+ dip_switch_state[i] = !gpio_read_pin(dip_switch_pad[i]);
#endif
#ifdef DIP_SWITCH_MATRIX_GRID
dip_switch_state[i] = peek_matrix(dip_switch_pad[i].row, dip_switch_pad[i].col, read_raw);
@@ -118,11 +131,21 @@ void dip_switch_read(bool forced) {
dip_switch_mask |= dip_switch_state[i] << i;
if (last_dip_switch_state[i] != dip_switch_state[i] || forced) {
has_dip_state_changed = true;
+#ifndef DIP_SWITCH_MAP_ENABLE
dip_switch_update_kb(i, dip_switch_state[i]);
+#else
+ dip_switch_exec_mapping(i, dip_switch_state[i]);
+#endif
}
}
if (has_dip_state_changed) {
+#ifndef DIP_SWITCH_MAP_ENABLE
dip_switch_update_mask_kb(dip_switch_mask);
+#endif
memcpy(last_dip_switch_state, dip_switch_state, sizeof(dip_switch_state));
}
}
+
+void dip_switch_task(void) {
+ dip_switch_read(false);
+}
diff --git a/quantum/dip_switch.h b/quantum/dip_switch.h
index 6e79dcb0bf..7629859359 100644
--- a/quantum/dip_switch.h
+++ b/quantum/dip_switch.h
@@ -20,11 +20,36 @@
#include <stdbool.h>
#include <stdint.h>
+#include "gpio.h"
+#include "util.h"
+
+#if defined(DIP_SWITCH_PINS)
+# define NUM_DIP_SWITCHES ARRAY_SIZE(((pin_t[])DIP_SWITCH_PINS))
+#elif defined(DIP_SWITCH_MATRIX_GRID)
+typedef struct matrix_intersection_t {
+ uint8_t row;
+ uint8_t col;
+} matrix_intersection_t;
+# define NUM_DIP_SWITCHES ARRAY_SIZE(((matrix_intersection_t[])DIP_SWITCH_MATRIX_GRID))
+#endif
+
+#ifndef NUM_DIP_SWITCHES
+# define NUM_DIP_SWITCHES 0
+#endif
bool dip_switch_update_kb(uint8_t index, bool active);
bool dip_switch_update_user(uint8_t index, bool active);
bool dip_switch_update_mask_user(uint32_t state);
bool dip_switch_update_mask_kb(uint32_t state);
-void dip_switch_init(void);
void dip_switch_read(bool forced);
+
+void dip_switch_init(void);
+void dip_switch_task(void);
+
+#ifdef DIP_SWITCH_MAP_ENABLE
+# define NUM_DIP_STATES 2
+# define DIP_SWITCH_OFF_ON(off, on) \
+ { (off), (on) }
+extern const uint16_t dip_switch_map[NUM_DIP_SWITCHES][NUM_DIP_STATES];
+#endif // DIP_SWITCH_MAP_ENABLE
diff --git a/quantum/eeconfig.c b/quantum/eeconfig.c
index d9eea13758..2d2180b4b4 100644
--- a/quantum/eeconfig.c
+++ b/quantum/eeconfig.c
@@ -54,7 +54,7 @@ void eeconfig_init_quantum(void) {
// Enable oneshot and autocorrect by default: 0b0001 0100 0000 0000
eeprom_update_word(EECONFIG_KEYMAP, 0x1400);
eeprom_update_byte(EECONFIG_BACKLIGHT, 0);
- eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default
+ eeprom_update_byte(EECONFIG_AUDIO, 0);
eeprom_update_dword(EECONFIG_RGBLIGHT, 0);
eeprom_update_byte(EECONFIG_RGBLIGHT_EXTENDED, 0);
eeprom_update_byte(EECONFIG_UNUSED, 0);
diff --git a/quantum/encoder.c b/quantum/encoder.c
index 7ab194ed52..735eb1cd71 100644
--- a/quantum/encoder.c
+++ b/quantum/encoder.c
@@ -1,81 +1,110 @@
-/*
- * Copyright 2018 Jack Humbert <jack.humb@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// Copyright 2022-2023 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
-#include "encoder.h"
-#include "keyboard.h"
+#include <string.h>
#include "action.h"
-#include "keycodes.h"
+#include "encoder.h"
#include "wait.h"
-#ifdef SPLIT_KEYBOARD
-# include "split_util.h"
-#endif
-
-// for memcpy
-#include <string.h>
-
#ifndef ENCODER_MAP_KEY_DELAY
-# include "action.h"
# define ENCODER_MAP_KEY_DELAY TAP_CODE_DELAY
#endif
-#if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION)
-# define ENCODER_RESOLUTION 4
-#endif
+__attribute__((weak)) bool should_process_encoder(void) {
+ return is_keyboard_master();
+}
-#if !defined(ENCODERS_PAD_A) || !defined(ENCODERS_PAD_B)
-# error "No encoder pads defined by ENCODERS_PAD_A and ENCODERS_PAD_B"
-#endif
+static encoder_events_t encoder_events;
+
+void encoder_init(void) {
+ memset(&encoder_events, 0, sizeof(encoder_events));
+ encoder_driver_init();
+}
-extern volatile bool isLeftHand;
+static bool encoder_handle_queue(void) {
+ bool changed = false;
+ while (encoder_events.tail != encoder_events.head) {
+ encoder_event_t event = encoder_events.queue[encoder_events.tail];
+ encoder_events.tail = (encoder_events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
-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;
+#ifdef ENCODER_MAP_ENABLE
-#ifdef ENCODER_RESOLUTIONS
-static uint8_t encoder_resolutions[NUM_ENCODERS] = ENCODER_RESOLUTIONS;
-#endif
+ // The delays below cater for Windows and its wonderful requirements.
+ action_exec(event.clockwise ? MAKE_ENCODER_CW_EVENT(event.index, true) : MAKE_ENCODER_CCW_EVENT(event.index, true));
+# if ENCODER_MAP_KEY_DELAY > 0
+ wait_ms(ENCODER_MAP_KEY_DELAY);
+# endif // ENCODER_MAP_KEY_DELAY > 0
-#ifndef ENCODER_DIRECTION_FLIP
-# define ENCODER_CLOCKWISE true
-# define ENCODER_COUNTER_CLOCKWISE false
-#else
-# define ENCODER_CLOCKWISE false
-# define ENCODER_COUNTER_CLOCKWISE true
-#endif
-static int8_t encoder_LUT[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
+ action_exec(event.clockwise ? MAKE_ENCODER_CW_EVENT(event.index, false) : MAKE_ENCODER_CCW_EVENT(event.index, false));
+# if ENCODER_MAP_KEY_DELAY > 0
+ wait_ms(ENCODER_MAP_KEY_DELAY);
+# endif // ENCODER_MAP_KEY_DELAY > 0
+
+#else // ENCODER_MAP_ENABLE
+
+ encoder_update_kb(event.index, event.clockwise ? true : false);
+
+#endif // ENCODER_MAP_ENABLE
+
+ changed = true;
+ }
+ return changed;
+}
-static uint8_t encoder_state[NUM_ENCODERS] = {0};
-static int8_t encoder_pulses[NUM_ENCODERS] = {0};
+bool encoder_task(void) {
+ bool changed = false;
-// encoder counts
-static uint8_t thisCount;
#ifdef SPLIT_KEYBOARD
-// encoder offsets for each hand
-static uint8_t thisHand, thatHand;
-// encoder counts for each hand
-static uint8_t thatCount;
-#endif
+ // Attempt to process existing encoder events in case split handling has already enqueued events
+ if (should_process_encoder()) {
+ changed |= encoder_handle_queue();
+ }
+#endif // SPLIT_KEYBOARD
+
+ // Let the encoder driver produce events
+ encoder_driver_task();
+
+ // Process any events that were enqueued
+ if (should_process_encoder()) {
+ changed |= encoder_handle_queue();
+ }
+
+ return changed;
+}
+
+bool encoder_queue_event(uint8_t index, bool clockwise) {
+ // Drop out if we're full
+ if ((encoder_events.head + 1) % MAX_QUEUED_ENCODER_EVENTS == encoder_events.tail) {
+ return false;
+ }
+
+ // Append the event
+ encoder_event_t new_event = {.index = index, .clockwise = clockwise ? 1 : 0};
+ encoder_events.queue[encoder_events.head] = new_event;
+
+ // Increment the head index
+ encoder_events.head = (encoder_events.head + 1) % MAX_QUEUED_ENCODER_EVENTS;
+
+ return true;
+}
+
+void encoder_retrieve_events(encoder_events_t *events) {
+ memcpy(events, &encoder_events, sizeof(encoder_events));
+}
-static uint8_t encoder_value[NUM_ENCODERS] = {0};
+#ifdef SPLIT_KEYBOARD
+void encoder_set_tail_index(uint8_t tail_index) {
+ encoder_events.tail = tail_index;
+}
-__attribute__((weak)) void encoder_wait_pullup_charge(void) {
- wait_us(100);
+void encoder_handle_slave_events(encoder_events_t *events) {
+ while (events->tail != events->head) {
+ encoder_event_t event = events->queue[events->tail];
+ events->tail = (events->tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ encoder_queue_event(event.index, event.clockwise ? true : false);
+ }
}
+#endif // SPLIT_KEYBOARD
__attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) {
return true;
@@ -106,192 +135,3 @@ __attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) {
#endif // ENCODER_TESTS
return res;
}
-
-__attribute__((weak)) bool should_process_encoder(void) {
- return is_keyboard_master();
-}
-
-void encoder_init(void) {
-#ifdef SPLIT_KEYBOARD
- thisHand = isLeftHand ? 0 : NUM_ENCODERS_LEFT;
- thatHand = NUM_ENCODERS_LEFT - thisHand;
- thisCount = isLeftHand ? NUM_ENCODERS_LEFT : NUM_ENCODERS_RIGHT;
- thatCount = isLeftHand ? NUM_ENCODERS_RIGHT : NUM_ENCODERS_LEFT;
-#else // SPLIT_KEYBOARD
- thisCount = NUM_ENCODERS;
-#endif
-
-#ifdef ENCODER_TESTS
- // Annoying that we have to clear out values during initialisation here, but
- // because all the arrays are static locals, rerunning tests in the same
- // executable doesn't reset any of these. Kinda crappy having test-only code
- // here, but it's the simplest solution.
- memset(encoder_value, 0, sizeof(encoder_value));
- memset(encoder_state, 0, sizeof(encoder_state));
- memset(encoder_pulses, 0, sizeof(encoder_pulses));
- static const pin_t encoders_pad_a_left[] = ENCODERS_PAD_A;
- static const pin_t encoders_pad_b_left[] = ENCODERS_PAD_B;
- for (uint8_t i = 0; i < thisCount; i++) {
- encoders_pad_a[i] = encoders_pad_a_left[i];
- encoders_pad_b[i] = encoders_pad_b_left[i];
- }
-#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)
- static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS_RIGHT;
-# else // defined(ENCODER_RESOLUTIONS_RIGHT)
- static const uint8_t encoder_resolutions_right[NUM_ENCODERS_RIGHT] = ENCODER_RESOLUTIONS;
-# endif // defined(ENCODER_RESOLUTIONS_RIGHT)
- for (uint8_t i = 0; i < NUM_ENCODERS_RIGHT; i++) {
- encoder_resolutions[NUM_ENCODERS_LEFT + i] = encoder_resolutions_right[i];
- }
-#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);
- }
-}
-
-#ifdef ENCODER_MAP_ENABLE
-static void encoder_exec_mapping(uint8_t index, bool clockwise) {
- // The delays below cater for Windows and its wonderful requirements.
- action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, true) : MAKE_ENCODER_CCW_EVENT(index, true));
-# if ENCODER_MAP_KEY_DELAY > 0
- wait_ms(ENCODER_MAP_KEY_DELAY);
-# endif // ENCODER_MAP_KEY_DELAY > 0
-
- action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, false) : MAKE_ENCODER_CCW_EVENT(index, false));
-# if ENCODER_MAP_KEY_DELAY > 0
- wait_ms(ENCODER_MAP_KEY_DELAY);
-# endif // ENCODER_MAP_KEY_DELAY > 0
-}
-#endif // ENCODER_MAP_ENABLE
-
-static bool encoder_update(uint8_t index, uint8_t state) {
- bool changed = false;
- uint8_t i = index;
-
-#ifdef ENCODER_RESOLUTIONS
- const uint8_t resolution = encoder_resolutions[i];
-#else
- const uint8_t resolution = ENCODER_RESOLUTION;
-#endif
-
-#ifdef SPLIT_KEYBOARD
- index += thisHand;
-#endif
- encoder_pulses[i] += encoder_LUT[state & 0xF];
-
-#ifdef ENCODER_DEFAULT_POS
- if ((encoder_pulses[i] >= resolution) || (encoder_pulses[i] <= -resolution) || ((state & 0x3) == ENCODER_DEFAULT_POS)) {
- if (encoder_pulses[i] >= 1) {
-#else
- if (encoder_pulses[i] >= resolution) {
-#endif
-
- encoder_value[index]++;
- changed = true;
-#ifdef SPLIT_KEYBOARD
- if (should_process_encoder())
-#endif // SPLIT_KEYBOARD
-#ifdef ENCODER_MAP_ENABLE
- encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE);
-#else // ENCODER_MAP_ENABLE
- encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
-#endif // ENCODER_MAP_ENABLE
- }
-
-#ifdef ENCODER_DEFAULT_POS
- if (encoder_pulses[i] <= -1) {
-#else
- if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise
-#endif
- encoder_value[index]--;
- changed = true;
-#ifdef SPLIT_KEYBOARD
- if (should_process_encoder())
-#endif // SPLIT_KEYBOARD
-#ifdef ENCODER_MAP_ENABLE
- encoder_exec_mapping(index, ENCODER_CLOCKWISE);
-#else // ENCODER_MAP_ENABLE
- encoder_update_kb(index, ENCODER_CLOCKWISE);
-#endif // ENCODER_MAP_ENABLE
- }
- encoder_pulses[i] %= resolution;
-#ifdef ENCODER_DEFAULT_POS
- encoder_pulses[i] = 0;
- }
-#endif
- return changed;
-}
-
-bool encoder_read(void) {
- bool changed = false;
- for (uint8_t i = 0; i < thisCount; i++) {
- uint8_t new_status = (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1);
- if ((encoder_state[i] & 0x3) != new_status) {
- encoder_state[i] <<= 2;
- encoder_state[i] |= new_status;
- changed |= encoder_update(i, encoder_state[i]);
- }
- }
- return changed;
-}
-
-#ifdef SPLIT_KEYBOARD
-void last_encoder_activity_trigger(void);
-
-void encoder_state_raw(uint8_t *slave_state) {
- memcpy(slave_state, &encoder_value[thisHand], sizeof(uint8_t) * thisCount);
-}
-
-void encoder_update_raw(uint8_t *slave_state) {
- bool changed = false;
- for (uint8_t i = 0; i < thatCount; i++) { // Note inverted logic -- we want the opposite side
- const uint8_t index = i + thatHand;
- int8_t delta = slave_state[i] - encoder_value[index];
- while (delta > 0) {
- delta--;
- encoder_value[index]++;
- changed = true;
-# ifdef ENCODER_MAP_ENABLE
- encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE);
-# else // ENCODER_MAP_ENABLE
- encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
-# endif // ENCODER_MAP_ENABLE
- }
- while (delta < 0) {
- delta++;
- encoder_value[index]--;
- changed = true;
-# ifdef ENCODER_MAP_ENABLE
- encoder_exec_mapping(index, ENCODER_CLOCKWISE);
-# else // ENCODER_MAP_ENABLE
- encoder_update_kb(index, ENCODER_CLOCKWISE);
-# endif // ENCODER_MAP_ENABLE
- }
- }
-
- // Update the last encoder input time -- handled external to encoder_read() when we're running a split
- if (changed) last_encoder_activity_trigger();
-}
-#endif
diff --git a/quantum/encoder.h b/quantum/encoder.h
index 1cbac98cb5..90414a43a0 100644
--- a/quantum/encoder.h
+++ b/quantum/encoder.h
@@ -22,45 +22,88 @@
#include "gpio.h"
#include "util.h"
+#ifdef ENCODER_ENABLE
+
+__attribute__((weak)) bool should_process_encoder(void);
+
void encoder_init(void);
-bool encoder_read(void);
+bool encoder_task(void);
+bool encoder_queue_event(uint8_t index, bool clockwise);
bool encoder_update_kb(uint8_t index, bool clockwise);
bool encoder_update_user(uint8_t index, bool clockwise);
-#ifdef SPLIT_KEYBOARD
+# ifdef SPLIT_KEYBOARD
+
+# if defined(ENCODERS_PAD_A_RIGHT)
+# ifndef NUM_ENCODERS_LEFT
+# define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A))
+# endif
+# ifndef NUM_ENCODERS_RIGHT
+# define NUM_ENCODERS_RIGHT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A_RIGHT))
+# endif
+# else
+# ifndef NUM_ENCODERS_LEFT
+# define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A))
+# endif
+# ifndef NUM_ENCODERS_RIGHT
+# define NUM_ENCODERS_RIGHT NUM_ENCODERS_LEFT
+# endif
+# endif
+# ifndef NUM_ENCODERS
+# define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT)
+# endif
+
+# else // SPLIT_KEYBOARD
-void encoder_state_raw(uint8_t* slave_state);
-void encoder_update_raw(uint8_t* slave_state);
+# ifndef NUM_ENCODERS
+# define NUM_ENCODERS ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A))
+# endif
+# define NUM_ENCODERS_LEFT NUM_ENCODERS
+# define NUM_ENCODERS_RIGHT 0
-# if defined(ENCODERS_PAD_A_RIGHT)
-# define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A))
-# define NUM_ENCODERS_RIGHT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A_RIGHT))
-# else
-# define NUM_ENCODERS_LEFT ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A))
-# define NUM_ENCODERS_RIGHT NUM_ENCODERS_LEFT
-# endif
-# define NUM_ENCODERS (NUM_ENCODERS_LEFT + NUM_ENCODERS_RIGHT)
+# endif // SPLIT_KEYBOARD
-#else // SPLIT_KEYBOARD
+# ifndef NUM_ENCODERS
+# define NUM_ENCODERS 0
+# define NUM_ENCODERS_LEFT 0
+# define NUM_ENCODERS_RIGHT 0
+# endif // NUM_ENCODERS
-# define NUM_ENCODERS ARRAY_SIZE(((pin_t[])ENCODERS_PAD_A))
-# define NUM_ENCODERS_LEFT NUM_ENCODERS
-# define NUM_ENCODERS_RIGHT 0
+# define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT)
-#endif // SPLIT_KEYBOARD
+# ifndef MAX_QUEUED_ENCODER_EVENTS
+# define MAX_QUEUED_ENCODER_EVENTS MAX(4, ((NUM_ENCODERS_MAX_PER_SIDE) + 1))
+# endif // MAX_QUEUED_ENCODER_EVENTS
-#ifndef NUM_ENCODERS
-# define NUM_ENCODERS 0
-# define NUM_ENCODERS_LEFT 0
-# define NUM_ENCODERS_RIGHT 0
-#endif // NUM_ENCODERS
+typedef struct encoder_event_t {
+ uint8_t index : 7;
+ uint8_t clockwise : 1;
+} encoder_event_t;
-#define NUM_ENCODERS_MAX_PER_SIDE MAX(NUM_ENCODERS_LEFT, NUM_ENCODERS_RIGHT)
+typedef struct encoder_events_t {
+ uint8_t head;
+ uint8_t tail;
+ encoder_event_t queue[MAX_QUEUED_ENCODER_EVENTS];
+} encoder_events_t;
-#ifdef ENCODER_MAP_ENABLE
-# define NUM_DIRECTIONS 2
-# define ENCODER_CCW_CW(ccw, cw) \
- { (cw), (ccw) }
+// Get the current queued events
+void encoder_retrieve_events(encoder_events_t *events);
+
+# ifdef SPLIT_KEYBOARD
+void encoder_set_tail_index(uint8_t tail_index);
+void encoder_handle_slave_events(encoder_events_t *events);
+# endif // SPLIT_KEYBOARD
+
+# ifdef ENCODER_MAP_ENABLE
+# define NUM_DIRECTIONS 2
+# define ENCODER_CCW_CW(ccw, cw) \
+ { (cw), (ccw) }
extern const uint16_t encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS];
-#endif // ENCODER_MAP_ENABLE
+# endif // ENCODER_MAP_ENABLE
+
+// "Custom encoder lite" support
+void encoder_driver_init(void);
+void encoder_driver_task(void);
+
+#endif // ENCODER_ENABLE
diff --git a/quantum/encoder/tests/config_encoder_common.h b/quantum/encoder/tests/config_encoder_common.h
new file mode 100644
index 0000000000..6b3b20182b
--- /dev/null
+++ b/quantum/encoder/tests/config_encoder_common.h
@@ -0,0 +1,6 @@
+// Copyright 2023 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+// Override the one in quantum/util because it doesn't like working on x64 builds.
+#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0]))
diff --git a/quantum/encoder/tests/config_mock.h b/quantum/encoder/tests/config_mock.h
index 703dcaf103..9eb59ddc88 100644
--- a/quantum/encoder/tests/config_mock.h
+++ b/quantum/encoder/tests/config_mock.h
@@ -1,6 +1,7 @@
-// Copyright 2022 Nick Brassel (@tzarc)
+// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+#include "config_encoder_common.h"
#define MATRIX_ROWS 1
#define MATRIX_COLS 1
diff --git a/quantum/encoder/tests/config_mock_split_left_eq_right.h b/quantum/encoder/tests/config_mock_split_left_eq_right.h
index c80ac4d519..ea795657ef 100644
--- a/quantum/encoder/tests/config_mock_split_left_eq_right.h
+++ b/quantum/encoder/tests/config_mock_split_left_eq_right.h
@@ -1,6 +1,7 @@
-// Copyright 2022 Nick Brassel (@tzarc)
+// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+#include "config_encoder_common.h"
#define MATRIX_ROWS 1
#define MATRIX_COLS 1
diff --git a/quantum/encoder/tests/config_mock_split_left_gt_right.h b/quantum/encoder/tests/config_mock_split_left_gt_right.h
index 91d5f3d605..abcfe03918 100644
--- a/quantum/encoder/tests/config_mock_split_left_gt_right.h
+++ b/quantum/encoder/tests/config_mock_split_left_gt_right.h
@@ -1,6 +1,7 @@
-// Copyright 2022 Nick Brassel (@tzarc)
+// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+#include "config_encoder_common.h"
#define MATRIX_ROWS 1
#define MATRIX_COLS 1
diff --git a/quantum/encoder/tests/config_mock_split_left_lt_right.h b/quantum/encoder/tests/config_mock_split_left_lt_right.h
index 4108a184a6..075c774b0d 100644
--- a/quantum/encoder/tests/config_mock_split_left_lt_right.h
+++ b/quantum/encoder/tests/config_mock_split_left_lt_right.h
@@ -1,6 +1,7 @@
-// Copyright 2022 Nick Brassel (@tzarc)
+// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+#include "config_encoder_common.h"
#define MATRIX_ROWS 1
#define MATRIX_COLS 1
diff --git a/quantum/encoder/tests/config_mock_split_no_left.h b/quantum/encoder/tests/config_mock_split_no_left.h
index 9db7fa7e41..dfd8358929 100644
--- a/quantum/encoder/tests/config_mock_split_no_left.h
+++ b/quantum/encoder/tests/config_mock_split_no_left.h
@@ -1,6 +1,7 @@
-// Copyright 2022 Nick Brassel (@tzarc)
+// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+#include "config_encoder_common.h"
#define MATRIX_ROWS 1
#define MATRIX_COLS 1
diff --git a/quantum/encoder/tests/config_mock_split_no_right.h b/quantum/encoder/tests/config_mock_split_no_right.h
index 14f18015e6..5683eade8c 100644
--- a/quantum/encoder/tests/config_mock_split_no_right.h
+++ b/quantum/encoder/tests/config_mock_split_no_right.h
@@ -1,6 +1,7 @@
-// Copyright 2022 Nick Brassel (@tzarc)
+// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+#include "config_encoder_common.h"
#define MATRIX_ROWS 1
#define MATRIX_COLS 1
diff --git a/quantum/encoder/tests/config_mock_split_role.h b/quantum/encoder/tests/config_mock_split_role.h
index c80ac4d519..ea795657ef 100644
--- a/quantum/encoder/tests/config_mock_split_role.h
+++ b/quantum/encoder/tests/config_mock_split_role.h
@@ -1,6 +1,7 @@
-// Copyright 2022 Nick Brassel (@tzarc)
+// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+#include "config_encoder_common.h"
#define MATRIX_ROWS 1
#define MATRIX_COLS 1
diff --git a/quantum/encoder/tests/encoder_tests.cpp b/quantum/encoder/tests/encoder_tests.cpp
index b7c18aeec0..499e413aed 100644
--- a/quantum/encoder/tests/encoder_tests.cpp
+++ b/quantum/encoder/tests/encoder_tests.cpp
@@ -41,7 +41,7 @@ bool encoder_update_kb(uint8_t index, bool clockwise) {
bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
- return encoder_read();
+ return encoder_task();
}
class EncoderTest : public ::testing::Test {};
diff --git a/quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp b/quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp
index 916e47b185..7d6b3e30e6 100644
--- a/quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp
+++ b/quantum/encoder/tests/encoder_tests_split_left_eq_right.cpp
@@ -33,22 +33,29 @@ struct update {
uint8_t updates_array_idx = 0;
update updates[32];
+bool isMaster;
bool isLeftHand;
+extern "C" {
+bool is_keyboard_master(void) {
+ return isMaster;
+}
+
bool encoder_update_kb(uint8_t index, bool clockwise) {
- if (!isLeftHand) {
+ if (!is_keyboard_master()) {
// this method has no effect on slave half
- printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
+ printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC");
return true;
}
updates[updates_array_idx % 32] = {index, clockwise};
updates_array_idx++;
return true;
}
+};
bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
- return encoder_read();
+ return encoder_task();
}
class EncoderSplitTestLeftEqRight : public ::testing::Test {
@@ -63,6 +70,7 @@ class EncoderSplitTestLeftEqRight : public ::testing::Test {
};
TEST_F(EncoderSplitTestLeftEqRight, TestInitLeft) {
+ isMaster = true;
isLeftHand = true;
encoder_init();
EXPECT_EQ(pinIsInputHigh[0], true);
@@ -77,6 +85,7 @@ TEST_F(EncoderSplitTestLeftEqRight, TestInitLeft) {
}
TEST_F(EncoderSplitTestLeftEqRight, TestInitRight) {
+ isMaster = true;
isLeftHand = false;
encoder_init();
EXPECT_EQ(pinIsInputHigh[0], false);
@@ -90,7 +99,8 @@ TEST_F(EncoderSplitTestLeftEqRight, TestInitRight) {
EXPECT_EQ(updates_array_idx, 0); // no updates received
}
-TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeft) {
+TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeftMaster) {
+ isMaster = true;
isLeftHand = true;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
@@ -102,9 +112,19 @@ TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeft) {
EXPECT_EQ(updates_array_idx, 1); // one update received
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
+
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightSent) {
+TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightMaster) {
+ isMaster = true;
isLeftHand = false;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
@@ -113,23 +133,60 @@ TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightSent) {
setAndRead(6, true);
setAndRead(7, true);
- uint8_t slave_state[32] = {0};
- encoder_state_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 1); // one update received
+ EXPECT_EQ(updates[0].index, 3);
+ EXPECT_EQ(updates[0].clockwise, true);
- EXPECT_EQ(slave_state[0], 0);
- EXPECT_EQ(slave_state[1], 0xFF);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestLeftEqRight, TestMultipleEncodersRightReceived) {
+TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseLeftSlave) {
+ isMaster = false;
isLeftHand = true;
encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(0, false);
+ setAndRead(1, false);
+ setAndRead(0, true);
+ setAndRead(1, true);
- uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder CW
- encoder_update_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
- EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
- EXPECT_EQ(updates[0].index, 2);
- EXPECT_EQ(updates[0].clockwise, false);
- EXPECT_EQ(updates[1].index, 3);
- EXPECT_EQ(updates[1].clockwise, true);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
+}
+
+TEST_F(EncoderSplitTestLeftEqRight, TestOneClockwiseRightSlave) {
+ isMaster = false;
+ isLeftHand = false;
+ encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(6, false);
+ setAndRead(7, false);
+ setAndRead(6, true);
+ setAndRead(7, true);
+
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
+
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
}
diff --git a/quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp b/quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp
index 7b64bb2981..2beb4e3972 100644
--- a/quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp
+++ b/quantum/encoder/tests/encoder_tests_split_left_gt_right.cpp
@@ -33,22 +33,29 @@ struct update {
uint8_t updates_array_idx = 0;
update updates[32];
+bool isMaster;
bool isLeftHand;
+extern "C" {
+bool is_keyboard_master(void) {
+ return isMaster;
+}
+
bool encoder_update_kb(uint8_t index, bool clockwise) {
- if (!isLeftHand) {
+ if (!is_keyboard_master()) {
// this method has no effect on slave half
- printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
+ printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC");
return true;
}
updates[updates_array_idx % 32] = {index, clockwise};
updates_array_idx++;
return true;
}
+};
bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
- return encoder_read();
+ return encoder_task();
}
class EncoderSplitTestLeftGreaterThanRight : public ::testing::Test {
@@ -94,7 +101,8 @@ TEST_F(EncoderSplitTestLeftGreaterThanRight, TestInitRight) {
EXPECT_EQ(updates_array_idx, 0); // no updates received
}
-TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeft) {
+TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeftMaster) {
+ isMaster = true;
isLeftHand = true;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
@@ -106,9 +114,19 @@ TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeft) {
EXPECT_EQ(updates_array_idx, 1); // one update received
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
+
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightSent) {
+TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightMaster) {
+ isMaster = true;
isLeftHand = false;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
@@ -117,23 +135,60 @@ TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightSent) {
setAndRead(6, true);
setAndRead(7, true);
- uint8_t slave_state[32] = {0};
- encoder_state_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 1); // one update received
+ EXPECT_EQ(updates[0].index, 3);
+ EXPECT_EQ(updates[0].clockwise, true);
- EXPECT_EQ(slave_state[0], 0xFF);
- EXPECT_EQ(slave_state[1], 0);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestLeftGreaterThanRight, TestMultipleEncodersRightReceived) {
+TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseLeftSlave) {
+ isMaster = false;
isLeftHand = true;
encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(0, false);
+ setAndRead(1, false);
+ setAndRead(0, true);
+ setAndRead(1, true);
- uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW
- encoder_update_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
- EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
- EXPECT_EQ(updates[0].index, 3);
- EXPECT_EQ(updates[0].clockwise, false);
- EXPECT_EQ(updates[1].index, 4);
- EXPECT_EQ(updates[1].clockwise, true);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
+}
+
+TEST_F(EncoderSplitTestLeftGreaterThanRight, TestOneClockwiseRightSlave) {
+ isMaster = false;
+ isLeftHand = false;
+ encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(6, false);
+ setAndRead(7, false);
+ setAndRead(6, true);
+ setAndRead(7, true);
+
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
+
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
}
diff --git a/quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp b/quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp
index a6519c5762..5612f8b658 100644
--- a/quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp
+++ b/quantum/encoder/tests/encoder_tests_split_left_lt_right.cpp
@@ -33,22 +33,29 @@ struct update {
uint8_t updates_array_idx = 0;
update updates[32];
+bool isMaster;
bool isLeftHand;
+extern "C" {
+bool is_keyboard_master(void) {
+ return isMaster;
+}
+
bool encoder_update_kb(uint8_t index, bool clockwise) {
- if (!isLeftHand) {
+ if (!is_keyboard_master()) {
// this method has no effect on slave half
- printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
+ printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC");
return true;
}
updates[updates_array_idx % 32] = {index, clockwise};
updates_array_idx++;
return true;
}
+};
bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
- return encoder_read();
+ return encoder_task();
}
class EncoderSplitTestLeftLessThanRight : public ::testing::Test {
@@ -94,7 +101,8 @@ TEST_F(EncoderSplitTestLeftLessThanRight, TestInitRight) {
EXPECT_EQ(updates_array_idx, 0); // no updates received
}
-TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeft) {
+TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeftMaster) {
+ isMaster = true;
isLeftHand = true;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
@@ -106,9 +114,19 @@ TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeft) {
EXPECT_EQ(updates_array_idx, 1); // one update received
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
+
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightSent) {
+TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightMaster) {
+ isMaster = true;
isLeftHand = false;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
@@ -117,23 +135,60 @@ TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightSent) {
setAndRead(6, true);
setAndRead(7, true);
- uint8_t slave_state[32] = {0};
- encoder_state_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 1); // one update received
+ EXPECT_EQ(updates[0].index, 3);
+ EXPECT_EQ(updates[0].clockwise, true);
- EXPECT_EQ(slave_state[0], 0);
- EXPECT_EQ(slave_state[1], 0xFF);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestLeftLessThanRight, TestMultipleEncodersRightReceived) {
+TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseLeftSlave) {
+ isMaster = false;
isLeftHand = true;
encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(0, false);
+ setAndRead(1, false);
+ setAndRead(0, true);
+ setAndRead(1, true);
- uint8_t slave_state[32] = {1, 0, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW
- encoder_update_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
- EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
- EXPECT_EQ(updates[0].index, 2);
- EXPECT_EQ(updates[0].clockwise, false);
- EXPECT_EQ(updates[1].index, 4);
- EXPECT_EQ(updates[1].clockwise, true);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
+}
+
+TEST_F(EncoderSplitTestLeftLessThanRight, TestOneClockwiseRightSlave) {
+ isMaster = false;
+ isLeftHand = false;
+ encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(6, false);
+ setAndRead(7, false);
+ setAndRead(6, true);
+ setAndRead(7, true);
+
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
+
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
}
diff --git a/quantum/encoder/tests/encoder_tests_split_no_left.cpp b/quantum/encoder/tests/encoder_tests_split_no_left.cpp
index b6b2d7e2d1..980e4074ff 100644
--- a/quantum/encoder/tests/encoder_tests_split_no_left.cpp
+++ b/quantum/encoder/tests/encoder_tests_split_no_left.cpp
@@ -33,22 +33,29 @@ struct update {
uint8_t updates_array_idx = 0;
update updates[32];
+bool isMaster;
bool isLeftHand;
+extern "C" {
+bool is_keyboard_master(void) {
+ return isMaster;
+}
+
bool encoder_update_kb(uint8_t index, bool clockwise) {
- if (!isLeftHand) {
+ if (!is_keyboard_master()) {
// this method has no effect on slave half
- printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
+ printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC");
return true;
}
updates[updates_array_idx % 32] = {index, clockwise};
updates_array_idx++;
return true;
}
+};
bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
- return encoder_read();
+ return encoder_task();
}
class EncoderSplitTestNoLeft : public ::testing::Test {
@@ -82,19 +89,8 @@ TEST_F(EncoderSplitTestNoLeft, TestInitRight) {
EXPECT_EQ(updates_array_idx, 0); // no updates received
}
-TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseLeft) {
- isLeftHand = true;
- encoder_init();
- // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
- setAndRead(0, false);
- setAndRead(1, false);
- setAndRead(0, true);
- setAndRead(1, true);
-
- EXPECT_EQ(updates_array_idx, 0); // no updates received
-}
-
-TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseRightSent) {
+TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseLeftMaster) {
+ isMaster = true;
isLeftHand = false;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
@@ -103,23 +99,38 @@ TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseRightSent) {
setAndRead(2, true);
setAndRead(3, true);
- uint8_t slave_state[32] = {0};
- encoder_state_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 1); // one update received
+ EXPECT_EQ(updates[0].index, 1);
+ EXPECT_EQ(updates[0].clockwise, true);
- EXPECT_EQ(slave_state[0], 0);
- EXPECT_EQ(slave_state[1], 0xFF);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestNoLeft, TestMultipleEncodersRightReceived) {
- isLeftHand = true;
+TEST_F(EncoderSplitTestNoLeft, TestOneClockwiseRightSlave) {
+ isMaster = false;
+ isLeftHand = false;
encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(2, false);
+ setAndRead(3, false);
+ setAndRead(2, true);
+ setAndRead(3, true);
- uint8_t slave_state[32] = {1, 0xFF}; // First right encoder is CCW, Second right encoder no change, third right encoder CW
- encoder_update_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
- EXPECT_EQ(updates_array_idx, 2); // two updates received, one for each changed item on the right side
- EXPECT_EQ(updates[0].index, 0);
- EXPECT_EQ(updates[0].clockwise, false);
- EXPECT_EQ(updates[1].index, 1);
- EXPECT_EQ(updates[1].clockwise, true);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
}
diff --git a/quantum/encoder/tests/encoder_tests_split_no_right.cpp b/quantum/encoder/tests/encoder_tests_split_no_right.cpp
index fa0a7c18a8..d39659853b 100644
--- a/quantum/encoder/tests/encoder_tests_split_no_right.cpp
+++ b/quantum/encoder/tests/encoder_tests_split_no_right.cpp
@@ -33,22 +33,29 @@ struct update {
uint8_t updates_array_idx = 0;
update updates[32];
+bool isMaster;
bool isLeftHand;
+extern "C" {
+bool is_keyboard_master(void) {
+ return isMaster;
+}
+
bool encoder_update_kb(uint8_t index, bool clockwise) {
- if (!isLeftHand) {
+ if (!is_keyboard_master()) {
// this method has no effect on slave half
- printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
+ printf("ignoring update on slave (%d,%s)\n", index, clockwise ? "CW" : "CC");
return true;
}
updates[updates_array_idx % 32] = {index, clockwise};
updates_array_idx++;
return true;
}
+};
bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
- return encoder_read();
+ return encoder_task();
}
class EncoderSplitTestNoRight : public ::testing::Test {
@@ -82,37 +89,48 @@ TEST_F(EncoderSplitTestNoRight, TestInitRight) {
EXPECT_EQ(updates_array_idx, 0); // no updates received
}
-TEST_F(EncoderSplitTestNoRight, TestOneClockwiseLeft) {
+TEST_F(EncoderSplitTestNoRight, TestOneClockwiseLeftMaster) {
+ isMaster = true;
isLeftHand = true;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
- setAndRead(0, false);
- setAndRead(1, false);
- setAndRead(0, true);
- setAndRead(1, true);
+ setAndRead(2, false);
+ setAndRead(3, false);
+ setAndRead(2, true);
+ setAndRead(3, true);
- EXPECT_EQ(updates_array_idx, 1); // one updates received
- EXPECT_EQ(updates[0].index, 0);
+ EXPECT_EQ(updates_array_idx, 1); // one update received
+ EXPECT_EQ(updates[0].index, 1);
EXPECT_EQ(updates[0].clockwise, true);
-}
-TEST_F(EncoderSplitTestNoRight, TestOneClockwiseRightSent) {
- isLeftHand = false;
- encoder_init();
-
- uint8_t slave_state[32] = {0xAA, 0xAA};
- encoder_state_raw(slave_state);
-
- EXPECT_EQ(slave_state[0], 0xAA);
- EXPECT_EQ(slave_state[1], 0xAA);
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 0); // No events should be queued on master
}
-TEST_F(EncoderSplitTestNoRight, TestMultipleEncodersRightReceived) {
+TEST_F(EncoderSplitTestNoRight, TestOneClockwiseRightSlave) {
+ isMaster = false;
isLeftHand = true;
encoder_init();
+ // send 4 pulses. with resolution 4, that's one step and we should get 1 update.
+ setAndRead(2, false);
+ setAndRead(3, false);
+ setAndRead(2, true);
+ setAndRead(3, true);
- uint8_t slave_state[32] = {1, 0xFF}; // These values would trigger updates if there were encoders on the other side
- encoder_update_raw(slave_state);
+ EXPECT_EQ(updates_array_idx, 0); // no updates received
- EXPECT_EQ(updates_array_idx, 0); // no updates received -- no right-hand encoders
+ int events_queued = 0;
+ encoder_events_t events;
+ encoder_retrieve_events(&events);
+ while (events.tail != events.head) {
+ events.tail = (events.tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
+ ++events_queued;
+ }
+ EXPECT_EQ(events_queued, 1); // One event should be queued on slave
}
diff --git a/quantum/encoder/tests/encoder_tests_split_role.cpp b/quantum/encoder/tests/encoder_tests_split_role.cpp
index 0ab7bfc2a7..b588af8c70 100644
--- a/quantum/encoder/tests/encoder_tests_split_role.cpp
+++ b/quantum/encoder/tests/encoder_tests_split_role.cpp
@@ -50,7 +50,7 @@ bool encoder_update_kb(uint8_t index, bool clockwise) {
bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
- return encoder_read();
+ return encoder_task();
}
class EncoderSplitTestRole : public ::testing::Test {
@@ -87,9 +87,6 @@ TEST_F(EncoderSplitTestRole, TestPrimaryRight) {
setAndRead(6, true);
setAndRead(7, true);
- uint8_t slave_state[32] = {0};
- encoder_state_raw(slave_state);
-
EXPECT_EQ(num_updates, 1); // one update received
}
@@ -116,8 +113,5 @@ TEST_F(EncoderSplitTestRole, TestNotPrimaryRight) {
setAndRead(6, true);
setAndRead(7, true);
- uint8_t slave_state[32] = {0};
- encoder_state_raw(slave_state);
-
EXPECT_EQ(num_updates, 0); // zero updates received
}
diff --git a/quantum/encoder/tests/mock.c b/quantum/encoder/tests/mock.c
index 61f2f8294d..1524e61ca4 100644
--- a/quantum/encoder/tests/mock.c
+++ b/quantum/encoder/tests/mock.c
@@ -19,14 +19,14 @@
bool pins[32] = {0};
bool pinIsInputHigh[32] = {0};
-uint8_t mockSetPinInputHigh(pin_t pin) {
+uint8_t mock_set_pin_input_high(pin_t pin) {
// dprintf("Setting pin %d input high.", pin);
pins[pin] = true;
pinIsInputHigh[pin] = true;
return 0;
}
-bool mockReadPin(pin_t pin) {
+bool mock_read_pin(pin_t pin) {
return pins[pin];
}
diff --git a/quantum/encoder/tests/mock.h b/quantum/encoder/tests/mock.h
index 80c336b5ef..28774b82ab 100644
--- a/quantum/encoder/tests/mock.h
+++ b/quantum/encoder/tests/mock.h
@@ -24,11 +24,11 @@ typedef uint8_t pin_t;
extern bool pins[];
extern bool pinIsInputHigh[];
-#define setPinInputHigh(pin) (mockSetPinInputHigh(pin))
-#define readPin(pin) (mockReadPin(pin))
+#define gpio_set_pin_input_high(pin) (mock_set_pin_input_high(pin))
+#define gpio_read_pin(pin) (mock_read_pin(pin))
-uint8_t mockSetPinInputHigh(pin_t pin);
+uint8_t mock_set_pin_input_high(pin_t pin);
-bool mockReadPin(pin_t pin);
+bool mock_read_pin(pin_t pin);
bool setPin(pin_t pin, bool val);
diff --git a/quantum/encoder/tests/mock_split.c b/quantum/encoder/tests/mock_split.c
index 5cc6cd19e1..fb5f074fbb 100644
--- a/quantum/encoder/tests/mock_split.c
+++ b/quantum/encoder/tests/mock_split.c
@@ -19,14 +19,14 @@
bool pins[32] = {0};
bool pinIsInputHigh[32] = {0};
-uint8_t mockSetPinInputHigh(pin_t pin) {
+uint8_t mock_set_pin_input_high(pin_t pin) {
// dprintf("Setting pin %d input high.", pin);
pins[pin] = true;
pinIsInputHigh[pin] = true;
return 0;
}
-bool mockReadPin(pin_t pin) {
+bool mock_read_pin(pin_t pin) {
return pins[pin];
}
@@ -36,7 +36,3 @@ bool setPin(pin_t pin, bool val) {
}
void last_encoder_activity_trigger(void) {}
-
-__attribute__((weak)) bool is_keyboard_master(void) {
- return true;
-}
diff --git a/quantum/encoder/tests/mock_split.h b/quantum/encoder/tests/mock_split.h
index 2fc12f1830..0d108afa6e 100644
--- a/quantum/encoder/tests/mock_split.h
+++ b/quantum/encoder/tests/mock_split.h
@@ -22,17 +22,14 @@
#define SPLIT_KEYBOARD
typedef uint8_t pin_t;
-void encoder_state_raw(uint8_t* slave_state);
-void encoder_update_raw(uint8_t* slave_state);
-
extern bool pins[];
extern bool pinIsInputHigh[];
-#define setPinInputHigh(pin) (mockSetPinInputHigh(pin))
-#define readPin(pin) (mockReadPin(pin))
+#define gpio_set_pin_input_high(pin) (mock_set_pin_input_high(pin))
+#define gpio_read_pin(pin) (mock_read_pin(pin))
-uint8_t mockSetPinInputHigh(pin_t pin);
+uint8_t mock_set_pin_input_high(pin_t pin);
-bool mockReadPin(pin_t pin);
+bool mock_read_pin(pin_t pin);
bool setPin(pin_t pin, bool val);
diff --git a/quantum/encoder/tests/rules.mk b/quantum/encoder/tests/rules.mk
index d01c1c66ee..eb6106039e 100644
--- a/quantum/encoder/tests/rules.mk
+++ b/quantum/encoder/tests/rules.mk
@@ -3,6 +3,7 @@ encoder_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock.h
encoder_SRC := \
platforms/test/timer.c \
+ drivers/encoder/encoder_quadrature.c \
$(QUANTUM_PATH)/encoder/tests/mock.c \
$(QUANTUM_PATH)/encoder/tests/encoder_tests.cpp \
$(QUANTUM_PATH)/encoder.c
@@ -13,6 +14,7 @@ encoder_split_left_eq_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_
encoder_split_left_eq_right_SRC := \
platforms/test/timer.c \
+ drivers/encoder/encoder_quadrature.c \
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_eq_right.cpp \
$(QUANTUM_PATH)/encoder.c
@@ -23,6 +25,7 @@ encoder_split_left_gt_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_
encoder_split_left_gt_right_SRC := \
platforms/test/timer.c \
+ drivers/encoder/encoder_quadrature.c \
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_gt_right.cpp \
$(QUANTUM_PATH)/encoder.c
@@ -33,6 +36,7 @@ encoder_split_left_lt_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_
encoder_split_left_lt_right_SRC := \
platforms/test/timer.c \
+ drivers/encoder/encoder_quadrature.c \
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_left_lt_right.cpp \
$(QUANTUM_PATH)/encoder.c
@@ -43,6 +47,7 @@ encoder_split_no_left_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split_
encoder_split_no_left_SRC := \
platforms/test/timer.c \
+ drivers/encoder/encoder_quadrature.c \
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_no_left.cpp \
$(QUANTUM_PATH)/encoder.c
@@ -53,6 +58,7 @@ encoder_split_no_right_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split
encoder_split_no_right_SRC := \
platforms/test/timer.c \
+ drivers/encoder/encoder_quadrature.c \
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_no_right.cpp \
$(QUANTUM_PATH)/encoder.c
@@ -63,6 +69,7 @@ encoder_split_role_CONFIG := $(QUANTUM_PATH)/encoder/tests/config_mock_split_rol
encoder_split_role_SRC := \
platforms/test/timer.c \
+ drivers/encoder/encoder_quadrature.c \
$(QUANTUM_PATH)/encoder/tests/mock_split.c \
$(QUANTUM_PATH)/encoder/tests/encoder_tests_split_role.cpp \
$(QUANTUM_PATH)/encoder.c
diff --git a/quantum/haptic.c b/quantum/haptic.c
index a1fea29625..6a466293a7 100644
--- a/quantum/haptic.c
+++ b/quantum/haptic.c
@@ -96,10 +96,10 @@ void haptic_init(void) {
#endif
eeconfig_debug_haptic();
#ifdef HAPTIC_ENABLE_PIN
- setPinOutput(HAPTIC_ENABLE_PIN);
+ gpio_set_pin_output(HAPTIC_ENABLE_PIN);
#endif
#ifdef HAPTIC_ENABLE_STATUS_LED
- setPinOutput(HAPTIC_ENABLE_STATUS_LED);
+ gpio_set_pin_output(HAPTIC_ENABLE_STATUS_LED);
#endif
}
@@ -356,9 +356,9 @@ void haptic_shutdown(void) {
void haptic_notify_usb_device_state_change(void) {
update_haptic_enable_gpios();
#if defined(HAPTIC_ENABLE_PIN)
- setPinOutput(HAPTIC_ENABLE_PIN);
+ gpio_set_pin_output(HAPTIC_ENABLE_PIN);
#endif
#if defined(HAPTIC_ENABLE_STATUS_LED)
- setPinOutput(HAPTIC_ENABLE_STATUS_LED);
+ gpio_set_pin_output(HAPTIC_ENABLE_STATUS_LED);
#endif
}
diff --git a/quantum/haptic.h b/quantum/haptic.h
index 5bd1a71916..b283d5d268 100644
--- a/quantum/haptic.h
+++ b/quantum/haptic.h
@@ -84,22 +84,22 @@ void haptic_notify_usb_device_state_change(void);
# ifndef HAPTIC_ENABLE_PIN
# error HAPTIC_ENABLE_PIN not defined
# endif
-# define HAPTIC_ENABLE_PIN_WRITE_ACTIVE() writePinLow(HAPTIC_ENABLE_PIN)
-# define HAPTIC_ENABLE_PIN_WRITE_INACTIVE() writePinHigh(HAPTIC_ENABLE_PIN)
+# define HAPTIC_ENABLE_PIN_WRITE_ACTIVE() gpio_write_pin_low(HAPTIC_ENABLE_PIN)
+# define HAPTIC_ENABLE_PIN_WRITE_INACTIVE() gpio_write_pin_high(HAPTIC_ENABLE_PIN)
#else
-# define HAPTIC_ENABLE_PIN_WRITE_ACTIVE() writePinHigh(HAPTIC_ENABLE_PIN)
-# define HAPTIC_ENABLE_PIN_WRITE_INACTIVE() writePinLow(HAPTIC_ENABLE_PIN)
+# define HAPTIC_ENABLE_PIN_WRITE_ACTIVE() gpio_write_pin_high(HAPTIC_ENABLE_PIN)
+# define HAPTIC_ENABLE_PIN_WRITE_INACTIVE() gpio_write_pin_low(HAPTIC_ENABLE_PIN)
#endif
#ifdef HAPTIC_ENABLE_STATUS_LED_ACTIVE_LOW
# ifndef HAPTIC_ENABLE_STATUS_LED
# error HAPTIC_ENABLE_STATUS_LED not defined
# endif
-# define HAPTIC_ENABLE_STATUS_LED_WRITE_ACTIVE() writePinLow(HAPTIC_ENABLE_STATUS_LED)
-# define HAPTIC_ENABLE_STATUS_LED_WRITE_INACTIVE() writePinHigh(HAPTIC_ENABLE_STATUS_LED)
+# define HAPTIC_ENABLE_STATUS_LED_WRITE_ACTIVE() gpio_write_pin_low(HAPTIC_ENABLE_STATUS_LED)
+# define HAPTIC_ENABLE_STATUS_LED_WRITE_INACTIVE() gpio_write_pin_high(HAPTIC_ENABLE_STATUS_LED)
#else
-# define HAPTIC_ENABLE_STATUS_LED_WRITE_ACTIVE() writePinHigh(HAPTIC_ENABLE_STATUS_LED)
-# define HAPTIC_ENABLE_STATUS_LED_WRITE_INACTIVE() writePinLow(HAPTIC_ENABLE_STATUS_LED)
+# define HAPTIC_ENABLE_STATUS_LED_WRITE_ACTIVE() gpio_write_pin_high(HAPTIC_ENABLE_STATUS_LED)
+# define HAPTIC_ENABLE_STATUS_LED_WRITE_INACTIVE() gpio_write_pin_low(HAPTIC_ENABLE_STATUS_LED)
#endif
#ifndef HAPTIC_OFF_IN_LOW_POWER
diff --git a/quantum/joystick.c b/quantum/joystick.c
index 02818e4acd..32f19b2cd9 100644
--- a/quantum/joystick.c
+++ b/quantum/joystick.c
@@ -15,10 +15,12 @@
*/
#include "joystick.h"
-
-#include "analog.h"
#include "wait.h"
+#if defined(JOYSTICK_ANALOG)
+# include "analog.h"
+#endif
+
joystick_t joystick_state = {
.buttons = {0},
.axes =
@@ -31,21 +33,47 @@ joystick_t joystick_state = {
};
// array defining the reading of analog values for each axis
-__attribute__((weak)) joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {};
+__attribute__((weak)) joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {
+#if JOYSTICK_AXIS_COUNT > 0
+ [0 ...(JOYSTICK_AXIS_COUNT - 1)] = JOYSTICK_AXIS_VIRTUAL
+#endif
+};
-__attribute__((weak)) void joystick_task(void) {
- joystick_read_axes();
+__attribute__((weak)) void joystick_axis_init(uint8_t axis) {
+ if (axis >= JOYSTICK_AXIS_COUNT) return;
+
+#if defined(JOYSTICK_ANALOG)
+ gpio_set_pin_input(joystick_axes[axis].input_pin);
+#endif
+}
+
+__attribute__((weak)) uint16_t joystick_axis_sample(uint8_t axis) {
+ if (axis >= JOYSTICK_AXIS_COUNT) return 0;
+
+#if defined(JOYSTICK_ANALOG)
+ return analogReadPin(joystick_axes[axis].input_pin);
+#else
+ // default to resting position
+ return joystick_axes[axis].mid_digit;
+#endif
+}
+
+static inline bool is_virtual_axis(uint8_t axis) {
+ return joystick_axes[axis].input_pin == NO_PIN;
}
void joystick_flush(void) {
- if (joystick_state.dirty) {
- host_joystick_send(&joystick_state);
- joystick_state.dirty = false;
- }
+ if (!joystick_state.dirty) return;
+
+ // TODO: host.h?
+ void host_joystick_send(joystick_t * joystick);
+ host_joystick_send(&joystick_state);
+ joystick_state.dirty = false;
}
void register_joystick_button(uint8_t button) {
if (button >= JOYSTICK_BUTTON_COUNT) return;
+
joystick_state.buttons[button / 8] |= 1 << (button % 8);
joystick_state.dirty = true;
joystick_flush();
@@ -53,6 +81,7 @@ void register_joystick_button(uint8_t button) {
void unregister_joystick_button(uint8_t button) {
if (button >= JOYSTICK_BUTTON_COUNT) return;
+
joystick_state.buttons[button / 8] &= ~(1 << (button % 8));
joystick_state.dirty = true;
joystick_flush();
@@ -61,37 +90,7 @@ void unregister_joystick_button(uint8_t button) {
int16_t joystick_read_axis(uint8_t axis) {
if (axis >= JOYSTICK_AXIS_COUNT) return 0;
- // disable pull-up resistor
- writePinLow(joystick_axes[axis].input_pin);
-
- // if pin was a pull-up input, we need to uncharge it by turning it low
- // before making it a low input
- setPinOutput(joystick_axes[axis].input_pin);
-
- wait_us(10);
-
- if (joystick_axes[axis].output_pin != JS_VIRTUAL_AXIS) {
- setPinOutput(joystick_axes[axis].output_pin);
- writePinHigh(joystick_axes[axis].output_pin);
- }
-
- if (joystick_axes[axis].ground_pin != JS_VIRTUAL_AXIS) {
- setPinOutput(joystick_axes[axis].ground_pin);
- writePinLow(joystick_axes[axis].ground_pin);
- }
-
- wait_us(10);
-
- setPinInput(joystick_axes[axis].input_pin);
-
- wait_us(10);
-
-#if defined(ANALOG_JOYSTICK_ENABLE) && (defined(__AVR__) || defined(PROTOCOL_CHIBIOS))
- int16_t axis_val = analogReadPin(joystick_axes[axis].input_pin);
-#else
- // default to resting position
- int16_t axis_val = joystick_axes[axis].mid_digit;
-#endif
+ int16_t axis_val = joystick_axis_sample(axis);
// test the converted value against the lower range
int32_t ref = joystick_axes[axis].mid_digit;
@@ -111,10 +110,22 @@ int16_t joystick_read_axis(uint8_t axis) {
return ranged_val;
}
+void joystick_init_axes(void) {
+#if JOYSTICK_AXIS_COUNT > 0
+ for (int i = 0; i < JOYSTICK_AXIS_COUNT; ++i) {
+ if (is_virtual_axis(i)) {
+ continue;
+ }
+
+ joystick_axis_init(i);
+ }
+#endif
+}
+
void joystick_read_axes(void) {
#if JOYSTICK_AXIS_COUNT > 0
for (int i = 0; i < JOYSTICK_AXIS_COUNT; ++i) {
- if (joystick_axes[i].input_pin == JS_VIRTUAL_AXIS) {
+ if (is_virtual_axis(i)) {
continue;
}
@@ -133,3 +144,11 @@ void joystick_set_axis(uint8_t axis, int16_t value) {
joystick_state.dirty = true;
}
}
+
+void joystick_init(void) {
+ joystick_init_axes();
+}
+
+void joystick_task(void) {
+ joystick_read_axes();
+}
diff --git a/quantum/joystick.h b/quantum/joystick.h
index 5de4ba66c6..5a69ceac64 100644
--- a/quantum/joystick.h
+++ b/quantum/joystick.h
@@ -52,24 +52,15 @@
#define JOYSTICK_MAX_VALUE ((1L << (JOYSTICK_AXIS_RESOLUTION - 1)) - 1)
-// configure on input_pin of the joystick_axes array entry to JS_VIRTUAL_AXIS
-// to prevent it from being read from the ADC. This allows outputing forged axis value.
-//
-#define JS_VIRTUAL_AXIS 0xFF
-
+// configure on input_pin of the joystick_axes array entry to NO_PIN
+// to prevent it from being read from the ADC. This allows outputting forged axis value.
#define JOYSTICK_AXIS_VIRTUAL \
- { JS_VIRTUAL_AXIS, JS_VIRTUAL_AXIS, JS_VIRTUAL_AXIS, 0, 1023 }
+ { NO_PIN, 0, JOYSTICK_MAX_VALUE / 2, JOYSTICK_MAX_VALUE }
#define JOYSTICK_AXIS_IN(INPUT_PIN, LOW, REST, HIGH) \
- { JS_VIRTUAL_AXIS, INPUT_PIN, JS_VIRTUAL_AXIS, LOW, REST, HIGH }
-#define JOYSTICK_AXIS_IN_OUT(INPUT_PIN, OUTPUT_PIN, LOW, REST, HIGH) \
- { OUTPUT_PIN, INPUT_PIN, JS_VIRTUAL_AXIS, LOW, REST, HIGH }
-#define JOYSTICK_AXIS_IN_OUT_GROUND(INPUT_PIN, OUTPUT_PIN, GROUND_PIN, LOW, REST, HIGH) \
- { OUTPUT_PIN, INPUT_PIN, GROUND_PIN, LOW, REST, HIGH }
+ { INPUT_PIN, LOW, REST, HIGH }
typedef struct {
- pin_t output_pin;
pin_t input_pin;
- pin_t ground_pin;
// the AVR ADC offers 10 bit precision, with significant bits on the higher part
uint16_t min_digit;
@@ -87,6 +78,14 @@ typedef struct {
extern joystick_t joystick_state;
+/**
+ * \brief Handle the initialization of the subsystem.
+ */
+void joystick_init(void);
+
+/**
+ * \brief Handle various subsystem background tasks.
+ */
void joystick_task(void);
/**
@@ -117,6 +116,9 @@ void unregister_joystick_button(uint8_t button);
*/
int16_t joystick_read_axis(uint8_t axis);
+/**
+ * \brief Sample and process the all axis.
+ */
void joystick_read_axes(void);
/**
@@ -127,6 +129,4 @@ void joystick_read_axes(void);
*/
void joystick_set_axis(uint8_t axis, int16_t value);
-void host_joystick_send(joystick_t *joystick);
-
/** \} */
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index 86a1a9fea3..5aaa4b452f 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "keycode_config.h"
#include "matrix.h"
#include "keymap_introspection.h"
-#include "magic.h"
#include "host.h"
#include "led.h"
#include "keycode.h"
@@ -33,6 +32,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "sendchar.h"
#include "eeconfig.h"
#include "action_layer.h"
+#ifdef BOOTMAGIC_ENABLE
+# include "bootmagic.h"
+#endif
#ifdef AUDIO_ENABLE
# include "audio.h"
#endif
@@ -135,6 +137,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef WPM_ENABLE
# include "wpm.h"
#endif
+#ifdef OS_DETECTION_ENABLE
+# include "os_detection.h"
+#endif
static uint32_t last_input_modification_time = 0;
uint32_t last_input_activity_time(void) {
@@ -370,28 +375,30 @@ void housekeeping_task(void) {
housekeeping_task_user();
}
-/** \brief Init tasks previously located in matrix_init_quantum
+/** \brief quantum_init
*
- * TODO: rationalise against keyboard_init and current split role
+ * Init global state
*/
void quantum_init(void) {
- magic();
- led_init_ports();
-#ifdef BACKLIGHT_ENABLE
- backlight_init_ports();
-#endif
-#ifdef AUDIO_ENABLE
- audio_init();
-#endif
-#ifdef LED_MATRIX_ENABLE
- led_matrix_init();
-#endif
-#ifdef RGB_MATRIX_ENABLE
- rgb_matrix_init();
-#endif
-#if defined(UNICODE_COMMON_ENABLE)
- unicode_input_mode_init();
+ /* check signature */
+ if (!eeconfig_is_enabled()) {
+ eeconfig_init();
+ }
+
+ /* init globals */
+ debug_config.raw = eeconfig_read_debug();
+ keymap_config.raw = eeconfig_read_keymap();
+
+#ifdef BOOTMAGIC_ENABLE
+ bootmagic();
#endif
+
+ /* read here just incase bootmagic process changed its value */
+ layer_state_t default_layer = (layer_state_t)eeconfig_read_default_layer();
+ default_layer_set(default_layer);
+
+ /* Also initialize layer state to trigger callback functions for layer_state */
+ layer_state_set_kb((layer_state_t)layer_state);
}
/** \brief keyboard_init
@@ -412,6 +419,22 @@ void keyboard_init(void) {
#endif
matrix_init();
quantum_init();
+ led_init_ports();
+#ifdef BACKLIGHT_ENABLE
+ backlight_init_ports();
+#endif
+#ifdef AUDIO_ENABLE
+ audio_init();
+#endif
+#ifdef LED_MATRIX_ENABLE
+ led_matrix_init();
+#endif
+#ifdef RGB_MATRIX_ENABLE
+ rgb_matrix_init();
+#endif
+#if defined(UNICODE_COMMON_ENABLE)
+ unicode_input_mode_init();
+#endif
#if defined(CRC_ENABLE)
crc_init();
#endif
@@ -440,6 +463,9 @@ void keyboard_init(void) {
#ifdef DIP_SWITCH_ENABLE
dip_switch_init();
#endif
+#ifdef JOYSTICK_ENABLE
+ joystick_init();
+#endif
#ifdef SLEEP_LED_ENABLE
sleep_led_init();
#endif
@@ -615,7 +641,7 @@ void quantum_task(void) {
#endif
#ifdef DIP_SWITCH_ENABLE
- dip_switch_read(false);
+ dip_switch_task();
#endif
#ifdef AUTO_SHIFT_ENABLE
@@ -663,7 +689,7 @@ void keyboard_task(void) {
#endif
#ifdef ENCODER_ENABLE
- if (encoder_read()) {
+ if (encoder_task()) {
last_encoder_activity_trigger();
activity_has_occurred = true;
}
@@ -718,4 +744,8 @@ void keyboard_task(void) {
#endif
led_task();
+
+#ifdef OS_DETECTION_ENABLE
+ os_detection_task();
+#endif
}
diff --git a/quantum/keyboard.h b/quantum/keyboard.h
index 5ea57815a7..0f39fde682 100644
--- a/quantum/keyboard.h
+++ b/quantum/keyboard.h
@@ -32,7 +32,7 @@ typedef struct {
uint8_t row;
} keypos_t;
-typedef enum keyevent_type_t { TICK_EVENT = 0, KEY_EVENT = 1, ENCODER_CW_EVENT = 2, ENCODER_CCW_EVENT = 3, COMBO_EVENT = 4 } keyevent_type_t;
+typedef enum keyevent_type_t { TICK_EVENT = 0, KEY_EVENT = 1, ENCODER_CW_EVENT = 2, ENCODER_CCW_EVENT = 3, COMBO_EVENT = 4, DIP_SWITCH_ON_EVENT = 5, DIP_SWITCH_OFF_EVENT = 6 } keyevent_type_t;
/* key event */
typedef struct {
@@ -48,6 +48,8 @@ typedef struct {
/* special keypos_t entries */
#define KEYLOC_ENCODER_CW 253
#define KEYLOC_ENCODER_CCW 252
+#define KEYLOC_DIP_SWITCH_ON 251
+#define KEYLOC_DIP_SWITCH_OFF 250
static inline bool IS_NOEVENT(const keyevent_t event) {
return event.type == TICK_EVENT;
@@ -64,6 +66,9 @@ static inline bool IS_COMBOEVENT(const keyevent_t event) {
static inline bool IS_ENCODEREVENT(const keyevent_t event) {
return event.type == ENCODER_CW_EVENT || event.type == ENCODER_CCW_EVENT;
}
+static inline bool IS_DIPSWITCHEVENT(const keyevent_t event) {
+ return event.type == DIP_SWITCH_ON_EVENT || event.type == DIP_SWITCH_OFF_EVENT;
+}
/* Common keypos_t object factory */
#define MAKE_KEYPOS(row_num, col_num) ((keypos_t){.row = (row_num), .col = (col_num)})
@@ -92,6 +97,12 @@ static inline bool IS_ENCODEREVENT(const keyevent_t event) {
# define MAKE_ENCODER_CCW_EVENT(enc_id, press) MAKE_EVENT(KEYLOC_ENCODER_CCW, (enc_id), (press), ENCODER_CCW_EVENT)
#endif // ENCODER_MAP_ENABLE
+#ifdef DIP_SWITCH_MAP_ENABLE
+/* Dip Switch events */
+# define MAKE_DIPSWITCH_ON_EVENT(switch_id, press) MAKE_EVENT(KEYLOC_DIP_SWITCH_ON, (switch_id), (press), DIP_SWITCH_ON_EVENT)
+# define MAKE_DIPSWITCH_OFF_EVENT(switch_id, press) MAKE_EVENT(KEYLOC_DIP_SWITCH_OFF, (switch_id), (press), DIP_SWITCH_OFF_EVENT)
+#endif // DIP_SWITCH_MAP_ENABLE
+
/* it runs once at early stage of startup before keyboard_init. */
void keyboard_setup(void);
/* it runs once after initializing host side protocol, debug and MCU peripherals. */
diff --git a/quantum/keycode_config.c b/quantum/keycode_config.c
index 864488a65c..cbfbcc8140 100644
--- a/quantum/keycode_config.c
+++ b/quantum/keycode_config.c
@@ -16,6 +16,8 @@
#include "keycode_config.h"
+keymap_config_t keymap_config;
+
/** \brief keycode_config
*
* This function is used to check a specific keycode against the bootmagic config,
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index 91e47a72ee..abdcd5c7ba 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -29,6 +29,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "encoder.h"
#endif
+#ifdef DIP_SWITCH_MAP_ENABLE
+# include "dip_switch.h"
+#endif
+
#ifdef BACKLIGHT_ENABLE
# include "backlight.h"
#endif
@@ -204,5 +208,13 @@ __attribute__((weak)) uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key
return keycode_at_encodermap_location(layer, key.col, false);
}
#endif // ENCODER_MAP_ENABLE
+#ifdef DIP_SWITCH_MAP_ENABLE
+ else if (key.row == KEYLOC_DIP_SWITCH_ON && key.col < NUM_DIP_SWITCHES) {
+ return keycode_at_dip_switch_map_location(key.col, true);
+ } else if (key.row == KEYLOC_DIP_SWITCH_OFF && key.col < NUM_DIP_SWITCHES) {
+ return keycode_at_dip_switch_map_location(key.col, false);
+ }
+#endif // DIP_SWITCH_MAP_ENABLE
+
return KC_NO;
}
diff --git a/quantum/keymap_extras/keymap_canadian_french.h b/quantum/keymap_extras/keymap_canadian_french.h
new file mode 100644
index 0000000000..63c9166a31
--- /dev/null
+++ b/quantum/keymap_extras/keymap_canadian_french.h
@@ -0,0 +1,122 @@
+// Copyright 2024 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*******************************************************************************
+ 88888888888 888 d8b .d888 d8b 888 d8b
+ 888 888 Y8P d88P" Y8P 888 Y8P
+ 888 888 888 888
+ 888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
+ 888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
+ 888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
+ 888 888 888 888 X88 888 888 888 Y8b. 888 X88
+ 888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
+ 888 888
+ 888 888
+ 888 888
+ .d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
+ d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
+ 888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
+ Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
+ "Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
+ 888
+ Y8b d88P
+ "Y88P"
+*******************************************************************************/
+
+#pragma once
+#include "keycodes.h"
+// clang-format off
+
+// Aliases
+#define FR_HASH KC_GRV // #
+#define FR_1 KC_1 // 1
+#define FR_2 KC_2 // 2
+#define FR_3 KC_3 // 3
+#define FR_4 KC_4 // 4
+#define FR_5 KC_5 // 5
+#define FR_6 KC_6 // 6
+#define FR_7 KC_7 // 7
+#define FR_8 KC_8 // 8
+#define FR_9 KC_9 // 9
+#define FR_0 KC_0 // 0
+#define FR_MINS KC_MINS // -
+#define FR_EQL KC_EQL // =
+#define FR_Q KC_Q // Q
+#define FR_W KC_W // W
+#define FR_E KC_E // E
+#define FR_R KC_R // R
+#define FR_T KC_T // T
+#define FR_Y KC_Y // Y
+#define FR_U KC_U // U
+#define FR_I KC_I // I
+#define FR_O KC_O // O
+#define FR_P KC_P // P
+#define FR_DCIR KC_LBRC // ^ (dead)
+#define FR_CEDL KC_RBRC // ¸ (dead)
+#define FR_A KC_A // A
+#define FR_S KC_S // S
+#define FR_D KC_D // D
+#define FR_F KC_F // F
+#define FR_G KC_G // G
+#define FR_H KC_H // H
+#define FR_J KC_J // J
+#define FR_K KC_K // K
+#define FR_L KC_L // L
+#define FR_SCLN KC_SCLN // ;
+#define FR_DGRV KC_QUOT // ` (dead)
+#define FR_LABK KC_NUHS // <
+#define FR_LDAQ KC_NUBS // «
+#define FR_Z KC_Z // Z
+#define FR_X KC_X // X
+#define FR_C KC_C // C
+#define FR_V KC_V // V
+#define FR_B KC_B // B
+#define FR_N KC_N // N
+#define FR_M KC_M // M
+#define FR_COMM KC_COMM // ,
+#define FR_DOT KC_DOT // .
+#define FR_EACU KC_SLSH // É
+#define FR_PIPE S(FR_HASH) // |
+#define FR_EXLM S(FR_1) // !
+#define FR_DQUO S(FR_2) // "
+#define FR_SLSH S(FR_3) // /
+#define FR_DLR S(FR_4) // $
+#define FR_PERC S(FR_5) // %
+#define FR_QUES S(FR_6) // ?
+#define FR_AMPR S(FR_7) // &
+#define FR_ASTR S(FR_8) // *
+#define FR_LPRN S(FR_9) // (
+#define FR_RPRN S(FR_0) // )
+#define FR_UNDS S(FR_MINS) // _
+#define FR_PLUS S(FR_EQL) // +
+#define FR_DIAE S(FR_CEDL) // ¨ (dead)
+#define FR_COLN S(FR_SCLN) // :
+#define FR_RABK S(FR_LABK) // >
+#define FR_RDAQ S(FR_LDAQ) // »
+#define FR_QUOT S(FR_COMM) // '
+#define FR_BSLS ALGR(FR_HASH) // (backslash)
+#define FR_PLMN ALGR(FR_1) // ±
+#define FR_AT ALGR(FR_2) // @
+#define FR_PND ALGR(FR_3) // £
+#define FR_CENT ALGR(FR_4) // ¢
+#define FR_CURR ALGR(FR_5) // ¤
+#define FR_NOT ALGR(FR_6) // ¬
+#define FR_BRKP ALGR(FR_7) // ¦
+#define FR_SUP2 ALGR(FR_8) // ²
+#define FR_SUP3 ALGR(FR_9) // ³
+#define FR_QRTR ALGR(FR_0) // ¼
+#define FR_HALF ALGR(FR_MINS) // ½
+#define FR_TQTR ALGR(FR_EQL) // ¾
+#define FR_SECT ALGR(FR_O) // §
+#define FR_PARA ALGR(FR_P) // ¶
+#define FR_LBRC ALGR(FR_DCIR) // [
+#define FR_RBRC ALGR(FR_CEDL) // ]
+#define FR_TILD ALGR(FR_SCLN) // ~
+#define FR_LCBR ALGR(FR_DGRV) // {
+#define FR_RCBR ALGR(FR_LABK) // }
+#define FR_DEG ALGR(FR_LDAQ) // °
+#define FR_MICR ALGR(FR_M) // µ
+#define FR_MACR ALGR(FR_COMM) // ¯
+#define FR_SHYP ALGR(FR_DOT) // ­ (soft hyphen)
+#define FR_ACUT ALGR(FR_EACU) // ´ (dead)
+
diff --git a/quantum/keymap_extras/keymap_spanish_latin_america.h b/quantum/keymap_extras/keymap_spanish_latin_america.h
new file mode 100644
index 0000000000..0ade828793
--- /dev/null
+++ b/quantum/keymap_extras/keymap_spanish_latin_america.h
@@ -0,0 +1,105 @@
+// Copyright 2024 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*******************************************************************************
+ 88888888888 888 d8b .d888 d8b 888 d8b
+ 888 888 Y8P d88P" Y8P 888 Y8P
+ 888 888 888 888
+ 888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
+ 888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
+ 888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
+ 888 888 888 888 X88 888 888 888 Y8b. 888 X88
+ 888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
+ 888 888
+ 888 888
+ 888 888
+ .d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
+ d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
+ 888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
+ Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
+ "Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
+ 888
+ Y8b d88P
+ "Y88P"
+*******************************************************************************/
+
+#pragma once
+#include "keycodes.h"
+// clang-format off
+
+// Aliases
+#define ES_PIPE KC_GRV // |
+#define ES_1 KC_1 // 1
+#define ES_2 KC_2 // 2
+#define ES_3 KC_3 // 3
+#define ES_4 KC_4 // 4
+#define ES_5 KC_5 // 5
+#define ES_6 KC_6 // 6
+#define ES_7 KC_7 // 7
+#define ES_8 KC_8 // 8
+#define ES_9 KC_9 // 9
+#define ES_0 KC_0 // 0
+#define ES_QUOT KC_MINS // '
+#define ES_IQUE KC_EQL // ¿
+#define ES_Q KC_Q // Q
+#define ES_W KC_W // W
+#define ES_E KC_E // E
+#define ES_R KC_R // R
+#define ES_T KC_T // T
+#define ES_Y KC_Y // Y
+#define ES_U KC_U // U
+#define ES_I KC_I // I
+#define ES_O KC_O // O
+#define ES_P KC_P // P
+#define ES_ACUT KC_LBRC // ´ (dead)
+#define ES_PLUS KC_RBRC // +
+#define ES_A KC_A // A
+#define ES_S KC_S // S
+#define ES_D KC_D // D
+#define ES_F KC_F // F
+#define ES_G KC_G // G
+#define ES_H KC_H // H
+#define ES_J KC_J // J
+#define ES_K KC_K // K
+#define ES_L KC_L // L
+#define ES_NTIL KC_SCLN // Ñ
+#define ES_LCBR KC_QUOT // {
+#define ES_RCBR KC_NUHS // }
+#define ES_LABK KC_NUBS // <
+#define ES_Z KC_Z // Z
+#define ES_X KC_X // X
+#define ES_C KC_C // C
+#define ES_V KC_V // V
+#define ES_B KC_B // B
+#define ES_N KC_N // N
+#define ES_M KC_M // M
+#define ES_COMM KC_COMM // ,
+#define ES_DOT KC_DOT // .
+#define ES_MINS KC_SLSH // -
+#define ES_MORD S(ES_PIPE) // °
+#define ES_EXLM S(ES_1) // !
+#define ES_DQUO S(ES_2) // "
+#define ES_NUMB S(ES_3) // #
+#define ES_DLR S(ES_4) // $
+#define ES_PERC S(ES_5) // %
+#define ES_AMPR S(ES_6) // &
+#define ES_SLSH S(ES_7) // /
+#define ES_LPRN S(ES_8) // (
+#define ES_RPRN S(ES_9) // )
+#define ES_EQL S(ES_0) // =
+#define ES_QUES S(ES_QUOT) // ?
+#define ES_IEXL S(ES_IQUE) // ¡
+#define ES_DIAE S(ES_ACUT) // ¨ (dead)
+#define ES_ASTR S(ES_PLUS) // *
+#define ES_LBRC S(ES_LCBR) // [
+#define ES_RBRC S(ES_RCBR) // ]
+#define ES_RABK S(ES_LABK) // >
+#define ES_SCLN S(ES_COMM) // ;
+#define ES_COLN S(ES_DOT) // :
+#define ES_UNDS S(ES_MINS) // _
+#define ES_NOT ALGR(ES_PIPE) // ¬
+#define ES_BSLS ALGR(ES_QUOT) // (backslash)
+#define ES_AT ALGR(ES_Q) // @
+#define ES_TILD ALGR(ES_PLUS) // ~
+#define ES_CIRC ALGR(ES_LCBR) // ^
+
diff --git a/quantum/keymap_extras/sendstring_canadian_french.h b/quantum/keymap_extras/sendstring_canadian_french.h
new file mode 100644
index 0000000000..2abba3a9d3
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_canadian_french.h
@@ -0,0 +1,120 @@
+/* Copyright 2023 Nebuleon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Sendstring lookup tables for Canadian French layouts
+
+#pragma once
+
+#include "keymap_canadian_french.h"
+#include "send_string.h"
+
+// clang-format off
+
+const uint8_t ascii_to_shift_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 1, 1, 0, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 0, 0, 0, 1),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 1, 0, 0, 0, 1, 1),
+ KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 0, 1),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 1, 0, 0, 0)
+};
+
+const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 1, 0, 1, 1, 0)
+};
+
+const uint8_t ascii_to_dead_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
+};
+
+const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
+ // NUL SOH STX ETX EOT ENQ ACK BEL
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // BS TAB LF VT FF CR SO SI
+ KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // CAN EM SUB ESC FS GS RS US
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+
+ // ! " # $ % & '
+ KC_SPC, FR_1, FR_2, FR_HASH, FR_4, FR_5, FR_7, FR_COMM,
+ // ( ) * + , - . /
+ FR_9, FR_0, FR_8, FR_EQL, FR_COMM, FR_MINS, FR_DOT, FR_3,
+ // 0 1 2 3 4 5 6 7
+ FR_0, FR_1, FR_2, FR_3, FR_4, FR_5, FR_6, FR_7,
+ // 8 9 : ; < = > ?
+ FR_8, FR_9, FR_SCLN, FR_SCLN, FR_LABK, FR_EQL, FR_LABK, FR_6,
+ // @ A B C D E F G
+ FR_2, FR_A, FR_B, FR_C, FR_D, FR_E, FR_F, FR_G,
+ // H I J K L M N O
+ FR_H, FR_I, FR_J, FR_K, FR_L, FR_M, FR_N, FR_O,
+ // P Q R S T U V W
+ FR_P, FR_Q, FR_R, FR_S, FR_T, FR_U, FR_V, FR_W,
+ // X Y Z [ \ ] ^ _
+ FR_X, FR_Y, FR_Z, FR_DCIR, FR_HASH, FR_CEDL, FR_DCIR, FR_MINS,
+ // ` a b c d e f g
+ FR_DGRV, FR_A, FR_B, FR_C, FR_D, FR_E, FR_F, FR_G,
+ // h i j k l m n o
+ FR_H, FR_I, FR_J, FR_K, FR_L, FR_M, FR_N, FR_O,
+ // p q r s t u v w
+ FR_P, FR_Q, FR_R, FR_S, FR_T, FR_U, FR_V, FR_W,
+ // x y z { | } ~ DEL
+ FR_X, FR_Y, FR_Z, FR_DGRV, FR_HASH, FR_LABK, FR_SCLN, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_spanish_latin_america.h b/quantum/keymap_extras/sendstring_spanish_latin_america.h
new file mode 100644
index 0000000000..3bfdf7d5cb
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_spanish_latin_america.h
@@ -0,0 +1,120 @@
+/* Copyright 2023 Juan David Díaz
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Sendstring lookup tables for Latam Spanish layouts
+
+#pragma once
+
+#include "send_string.h"
+#include "keymap_spanish_latin_america.h"
+
+// clang-format off
+
+const uint8_t ascii_to_shift_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 1, 1, 0, 1, 1, 1, 0),
+ KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 0, 1),
+ KCLUT_ENTRY(0, 0, 1, 1, 0, 1, 1, 0),
+ KCLUT_ENTRY(0, 0, 1, 1, 0, 1, 1, 1),
+ KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 0, 1, 0, 1),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
+};
+
+const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 1, 0, 1, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0)
+};
+
+const uint8_t ascii_to_dead_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
+};
+
+const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
+ // NUL SOH STX ETX EOT ENQ ACK BEL
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // BS TAB LF VT FF CR SO SI
+ KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // CAN EM SUB ESC FS GS RS US
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+
+ // ! " # $ % & '
+ KC_SPC, ES_1, ES_2, ES_3, ES_4, ES_5, ES_6, ES_QUOT,
+ // ( ) * + , - . /
+ ES_8, ES_9, ES_PLUS, ES_PLUS, ES_COMM, ES_MINS, ES_DOT, ES_7,
+ // 0 1 2 3 4 5 6 7
+ ES_0, ES_1, ES_2, ES_3, ES_4, ES_5, ES_6, ES_7,
+ // 8 9 : ; < = > ?
+ ES_8, ES_9, ES_DOT, ES_COMM, ES_LABK, ES_0, ES_LABK, ES_QUOT,
+ // @ A B C D E F G
+ ES_Q, ES_A, ES_B, ES_C, ES_D, ES_E, ES_F, ES_G,
+ // H I J K L M N O
+ ES_H, ES_I, ES_J, ES_K, ES_L, ES_M, ES_N, ES_O,
+ // P Q R S T U V W
+ ES_P, ES_Q, ES_R, ES_S, ES_T, ES_U, ES_V, ES_W,
+ // X Y Z [ \ ] ^ _
+ ES_X, ES_Y, ES_Z, ES_LCBR, ES_QUOT, ES_RCBR, ES_LCBR, ES_MINS,
+ // ` a b c d e f g
+ ES_RCBR, ES_A, ES_B, ES_C, ES_D, ES_E, ES_F, ES_G,
+ // h i j k l m n o
+ ES_H, ES_I, ES_J, ES_K, ES_L, ES_M, ES_N, ES_O,
+ // p q r s t u v w
+ ES_P, ES_Q, ES_R, ES_S, ES_T, ES_U, ES_V, ES_W,
+ // x y z { | } ~ DEL
+ ES_X, ES_Y, ES_Z, ES_LCBR, ES_PIPE, ES_RCBR, ES_PLUS, KC_DEL
+};
diff --git a/quantum/keymap_introspection.c b/quantum/keymap_introspection.c
index e4a01d2e9a..71e3b429ea 100644
--- a/quantum/keymap_introspection.c
+++ b/quantum/keymap_introspection.c
@@ -72,6 +72,24 @@ __attribute__((weak)) uint16_t keycode_at_encodermap_location(uint8_t layer_num,
#endif // defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Dip Switch mapping
+
+#if defined(DIP_SWITCH_ENABLE) && defined(DIP_SWITCH_MAP_ENABLE)
+
+uint16_t keycode_at_dip_switch_map_location_raw(uint8_t switch_idx, bool on) {
+ if (switch_idx < NUM_DIP_SWITCHES) {
+ return pgm_read_word(&dip_switch_map[switch_idx][!!on]);
+ }
+ return KC_TRNS;
+}
+
+uint16_t keycode_at_dip_switch_map_location(uint8_t switch_idx, bool on) {
+ return keycode_at_dip_switch_map_location_raw(switch_idx, on);
+}
+
+#endif // defined(DIP_SWITCH_ENABLE) && defined(DIP_SWITCH_MAP_ENABLE)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Combos
#if defined(COMBO_ENABLE)
diff --git a/quantum/keymap_introspection.h b/quantum/keymap_introspection.h
index 2012a2b8cc..f7516bf42a 100644
--- a/quantum/keymap_introspection.h
+++ b/quantum/keymap_introspection.h
@@ -36,6 +36,18 @@ uint16_t keycode_at_encodermap_location(uint8_t layer_num, uint8_t encoder_idx,
#endif // defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Dip Switch mapping
+
+#if defined(DIP_SWITCH_ENABLE) && defined(DIP_SWITCH_MAP_ENABLE)
+
+// Get the keycode for the dip_switch mapping location, stored in firmware rather than any other persistent storage
+uint16_t keycode_at_dip_switch_map_location_raw(uint8_t switch_idx, bool on);
+// Get the keycode for the dip_switch mapping location, potentially stored dynamically
+uint16_t keycode_at_dip_switch_map_location(uint8_t switch_idx, bool on);
+
+#endif // defined(DIP_SWITCH_ENABLE) && defined(DIP_SWITCH_MAP_ENABLE)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Combos
#if defined(COMBO_ENABLE)
diff --git a/quantum/led.c b/quantum/led.c
index 8d86374a6f..e2b5985109 100644
--- a/quantum/led.c
+++ b/quantum/led.c
@@ -98,19 +98,19 @@ __attribute__((weak)) void led_update_ports(led_t led_state) {
#endif
#ifdef LED_NUM_LOCK_PIN
- writePin(LED_NUM_LOCK_PIN, led_state.num_lock);
+ gpio_write_pin(LED_NUM_LOCK_PIN, led_state.num_lock);
#endif
#ifdef LED_CAPS_LOCK_PIN
- writePin(LED_CAPS_LOCK_PIN, led_state.caps_lock);
+ gpio_write_pin(LED_CAPS_LOCK_PIN, led_state.caps_lock);
#endif
#ifdef LED_SCROLL_LOCK_PIN
- writePin(LED_SCROLL_LOCK_PIN, led_state.scroll_lock);
+ gpio_write_pin(LED_SCROLL_LOCK_PIN, led_state.scroll_lock);
#endif
#ifdef LED_COMPOSE_PIN
- writePin(LED_COMPOSE_PIN, led_state.compose);
+ gpio_write_pin(LED_COMPOSE_PIN, led_state.compose);
#endif
#ifdef LED_KANA_PIN
- writePin(LED_KANA_PIN, led_state.kana);
+ gpio_write_pin(LED_KANA_PIN, led_state.kana);
#endif
}
@@ -118,24 +118,24 @@ __attribute__((weak)) void led_update_ports(led_t led_state) {
*/
__attribute__((weak)) void led_init_ports(void) {
#ifdef LED_NUM_LOCK_PIN
- setPinOutput(LED_NUM_LOCK_PIN);
- writePin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE);
+ gpio_set_pin_output(LED_NUM_LOCK_PIN);
+ gpio_write_pin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE);
#endif
#ifdef LED_CAPS_LOCK_PIN
- setPinOutput(LED_CAPS_LOCK_PIN);
- writePin(LED_CAPS_LOCK_PIN, !LED_PIN_ON_STATE);
+ gpio_set_pin_output(LED_CAPS_LOCK_PIN);
+ gpio_write_pin(LED_CAPS_LOCK_PIN, !LED_PIN_ON_STATE);
#endif
#ifdef LED_SCROLL_LOCK_PIN
- setPinOutput(LED_SCROLL_LOCK_PIN);
- writePin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE);
+ gpio_set_pin_output(LED_SCROLL_LOCK_PIN);
+ gpio_write_pin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE);
#endif
#ifdef LED_COMPOSE_PIN
- setPinOutput(LED_COMPOSE_PIN);
- writePin(LED_COMPOSE_PIN, !LED_PIN_ON_STATE);
+ gpio_set_pin_output(LED_COMPOSE_PIN);
+ gpio_write_pin(LED_COMPOSE_PIN, !LED_PIN_ON_STATE);
#endif
#ifdef LED_KANA_PIN
- setPinOutput(LED_KANA_PIN);
- writePin(LED_KANA_PIN, !LED_PIN_ON_STATE);
+ gpio_set_pin_output(LED_KANA_PIN);
+ gpio_write_pin(LED_KANA_PIN, !LED_PIN_ON_STATE);
#endif
}
@@ -183,9 +183,7 @@ void led_task(void) {
last_led_modification_time = timer_read32();
if (debug_keyboard) {
- debug("led_task: ");
- debug_hex8(led_status);
- debug("\n");
+ dprintf("led_task: %02X\n", led_status);
}
led_set(led_status);
}
diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c
index 4d67a295df..c0fb4c810b 100644
--- a/quantum/led_matrix/led_matrix.c
+++ b/quantum/led_matrix/led_matrix.c
@@ -74,9 +74,6 @@ static uint8_t led_last_enable = UINT8_MAX;
static uint8_t led_last_effect = UINT8_MAX;
static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false};
static led_task_states led_task_state = SYNCING;
-#if LED_MATRIX_TIMEOUT > 0
-static uint32_t led_anykey_timer;
-#endif // LED_MATRIX_TIMEOUT > 0
// double buffers
static uint32_t led_timer_buffer;
@@ -101,7 +98,7 @@ void eeconfig_update_led_matrix_default(void) {
led_matrix_eeconfig.mode = LED_MATRIX_DEFAULT_MODE;
led_matrix_eeconfig.val = LED_MATRIX_DEFAULT_VAL;
led_matrix_eeconfig.speed = LED_MATRIX_DEFAULT_SPD;
- led_matrix_eeconfig.flags = LED_FLAG_ALL;
+ led_matrix_eeconfig.flags = LED_MATRIX_DEFAULT_FLAGS;
eeconfig_flush_led_matrix(true);
}
@@ -114,6 +111,16 @@ void eeconfig_debug_led_matrix(void) {
dprintf("led_matrix_eeconfig.flags = %d\n", led_matrix_eeconfig.flags);
}
+void led_matrix_reload_from_eeprom(void) {
+ led_matrix_disable_noeeprom();
+ /* Reset back to what we have in eeprom */
+ eeconfig_init_led_matrix();
+ eeconfig_debug_led_matrix(); // display current eeprom values
+ if (led_matrix_eeconfig.enable) {
+ led_matrix_mode_noeeprom(led_matrix_eeconfig.mode);
+ }
+}
+
__attribute__((weak)) uint8_t led_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) {
return 0;
}
@@ -156,9 +163,6 @@ void process_led_matrix(uint8_t row, uint8_t col, bool pressed) {
#ifndef LED_MATRIX_SPLIT
if (!is_keyboard_master()) return;
#endif
-#if LED_MATRIX_TIMEOUT > 0
- led_anykey_timer = 0;
-#endif // LED_MATRIX_TIMEOUT > 0
#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
uint8_t led[LED_HITS_TO_REMEMBER];
@@ -208,22 +212,11 @@ static bool led_matrix_none(effect_params_t *params) {
}
static void led_task_timers(void) {
-#if defined(LED_MATRIX_KEYREACTIVE_ENABLED) || LED_MATRIX_TIMEOUT > 0
+#if defined(LED_MATRIX_KEYREACTIVE_ENABLED)
uint32_t deltaTime = sync_timer_elapsed32(led_timer_buffer);
-#endif // defined(LED_MATRIX_KEYREACTIVE_ENABLED) || LED_MATRIX_TIMEOUT > 0
+#endif // defined(LED_MATRIX_KEYREACTIVE_ENABLED)
led_timer_buffer = sync_timer_read32();
- // Update double buffer timers
-#if LED_MATRIX_TIMEOUT > 0
- if (led_anykey_timer < UINT32_MAX) {
- if (UINT32_MAX - deltaTime < led_anykey_timer) {
- led_anykey_timer = UINT32_MAX;
- } else {
- led_anykey_timer += deltaTime;
- }
- }
-#endif // LED_MATRIX_TIMEOUT > 0
-
// Update double buffer last hit timers
#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
uint8_t count = last_hit_buffer.count;
@@ -329,7 +322,7 @@ void led_matrix_task(void) {
// while suspended and just do a software shutdown. This is a cheap hack for now.
bool suspend_backlight = suspend_state ||
#if LED_MATRIX_TIMEOUT > 0
- (led_anykey_timer > (uint32_t)LED_MATRIX_TIMEOUT) ||
+ (last_input_activity_elapsed() > (uint32_t)LED_MATRIX_TIMEOUT) ||
#endif // LED_MATRIX_TIMEOUT > 0
false;
@@ -432,12 +425,6 @@ void led_matrix_init(void) {
}
#endif // LED_MATRIX_KEYREACTIVE_ENABLED
- if (!eeconfig_is_enabled()) {
- dprintf("led_matrix_init_drivers eeconfig is not enabled.\n");
- eeconfig_init();
- eeconfig_update_led_matrix_default();
- }
-
eeconfig_init_led_matrix();
if (!led_matrix_eeconfig.mode) {
dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n");
@@ -447,7 +434,7 @@ void led_matrix_init(void) {
}
void led_matrix_set_suspend_state(bool state) {
-#ifdef LED_DISABLE_WHEN_USB_SUSPENDED
+#ifdef LED_MATRIX_SLEEP
if (state && !suspend_state && is_keyboard_master()) { // only run if turning off, and only once
led_task_render(0); // turn off all LEDs when suspending
led_task_flush(0); // and actually flash led state to LEDs
diff --git a/quantum/led_matrix/led_matrix.h b/quantum/led_matrix/led_matrix.h
index c903a230f4..941d42aeca 100644
--- a/quantum/led_matrix/led_matrix.h
+++ b/quantum/led_matrix/led_matrix.h
@@ -23,32 +23,9 @@
#include <stdint.h>
#include <stdbool.h>
#include "led_matrix_types.h"
+#include "led_matrix_drivers.h"
#include "keyboard.h"
-#if defined(LED_MATRIX_IS31FL3218)
-# include "is31fl3218-simple.h"
-#elif defined(LED_MATRIX_IS31FL3731)
-# include "is31fl3731-simple.h"
-#endif
-#ifdef LED_MATRIX_IS31FL3733
-# include "is31fl3733-simple.h"
-#endif
-#ifdef LED_MATRIX_IS31FL3736
-# include "is31fl3736-simple.h"
-#endif
-#ifdef LED_MATRIX_IS31FL3737
-# include "is31fl3737-simple.h"
-#endif
-#ifdef LED_MATRIX_IS31FL3741
-# include "is31fl3741-simple.h"
-#endif
-#if defined(IS31FLCOMMON)
-# include "is31flcommon.h"
-#endif
-#ifdef LED_MATRIX_SNLED27351
-# include "snled27351-simple.h"
-#endif
-
#ifndef LED_MATRIX_TIMEOUT
# define LED_MATRIX_TIMEOUT 0
#endif
@@ -81,6 +58,10 @@
# define LED_MATRIX_DEFAULT_SPD UINT8_MAX / 2
#endif
+#ifndef LED_MATRIX_DEFAULT_FLAGS
+# define LED_MATRIX_DEFAULT_FLAGS LED_FLAG_ALL
+#endif
+
#ifndef LED_MATRIX_LED_FLUSH_LIMIT
# define LED_MATRIX_LED_FLUSH_LIMIT 16
#endif
@@ -159,6 +140,8 @@ bool led_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max);
void led_matrix_init(void);
+void led_matrix_reload_from_eeprom(void);
+
void led_matrix_set_suspend_state(bool state);
bool led_matrix_get_suspend_state(void);
void led_matrix_toggle(void);
@@ -193,18 +176,6 @@ led_flags_t led_matrix_get_flags(void);
void led_matrix_set_flags(led_flags_t flags);
void led_matrix_set_flags_noeeprom(led_flags_t flags);
-typedef struct {
- /* Perform any initialisation required for the other driver functions to work. */
- void (*init)(void);
-
- /* Set the brightness of a single LED in the buffer. */
- void (*set_value)(int index, uint8_t value);
- /* Set the brightness of all LEDS on the keyboard in the buffer. */
- void (*set_value_all)(uint8_t value);
- /* Flush any buffered changes to the hardware. */
- void (*flush)(void);
-} led_matrix_driver_t;
-
static inline bool led_matrix_check_finished_leds(uint8_t led_idx) {
#if defined(LED_MATRIX_SPLIT)
if (is_keyboard_left()) {
@@ -217,8 +188,6 @@ static inline bool led_matrix_check_finished_leds(uint8_t led_idx) {
#endif
}
-extern const led_matrix_driver_t led_matrix_driver;
-
extern led_eeconfig_t led_matrix_eeconfig;
extern uint32_t g_led_timer;
diff --git a/quantum/led_matrix/led_matrix_drivers.c b/quantum/led_matrix/led_matrix_drivers.c
index 117bed9851..2e80bd0375 100644
--- a/quantum/led_matrix/led_matrix_drivers.c
+++ b/quantum/led_matrix/led_matrix_drivers.c
@@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "led_matrix.h"
+#include "led_matrix_drivers.h"
/* Each driver needs to define a struct:
*
@@ -33,6 +33,14 @@ const led_matrix_driver_t led_matrix_driver = {
.set_value_all = is31fl3218_set_value_all,
};
+#elif defined(LED_MATRIX_IS31FL3729)
+const led_matrix_driver_t led_matrix_driver = {
+ .init = is31fl3729_init_drivers,
+ .flush = is31fl3729_flush,
+ .set_value = is31fl3729_set_value,
+ .set_value_all = is31fl3729_set_value_all,
+};
+
#elif defined(LED_MATRIX_IS31FL3731)
const led_matrix_driver_t led_matrix_driver = {
.init = is31fl3731_init_drivers,
@@ -73,12 +81,36 @@ const led_matrix_driver_t led_matrix_driver = {
.set_value_all = is31fl3741_set_value_all,
};
-#elif defined(IS31FLCOMMON)
+#elif defined(LED_MATRIX_IS31FL3742A)
+const led_matrix_driver_t led_matrix_driver = {
+ .init = is31fl3742a_init_drivers,
+ .flush = is31fl3742a_flush,
+ .set_value = is31fl3742a_set_value,
+ .set_value_all = is31fl3742a_set_value_all,
+};
+
+#elif defined(LED_MATRIX_IS31FL3743A)
+const led_matrix_driver_t led_matrix_driver = {
+ .init = is31fl3743a_init_drivers,
+ .flush = is31fl3743a_flush,
+ .set_value = is31fl3743a_set_value,
+ .set_value_all = is31fl3743a_set_value_all,
+};
+
+#elif defined(LED_MATRIX_IS31FL3745)
+const led_matrix_driver_t led_matrix_driver = {
+ .init = is31fl3745_init_drivers,
+ .flush = is31fl3745_flush,
+ .set_value = is31fl3745_set_value,
+ .set_value_all = is31fl3745_set_value_all,
+};
+
+#elif defined(LED_MATRIX_IS31FL3746A)
const led_matrix_driver_t led_matrix_driver = {
- .init = IS31FL_simple_init_drivers,
- .flush = IS31FL_common_flush,
- .set_value = IS31FL_simple_set_brightness,
- .set_value_all = IS31FL_simple_set_brigntness_all,
+ .init = is31fl3746a_init_drivers,
+ .flush = is31fl3746a_flush,
+ .set_value = is31fl3746a_set_value,
+ .set_value_all = is31fl3746a_set_value_all,
};
#elif defined(LED_MATRIX_SNLED27351)
diff --git a/quantum/led_matrix/led_matrix_drivers.h b/quantum/led_matrix/led_matrix_drivers.h
new file mode 100644
index 0000000000..a961784a62
--- /dev/null
+++ b/quantum/led_matrix/led_matrix_drivers.h
@@ -0,0 +1,46 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined(LED_MATRIX_IS31FL3218)
+# include "is31fl3218-mono.h"
+#elif defined(LED_MATRIX_IS31FL3729)
+# include "is31fl3729-mono.h"
+#elif defined(LED_MATRIX_IS31FL3731)
+# include "is31fl3731-mono.h"
+#elif defined(LED_MATRIX_IS31FL3733)
+# include "is31fl3733-mono.h"
+#elif defined(LED_MATRIX_IS31FL3736)
+# include "is31fl3736-mono.h"
+#elif defined(LED_MATRIX_IS31FL3737)
+# include "is31fl3737-mono.h"
+#elif defined(LED_MATRIX_IS31FL3741)
+# include "is31fl3741-mono.h"
+#elif defined(LED_MATRIX_IS31FL3742A)
+# include "is31fl3742a-mono.h"
+#elif defined(LED_MATRIX_IS31FL3743A)
+# include "is31fl3743a-mono.h"
+#elif defined(LED_MATRIX_IS31FL3745)
+# include "is31fl3745-mono.h"
+#elif defined(LED_MATRIX_IS31FL3746A)
+# include "is31fl3746a-mono.h"
+#elif defined(LED_MATRIX_SNLED27351)
+# include "snled27351-mono.h"
+#endif
+
+typedef struct {
+ /* Perform any initialisation required for the other driver functions to work. */
+ void (*init)(void);
+
+ /* Set the brightness of a single LED in the buffer. */
+ void (*set_value)(int index, uint8_t value);
+ /* Set the brightness of all LEDS on the keyboard in the buffer. */
+ void (*set_value_all)(uint8_t value);
+ /* Flush any buffered changes to the hardware. */
+ void (*flush)(void);
+} led_matrix_driver_t;
+
+extern const led_matrix_driver_t led_matrix_driver;
diff --git a/quantum/logging/debug.h b/quantum/logging/debug.h
index 8415310356..d0590474c0 100644
--- a/quantum/logging/debug.h
+++ b/quantum/logging/debug.h
@@ -17,6 +17,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
+#ifndef PROTOCOL_ARM_ATSAM
+# include <stdio.h>
+#endif
+
#include <stdbool.h>
#include "print.h"
@@ -54,116 +58,14 @@ extern debug_config_t debug_config;
* Debug print utils
*/
#ifndef NO_DEBUG
-
-# define dprint(s) \
- do { \
- if (debug_enable) print(s); \
- } while (0)
-# define dprintln(s) \
- do { \
- if (debug_enable) println(s); \
- } while (0)
-# define dprintf(fmt, ...) \
- do { \
- if (debug_enable) xprintf(fmt, ##__VA_ARGS__); \
- } while (0)
-# define dmsg(s) dprintf("%s at %d: %s\n", __FILE__, __LINE__, s)
-
-/* Deprecated. DO NOT USE these anymore, use dprintf instead. */
-# define debug(s) \
- do { \
- if (debug_enable) print(s); \
- } while (0)
-# define debugln(s) \
- do { \
- if (debug_enable) println(s); \
- } while (0)
-# define debug_msg(s) \
- do { \
- if (debug_enable) { \
- print(__FILE__); \
- print(" at "); \
- print_dec(__LINE__); \
- print(" in "); \
- print(": "); \
- print(s); \
- } \
- } while (0)
-# define debug_dec(data) \
- do { \
- if (debug_enable) print_dec(data); \
- } while (0)
-# define debug_decs(data) \
- do { \
- if (debug_enable) print_decs(data); \
- } while (0)
-# define debug_hex4(data) \
- do { \
- if (debug_enable) print_hex4(data); \
- } while (0)
-# define debug_hex8(data) \
- do { \
- if (debug_enable) print_hex8(data); \
+# define dprintf(fmt, ...) \
+ do { \
+ if (debug_config.enable) xprintf(fmt, ##__VA_ARGS__); \
} while (0)
-# define debug_hex16(data) \
- do { \
- if (debug_enable) print_hex16(data); \
- } while (0)
-# define debug_hex32(data) \
- do { \
- if (debug_enable) print_hex32(data); \
- } while (0)
-# define debug_bin8(data) \
- do { \
- if (debug_enable) print_bin8(data); \
- } while (0)
-# define debug_bin16(data) \
- do { \
- if (debug_enable) print_bin16(data); \
- } while (0)
-# define debug_bin32(data) \
- do { \
- if (debug_enable) print_bin32(data); \
- } while (0)
-# define debug_bin_reverse8(data) \
- do { \
- if (debug_enable) print_bin_reverse8(data); \
- } while (0)
-# define debug_bin_reverse16(data) \
- do { \
- if (debug_enable) print_bin_reverse16(data); \
- } while (0)
-# define debug_bin_reverse32(data) \
- do { \
- if (debug_enable) print_bin_reverse32(data); \
- } while (0)
-# define debug_hex(data) debug_hex8(data)
-# define debug_bin(data) debug_bin8(data)
-# define debug_bin_reverse(data) debug_bin8(data)
-
#else /* NO_DEBUG */
-
-# define dprint(s)
-# define dprintln(s)
# define dprintf(fmt, ...)
-# define dmsg(s)
-# define debug(s)
-# define debugln(s)
-# define debug_msg(s)
-# define debug_dec(data)
-# define debug_decs(data)
-# define debug_hex4(data)
-# define debug_hex8(data)
-# define debug_hex16(data)
-# define debug_hex32(data)
-# define debug_bin8(data)
-# define debug_bin16(data)
-# define debug_bin32(data)
-# define debug_bin_reverse8(data)
-# define debug_bin_reverse16(data)
-# define debug_bin_reverse32(data)
-# define debug_hex(data)
-# define debug_bin(data)
-# define debug_bin_reverse(data)
-
#endif /* NO_DEBUG */
+
+#define dprint(s) dprintf(s)
+#define dprintln(s) dprintf(s "\r\n")
+#define dmsg(s) dprintf("%s at %d: %s\n", __FILE__, __LINE__, s)
diff --git a/quantum/logging/print.h b/quantum/logging/print.h
index 4c4195de50..984bc10758 100644
--- a/quantum/logging/print.h
+++ b/quantum/logging/print.h
@@ -52,40 +52,27 @@ void print_set_sendchar(sendchar_func_t func);
# if __has_include_next("_print.h")
# include_next "_print.h" /* Include the platforms print.h */
# else
-// Fall back to lib/printf
-# include "printf.h" // lib/printf/printf.h
-
-// Create user & normal print defines
-# define print(s) printf(s)
-# define println(s) printf(s "\r\n")
+# include "printf.h" // // Fall back to lib/printf/printf.h
# define xprintf printf
-# define uprint(s) printf(s)
-# define uprintln(s) printf(s "\r\n")
-# define uprintf printf
-
-# endif /* __has_include_next("_print.h") */
-#else /* NO_PRINT */
-# undef xprintf
+# endif
+#else
// Remove print defines
-# define print(s)
-# define println(s)
+# undef xprintf
# define xprintf(fmt, ...)
-# define uprintf(fmt, ...)
-# define uprint(s)
-# define uprintln(s)
+#endif
-#endif /* NO_PRINT */
+// Resolve before USER_PRINT can remove
+#define uprintf xprintf
#ifdef USER_PRINT
// Remove normal print defines
-# undef print
-# undef println
# undef xprintf
-# define print(s)
-# define println(s)
# define xprintf(fmt, ...)
#endif
+#define print(s) xprintf(s)
+#define println(s) xprintf(s "\r\n")
+
#define print_dec(i) xprintf("%u", i)
#define print_decs(i) xprintf("%d", i)
/* hex */
@@ -121,6 +108,9 @@ void print_set_sendchar(sendchar_func_t func);
//
// !!! DO NOT USE USER PRINT CALLS IN THE BODY OF QMK/TMK !!!
+#define uprint(s) uprintf(s)
+#define uprintln(s) uprintf(s "\r\n")
+
/* decimal */
#define uprint_dec(i) uprintf("%u", i)
#define uprint_decs(i) uprintf("%d", i)
diff --git a/quantum/matrix.c b/quantum/matrix.c
index f087a215d4..d4586efac2 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -78,27 +78,27 @@ __attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[]
static inline void setPinOutput_writeLow(pin_t pin) {
ATOMIC_BLOCK_FORCEON {
- setPinOutput(pin);
- writePinLow(pin);
+ gpio_set_pin_output(pin);
+ gpio_write_pin_low(pin);
}
}
static inline void setPinOutput_writeHigh(pin_t pin) {
ATOMIC_BLOCK_FORCEON {
- setPinOutput(pin);
- writePinHigh(pin);
+ gpio_set_pin_output(pin);
+ gpio_write_pin_high(pin);
}
}
static inline void setPinInputHigh_atomic(pin_t pin) {
ATOMIC_BLOCK_FORCEON {
- setPinInputHigh(pin);
+ gpio_set_pin_input_high(pin);
}
}
static inline uint8_t readMatrixPin(pin_t pin) {
if (pin != NO_PIN) {
- return (readPin(pin) == MATRIX_INPUT_PRESSED_STATE) ? 0 : 1;
+ return (gpio_read_pin(pin) == MATRIX_INPUT_PRESSED_STATE) ? 0 : 1;
} else {
return 1;
}
@@ -113,7 +113,7 @@ __attribute__((weak)) void matrix_init_pins(void) {
for (int col = 0; col < MATRIX_COLS; col++) {
pin_t pin = direct_pins[row][col];
if (pin != NO_PIN) {
- setPinInputHigh(pin);
+ gpio_set_pin_input_high(pin);
}
}
}
diff --git a/quantum/os_detection.c b/quantum/os_detection.c
index e606227136..96b026e247 100644
--- a/quantum/os_detection.c
+++ b/quantum/os_detection.c
@@ -17,6 +17,10 @@
#include "os_detection.h"
#include <string.h>
+#include "timer.h"
+#ifdef OS_DETECTION_KEYBOARD_RESET
+# include "quantum.h"
+#endif
#ifdef OS_DETECTION_DEBUG_ENABLE
# include "eeconfig.h"
@@ -26,10 +30,19 @@
# define STORED_USB_SETUPS 50
# define EEPROM_USER_OFFSET (uint8_t*)EECONFIG_SIZE
-uint16_t usb_setups[STORED_USB_SETUPS];
+static uint16_t usb_setups[STORED_USB_SETUPS];
+#endif
+
+#ifndef OS_DETECTION_DEBOUNCE
+# define OS_DETECTION_DEBOUNCE 200
+#endif
+
+// 2s should always be more than enough (otherwise, you may have other issues)
+#if OS_DETECTION_DEBOUNCE > 2000
+# undef OS_DETECTION_DEBOUNCE
+# define OS_DETECTION_DEBOUNCE 2000
#endif
-#ifdef OS_DETECTION_ENABLE
struct setups_data_t {
uint8_t count;
uint8_t cnt_02;
@@ -45,47 +58,55 @@ struct setups_data_t setups_data = {
.cnt_ff = 0,
};
-os_variant_t detected_os = OS_UNSURE;
-
-// Some collected sequences of wLength can be found in tests.
-void make_guess(void) {
- if (setups_data.count < 3) {
- return;
- }
- if (setups_data.cnt_ff >= 2 && setups_data.cnt_04 >= 1) {
- detected_os = OS_WINDOWS;
- return;
+static volatile os_variant_t detected_os = OS_UNSURE;
+static os_variant_t reported_os = OS_UNSURE;
+
+// we need to be able to report OS_UNSURE if that is the stable result of the guesses
+static bool first_report = true;
+
+// to react on USB state changes
+static volatile enum usb_device_state current_usb_device_state = USB_DEVICE_STATE_INIT;
+static enum usb_device_state reported_usb_device_state = USB_DEVICE_STATE_INIT;
+
+// the OS detection might be unstable for a while, "debounce" it
+static volatile bool debouncing = false;
+static volatile fast_timer_t last_time;
+
+void os_detection_task(void) {
+ if (current_usb_device_state == USB_DEVICE_STATE_CONFIGURED) {
+ // debouncing goes for both the detected OS as well as the USB state
+ if (debouncing && timer_elapsed_fast(last_time) >= OS_DETECTION_DEBOUNCE) {
+ debouncing = false;
+ reported_usb_device_state = current_usb_device_state;
+ if (detected_os != reported_os || first_report) {
+ first_report = false;
+ reported_os = detected_os;
+ process_detected_host_os_kb(detected_os);
+ }
+ }
}
- if (setups_data.count == setups_data.cnt_ff) {
- // Linux has 3 packets with 0xFF.
- detected_os = OS_LINUX;
- return;
- }
- if (setups_data.count == 5 && setups_data.last_wlength == 0xFF && setups_data.cnt_ff == 1 && setups_data.cnt_02 == 2) {
- detected_os = OS_MACOS;
- return;
- }
- if (setups_data.count == 4 && setups_data.cnt_ff == 0 && setups_data.cnt_02 == 2) {
- // iOS and iPadOS don't have the last 0xFF packet.
- detected_os = OS_IOS;
- return;
- }
- if (setups_data.cnt_ff == 0 && setups_data.cnt_02 == 3 && setups_data.cnt_04 == 1) {
- // This is actually PS5.
- detected_os = OS_LINUX;
- return;
- }
- if (setups_data.cnt_ff >= 1 && setups_data.cnt_02 == 0 && setups_data.cnt_04 == 0) {
- // This is actually Quest 2 or Nintendo Switch.
- detected_os = OS_LINUX;
- return;
+#ifdef OS_DETECTION_KEYBOARD_RESET
+ // resetting the keyboard on the USB device state change callback results in instability, so delegate that to this task
+ // only take action if it's been stable at least once, to avoid issues with some KVMs
+ else if (current_usb_device_state == USB_DEVICE_STATE_INIT && reported_usb_device_state != USB_DEVICE_STATE_INIT) {
+ soft_reset_keyboard();
}
+#endif
+}
+
+__attribute__((weak)) bool process_detected_host_os_kb(os_variant_t detected_os) {
+ return process_detected_host_os_user(detected_os);
}
+__attribute__((weak)) bool process_detected_host_os_user(os_variant_t detected_os) {
+ return true;
+}
+
+// Some collected sequences of wLength can be found in tests.
void process_wlength(const uint16_t w_length) {
-# ifdef OS_DETECTION_DEBUG_ENABLE
+#ifdef OS_DETECTION_DEBUG_ENABLE
usb_setups[setups_data.count] = w_length;
-# endif
+#endif
setups_data.count++;
setups_data.last_wlength = w_length;
if (w_length == 0x2) {
@@ -95,7 +116,37 @@ void process_wlength(const uint16_t w_length) {
} else if (w_length == 0xFF) {
setups_data.cnt_ff++;
}
- make_guess();
+
+ // now try to make a guess
+ os_variant_t guessed = OS_UNSURE;
+ if (setups_data.count >= 3) {
+ if (setups_data.cnt_ff >= 2 && setups_data.cnt_04 >= 1) {
+ guessed = OS_WINDOWS;
+ } else if (setups_data.count == setups_data.cnt_ff) {
+ // Linux has 3 packets with 0xFF.
+ guessed = OS_LINUX;
+ } else if (setups_data.count == 5 && setups_data.last_wlength == 0xFF && setups_data.cnt_ff == 1 && setups_data.cnt_02 == 2) {
+ guessed = OS_MACOS;
+ } else if (setups_data.count == 4 && setups_data.cnt_ff == 0 && setups_data.cnt_02 == 2) {
+ // iOS and iPadOS don't have the last 0xFF packet.
+ guessed = OS_IOS;
+ } else if (setups_data.cnt_ff == 0 && setups_data.cnt_02 == 3 && setups_data.cnt_04 == 1) {
+ // This is actually PS5.
+ guessed = OS_LINUX;
+ } else if (setups_data.cnt_ff >= 1 && setups_data.cnt_02 == 0 && setups_data.cnt_04 == 0) {
+ // This is actually Quest 2 or Nintendo Switch.
+ guessed = OS_LINUX;
+ }
+ }
+
+ // only replace the guessed value if not unsure
+ if (guessed != OS_UNSURE) {
+ detected_os = guessed;
+ }
+
+ // whatever the result, debounce
+ last_time = timer_read_fast();
+ debouncing = true;
}
os_variant_t detected_host_os(void) {
@@ -104,15 +155,28 @@ os_variant_t detected_host_os(void) {
void erase_wlength_data(void) {
memset(&setups_data, 0, sizeof(setups_data));
- detected_os = OS_UNSURE;
+ detected_os = OS_UNSURE;
+ reported_os = OS_UNSURE;
+ current_usb_device_state = USB_DEVICE_STATE_INIT;
+ reported_usb_device_state = USB_DEVICE_STATE_INIT;
+ debouncing = false;
+ first_report = true;
}
-# if defined(SPLIT_KEYBOARD) && defined(SPLIT_DETECTED_OS_ENABLE)
+void os_detection_notify_usb_device_state_change(enum usb_device_state usb_device_state) {
+ // treat this like any other source of instability
+ current_usb_device_state = usb_device_state;
+ last_time = timer_read_fast();
+ debouncing = true;
+}
+
+#if defined(SPLIT_KEYBOARD) && defined(SPLIT_DETECTED_OS_ENABLE)
void slave_update_detected_host_os(os_variant_t os) {
detected_os = os;
+ last_time = timer_read_fast();
+ debouncing = true;
}
-# endif // defined(SPLIT_KEYBOARD) && defined(SPLIT_DETECTED_OS_ENABLE)
-#endif // OS_DETECTION_ENABLE
+#endif
#ifdef OS_DETECTION_DEBUG_ENABLE
void print_stored_setups(void) {
diff --git a/quantum/os_detection.h b/quantum/os_detection.h
index 3496ea0ed2..b8cd898335 100644
--- a/quantum/os_detection.h
+++ b/quantum/os_detection.h
@@ -17,8 +17,9 @@
#pragma once
#include <stdint.h>
+#include <stdbool.h>
+#include "usb_device_state.h"
-#ifdef OS_DETECTION_ENABLE
typedef enum {
OS_UNSURE,
OS_LINUX,
@@ -30,10 +31,15 @@ typedef enum {
void process_wlength(const uint16_t w_length);
os_variant_t detected_host_os(void);
void erase_wlength_data(void);
+void os_detection_notify_usb_device_state_change(enum usb_device_state usb_device_state);
-# if defined(SPLIT_KEYBOARD) && defined(SPLIT_DETECTED_OS_ENABLE)
+void os_detection_task(void);
+
+bool process_detected_host_os_kb(os_variant_t os);
+bool process_detected_host_os_user(os_variant_t os);
+
+#if defined(SPLIT_KEYBOARD) && defined(SPLIT_DETECTED_OS_ENABLE)
void slave_update_detected_host_os(os_variant_t os);
-# endif // defined(SPLIT_KEYBOARD) && defined(SPLIT_DETECTED_OS_ENABLE)
#endif
#ifdef OS_DETECTION_DEBUG_ENABLE
diff --git a/quantum/os_detection/tests/os_detection.cpp b/quantum/os_detection/tests/os_detection.cpp
index 102349852e..a9f671156b 100644
--- a/quantum/os_detection/tests/os_detection.cpp
+++ b/quantum/os_detection/tests/os_detection.cpp
@@ -18,12 +18,20 @@
extern "C" {
#include "os_detection.h"
+#include "timer.h"
+
+void advance_time(uint32_t ms);
}
+static uint32_t reported_count;
+static os_variant_t reported_os;
+
class OsDetectionTest : public ::testing::Test {
protected:
void SetUp() override {
erase_wlength_data();
+ reported_count = 0;
+ reported_os = OS_UNSURE;
}
};
@@ -34,6 +42,26 @@ os_variant_t check_sequence(const std::vector<uint16_t> &w_lengths) {
return detected_host_os();
}
+bool process_detected_host_os_kb(os_variant_t os) {
+ reported_count = reported_count + 1;
+ reported_os = os;
+
+ return true;
+}
+
+void assert_not_reported(void) {
+ // check that it does not report the result, nor any intermediate results
+ EXPECT_EQ(reported_count, 0);
+ EXPECT_EQ(reported_os, OS_UNSURE);
+}
+
+void assert_reported(os_variant_t os) {
+ // check that it reports exclusively the result, not any intermediate results
+ EXPECT_EQ(reported_count, 1);
+ EXPECT_EQ(reported_os, os);
+ EXPECT_EQ(reported_os, detected_host_os());
+}
+
/* Some collected data.
ChibiOS:
@@ -77,88 +105,291 @@ Quest 2: [FF, FF, FF, FE, ...]
*/
TEST_F(OsDetectionTest, TestLinux) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestChibiosMacos) {
EXPECT_EQ(check_sequence({0x2, 0x24, 0x2, 0x28, 0xFF}), OS_MACOS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestLufaMacos) {
EXPECT_EQ(check_sequence({0x2, 0x10, 0x2, 0xE, 0xFF}), OS_MACOS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestVusbMacos) {
EXPECT_EQ(check_sequence({0x2, 0xE, 0x2, 0xE, 0xFF}), OS_MACOS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestChibiosIos) {
EXPECT_EQ(check_sequence({0x2, 0x24, 0x2, 0x28}), OS_IOS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestLufaIos) {
EXPECT_EQ(check_sequence({0x2, 0x10, 0x2, 0xE}), OS_IOS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestVusbIos) {
EXPECT_EQ(check_sequence({0x2, 0xE, 0x2, 0xE}), OS_IOS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestChibiosWindows10) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x24, 0x4, 0x24, 0x4, 0xFF, 0x24, 0xFF, 0x4, 0xFF, 0x24, 0x4, 0x24, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestChibiosWindows10_2) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24}), OS_WINDOWS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestLufaWindows10) {
EXPECT_EQ(check_sequence({0x12, 0xFF, 0xFF, 0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestLufaWindows10_2) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x10, 0xFF, 0x4, 0xFF, 0x10, 0xFF, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestLufaWindows10_3) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x10, 0x4, 0x10}), OS_WINDOWS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestVusbWindows10) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0xE, 0xFF}), OS_WINDOWS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestVusbWindows10_2) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0xE, 0x4}), OS_WINDOWS);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestChibiosPs5) {
EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0x28, 0x2, 0x24}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestLufaPs5) {
EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0xE, 0x2, 0x10}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestVusbPs5) {
EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0xE, 0x2}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestChibiosNintendoSwitch) {
EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestLufaNintendoSwitch) {
EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestVusbNintendoSwitch) {
EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestChibiosQuest2) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
TEST_F(OsDetectionTest, TestVusbQuest2) {
EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
+}
+
+// Regression reported in https://github.com/qmk/qmk_firmware/pull/21777#issuecomment-1922815841
+TEST_F(OsDetectionTest, TestDetectMacM1AsIOS) {
+ EXPECT_EQ(check_sequence({0x02, 0x32, 0x02, 0x24, 0x101, 0xFF}), OS_IOS);
+ os_detection_task();
+ assert_not_reported();
+}
+
+TEST_F(OsDetectionTest, TestDoNotReportIfUsbUnstable) {
+ EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
+
+ advance_time(OS_DETECTION_DEBOUNCE);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+}
+
+TEST_F(OsDetectionTest, TestReportAfterDebounce) {
+ EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
+ os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
+ os_detection_task();
+ assert_not_reported();
+
+ advance_time(1);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+
+ advance_time(OS_DETECTION_DEBOUNCE - 3);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+
+ advance_time(1);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+
+ // advancing the timer alone must not cause a report
+ advance_time(1);
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+ // the task will cause a report
+ os_detection_task();
+ assert_reported(OS_LINUX);
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+
+ // check that it remains the same after a long time
+ advance_time(OS_DETECTION_DEBOUNCE * 15);
+ assert_reported(OS_LINUX);
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+}
+
+TEST_F(OsDetectionTest, TestReportAfterDebounceLongWait) {
+ EXPECT_EQ(check_sequence({0x12, 0xFF, 0xFF, 0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
+ os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
+ os_detection_task();
+ assert_not_reported();
+
+ advance_time(1);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+
+ // advancing the timer alone must not cause a report
+ advance_time(OS_DETECTION_DEBOUNCE * 15);
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+ // the task will cause a report
+ os_detection_task();
+ assert_reported(OS_WINDOWS);
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+
+ // check that it remains the same after a long time
+ advance_time(OS_DETECTION_DEBOUNCE * 10);
+ os_detection_task();
+ assert_reported(OS_WINDOWS);
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+}
+
+TEST_F(OsDetectionTest, TestReportUnsure) {
+ EXPECT_EQ(check_sequence({0x12, 0xFF}), OS_UNSURE);
+ os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
+ os_detection_task();
+ assert_not_reported();
+
+ advance_time(1);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_UNSURE);
+
+ // advancing the timer alone must not cause a report
+ advance_time(OS_DETECTION_DEBOUNCE - 1);
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_UNSURE);
+ // the task will cause a report
+ os_detection_task();
+ assert_reported(OS_UNSURE);
+ EXPECT_EQ(detected_host_os(), OS_UNSURE);
+
+ // check that it remains the same after a long time
+ advance_time(OS_DETECTION_DEBOUNCE * 10);
+ os_detection_task();
+ assert_reported(OS_UNSURE);
+ EXPECT_EQ(detected_host_os(), OS_UNSURE);
+}
+
+TEST_F(OsDetectionTest, TestDoNotReportIntermediateResults) {
+ EXPECT_EQ(check_sequence({0x12, 0xFF}), OS_UNSURE);
+ os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
+ os_detection_task();
+ assert_not_reported();
+
+ advance_time(OS_DETECTION_DEBOUNCE - 1);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_UNSURE);
+
+ // at this stage, the final result has not been reached yet
+ EXPECT_EQ(check_sequence({0xFF}), OS_LINUX);
+ os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
+ advance_time(OS_DETECTION_DEBOUNCE - 1);
+ os_detection_task();
+ assert_not_reported();
+ // the intermedite but yet unstable result is exposed through detected_host_os()
+ EXPECT_EQ(detected_host_os(), OS_LINUX);
+
+ // the remainder is processed
+ EXPECT_EQ(check_sequence({0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
+ os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
+ advance_time(OS_DETECTION_DEBOUNCE - 1);
+ os_detection_task();
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+
+ // advancing the timer alone must not cause a report
+ advance_time(1);
+ assert_not_reported();
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+ // the task will cause a report
+ os_detection_task();
+ assert_reported(OS_WINDOWS);
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+
+ // check that it remains the same after a long time
+ advance_time(OS_DETECTION_DEBOUNCE * 10);
+ os_detection_task();
+ assert_reported(OS_WINDOWS);
+ EXPECT_EQ(detected_host_os(), OS_WINDOWS);
+}
+
+TEST_F(OsDetectionTest, TestDoNotGoBackToUnsure) {
+ // 0x02 would cause it to go back to Unsure, so check that it does not
+ EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE, 0x02}), OS_LINUX);
+ os_detection_task();
+ assert_not_reported();
}
diff --git a/quantum/os_detection/tests/rules.mk b/quantum/os_detection/tests/rules.mk
index 9bfe373f46..1b69b71ba9 100644
--- a/quantum/os_detection/tests/rules.mk
+++ b/quantum/os_detection/tests/rules.mk
@@ -1,5 +1,7 @@
os_detection_DEFS := -DOS_DETECTION_ENABLE
+os_detection_DEFS += -DOS_DETECTION_DEBOUNCE=50
os_detection_SRC := \
$(QUANTUM_PATH)/os_detection/tests/os_detection.cpp \
- $(QUANTUM_PATH)/os_detection.c
+ $(QUANTUM_PATH)/os_detection.c \
+ $(PLATFORM_PATH)/$(PLATFORM_KEY)/timer.c
diff --git a/quantum/painter/qp.h b/quantum/painter/qp.h
index 873a9d9f32..02acbf589a 100644
--- a/quantum/painter/qp.h
+++ b/quantum/painter/qp.h
@@ -509,6 +509,12 @@ int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, pai
# define ILI9341_NUM_DEVICES 0
#endif // QUANTUM_PAINTER_ILI9341_ENABLE
+#ifdef QUANTUM_PAINTER_ILI9486_ENABLE
+# include "qp_ili9486.h"
+#else // QUANTUM_PAINTER_ILI9486_ENABLE
+# define ILI9486_NUM_DEVICES 0
+#endif // QUANTUM_PAINTER_ILI9486_ENABLE
+
#ifdef QUANTUM_PAINTER_ILI9488_ENABLE
# include "qp_ili9488.h"
#else // QUANTUM_PAINTER_ILI9488_ENABLE
diff --git a/quantum/painter/qp_draw.h b/quantum/painter/qp_draw.h
index 3d073efe8c..7546c061a7 100644
--- a/quantum/painter/qp_draw.h
+++ b/quantum/painter/qp_draw.h
@@ -92,4 +92,9 @@ typedef struct qp_internal_byte_output_state_t {
bool qp_internal_byte_appender(uint8_t byteval, void* cb_arg);
+// Helper shared between image and font rendering, sends pixels to the display using:
+// - qp_internal_decode_palette + qp_internal_pixel_appender (bpp <= 8)
+// - qp_internal_send_bytes (bpp > 8)
+bool qp_internal_appender(painter_device_t device, uint8_t bpp, uint32_t pixel_count, qp_internal_byte_input_callback input_callback, void* input_state);
+
qp_internal_byte_input_callback qp_internal_prepare_input_state(qp_internal_byte_input_state_t* input_state, painter_compression_t compression);
diff --git a/quantum/painter/qp_draw_codec.c b/quantum/painter/qp_draw_codec.c
index cee2e32e28..4ff41d0650 100644
--- a/quantum/painter/qp_draw_codec.c
+++ b/quantum/painter/qp_draw_codec.c
@@ -1,4 +1,5 @@
// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "qp_internal.h"
@@ -164,6 +165,45 @@ bool qp_internal_byte_appender(uint8_t byteval, void* cb_arg) {
return true;
}
+// Helper shared between image and font rendering -- uses either (qp_internal_decode_palette + qp_internal_pixel_appender) or (qp_internal_send_bytes) to send data data to the display based on the asset's native-ness
+bool qp_internal_appender(painter_device_t device, uint8_t bpp, uint32_t pixel_count, qp_internal_byte_input_callback input_callback, void* input_state) {
+ painter_driver_t* driver = (painter_driver_t*)device;
+
+ bool ret = false;
+
+ // Non-native pixel format
+ if (bpp <= 8) {
+ // Set up the output state
+ qp_internal_pixel_output_state_t output_state = {.device = device, .pixel_write_pos = 0, .max_pixels = qp_internal_num_pixels_in_buffer(device)};
+
+ // Decode the pixel data and stream to the display
+ ret = qp_internal_decode_palette(device, pixel_count, bpp, input_callback, input_state, qp_internal_global_pixel_lookup_table, qp_internal_pixel_appender, &output_state);
+ // Any leftovers need transmission as well.
+ if (ret && output_state.pixel_write_pos > 0) {
+ ret &= driver->driver_vtable->pixdata(device, qp_internal_global_pixdata_buffer, output_state.pixel_write_pos);
+ }
+ }
+
+ // Native pixel format
+ else if (bpp != driver->native_bits_per_pixel) {
+ qp_dprintf("Asset's bpp (%d) doesn't match the target display's native_bits_per_pixel (%d)\n", bpp, driver->native_bits_per_pixel);
+ return false;
+ } else {
+ // Set up the output state
+ qp_internal_byte_output_state_t output_state = {.device = device, .byte_write_pos = 0, .max_bytes = qp_internal_num_pixels_in_buffer(device) * driver->native_bits_per_pixel / 8};
+
+ // Stream the raw pixel data to the display
+ uint32_t byte_count = pixel_count * bpp / 8;
+ ret = qp_internal_send_bytes(device, byte_count, input_callback, input_state, qp_internal_byte_appender, &output_state);
+ // Any leftovers need transmission as well.
+ if (ret && output_state.byte_write_pos > 0) {
+ ret &= driver->driver_vtable->pixdata(device, qp_internal_global_pixdata_buffer, output_state.byte_write_pos * 8 / driver->native_bits_per_pixel);
+ }
+ }
+
+ return ret;
+}
+
qp_internal_byte_input_callback qp_internal_prepare_input_state(qp_internal_byte_input_state_t* input_state, painter_compression_t compression) {
switch (compression) {
case IMAGE_UNCOMPRESSED:
diff --git a/quantum/painter/qp_draw_image.c b/quantum/painter/qp_draw_image.c
index 87c59148c2..18fa38cb19 100644
--- a/quantum/painter/qp_draw_image.c
+++ b/quantum/painter/qp_draw_image.c
@@ -263,33 +263,8 @@ static bool qp_drawimage_recolor_impl(painter_device_t device, uint16_t x, uint1
return false;
}
- bool ret = false;
- if (!frame_info->is_panel_native) {
- // Set up the output state
- qp_internal_pixel_output_state_t output_state = {.device = device, .pixel_write_pos = 0, .max_pixels = qp_internal_num_pixels_in_buffer(device)};
-
- // Decode the pixel data and stream to the display
- ret = qp_internal_decode_palette(device, pixel_count, frame_info->bpp, input_callback, &input_state, qp_internal_global_pixel_lookup_table, qp_internal_pixel_appender, &output_state);
- // Any leftovers need transmission as well.
- if (ret && output_state.pixel_write_pos > 0) {
- ret &= driver->driver_vtable->pixdata(device, qp_internal_global_pixdata_buffer, output_state.pixel_write_pos);
- }
- } else if (frame_info->bpp != driver->native_bits_per_pixel) {
- // Prevent stuff like drawing 24bpp images on 16bpp displays
- qp_dprintf("Image's bpp doesn't match the target display's native_bits_per_pixel\n");
- return false;
- } else {
- // Set up the output state
- qp_internal_byte_output_state_t output_state = {.device = device, .byte_write_pos = 0, .max_bytes = qp_internal_num_pixels_in_buffer(device) * driver->native_bits_per_pixel / 8};
-
- // Stream the raw pixel data to the display
- uint32_t byte_count = pixel_count * frame_info->bpp / 8;
- ret = qp_internal_send_bytes(device, byte_count, input_callback, &input_state, qp_internal_byte_appender, &output_state);
- // Any leftovers need transmission as well.
- if (ret && output_state.byte_write_pos > 0) {
- ret &= driver->driver_vtable->pixdata(device, qp_internal_global_pixdata_buffer, output_state.byte_write_pos * 8 / driver->native_bits_per_pixel);
- }
- }
+ // Decode and stream pixels
+ bool ret = qp_internal_appender(device, frame_info->bpp, pixel_count, input_callback, &input_state);
qp_dprintf("qp_drawimage_recolor: %s\n", ret ? "ok" : "fail");
qp_comms_stop(device);
diff --git a/quantum/painter/qp_draw_text.c b/quantum/painter/qp_draw_text.c
index 1ac5cab646..664c89c6e5 100644
--- a/quantum/painter/qp_draw_text.c
+++ b/quantum/painter/qp_draw_text.c
@@ -364,16 +364,9 @@ static inline bool qp_font_code_point_handler_drawglyph(qff_font_handle_t *qff_f
// Move the x-position for the next glyph
state->xpos += width;
- // Decode the pixel data for the glyph
+ // Decode the pixel data for the glyph, and stream it
uint32_t pixel_count = ((uint32_t)width) * height;
- bool ret = qp_internal_decode_palette(state->device, pixel_count, qff_font->bpp, state->input_callback, state->input_state, qp_internal_global_pixel_lookup_table, qp_internal_pixel_appender, state->output_state);
-
- // Any leftovers need transmission as well.
- if (ret && state->output_state->pixel_write_pos > 0) {
- ret &= driver->driver_vtable->pixdata(state->device, qp_internal_global_pixdata_buffer, state->output_state->pixel_write_pos);
- }
-
- return ret;
+ return qp_internal_appender(state->device, qff_font->bpp, pixel_count, state->input_callback, state->input_state);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/quantum/painter/qp_internal.c b/quantum/painter/qp_internal.c
index 0e81467e26..1f0f981796 100644
--- a/quantum/painter/qp_internal.c
+++ b/quantum/painter/qp_internal.c
@@ -11,6 +11,7 @@ enum {
// NOTE: We intentionally do not include surfaces here, despite them conforming to the same API.
QP_NUM_DEVICES = (ILI9163_NUM_DEVICES) // ILI9163
+ (ILI9341_NUM_DEVICES) // ILI9341
+ + (ILI9486_NUM_DEVICES) // ILI9486
+ (ILI9488_NUM_DEVICES) // ILI9488
+ (ST7789_NUM_DEVICES) // ST7789
+ (ST7735_NUM_DEVICES) // ST7735
diff --git a/quantum/painter/rules.mk b/quantum/painter/rules.mk
index ca81cffb03..d991a6d742 100644
--- a/quantum/painter/rules.mk
+++ b/quantum/painter/rules.mk
@@ -9,6 +9,7 @@ VALID_QUANTUM_PAINTER_DRIVERS := \
surface \
ili9163_spi \
ili9341_spi \
+ ili9486_spi \
ili9488_spi \
st7735_spi \
st7789_spi \
@@ -80,6 +81,17 @@ define handle_quantum_painter_driver
$(DRIVER_PATH)/painter/tft_panel/qp_tft_panel.c \
$(DRIVER_PATH)/painter/ili9xxx/qp_ili9341.c \
+ else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),ili9486_spi)
+ QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes
+ QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes
+ OPT_DEFS += -DQUANTUM_PAINTER_ILI9486_ENABLE -DQUANTUM_PAINTER_ILI9486_SPI_ENABLE
+ COMMON_VPATH += \
+ $(DRIVER_PATH)/painter/tft_panel \
+ $(DRIVER_PATH)/painter/ili9xxx
+ SRC += \
+ $(DRIVER_PATH)/painter/tft_panel/qp_tft_panel.c \
+ $(DRIVER_PATH)/painter/ili9xxx/qp_ili9486.c \
+
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),ili9488_spi)
QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes
QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes
diff --git a/quantum/pointing_device/pointing_device.c b/quantum/pointing_device/pointing_device.c
index 17dc701a41..bcced166c0 100644
--- a/quantum/pointing_device/pointing_device.c
+++ b/quantum/pointing_device/pointing_device.c
@@ -149,9 +149,9 @@ __attribute__((weak)) void pointing_device_init(void) {
pointing_device_driver.init();
#ifdef POINTING_DEVICE_MOTION_PIN
# ifdef POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
- setPinInputHigh(POINTING_DEVICE_MOTION_PIN);
+ gpio_set_pin_input_high(POINTING_DEVICE_MOTION_PIN);
# else
- setPinInput(POINTING_DEVICE_MOTION_PIN);
+ gpio_set_pin_input(POINTING_DEVICE_MOTION_PIN);
# endif
#endif
}
@@ -247,18 +247,19 @@ __attribute__((weak)) bool pointing_device_task(void) {
# error POINTING_DEVICE_MOTION_PIN not supported when sharing the pointing device report between sides.
# endif
# ifdef POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
- if (!readPin(POINTING_DEVICE_MOTION_PIN))
+ if (!gpio_read_pin(POINTING_DEVICE_MOTION_PIN))
# else
- if (readPin(POINTING_DEVICE_MOTION_PIN))
+ if (gpio_read_pin(POINTING_DEVICE_MOTION_PIN))
# endif
+ {
#endif
#if defined(SPLIT_POINTING_ENABLE)
# if defined(POINTING_DEVICE_COMBINED)
static uint8_t old_buttons = 0;
- local_mouse_report.buttons = old_buttons;
- local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
- old_buttons = local_mouse_report.buttons;
+ local_mouse_report.buttons = old_buttons;
+ local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
+ old_buttons = local_mouse_report.buttons;
# elif defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT)
local_mouse_report = POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_report(local_mouse_report) : shared_mouse_report;
# else
@@ -268,6 +269,10 @@ __attribute__((weak)) bool pointing_device_task(void) {
local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
#endif // defined(SPLIT_POINTING_ENABLE)
+#ifdef POINTING_DEVICE_MOTION_PIN
+ }
+#endif
+
// allow kb to intercept and modify report
#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED)
if (is_keyboard_left()) {
diff --git a/quantum/pointing_device/pointing_device_auto_mouse.c b/quantum/pointing_device/pointing_device_auto_mouse.c
index 3135b9e531..1b11fffedb 100644
--- a/quantum/pointing_device/pointing_device_auto_mouse.c
+++ b/quantum/pointing_device/pointing_device_auto_mouse.c
@@ -17,6 +17,7 @@
#ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
+# include <stdlib.h>
# include <string.h>
# include "pointing_device_auto_mouse.h"
# include "debug.h"
@@ -217,7 +218,11 @@ void auto_mouse_layer_off(void) {
* @return bool of pointing_device activation
*/
__attribute__((weak)) bool auto_mouse_activation(report_mouse_t mouse_report) {
- return mouse_report.x != 0 || mouse_report.y != 0 || mouse_report.h != 0 || mouse_report.v != 0 || mouse_report.buttons;
+ auto_mouse_context.total_mouse_movement.x += mouse_report.x;
+ auto_mouse_context.total_mouse_movement.y += mouse_report.y;
+ auto_mouse_context.total_mouse_movement.h += mouse_report.h;
+ auto_mouse_context.total_mouse_movement.v += mouse_report.v;
+ return abs(auto_mouse_context.total_mouse_movement.x) > AUTO_MOUSE_THRESHOLD || abs(auto_mouse_context.total_mouse_movement.y) > AUTO_MOUSE_THRESHOLD || abs(auto_mouse_context.total_mouse_movement.h) > AUTO_MOUSE_THRESHOLD || abs(auto_mouse_context.total_mouse_movement.v) > AUTO_MOUSE_THRESHOLD || mouse_report.buttons;
}
/**
@@ -235,14 +240,16 @@ void pointing_device_task_auto_mouse(report_mouse_t mouse_report) {
// update activation and reset debounce
auto_mouse_context.status.is_activated = auto_mouse_activation(mouse_report);
if (is_auto_mouse_active()) {
- auto_mouse_context.timer.active = timer_read();
- auto_mouse_context.timer.delay = 0;
+ auto_mouse_context.total_mouse_movement = (total_mouse_movement_t){.x = 0, .y = 0, .h = 0, .v = 0};
+ auto_mouse_context.timer.active = timer_read();
+ auto_mouse_context.timer.delay = 0;
if (!layer_state_is((AUTO_MOUSE_TARGET_LAYER))) {
layer_on((AUTO_MOUSE_TARGET_LAYER));
}
} else if (layer_state_is((AUTO_MOUSE_TARGET_LAYER)) && timer_elapsed(auto_mouse_context.timer.active) > auto_mouse_context.config.timeout) {
layer_off((AUTO_MOUSE_TARGET_LAYER));
- auto_mouse_context.timer.active = 0;
+ auto_mouse_context.timer.active = 0;
+ auto_mouse_context.total_mouse_movement = (total_mouse_movement_t){.x = 0, .y = 0, .h = 0, .v = 0};
}
}
diff --git a/quantum/pointing_device/pointing_device_auto_mouse.h b/quantum/pointing_device/pointing_device_auto_mouse.h
index 1343855e00..904f18b68e 100644
--- a/quantum/pointing_device/pointing_device_auto_mouse.h
+++ b/quantum/pointing_device/pointing_device_auto_mouse.h
@@ -42,9 +42,18 @@
#ifndef AUTO_MOUSE_DEBOUNCE
# define AUTO_MOUSE_DEBOUNCE 25
#endif
+#ifndef AUTO_MOUSE_THRESHOLD
+# define AUTO_MOUSE_THRESHOLD 10
+#endif
/* data structure */
typedef struct {
+ mouse_xy_report_t x;
+ mouse_xy_report_t y;
+ int8_t v;
+ int8_t h;
+} total_mouse_movement_t;
+typedef struct {
struct {
bool is_enabled;
uint8_t layer;
@@ -60,6 +69,7 @@ typedef struct {
bool is_toggled;
int8_t mouse_key_tracker;
} status;
+ total_mouse_movement_t total_mouse_movement;
} auto_mouse_context_t;
/* ----------Set up and control------------------------------------------------------------------------------ */
diff --git a/quantum/process_keycode/process_caps_word.c b/quantum/process_keycode/process_caps_word.c
index 1088c8f76c..b8fb868c6d 100644
--- a/quantum/process_keycode/process_caps_word.c
+++ b/quantum/process_keycode/process_caps_word.c
@@ -14,6 +14,7 @@
#include "process_caps_word.h"
#include "process_auto_shift.h"
+#include "process_space_cadet.h"
#include "caps_word.h"
#include "keycodes.h"
#include "quantum_keycodes.h"
@@ -110,6 +111,9 @@ bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
# endif // COMMAND_ENABLE
) {
caps_word_on();
+# ifdef SPACE_CADET_ENABLE
+ reset_space_cadet();
+# endif // SPACE_CADET_ENABLE
}
# endif // defined(COMMAND_ENABLE) && !defined(IS_COMMAND)
#endif // BOTH_SHIFTS_TURNS_ON_CAPS_WORD
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c
index 377fcb69e2..5ecd897d16 100644
--- a/quantum/process_keycode/process_midi.c
+++ b/quantum/process_keycode/process_midi.c
@@ -38,7 +38,7 @@ void process_midi_all_notes_off(void) {
#endif // MIDI_BASIC
#ifdef MIDI_ADVANCED
-static uint8_t tone_status[2][MIDI_TONE_COUNT];
+static uint8_t tone_status[MIDI_TONE_COUNT];
static uint8_t midi_modulation;
static int8_t midi_modulation_step;
@@ -57,8 +57,7 @@ void midi_init(void) {
midi_config.modulation_interval = 8;
for (uint8_t i = 0; i < MIDI_TONE_COUNT; i++) {
- tone_status[0][i] = MIDI_INVALID_NOTE;
- tone_status[1][i] = 0;
+ tone_status[i] = MIDI_INVALID_NOTE;
}
midi_modulation = 0;
@@ -77,21 +76,19 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) {
uint8_t tone = keycode - MIDI_TONE_MIN;
uint8_t velocity = midi_config.velocity;
if (record->event.pressed) {
- uint8_t note = midi_compute_note(keycode);
- midi_send_noteon(&midi_device, channel, note, velocity);
- dprintf("midi noteon channel:%d note:%d velocity:%d\n", channel, note, velocity);
- tone_status[1][tone] += 1;
- if (tone_status[0][tone] == MIDI_INVALID_NOTE) {
- tone_status[0][tone] = note;
+ if (tone_status[tone] == MIDI_INVALID_NOTE) {
+ uint8_t note = midi_compute_note(keycode);
+ midi_send_noteon(&midi_device, channel, note, velocity);
+ dprintf("midi noteon channel:%d note:%d velocity:%d\n", channel, note, velocity);
+ tone_status[tone] = note;
}
} else {
- uint8_t note = tone_status[0][tone];
- tone_status[1][tone] -= 1;
- if (tone_status[1][tone] == 0) {
+ uint8_t note = tone_status[tone];
+ if (note != MIDI_INVALID_NOTE) {
midi_send_noteoff(&midi_device, channel, note, velocity);
dprintf("midi noteoff channel:%d note:%d velocity:%d\n", channel, note, velocity);
- tone_status[0][tone] = MIDI_INVALID_NOTE;
}
+ tone_status[tone] = MIDI_INVALID_NOTE;
}
return false;
}
diff --git a/quantum/process_keycode/process_space_cadet.c b/quantum/process_keycode/process_space_cadet.c
index f948ad6238..3e280d57d9 100644
--- a/quantum/process_keycode/process_space_cadet.c
+++ b/quantum/process_keycode/process_space_cadet.c
@@ -157,10 +157,14 @@ bool process_space_cadet(uint16_t keycode, keyrecord_t *record) {
}
default: {
if (record->event.pressed) {
- sc_last = 0;
+ reset_space_cadet();
}
break;
}
}
return true;
}
+
+void reset_space_cadet() {
+ sc_last = 0;
+}
diff --git a/quantum/process_keycode/process_space_cadet.h b/quantum/process_keycode/process_space_cadet.h
index 6d10051532..9d254e26fd 100644
--- a/quantum/process_keycode/process_space_cadet.h
+++ b/quantum/process_keycode/process_space_cadet.h
@@ -21,3 +21,4 @@
void perform_space_cadet(keyrecord_t *record, uint16_t sc_keycode, uint8_t holdMod, uint8_t tapMod, uint8_t keycode);
bool process_space_cadet(uint16_t keycode, keyrecord_t *record);
+void reset_space_cadet(void);
diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c
index bd4361580b..c491d6f1d8 100644
--- a/quantum/process_keycode/process_steno.c
+++ b/quantum/process_keycode/process_steno.c
@@ -128,9 +128,6 @@ static const uint16_t combinedmap_second[] PROGMEM = {STN_S2, STN_KL, STN_WL, ST
#ifdef STENO_ENABLE_ALL
void steno_init(void) {
- if (!eeconfig_is_enabled()) {
- eeconfig_init();
- }
mode = eeprom_read_byte(EECONFIG_STENOMODE);
}
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index b8a8d32f35..ce3b8fc81f 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -133,7 +133,7 @@ bool preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
if (!active_td || keycode == active_td) return false;
- action = &tap_dance_actions[TD_INDEX(active_td)];
+ action = &tap_dance_actions[QK_TAP_DANCE_GET_INDEX(active_td)];
action->state.interrupted = true;
action->state.interrupting_keycode = keycode;
process_tap_dance_action_on_dance_finished(action);
@@ -154,7 +154,7 @@ bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
- action = &tap_dance_actions[TD_INDEX(keycode)];
+ action = &tap_dance_actions[QK_TAP_DANCE_GET_INDEX(keycode)];
action->state.pressed = record->event.pressed;
if (record->event.pressed) {
@@ -182,7 +182,7 @@ void tap_dance_task(void) {
if (!active_td || timer_elapsed(last_tap_time) <= GET_TAPPING_TERM(active_td, &(keyrecord_t){})) return;
- action = &tap_dance_actions[TD_INDEX(active_td)];
+ action = &tap_dance_actions[QK_TAP_DANCE_GET_INDEX(active_td)];
if (!action->state.interrupted) {
process_tap_dance_action_on_dance_finished(action);
}
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index 2b114dabd3..c0137c14a3 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "action.h"
+#include "quantum_keycodes.h"
typedef struct {
uint16_t interrupting_keycode;
@@ -74,8 +75,7 @@ typedef struct {
#define ACTION_TAP_DANCE_FN_ADVANCED_WITH_RELEASE(user_fn_on_each_tap, user_fn_on_each_release, user_fn_on_dance_finished, user_fn_on_dance_reset) \
{ .fn = {user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset, user_fn_on_each_release}, .user_data = NULL, }
-#define TD(n) (QK_TAP_DANCE | TD_INDEX(n))
-#define TD_INDEX(code) ((code)&0xFF)
+#define TD_INDEX(code) QK_TAP_DANCE_GET_INDEX(code)
#define TAP_DANCE_KEYCODE(state) TD(((tap_dance_action_t *)state) - tap_dance_actions)
extern tap_dance_action_t tap_dance_actions[];
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 996e93a12f..5446ab1ad7 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -42,7 +42,6 @@
#include "action_layer.h"
#include "eeconfig.h"
#include "bootloader.h"
-#include "bootmagic.h"
#include "timer.h"
#include "sync_timer.h"
#include "gpio.h"
@@ -59,6 +58,10 @@
#include <stdio.h>
#include <string.h>
+#ifdef BOOTMAGIC_ENABLE
+# include "bootmagic.h"
+#endif
+
#ifdef DEFERRED_EXEC_ENABLE
# include "deferred_exec.h"
#endif
@@ -233,6 +236,10 @@ extern layer_state_t layer_state;
# include "process_repeat_key.h"
#endif
+#ifdef OS_DETECTION_ENABLE
+# include "os_detection.h"
+#endif
+
void set_single_persistent_default_layer(uint8_t default_layer);
#define IS_LAYER_ON(layer) layer_state_is(layer)
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index d3249bd455..882e1d07ae 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -190,6 +190,10 @@
#define SH_T(kc) (QK_SWAP_HANDS | ((kc)&0xFF))
#define QK_SWAP_HANDS_GET_TAP_KEYCODE(kc) ((kc)&0xFF)
+// Tap dance
+#define TD(i) (QK_TAP_DANCE | ((i)&0xFF))
+#define QK_TAP_DANCE_GET_INDEX(kc) ((kc)&0xFF)
+
// MIDI aliases
#define MIDI_TONE_MIN QK_MIDI_NOTE_C_0
#define MIDI_TONE_MAX QK_MIDI_NOTE_B_5
diff --git a/quantum/rgb_matrix/animations/solid_reactive_anim.h b/quantum/rgb_matrix/animations/solid_reactive_anim.h
index edf6041350..e18ffb5f2b 100644
--- a/quantum/rgb_matrix/animations/solid_reactive_anim.h
+++ b/quantum/rgb_matrix/animations/solid_reactive_anim.h
@@ -7,7 +7,7 @@ static HSV SOLID_REACTIVE_math(HSV hsv, uint16_t offset) {
# ifdef RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE
hsv.h = scale16by8(g_rgb_timer, qadd8(rgb_matrix_config.speed, 8) >> 4);
# endif
- hsv.h += qsub8(130, offset);
+ hsv.h += scale8(255 - offset, 64);
return hsv;
}
diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c
index d93d189827..655aca1867 100644
--- a/quantum/rgb_matrix/rgb_matrix.c
+++ b/quantum/rgb_matrix/rgb_matrix.c
@@ -76,9 +76,6 @@ static uint8_t rgb_last_enable = UINT8_MAX;
static uint8_t rgb_last_effect = UINT8_MAX;
static effect_params_t rgb_effect_params = {0, LED_FLAG_ALL, false};
static rgb_task_states rgb_task_state = SYNCING;
-#if RGB_MATRIX_TIMEOUT > 0
-static uint32_t rgb_anykey_timer;
-#endif // RGB_MATRIX_TIMEOUT > 0
// double buffers
static uint32_t rgb_timer_buffer;
@@ -103,7 +100,7 @@ void eeconfig_update_rgb_matrix_default(void) {
rgb_matrix_config.mode = RGB_MATRIX_DEFAULT_MODE;
rgb_matrix_config.hsv = (HSV){RGB_MATRIX_DEFAULT_HUE, RGB_MATRIX_DEFAULT_SAT, RGB_MATRIX_DEFAULT_VAL};
rgb_matrix_config.speed = RGB_MATRIX_DEFAULT_SPD;
- rgb_matrix_config.flags = LED_FLAG_ALL;
+ rgb_matrix_config.flags = RGB_MATRIX_DEFAULT_FLAGS;
eeconfig_flush_rgb_matrix(true);
}
@@ -163,9 +160,6 @@ void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) {
#ifndef RGB_MATRIX_SPLIT
if (!is_keyboard_master()) return;
#endif
-#if RGB_MATRIX_TIMEOUT > 0
- rgb_anykey_timer = 0;
-#endif // RGB_MATRIX_TIMEOUT > 0
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
uint8_t led[LED_HITS_TO_REMEMBER];
@@ -246,18 +240,11 @@ static bool rgb_matrix_none(effect_params_t *params) {
}
static void rgb_task_timers(void) {
-#if defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_MATRIX_TIMEOUT > 0
+#if defined(RGB_MATRIX_KEYREACTIVE_ENABLED)
uint32_t deltaTime = sync_timer_elapsed32(rgb_timer_buffer);
-#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_MATRIX_TIMEOUT > 0
+#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED)
rgb_timer_buffer = sync_timer_read32();
- // Update double buffer timers
-#if RGB_MATRIX_TIMEOUT > 0
- if (rgb_anykey_timer + deltaTime <= UINT32_MAX) {
- rgb_anykey_timer += deltaTime;
- }
-#endif // RGB_MATRIX_TIMEOUT > 0
-
// Update double buffer last hit timers
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
uint8_t count = last_hit_buffer.count;
@@ -370,7 +357,7 @@ void rgb_matrix_task(void) {
// while suspended and just do a software shutdown. This is a cheap hack for now.
bool suspend_backlight = suspend_state ||
#if RGB_MATRIX_TIMEOUT > 0
- (rgb_anykey_timer > (uint32_t)RGB_MATRIX_TIMEOUT) ||
+ (last_input_activity_elapsed() > (uint32_t)RGB_MATRIX_TIMEOUT) ||
#endif // RGB_MATRIX_TIMEOUT > 0
false;
@@ -473,12 +460,6 @@ void rgb_matrix_init(void) {
}
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED
- if (!eeconfig_is_enabled()) {
- dprintf("rgb_matrix_init_drivers eeconfig is not enabled.\n");
- eeconfig_init();
- eeconfig_update_rgb_matrix_default();
- }
-
eeconfig_init_rgb_matrix();
if (!rgb_matrix_config.mode) {
dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n");
@@ -488,7 +469,7 @@ void rgb_matrix_init(void) {
}
void rgb_matrix_set_suspend_state(bool state) {
-#ifdef RGB_DISABLE_WHEN_USB_SUSPENDED
+#ifdef RGB_MATRIX_SLEEP
if (state && !suspend_state) { // only run if turning off, and only once
rgb_task_render(0); // turn off all LEDs when suspending
rgb_task_flush(0); // and actually flash led state to LEDs
diff --git a/quantum/rgb_matrix/rgb_matrix.h b/quantum/rgb_matrix/rgb_matrix.h
index 9a3ffb8ea3..f8a6845e02 100644
--- a/quantum/rgb_matrix/rgb_matrix.h
+++ b/quantum/rgb_matrix/rgb_matrix.h
@@ -21,31 +21,10 @@
#include <stdint.h>
#include <stdbool.h>
#include "rgb_matrix_types.h"
+#include "rgb_matrix_drivers.h"
#include "color.h"
#include "keyboard.h"
-#if defined(RGB_MATRIX_IS31FL3218)
-# include "is31fl3218.h"
-#elif defined(RGB_MATRIX_IS31FL3731)
-# include "is31fl3731.h"
-#elif defined(RGB_MATRIX_IS31FL3733)
-# include "is31fl3733.h"
-#elif defined(RGB_MATRIX_IS31FL3736)
-# include "is31fl3736.h"
-#elif defined(RGB_MATRIX_IS31FL3737)
-# include "is31fl3737.h"
-#elif defined(RGB_MATRIX_IS31FL3741)
-# include "is31fl3741.h"
-#elif defined(IS31FLCOMMON)
-# include "is31flcommon.h"
-#elif defined(RGB_MATRIX_SNLED27351)
-# include "snled27351.h"
-#elif defined(RGB_MATRIX_AW20216S)
-# include "aw20216s.h"
-#elif defined(RGB_MATRIX_WS2812)
-# include "ws2812.h"
-#endif
-
#ifndef RGB_MATRIX_TIMEOUT
# define RGB_MATRIX_TIMEOUT 0
#endif
@@ -99,6 +78,10 @@
# define RGB_MATRIX_DEFAULT_SPD UINT8_MAX / 2
#endif
+#ifndef RGB_MATRIX_DEFAULT_FLAGS
+# define RGB_MATRIX_DEFAULT_FLAGS LED_FLAG_ALL
+#endif
+
#ifndef RGB_MATRIX_LED_FLUSH_LIMIT
# define RGB_MATRIX_LED_FLUSH_LIMIT 16
#endif
@@ -272,17 +255,6 @@ void rgb_matrix_set_flags_noeeprom(led_flags_t flags);
# define rgblight_decrease_speed_noeeprom rgb_matrix_decrease_speed_noeeprom
#endif
-typedef struct {
- /* Perform any initialisation required for the other driver functions to work. */
- void (*init)(void);
- /* Set the colour of a single LED in the buffer. */
- void (*set_color)(int index, uint8_t r, uint8_t g, uint8_t b);
- /* Set the colour of all LEDS on the keyboard in the buffer. */
- void (*set_color_all)(uint8_t r, uint8_t g, uint8_t b);
- /* Flush any buffered changes to the hardware. */
- void (*flush)(void);
-} rgb_matrix_driver_t;
-
static inline bool rgb_matrix_check_finished_leds(uint8_t led_idx) {
#if defined(RGB_MATRIX_SPLIT)
if (is_keyboard_left()) {
@@ -295,8 +267,6 @@ static inline bool rgb_matrix_check_finished_leds(uint8_t led_idx) {
#endif
}
-extern const rgb_matrix_driver_t rgb_matrix_driver;
-
extern rgb_config_t rgb_matrix_config;
extern uint32_t g_rgb_timer;
diff --git a/quantum/rgb_matrix/rgb_matrix_drivers.c b/quantum/rgb_matrix/rgb_matrix_drivers.c
index 0f979cb233..95d1e884f0 100644
--- a/quantum/rgb_matrix/rgb_matrix_drivers.c
+++ b/quantum/rgb_matrix/rgb_matrix_drivers.c
@@ -14,7 +14,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "rgb_matrix.h"
+#include "rgb_matrix_drivers.h"
+
+#include <stdbool.h>
+#include "keyboard.h"
+#include "color.h"
#include "util.h"
/* Each driver needs to define the struct
@@ -32,6 +36,14 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
.set_color_all = is31fl3218_set_color_all,
};
+#elif defined(RGB_MATRIX_IS31FL3729)
+const rgb_matrix_driver_t rgb_matrix_driver = {
+ .init = is31fl3729_init_drivers,
+ .flush = is31fl3729_flush,
+ .set_color = is31fl3729_set_color,
+ .set_color_all = is31fl3729_set_color_all,
+};
+
#elif defined(RGB_MATRIX_IS31FL3731)
const rgb_matrix_driver_t rgb_matrix_driver = {
.init = is31fl3731_init_drivers,
@@ -72,12 +84,36 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
.set_color_all = is31fl3741_set_color_all,
};
-#elif defined(IS31FLCOMMON)
+#elif defined(RGB_MATRIX_IS31FL3742A)
+const rgb_matrix_driver_t rgb_matrix_driver = {
+ .init = is31fl3742a_init_drivers,
+ .flush = is31fl3742a_flush,
+ .set_color = is31fl3742a_set_color,
+ .set_color_all = is31fl3742a_set_color_all,
+};
+
+#elif defined(RGB_MATRIX_IS31FL3743A)
+const rgb_matrix_driver_t rgb_matrix_driver = {
+ .init = is31fl3743a_init_drivers,
+ .flush = is31fl3743a_flush,
+ .set_color = is31fl3743a_set_color,
+ .set_color_all = is31fl3743a_set_color_all,
+};
+
+#elif defined(RGB_MATRIX_IS31FL3745)
+const rgb_matrix_driver_t rgb_matrix_driver = {
+ .init = is31fl3745_init_drivers,
+ .flush = is31fl3745_flush,
+ .set_color = is31fl3745_set_color,
+ .set_color_all = is31fl3745_set_color_all,
+};
+
+#elif defined(RGB_MATRIX_IS31FL3746A)
const rgb_matrix_driver_t rgb_matrix_driver = {
- .init = IS31FL_RGB_init_drivers,
- .flush = IS31FL_common_flush,
- .set_color = IS31FL_RGB_set_color,
- .set_color_all = IS31FL_RGB_set_color_all,
+ .init = is31fl3746a_init_drivers,
+ .flush = is31fl3746a_flush,
+ .set_color = is31fl3746a_set_color,
+ .set_color_all = is31fl3746a_set_color_all,
};
#elif defined(RGB_MATRIX_SNLED27351)
@@ -103,7 +139,7 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
# endif
// LED color buffer
-rgb_led_t rgb_matrix_ws2812_array[RGB_MATRIX_LED_COUNT];
+rgb_led_t rgb_matrix_ws2812_array[WS2812_LED_COUNT];
bool ws2812_dirty = false;
static void init(void) {
@@ -112,7 +148,7 @@ static void init(void) {
static void flush(void) {
if (ws2812_dirty) {
- ws2812_setleds(rgb_matrix_ws2812_array, RGB_MATRIX_LED_COUNT);
+ ws2812_setleds(rgb_matrix_ws2812_array, WS2812_LED_COUNT);
ws2812_dirty = false;
}
}
diff --git a/quantum/rgb_matrix/rgb_matrix_drivers.h b/quantum/rgb_matrix/rgb_matrix_drivers.h
new file mode 100644
index 0000000000..a24cb03a18
--- /dev/null
+++ b/quantum/rgb_matrix/rgb_matrix_drivers.h
@@ -0,0 +1,49 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined(RGB_MATRIX_AW20216S)
+# include "aw20216s.h"
+#elif defined(RGB_MATRIX_IS31FL3218)
+# include "is31fl3218.h"
+#elif defined(RGB_MATRIX_IS31FL3729)
+# include "is31fl3729.h"
+#elif defined(RGB_MATRIX_IS31FL3731)
+# include "is31fl3731.h"
+#elif defined(RGB_MATRIX_IS31FL3733)
+# include "is31fl3733.h"
+#elif defined(RGB_MATRIX_IS31FL3736)
+# include "is31fl3736.h"
+#elif defined(RGB_MATRIX_IS31FL3737)
+# include "is31fl3737.h"
+#elif defined(RGB_MATRIX_IS31FL3741)
+# include "is31fl3741.h"
+#elif defined(RGB_MATRIX_IS31FL3742A)
+# include "is31fl3742a.h"
+#elif defined(RGB_MATRIX_IS31FL3743A)
+# include "is31fl3743a.h"
+#elif defined(RGB_MATRIX_IS31FL3745)
+# include "is31fl3745.h"
+#elif defined(RGB_MATRIX_IS31FL3746A)
+# include "is31fl3746a.h"
+#elif defined(RGB_MATRIX_SNLED27351)
+# include "snled27351.h"
+#elif defined(RGB_MATRIX_WS2812)
+# include "ws2812.h"
+#endif
+
+typedef struct {
+ /* Perform any initialisation required for the other driver functions to work. */
+ void (*init)(void);
+ /* Set the colour of a single LED in the buffer. */
+ void (*set_color)(int index, uint8_t r, uint8_t g, uint8_t b);
+ /* Set the colour of all LEDS on the keyboard in the buffer. */
+ void (*set_color_all)(uint8_t r, uint8_t g, uint8_t b);
+ /* Flush any buffered changes to the hardware. */
+ void (*flush)(void);
+} rgb_matrix_driver_t;
+
+extern const rgb_matrix_driver_t rgb_matrix_driver;
diff --git a/quantum/rgblight/rgblight.c b/quantum/rgblight/rgblight.c
index 8ac886d441..530cb04688 100644
--- a/quantum/rgblight/rgblight.c
+++ b/quantum/rgblight/rgblight.c
@@ -116,7 +116,7 @@ animation_status_t animation_status = {};
#endif
#ifndef LED_ARRAY
-rgb_led_t led[RGBLED_NUM];
+rgb_led_t led[RGBLIGHT_LED_COUNT];
# define LED_ARRAY led
#endif
@@ -126,7 +126,7 @@ rgblight_segment_t const *const *rgblight_layers = NULL;
static bool deferred_set_layer_state = false;
#endif
-rgblight_ranges_t rgblight_ranges = {0, RGBLED_NUM, 0, RGBLED_NUM, RGBLED_NUM};
+rgblight_ranges_t rgblight_ranges = {0, RGBLIGHT_LED_COUNT, 0, RGBLIGHT_LED_COUNT, RGBLIGHT_LED_COUNT};
void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) {
rgblight_ranges.clipping_start_pos = start_pos;
@@ -134,8 +134,8 @@ void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) {
}
void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) {
- if (start_pos >= RGBLED_NUM) return;
- if (start_pos + num_leds > RGBLED_NUM) return;
+ if (start_pos >= RGBLIGHT_LED_COUNT) return;
+ if (start_pos + num_leds > RGBLIGHT_LED_COUNT) return;
rgblight_ranges.effect_start_pos = start_pos;
rgblight_ranges.effect_end_pos = start_pos + num_leds;
rgblight_ranges.effect_num_leds = num_leds;
@@ -229,13 +229,7 @@ void rgblight_init(void) {
return;
}
- dprintf("rgblight_init called.\n");
dprintf("rgblight_init start!\n");
- if (!eeconfig_is_enabled()) {
- dprintf("rgblight_init eeconfig is not enabled.\n");
- eeconfig_init();
- eeconfig_update_rgblight_default();
- }
rgblight_config.raw = eeconfig_read_rgblight();
RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
if (!rgblight_config.mode) {
@@ -664,7 +658,7 @@ void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
}
void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
- if (!rgblight_config.enable || index >= RGBLED_NUM) {
+ if (!rgblight_config.enable || index >= RGBLIGHT_LED_COUNT) {
return;
}
@@ -700,7 +694,7 @@ static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_
#endif
void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end) {
- if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLED_NUM) {
+ if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLIGHT_LED_COUNT) {
return;
}
@@ -727,19 +721,19 @@ void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start,
#ifndef RGBLIGHT_SPLIT
void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) {
- rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLED_NUM / 2);
+ rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLIGHT_LED_COUNT / 2);
}
void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) {
- rgblight_setrgb_range(r, g, b, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM);
+ rgblight_setrgb_range(r, g, b, (uint8_t)RGBLIGHT_LED_COUNT / 2, (uint8_t)RGBLIGHT_LED_COUNT);
}
void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) {
- rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLED_NUM / 2);
+ rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLIGHT_LED_COUNT / 2);
}
void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) {
- rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM);
+ rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLIGHT_LED_COUNT / 2, (uint8_t)RGBLIGHT_LED_COUNT);
}
#endif // ifndef RGBLIGHT_SPLIT
@@ -789,7 +783,7 @@ static void rgblight_layers_write(void) {
break; // No more segments
}
// Write segment.count LEDs
- rgb_led_t *const limit = &led[MIN(segment.index + segment.count, RGBLED_NUM)];
+ rgb_led_t *const limit = &led[MIN(segment.index + segment.count, RGBLIGHT_LED_COUNT)];
for (rgb_led_t *led_ptr = &led[segment.index]; led_ptr < limit; led_ptr++) {
# ifdef RGBLIGHT_LAYERS_RETAIN_VAL
sethsv(segment.hue, segment.sat, current_val, led_ptr);
@@ -900,12 +894,6 @@ void rgblight_wakeup(void) {
#endif
-__attribute__((weak)) void rgblight_call_driver(rgb_led_t *start_led, uint8_t num_leds) {
- ws2812_setleds(start_led, num_leds);
-}
-
-#ifndef RGBLIGHT_CUSTOM
-
void rgblight_set(void) {
rgb_led_t *start_led;
uint8_t num_leds = rgblight_ranges.clipping_num_leds;
@@ -915,42 +903,41 @@ void rgblight_set(void) {
led[i].r = 0;
led[i].g = 0;
led[i].b = 0;
-# ifdef RGBW
+#ifdef RGBW
led[i].w = 0;
-# endif
+#endif
}
}
-# ifdef RGBLIGHT_LAYERS
+#ifdef RGBLIGHT_LAYERS
if (rgblight_layers != NULL
-# if !defined(RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF)
+# if !defined(RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF)
&& rgblight_config.enable
-# elif defined(RGBLIGHT_SLEEP)
+# elif defined(RGBLIGHT_SLEEP)
&& !is_suspended
-# endif
+# endif
) {
rgblight_layers_write();
}
-# endif
+#endif
-# ifdef RGBLIGHT_LED_MAP
- rgb_led_t led0[RGBLED_NUM];
- for (uint8_t i = 0; i < RGBLED_NUM; i++) {
+#ifdef RGBLIGHT_LED_MAP
+ rgb_led_t led0[RGBLIGHT_LED_COUNT];
+ for (uint8_t i = 0; i < RGBLIGHT_LED_COUNT; i++) {
led0[i] = led[pgm_read_byte(&led_map[i])];
}
start_led = led0 + rgblight_ranges.clipping_start_pos;
-# else
+#else
start_led = led + rgblight_ranges.clipping_start_pos;
-# endif
+#endif
-# ifdef RGBW
+#ifdef RGBW
for (uint8_t i = 0; i < num_leds; i++) {
convert_rgb_to_rgbw(&start_led[i]);
}
-# endif
- rgblight_call_driver(start_led, num_leds);
-}
#endif
+ rgblight_driver.setleds(start_led, num_leds);
+}
#ifdef RGBLIGHT_SPLIT
/* for split keyboard master side */
@@ -1279,8 +1266,8 @@ void rgblight_effect_snake(animation_status_t *anim) {
# endif
for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
k = pos + j * increment;
- if (k > RGBLED_NUM) {
- k = k % (RGBLED_NUM);
+ if (k > RGBLIGHT_LED_COUNT) {
+ k = k % (RGBLIGHT_LED_COUNT);
}
if (k < 0) {
k = k + rgblight_ranges.effect_num_leds;
@@ -1465,7 +1452,7 @@ typedef struct PACKED {
uint8_t max_life;
} TwinkleState;
-static TwinkleState led_twinkle_state[RGBLED_NUM];
+static TwinkleState led_twinkle_state[RGBLIGHT_LED_COUNT];
void rgblight_effect_twinkle(animation_status_t *anim) {
const bool random_color = anim->delta / 3;
diff --git a/quantum/rgblight/rgblight.h b/quantum/rgblight/rgblight.h
index a222ab6b9f..9e2b073776 100644
--- a/quantum/rgblight/rgblight.h
+++ b/quantum/rgblight/rgblight.h
@@ -16,6 +16,12 @@
#pragma once
+// DEPRECATED DEFINES - DO NOT USE
+#if defined(RGBLED_NUM)
+# define RGBLIGHT_LED_COUNT RGBLED_NUM
+#endif
+// ========
+
/***** rgblight_mode(mode)/rgblight_mode_noeeprom(mode) ****
old mode number (before 0.6.117) to new mode name table
@@ -160,6 +166,7 @@ enum RGBLIGHT_EFFECT_MODE {
#include <stdint.h>
#include <stdbool.h>
+#include "rgblight_drivers.h"
#include "progmem.h"
#include "eeconfig.h"
#include "ws2812.h"
@@ -233,7 +240,7 @@ void rgblight_unblink_all_but_layer(uint8_t layer);
#endif
-extern rgb_led_t led[RGBLED_NUM];
+extern rgb_led_t led[RGBLIGHT_LED_COUNT];
extern const uint8_t RGBLED_BREATHING_INTERVALS[4] PROGMEM;
extern const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[3] PROGMEM;
diff --git a/quantum/rgblight/rgblight_drivers.c b/quantum/rgblight/rgblight_drivers.c
new file mode 100644
index 0000000000..45b60e1a5f
--- /dev/null
+++ b/quantum/rgblight/rgblight_drivers.c
@@ -0,0 +1,20 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "rgblight_drivers.h"
+
+#if defined(RGBLIGHT_WS2812)
+# include "ws2812.h"
+
+const rgblight_driver_t rgblight_driver = {
+ .setleds = ws2812_setleds,
+};
+
+#elif defined(RGBLIGHT_APA102)
+# include "apa102.h"
+
+const rgblight_driver_t rgblight_driver = {
+ .setleds = apa102_setleds,
+};
+
+#endif
diff --git a/quantum/rgblight/rgblight_drivers.h b/quantum/rgblight/rgblight_drivers.h
new file mode 100644
index 0000000000..f7125a6f3d
--- /dev/null
+++ b/quantum/rgblight/rgblight_drivers.h
@@ -0,0 +1,13 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <stdint.h>
+#include "color.h"
+
+typedef struct {
+ void (*setleds)(rgb_led_t *ledarray, uint16_t number_of_leds);
+} rgblight_driver_t;
+
+extern const rgblight_driver_t rgblight_driver;
diff --git a/quantum/send_string/send_string.c b/quantum/send_string/send_string.c
index 820fc25163..8b59c19219 100644
--- a/quantum/send_string/send_string.c
+++ b/quantum/send_string/send_string.c
@@ -147,7 +147,7 @@ __attribute__((weak)) const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
#define PGM_LOADBIT(mem, pos) ((pgm_read_byte(&((mem)[(pos) / 8])) >> ((pos) % 8)) & 0x01)
void send_string(const char *string) {
- send_string_with_delay(string, 0);
+ send_string_with_delay(string, TAP_CODE_DELAY);
}
void send_string_with_delay(const char *string, uint8_t interval) {
@@ -156,6 +156,7 @@ void send_string_with_delay(const char *string, uint8_t interval) {
if (!ascii_code) break;
if (ascii_code == SS_QMK_PREFIX) {
ascii_code = *(++string);
+
if (ascii_code == SS_TAP_CODE) {
// tap
uint8_t keycode = *(++string);
@@ -172,28 +173,30 @@ void send_string_with_delay(const char *string, uint8_t interval) {
// delay
int ms = 0;
uint8_t keycode = *(++string);
+
while (isdigit(keycode)) {
ms *= 10;
ms += keycode - '0';
keycode = *(++string);
}
- while (ms--)
- wait_ms(1);
+
+ wait_ms(ms);
}
+
+ wait_ms(interval);
} else {
- send_char(ascii_code);
+ send_char_with_delay(ascii_code, interval);
}
+
++string;
- // interval
- {
- uint8_t ms = interval;
- while (ms--)
- wait_ms(1);
- }
}
}
void send_char(char ascii_code) {
+ send_char_with_delay(ascii_code, TAP_CODE_DELAY);
+}
+
+void send_char_with_delay(char ascii_code, uint8_t interval) {
#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL)
if (ascii_code == '\a') { // BEL
PLAY_SONG(bell_song);
@@ -208,19 +211,30 @@ void send_char(char ascii_code) {
if (is_shifted) {
register_code(KC_LEFT_SHIFT);
+ wait_ms(interval);
}
+
if (is_altgred) {
register_code(KC_RIGHT_ALT);
+ wait_ms(interval);
}
- tap_code(keycode);
+
+ tap_code_delay(keycode, interval);
+ wait_ms(interval);
+
if (is_altgred) {
unregister_code(KC_RIGHT_ALT);
+ wait_ms(interval);
}
+
if (is_shifted) {
unregister_code(KC_LEFT_SHIFT);
+ wait_ms(interval);
}
+
if (is_dead) {
tap_code(KC_SPACE);
+ wait_ms(interval);
}
}
diff --git a/quantum/send_string/send_string.h b/quantum/send_string/send_string.h
index dbaed43ebc..f727ec507d 100644
--- a/quantum/send_string/send_string.h
+++ b/quantum/send_string/send_string.h
@@ -49,7 +49,7 @@ extern const uint8_t ascii_to_keycode_lut[128];
/**
* \brief Type out a string of ASCII characters.
*
- * This function simply calls `send_string_with_delay(string, 0)`.
+ * This function simply calls `send_string_with_delay(string, TAP_CODE_DELAY)`.
*
* Most keycodes from the basic keycode range are also supported by way of a special sequence - see `send_string_keycodes.h`.
*
@@ -61,18 +61,28 @@ void send_string(const char *string);
* \brief Type out a string of ASCII characters, with a delay between each character.
*
* \param string The string to type out.
- * \param interval The amount of time, in milliseconds, to wait before typing the next character.
+ * \param interval The amount of time, in milliseconds, to wait before typing the next character. Note this can be set to 0 to ensure no delay, regardless of what TAP_CODE_DELAY is set to.
*/
void send_string_with_delay(const char *string, uint8_t interval);
/**
* \brief Type out an ASCII character.
*
+ * This function simply calls `send_char_with_delay(string, TAP_CODE_DELAY)`.
+ *
* \param ascii_code The character to type.
*/
void send_char(char ascii_code);
/**
+ * \brief Type out an ASCII character, with a delay between any modifiers.
+ *
+ * \param ascii_code The character to type.
+ * \param interval The amount of time, in milliseconds, to wait in between key presses. Note this can be set to 0 to ensure no delay, regardless of what TAP_CODE_DELAY is set to.
+ */
+void send_char_with_delay(char ascii_code, uint8_t interval);
+
+/**
* \brief Type out an eight digit (unsigned 32-bit) hexadecimal value.
*
* The format is `[0-9a-f]{8}`, eg. `00000000` through `ffffffff`.
diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c
index 874339361d..96f19bfd84 100644
--- a/quantum/split_common/split_util.c
+++ b/quantum/split_common/split_util.c
@@ -123,14 +123,14 @@ void split_watchdog_task(void) {
void matrix_io_delay(void);
static uint8_t peek_matrix_intersection(pin_t out_pin, pin_t in_pin) {
- setPinInputHigh(in_pin);
- setPinOutput(out_pin);
- writePinLow(out_pin);
+ gpio_set_pin_input_high(in_pin);
+ gpio_set_pin_output(out_pin);
+ gpio_write_pin_low(out_pin);
// It's almost unnecessary, but wait until it's down to low, just in case.
wait_us(1);
- uint8_t pin_state = readPin(in_pin);
+ uint8_t pin_state = gpio_read_pin(in_pin);
// Set out_pin to a setting that is less susceptible to noise.
- setPinInputHigh(out_pin);
+ gpio_set_pin_input_high(out_pin);
matrix_io_delay(); // Wait for the pull-up to go HIGH.
return pin_state;
}
@@ -138,19 +138,19 @@ static uint8_t peek_matrix_intersection(pin_t out_pin, pin_t in_pin) {
__attribute__((weak)) bool is_keyboard_left_impl(void) {
#if defined(SPLIT_HAND_PIN)
- setPinInput(SPLIT_HAND_PIN);
+ gpio_set_pin_input(SPLIT_HAND_PIN);
wait_us(100);
// Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand
# ifdef SPLIT_HAND_PIN_LOW_IS_LEFT
- return !readPin(SPLIT_HAND_PIN);
+ return !gpio_read_pin(SPLIT_HAND_PIN);
# else
- return readPin(SPLIT_HAND_PIN);
+ return gpio_read_pin(SPLIT_HAND_PIN);
# endif
#elif defined(SPLIT_HAND_MATRIX_GRID)
-# ifdef SPLIT_HAND_MATRIX_GRID_LOW_IS_RIGHT
- return peek_matrix_intersection(SPLIT_HAND_MATRIX_GRID);
-# else
+# ifdef SPLIT_HAND_MATRIX_GRID_LOW_IS_LEFT
return !peek_matrix_intersection(SPLIT_HAND_MATRIX_GRID);
+# else
+ return peek_matrix_intersection(SPLIT_HAND_MATRIX_GRID);
# endif
#elif defined(EE_HANDS)
if (!eeconfig_is_enabled()) {
diff --git a/quantum/split_common/transaction_id_define.h b/quantum/split_common/transaction_id_define.h
index 4d4d2b9570..05b3bf7b62 100644
--- a/quantum/split_common/transaction_id_define.h
+++ b/quantum/split_common/transaction_id_define.h
@@ -31,6 +31,7 @@ enum serial_transaction_id {
#ifdef ENCODER_ENABLE
GET_ENCODERS_CHECKSUM,
GET_ENCODERS_DATA,
+ PUT_ENCODER_TAIL,
#endif // ENCODER_ENABLE
#ifndef DISABLE_SYNC_TIMER
diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c
index 2b9423cd63..2cfa83e7a3 100644
--- a/quantum/split_common/transactions.c
+++ b/quantum/split_common/transactions.c
@@ -234,21 +234,28 @@ static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_ro
#ifdef ENCODER_ENABLE
static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
- static uint32_t last_update = 0;
- uint8_t temp_state[NUM_ENCODERS_MAX_PER_SIDE];
+ static uint32_t last_update = 0;
+ encoder_events_t temp_events;
- bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, temp_state, split_shmem->encoders.state, sizeof(temp_state));
- if (okay) encoder_update_raw(temp_state);
+ bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, &temp_events, &split_shmem->encoders.events, sizeof(temp_events));
+ if (okay) {
+ encoder_handle_slave_events(&split_shmem->encoders.events);
+ transport_write(PUT_ENCODER_TAIL, &split_shmem->encoders.events.tail, sizeof(split_shmem->encoders.events.tail));
+ split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events));
+ }
return okay;
}
static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
- uint8_t encoder_state[NUM_ENCODERS_MAX_PER_SIDE];
- encoder_state_raw(encoder_state);
// Always prepare the encoder state for read.
- memcpy(split_shmem->encoders.state, encoder_state, sizeof(encoder_state));
+ encoder_retrieve_events(&split_shmem->encoders.events);
// Now update the checksum given that the encoders has been written to
- split_shmem->encoders.checksum = crc8(encoder_state, sizeof(encoder_state));
+ split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events));
+}
+
+static void encoder_handlers_slave_reset(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
+ uint8_t tail_index = *(uint8_t *)initiator2target_buffer;
+ encoder_set_tail_index(tail_index);
}
// clang-format off
@@ -256,7 +263,8 @@ static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sl
# define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(encoder)
# define TRANSACTIONS_ENCODERS_REGISTRATIONS \
[GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \
- [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.state),
+ [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.events), \
+ [PUT_ENCODER_TAIL] = trans_initiator2target_initializer_cb(encoders.events.tail, encoder_handlers_slave_reset),
// clang-format on
#else // ENCODER_ENABLE
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index aade3c98d7..83edc34859 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -56,7 +56,7 @@ i2c_status_t transport_trigger_callback(int8_t id) {
// Kick off the "callback executor", now that data has been written to the slave
split_shmem->transaction_id = id;
split_transaction_desc_t *trans = &split_transaction_table[I2C_EXECUTE_CALLBACK];
- return i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, SLAVE_I2C_TIMEOUT);
+ return i2c_write_register(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, SLAVE_I2C_TIMEOUT);
}
bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
@@ -65,7 +65,7 @@ bool transport_execute_transaction(int8_t id, const void *initiator2target_buf,
if (initiator2target_length > 0) {
size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length;
memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len);
- if ((status = i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
+ if ((status = i2c_write_register(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
return false;
}
}
@@ -77,7 +77,7 @@ bool transport_execute_transaction(int8_t id, const void *initiator2target_buf,
if (target2initiator_length > 0) {
size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length;
- if ((status = i2c_readReg(SLAVE_I2C_ADDRESS, trans->target2initiator_offset, split_trans_target2initiator_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
+ if ((status = i2c_read_register(SLAVE_I2C_ADDRESS, trans->target2initiator_offset, split_trans_target2initiator_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
return false;
}
memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len);
diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h
index 2e2b918d45..4f6b968fa8 100644
--- a/quantum/split_common/transport.h
+++ b/quantum/split_common/transport.h
@@ -65,8 +65,8 @@ typedef struct _split_master_matrix_sync_t {
#ifdef ENCODER_ENABLE
typedef struct _split_slave_encoder_sync_t {
- uint8_t checksum;
- uint8_t state[NUM_ENCODERS_MAX_PER_SIDE];
+ uint8_t checksum;
+ encoder_events_t events;
} split_slave_encoder_sync_t;
#endif // ENCODER_ENABLE