diff options
Diffstat (limited to 'quantum')
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 |