From 854547330704fb1b1f07d547d49728da8b92b2a3 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Tue, 31 May 2022 15:38:08 +1000 Subject: Removes terminal from QMK. (#17258) --- quantum/process_keycode/process_terminal.c | 330 ------------------------- quantum/process_keycode/process_terminal.h | 24 -- quantum/process_keycode/process_terminal_nop.h | 22 -- quantum/quantum.c | 3 - quantum/quantum.h | 6 - quantum/quantum_keycodes.h | 6 +- quantum/quantum_keycodes_legacy.h | 3 + 7 files changed, 6 insertions(+), 388 deletions(-) delete mode 100644 quantum/process_keycode/process_terminal.c delete mode 100644 quantum/process_keycode/process_terminal.h delete mode 100644 quantum/process_keycode/process_terminal_nop.h (limited to 'quantum') diff --git a/quantum/process_keycode/process_terminal.c b/quantum/process_keycode/process_terminal.c deleted file mode 100644 index da1c4d506f..0000000000 --- a/quantum/process_keycode/process_terminal.c +++ /dev/null @@ -1,330 +0,0 @@ -/* Copyright 2017 Jack Humbert - * - * 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 . - */ - -#include "process_terminal.h" -#include -#include "version.h" -#include -#include - -#ifndef CMD_BUFF_SIZE -# define CMD_BUFF_SIZE 5 -#endif - -bool terminal_enabled = false; -char buffer[80] = ""; -char cmd_buffer[CMD_BUFF_SIZE][80]; -bool cmd_buffer_enabled = true; // replace with ifdef? -char newline[2] = "\n"; -char arguments[6][20]; -bool firstTime = true; - -short int current_cmd_buffer_pos = 0; // used for up/down arrows - keeps track of where you are in the command buffer - -__attribute__((weak)) const char terminal_prompt[8] = "> "; - -#ifdef AUDIO_ENABLE -# ifndef TERMINAL_SONG -# define TERMINAL_SONG SONG(TERMINAL_SOUND) -# endif -float terminal_song[][2] = TERMINAL_SONG; -# define TERMINAL_BELL() PLAY_SONG(terminal_song) -#else -# define TERMINAL_BELL() -#endif - -__attribute__((weak)) const char keycode_to_ascii_lut[58] = {0, 0, 0, 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 0, 0, 0, '\t', ' ', '-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', '.', '/'}; - -__attribute__((weak)) const char shifted_keycode_to_ascii_lut[58] = {0, 0, 0, 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', 0, 0, 0, '\t', ' ', '_', '+', '{', '}', '|', 0, ':', '\'', '~', '<', '>', '?'}; - -struct stringcase { - char *string; - void (*func)(void); -} typedef stringcase; - -void enable_terminal(void) { - terminal_enabled = true; - strcpy(buffer, ""); - memset(cmd_buffer, 0, CMD_BUFF_SIZE * 80); - for (int i = 0; i < 6; i++) - strcpy(arguments[i], ""); - // select all text to start over - // SEND_STRING(SS_LCTL("a")); - send_string(terminal_prompt); -} - -void disable_terminal(void) { - terminal_enabled = false; - SEND_STRING("\n"); -} - -void push_to_cmd_buffer(void) { - if (cmd_buffer_enabled) { - if (cmd_buffer == NULL) { - return; - } else { - if (firstTime) { - firstTime = false; - strcpy(cmd_buffer[0], buffer); - return; - } - - for (int i = CMD_BUFF_SIZE - 1; i > 0; --i) { - strncpy(cmd_buffer[i], cmd_buffer[i - 1], 80); - } - - strcpy(cmd_buffer[0], buffer); - - return; - } - } -} - -void terminal_about(void) { - SEND_STRING("QMK Firmware\n"); - SEND_STRING(" v"); - SEND_STRING(QMK_VERSION); - SEND_STRING("\n" SS_TAP(X_HOME) " Built: "); - SEND_STRING(QMK_BUILDDATE); - send_string(newline); -#ifdef TERMINAL_HELP - if (strlen(arguments[1]) != 0) { - SEND_STRING("You entered: "); - send_string(arguments[1]); - send_string(newline); - } -#endif -} - -void terminal_help(void); - -extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; - -void terminal_keycode(void) { - if (strlen(arguments[1]) != 0 && strlen(arguments[2]) != 0 && strlen(arguments[3]) != 0) { - char keycode_dec[5]; - char keycode_hex[5]; - uint16_t layer = strtol(arguments[1], (char **)NULL, 10); - uint16_t row = strtol(arguments[2], (char **)NULL, 10); - uint16_t col = strtol(arguments[3], (char **)NULL, 10); - uint16_t keycode = pgm_read_word(&keymaps[layer][row][col]); - itoa(keycode, keycode_dec, 10); - itoa(keycode, keycode_hex, 16); - SEND_STRING("0x"); - send_string(keycode_hex); - SEND_STRING(" ("); - send_string(keycode_dec); - SEND_STRING(")\n"); - } else { -#ifdef TERMINAL_HELP - SEND_STRING("usage: keycode \n"); -#endif - } -} - -void terminal_keymap(void) { - if (strlen(arguments[1]) != 0) { - uint16_t layer = strtol(arguments[1], (char **)NULL, 10); - for (int r = 0; r < MATRIX_ROWS; r++) { - for (int c = 0; c < MATRIX_COLS; c++) { - uint16_t keycode = pgm_read_word(&keymaps[layer][r][c]); - char keycode_s[8]; - sprintf(keycode_s, "0x%04x,", keycode); - send_string(keycode_s); - } - send_string(newline); - } - } else { -#ifdef TERMINAL_HELP - SEND_STRING("usage: keymap \n"); -#endif - } -} - -void print_cmd_buff(void) { - /* without the below wait, a race condition can occur wherein the - buffer can be printed before it has been fully moved */ - wait_ms(250); - for (int i = 0; i < CMD_BUFF_SIZE; i++) { - char tmpChar = ' '; - itoa(i, &tmpChar, 10); - const char *tmpCnstCharStr = &tmpChar; // because sned_string wont take a normal char * - send_string(tmpCnstCharStr); - SEND_STRING(". "); - send_string(cmd_buffer[i]); - SEND_STRING("\n"); - } -} - -void flush_cmd_buffer(void) { - memset(cmd_buffer, 0, CMD_BUFF_SIZE * 80); - SEND_STRING("Buffer Cleared!\n"); -} - -stringcase terminal_cases[] = {{"about", terminal_about}, {"help", terminal_help}, {"keycode", terminal_keycode}, {"keymap", terminal_keymap}, {"flush-buffer", flush_cmd_buffer}, {"print-buffer", print_cmd_buff}, {"exit", disable_terminal}}; - -void terminal_help(void) { - SEND_STRING("commands available:\n "); - for (stringcase *case_p = terminal_cases; case_p != terminal_cases + sizeof(terminal_cases) / sizeof(terminal_cases[0]); case_p++) { - send_string(case_p->string); - SEND_STRING(" "); - } - send_string(newline); -} - -void command_not_found(void) { - wait_ms(50); // sometimes buffer isnt grabbed quick enough - SEND_STRING("command \""); - send_string(buffer); - SEND_STRING("\" not found\n"); -} - -void process_terminal_command(void) { - // we capture return bc of the order of events, so we need to manually send a newline - send_string(newline); - - char * pch; - uint8_t i = 0; - pch = strtok(buffer, " "); - while (pch != NULL) { - strcpy(arguments[i], pch); - pch = strtok(NULL, " "); - i++; - } - - bool command_found = false; - for (stringcase *case_p = terminal_cases; case_p != terminal_cases + sizeof(terminal_cases) / sizeof(terminal_cases[0]); case_p++) { - if (0 == strcmp(case_p->string, buffer)) { - command_found = true; - (*case_p->func)(); - break; - } - } - - if (!command_found) command_not_found(); - - if (terminal_enabled) { - strcpy(buffer, ""); - for (int i = 0; i < 6; i++) - strcpy(arguments[i], ""); - SEND_STRING(SS_TAP(X_HOME)); - send_string(terminal_prompt); - } -} -void check_pos(void) { - if (current_cmd_buffer_pos >= CMD_BUFF_SIZE) { // if over the top, move it back down to the top of the buffer so you can climb back down... - current_cmd_buffer_pos = CMD_BUFF_SIZE - 1; - } else if (current_cmd_buffer_pos < 0) { //...and if you fall under the bottom of the buffer, reset back to 0 so you can climb back up - current_cmd_buffer_pos = 0; - } -} - -bool process_terminal(uint16_t keycode, keyrecord_t *record) { - if (keycode == TERM_ON && record->event.pressed) { - enable_terminal(); - return false; - } - - if (terminal_enabled && record->event.pressed) { - if (keycode == TERM_OFF && record->event.pressed) { - disable_terminal(); - return false; - } - - if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) { - keycode = keycode & 0xFF; - } - - if (keycode < 256) { - uint8_t str_len; - char char_to_add; - switch (keycode) { - case KC_ENTER: - case KC_KP_ENTER: - push_to_cmd_buffer(); - current_cmd_buffer_pos = 0; - process_terminal_command(); - return false; - break; - case KC_ESCAPE: - SEND_STRING("\n"); - enable_terminal(); - return false; - break; - case KC_BACKSPACE: - str_len = strlen(buffer); - if (str_len > 0) { - buffer[str_len - 1] = 0; - return true; - } else { - TERMINAL_BELL(); - return false; - } - break; - case KC_LEFT: - return false; - break; - case KC_RIGHT: - return false; - break; - case KC_UP: // 0 = recent - check_pos(); // check our current buffer position is valid - if (current_cmd_buffer_pos <= CMD_BUFF_SIZE - 1) { // once we get to the top, dont do anything - str_len = strlen(buffer); - for (int i = 0; i < str_len; ++i) { - send_string(SS_TAP(X_BSPACE)); // clear w/e is on the line already - // process_terminal(KC_BACKSPACE,record); - } - strncpy(buffer, cmd_buffer[current_cmd_buffer_pos], 80); - - send_string(buffer); - ++current_cmd_buffer_pos; // get ready to access the above cmd if up/down is pressed again - } - return false; - break; - case KC_DOWN: - check_pos(); - if (current_cmd_buffer_pos >= 0) { // once we get to the bottom, dont do anything - str_len = strlen(buffer); - for (int i = 0; i < str_len; ++i) { - send_string(SS_TAP(X_BSPACE)); // clear w/e is on the line already - // process_terminal(KC_BACKSPACE,record); - } - strncpy(buffer, cmd_buffer[current_cmd_buffer_pos], 79); - - send_string(buffer); - --current_cmd_buffer_pos; // get ready to access the above cmd if down/up is pressed again - } - return false; - break; - default: - if (keycode <= 58) { - char_to_add = 0; - if (get_mods() & (MOD_BIT(KC_LEFT_SHIFT) | MOD_BIT(KC_RIGHT_SHIFT))) { - char_to_add = shifted_keycode_to_ascii_lut[keycode]; - } else if (get_mods() == 0) { - char_to_add = keycode_to_ascii_lut[keycode]; - } - if (char_to_add != 0) { - strncat(buffer, &char_to_add, 1); - } - } - break; - } - } - } - return true; -} diff --git a/quantum/process_keycode/process_terminal.h b/quantum/process_keycode/process_terminal.h deleted file mode 100644 index 0159131e5b..0000000000 --- a/quantum/process_keycode/process_terminal.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright 2017 Jack Humbert - * - * 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 . - */ - -#pragma once - -#include "quantum.h" - -extern const char keycode_to_ascii_lut[58]; -extern const char shifted_keycode_to_ascii_lut[58]; -extern const char terminal_prompt[8]; -bool process_terminal(uint16_t keycode, keyrecord_t *record); diff --git a/quantum/process_keycode/process_terminal_nop.h b/quantum/process_keycode/process_terminal_nop.h deleted file mode 100644 index 36e25320c5..0000000000 --- a/quantum/process_keycode/process_terminal_nop.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2017 Jack Humbert - * - * 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 . - */ - -#pragma once - -#include "quantum.h" - -#define TERM_ON KC_NO -#define TERM_OFF KC_NO diff --git a/quantum/quantum.c b/quantum/quantum.c index ac3e2d90b4..4efcc6bd8f 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -304,9 +304,6 @@ bool process_record_quantum(keyrecord_t *record) { #ifdef DYNAMIC_TAPPING_TERM_ENABLE process_dynamic_tapping_term(keycode, record) && #endif -#ifdef TERMINAL_ENABLE - process_terminal(keycode, record) && -#endif #ifdef CAPS_WORD_ENABLE process_caps_word(keycode, record) && #endif diff --git a/quantum/quantum.h b/quantum/quantum.h index 92e1af1c40..8a7a20c706 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -141,12 +141,6 @@ extern layer_state_t layer_state; # include "process_key_lock.h" #endif -#ifdef TERMINAL_ENABLE -# include "process_terminal.h" -#else -# include "process_terminal_nop.h" -#endif - #ifdef SPACE_CADET_ENABLE # include "process_space_cadet.h" #endif diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index 40355d799a..869826ce19 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -473,9 +473,9 @@ enum quantum_keycodes { // Lock Key KC_LOCK, // 5D2B - // Terminal - TERM_ON, // 5D2C - TERM_OFF, // 5D2D + // Unused slots + UNUSED_000, // 5D2C + UNUSED_001, // 5D2D // Sequencer SQ_ON, // 5D2E diff --git a/quantum/quantum_keycodes_legacy.h b/quantum/quantum_keycodes_legacy.h index ed9455ee74..51380d9c50 100644 --- a/quantum/quantum_keycodes_legacy.h +++ b/quantum/quantum_keycodes_legacy.h @@ -11,3 +11,6 @@ #define KC_GESC QK_GRAVE_ESCAPE #define EEP_RST QK_CLEAR_EEPROM + +#define TERM_ON _Static_assert(false, "The Terminal feature has been removed from QMK. Please remove use of TERM_ON/TERM_OFF from your keymap.") +#define TERM_OFF _Static_assert(false, "The Terminal feature has been removed from QMK.. Please remove use of TERM_ON/TERM_OFF from your keymap.") \ No newline at end of file -- cgit v1.2.3 From d44a950c107492b801d567a507e2213376e7f47c Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Tue, 31 May 2022 07:55:33 +0200 Subject: Use TAP_HOLD_CAPS_DELAY for KC_LOCKING_CAPS_LOCK (#17099) --- quantum/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/action.c b/quantum/action.c index 4e81a5466f..83f6e2a970 100644 --- a/quantum/action.c +++ b/quantum/action.c @@ -844,7 +844,7 @@ __attribute__((weak)) void register_code(uint8_t code) { # endif add_key(KC_CAPS_LOCK); send_keyboard_report(); - wait_ms(100); + wait_ms(TAP_HOLD_CAPS_DELAY); del_key(KC_CAPS_LOCK); send_keyboard_report(); } -- cgit v1.2.3 From af02baae78a3c4a06a646bc338b35524b5e5e7f5 Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Wed, 1 Jun 2022 00:10:05 +0100 Subject: Allow larger SPLIT_USB_TIMEOUT with default SPLIT_USB_TIMEOUT_POLL (#17272) * Switch SPLIT_USB_DETECT loop to uint16_t * Add assertion --- quantum/split_common/split_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index 7d50adf758..8b11e51374 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -57,8 +57,9 @@ static uint8_t connection_errors = 0; volatile bool isLeftHand = true; #if defined(SPLIT_USB_DETECT) +_Static_assert((SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL) <= UINT16_MAX, "Please lower SPLIT_USB_TIMEOUT and/or increase SPLIT_USB_TIMEOUT_POLL."); static bool usbIsActive(void) { - for (uint8_t i = 0; i < (SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL); i++) { + for (uint16_t i = 0; i < (SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL); i++) { // This will return true if a USB connection has been established if (usb_connected_state()) { return true; -- cgit v1.2.3 From 08c556b78b9dc672a2aa2388bbd3fdf408e3ce98 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Sun, 5 Jun 2022 10:26:02 +1000 Subject: Add keymap wrappers for introspection into the keymap. (#17229) * Introspection handlers for keymaps. * Renaming. --- builddefs/build_keyboard.mk | 4 +++- quantum/keymap.h | 2 ++ quantum/keymap_introspection.c | 25 +++++++++++++++++++++++++ quantum/keymap_introspection.h | 15 +++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 quantum/keymap_introspection.c create mode 100644 quantum/keymap_introspection.h (limited to 'quantum') diff --git a/builddefs/build_keyboard.mk b/builddefs/build_keyboard.mk index dc86b232df..a258f33216 100644 --- a/builddefs/build_keyboard.mk +++ b/builddefs/build_keyboard.mk @@ -390,10 +390,12 @@ ifneq ("$(KEYMAP_H)","") CONFIG_H += $(KEYMAP_H) endif +OPT_DEFS += -DKEYMAP_C=\"$(KEYMAP_C)\" + # project specific files SRC += \ $(KEYBOARD_SRC) \ - $(KEYMAP_C) \ + $(QUANTUM_DIR)/keymap_introspection.c \ $(QUANTUM_SRC) \ $(QUANTUM_DIR)/main.c \ diff --git a/quantum/keymap.h b/quantum/keymap.h index d64b271efb..081bc54ebe 100644 --- a/quantum/keymap.h +++ b/quantum/keymap.h @@ -55,3 +55,5 @@ extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; // Ensure we have a forward declaration for the encoder map # include "encoder.h" #endif + +#include "keymap_introspection.h" diff --git a/quantum/keymap_introspection.c b/quantum/keymap_introspection.c new file mode 100644 index 0000000000..9628b41eef --- /dev/null +++ b/quantum/keymap_introspection.c @@ -0,0 +1,25 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later + +// Pull the actual keymap code so that we can inspect stuff from it +#include KEYMAP_C + +#include "keymap_introspection.h" + +#define NUM_KEYMAP_LAYERS ((uint8_t)(sizeof(keymaps) / ((MATRIX_ROWS) * (MATRIX_COLS) * sizeof(uint16_t)))) + +uint8_t keymap_layer_count(void) { + return NUM_KEYMAP_LAYERS; +} + +#if defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE) + +# define NUM_ENCODERMAP_LAYERS ((uint8_t)(sizeof(encoder_map) / ((NUM_ENCODERS) * (2) * sizeof(uint16_t)))) + +uint8_t encodermap_layer_count(void) { + return NUM_ENCODERMAP_LAYERS; +} + +_Static_assert(NUM_KEYMAP_LAYERS == NUM_ENCODERMAP_LAYERS, "Number of encoder_map layers doesn't match the number of keymap layers"); + +#endif // defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE) diff --git a/quantum/keymap_introspection.h b/quantum/keymap_introspection.h new file mode 100644 index 0000000000..23f6f2016f --- /dev/null +++ b/quantum/keymap_introspection.h @@ -0,0 +1,15 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +// Get the number of layers defined in the keymap +uint8_t keymap_layer_count(void); + +#if defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE) + +// Get the number of layers defined in the encoder map +uint8_t encodermap_layer_count(void); + +#endif // defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE) -- cgit v1.2.3 From 85b3b98570262b97851b726a31819e8864ff1bb3 Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Mon, 6 Jun 2022 01:33:32 +0100 Subject: Move SPLIT_HAND_PIN setup to split_pre_init (#17271) * Move SPLIT_HAND_PIN setup to split_pre_init * doppelganger should use old behaviour * Add comment for future Co-authored-by: Joel Challis Co-authored-by: Joel Challis --- keyboards/doppelganger/doppelganger.c | 36 ++++++++++++++++++++--------------- quantum/split_common/split_util.c | 5 ++++- 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'quantum') diff --git a/keyboards/doppelganger/doppelganger.c b/keyboards/doppelganger/doppelganger.c index 04d19480da..304d764028 100644 --- a/keyboards/doppelganger/doppelganger.c +++ b/keyboards/doppelganger/doppelganger.c @@ -15,25 +15,31 @@ */ #include "doppelganger.h" -void keyboard_pre_init_kb (void) { - setPinOutput(C6); - setPinOutput(B0); +void keyboard_pre_init_kb(void) { + setPinOutput(C6); + setPinOutput(B0); } bool led_update_kb(led_t led_state) { - bool res = led_update_user(led_state); - if(res) { - // writePin sets the pin high for 1 and low for 0. - // In this example the pins are inverted, setting - // it low/0 turns it on, and high/1 turns the LED off. - // This behavior depends on whether the LED is between the pin - // and VCC or the pin and GND. - writePin(C6, !led_state.caps_lock); - } - return res; + bool res = led_update_user(led_state); + if (res) { + // writePin sets the pin high for 1 and low for 0. + // In this example the pins are inverted, setting + // it low/0 turns it on, and high/1 turns the LED off. + // This behavior depends on whether the LED is between the pin + // and VCC or the pin and GND. + writePin(C6, !led_state.caps_lock); + } + return res; } __attribute__((weak)) layer_state_t layer_state_set_user(layer_state_t state) { - writePin(B0, !(state & (1UL << 1))); - return state; + writePin(B0, !(state & (1UL << 1))); + return state; +} + +// Override core logic as we reuse SPLIT_HAND_PIN within matrix pins +bool is_keyboard_left(void) { + setPinInput(SPLIT_HAND_PIN); + return readPin(SPLIT_HAND_PIN); } diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index 8b11e51374..48b9cce6d4 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -94,7 +94,6 @@ static uint8_t peek_matrix_intersection(pin_t out_pin, pin_t in_pin) { __attribute__((weak)) bool is_keyboard_left(void) { #if defined(SPLIT_HAND_PIN) // Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand - setPinInput(SPLIT_HAND_PIN); # ifdef SPLIT_HAND_PIN_LOW_IS_LEFT return !readPin(SPLIT_HAND_PIN); # else @@ -133,6 +132,10 @@ __attribute__((weak)) bool is_keyboard_master(void) { // this code runs before the keyboard is fully initialized void split_pre_init(void) { +#if defined(SPLIT_HAND_PIN) + setPinInput(SPLIT_HAND_PIN); + wait_us(100); +#endif isLeftHand = is_keyboard_left(); #if defined(RGBLIGHT_ENABLE) && defined(RGBLED_SPLIT) -- cgit v1.2.3 From 0ab51ee29d6e980a50b27f122a10d0f7de4b1aed Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Wed, 8 Jun 2022 18:39:16 -0700 Subject: Add support for large Mouse Reports (#16371) Co-authored-by: Sergey Vlasov Co-authored-by: Ryan --- docs/config_options.md | 2 + docs/feature_pointing_device.md | 1 + keyboards/ploopyco/mouse/keymaps/drashna/config.h | 2 +- quantum/pointing_device.c | 31 +++++++++--- quantum/pointing_device.h | 10 ++++ quantum/pointing_device_drivers.c | 62 ++++++++++++++--------- tmk_core/protocol/host.c | 5 ++ tmk_core/protocol/report.h | 18 +++++-- tmk_core/protocol/usb_descriptor.c | 15 +++++- tmk_core/protocol/vusb/vusb.c | 16 +++++- 10 files changed, 123 insertions(+), 39 deletions(-) (limited to 'quantum') diff --git a/docs/config_options.md b/docs/config_options.md index 8227a0e074..9aa360576a 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -174,6 +174,8 @@ If you define these options you will enable the associated feature, which may in * sets the timer for leader key chords to run on each key press rather than overall * `#define LEADER_KEY_STRICT_KEY_PROCESSING` * Disables keycode filtering for Mod-Tap and Layer-Tap keycodes. Eg, if you enable this, you would need to specify `MT(MOD_CTL, KC_A)` if you want to use `KC_A`. +* `#define MOUSE_EXTENDED_REPORT` + * Enables support for extended reports (-32767 to 32767, instead of -127 to 127), which may allow for smoother reporting, and prevent maxing out of the reports. Applies to both Pointing Device and Mousekeys. * `#define ONESHOT_TIMEOUT 300` * how long before oneshot times out * `#define ONESHOT_TAP_TOGGLE 2` diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md index 02c1e64a31..250e2843f6 100644 --- a/docs/feature_pointing_device.md +++ b/docs/feature_pointing_device.md @@ -259,6 +259,7 @@ The following configuration options are only available when using `SPLIT_POINTIN |`POINTING_DEVICE_ROTATION_270_RIGHT` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ | |`POINTING_DEVICE_INVERT_X_RIGHT` | (Optional) Inverts the X axis report. | _not defined_ | |`POINTING_DEVICE_INVERT_Y_RIGHT` | (Optional) Inverts the Y axis report. | _not defined_ | +|`MOUSE_EXTENDED_REPORT` | (Optional) Enables support for extended mouse reports. (-32767 to 32767, instead of just -127 to 127) | !> If there is a `_RIGHT` configuration option or callback, the [common configuration](feature_pointing_device.md?id=common-configuration) option will work for the left. For correct left/right detection you should setup a [handedness option](feature_split_keyboard?id=setting-handedness), `EE_HANDS` is usually a good option for an existing board that doesn't do handedness by hardware. diff --git a/keyboards/ploopyco/mouse/keymaps/drashna/config.h b/keyboards/ploopyco/mouse/keymaps/drashna/config.h index 9aa9a40769..1dc1b7695f 100644 --- a/keyboards/ploopyco/mouse/keymaps/drashna/config.h +++ b/keyboards/ploopyco/mouse/keymaps/drashna/config.h @@ -28,4 +28,4 @@ #define RGBLIGHT_EFFECT_TWINKLE #define RGBLIGHT_SLEEP -#define MOUSE_EXT_REPORT +#define MOUSE_EXTENDED_REPORT diff --git a/quantum/pointing_device.c b/quantum/pointing_device.c index a160647890..3c2e2bc09d 100644 --- a/quantum/pointing_device.c +++ b/quantum/pointing_device.c @@ -177,7 +177,8 @@ __attribute__((weak)) void pointing_device_send(void) { report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report) { // Support rotation of the sensor data #if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270) - int8_t x = mouse_report.x, y = mouse_report.y; + mouse_xy_report_t x = mouse_report.x; + mouse_xy_report_t y = mouse_report.y; # if defined(POINTING_DEVICE_ROTATION_90) mouse_report.x = y; mouse_report.y = -x; @@ -347,7 +348,7 @@ void pointing_device_set_cpi_on_side(bool left, uint16_t cpi) { * @param[in] int16_t value * @return int8_t clamped value */ -static inline int8_t pointing_device_movement_clamp(int16_t value) { +static inline int8_t pointing_device_hv_clamp(int16_t value) { if (value < INT8_MIN) { return INT8_MIN; } else if (value > INT8_MAX) { @@ -357,6 +358,21 @@ static inline int8_t pointing_device_movement_clamp(int16_t value) { } } +/** + * @brief clamps int16_t to int8_t + * + * @param[in] clamp_range_t value + * @return mouse_xy_report_t clamped value + */ +static inline mouse_xy_report_t pointing_device_xy_clamp(clamp_range_t value) { + if (value < XY_REPORT_MIN) { + return XY_REPORT_MIN; + } else if (value > XY_REPORT_MAX) { + return XY_REPORT_MAX; + } else { + return value; + } +} /** * @brief combines 2 mouse reports and returns 2 * @@ -369,10 +385,10 @@ static inline int8_t pointing_device_movement_clamp(int16_t value) { * @return combined report_mouse_t of left_report and right_report */ report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report) { - left_report.x = pointing_device_movement_clamp((int16_t)left_report.x + right_report.x); - left_report.y = pointing_device_movement_clamp((int16_t)left_report.y + right_report.y); - left_report.h = pointing_device_movement_clamp((int16_t)left_report.h + right_report.h); - left_report.v = pointing_device_movement_clamp((int16_t)left_report.v + right_report.v); + left_report.x = pointing_device_xy_clamp((clamp_range_t)left_report.x + right_report.x); + left_report.y = pointing_device_xy_clamp((clamp_range_t)left_report.y + right_report.y); + left_report.h = pointing_device_hv_clamp((int16_t)left_report.h + right_report.h); + left_report.v = pointing_device_hv_clamp((int16_t)left_report.v + right_report.v); left_report.buttons |= right_report.buttons; return left_report; } @@ -390,7 +406,8 @@ report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, repor report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report) { // Support rotation of the sensor data # if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) - int8_t x = mouse_report.x, y = mouse_report.y; + mouse_xy_report_t x = mouse_report.x; + mouse_xy_report_t y = mouse_report.y; # if defined(POINTING_DEVICE_ROTATION_90_RIGHT) mouse_report.x = y; mouse_report.y = -x; diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h index 5c0eaeaf34..1e5ef9590c 100644 --- a/quantum/pointing_device.h +++ b/quantum/pointing_device.h @@ -75,6 +75,16 @@ typedef enum { POINTING_DEVICE_BUTTON8, } pointing_device_buttons_t; +#ifdef MOUSE_EXTENDED_REPORT +# define XY_REPORT_MIN INT16_MIN +# define XY_REPORT_MAX INT16_MAX +typedef int32_t clamp_range_t; +#else +# define XY_REPORT_MIN INT8_MIN +# define XY_REPORT_MAX INT8_MAX +typedef int16_t clamp_range_t; +#endif + void pointing_device_init(void); void pointing_device_task(void); void pointing_device_send(void); diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c index 56363c7ac6..41d7018c86 100644 --- a/quantum/pointing_device_drivers.c +++ b/quantum/pointing_device_drivers.c @@ -22,8 +22,8 @@ #include "timer.h" #include -// hid mouse reports cannot exceed -127 to 127, so constrain to that value -#define constrain_hid(amt) ((amt) < -127 ? -127 : ((amt) > 127 ? 127 : (amt))) +#define CONSTRAIN_HID(amt) ((amt) < INT8_MIN ? INT8_MIN : ((amt) > INT8_MAX ? INT8_MAX : (amt))) +#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt))) // get_report functions should probably be moved to their respective drivers. #if defined(POINTING_DEVICE_DRIVER_adns5050) @@ -35,8 +35,8 @@ report_mouse_t adns5050_get_report(report_mouse_t mouse_report) { if (debug_mouse) dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy); # endif - mouse_report.x = data.dx; - mouse_report.y = data.dy; + mouse_report.x = (mouse_xy_report_t)data.dx; + mouse_report.y = (mouse_xy_report_t)data.dy; } return mouse_report; @@ -55,11 +55,8 @@ const pointing_device_driver_t pointing_device_driver = { report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report) { report_adns9800_t sensor_report = adns9800_get_report(); - int8_t clamped_x = constrain_hid(sensor_report.x); - int8_t clamped_y = constrain_hid(sensor_report.y); - - mouse_report.x = clamped_x; - mouse_report.y = clamped_y; + mouse_report.x = CONSTRAIN_HID_XY(sensor_report.x); + mouse_report.y = CONSTRAIN_HID_XY(sensor_report.y); return mouse_report; } @@ -107,16 +104,16 @@ const pointing_device_driver_t pointing_device_driver = { # endif report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { - pinnacle_data_t touchData = cirque_pinnacle_read_data(); - static uint16_t x = 0, y = 0, mouse_timer = 0; - int8_t report_x = 0, report_y = 0; - static bool is_z_down = false; + pinnacle_data_t touchData = cirque_pinnacle_read_data(); + static uint16_t x = 0, y = 0, mouse_timer = 0; + mouse_xy_report_t report_x = 0, report_y = 0; + static bool is_z_down = false; cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); // Scale coordinates to arbitrary X, Y resolution if (x && y && touchData.xValue && touchData.yValue) { - report_x = (int8_t)(touchData.xValue - x); - report_y = (int8_t)(touchData.yValue - y); + report_x = (mouse_xy_report_t)(touchData.xValue - x); + report_y = (mouse_xy_report_t)(touchData.yValue - y); } x = touchData.xValue; y = touchData.yValue; @@ -157,11 +154,26 @@ const pointing_device_driver_t pointing_device_driver = { // clang-format on #elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) + +mouse_xy_report_t pimoroni_trackball_adapt_values(clamp_range_t* offset) { + if (*offset > XY_REPORT_MAX) { + *offset -= XY_REPORT_MAX; + return (mouse_xy_report_t)XY_REPORT_MAX; + } else if (*offset < XY_REPORT_MIN) { + *offset += XY_REPORT_MAX; + return (mouse_xy_report_t)XY_REPORT_MIN; + } else { + mouse_xy_report_t temp_return = *offset; + *offset = 0; + return temp_return; + } +} + report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) { - static uint16_t debounce = 0; - static uint8_t error_count = 0; - pimoroni_data_t pimoroni_data = {0}; - static int16_t x_offset = 0, y_offset = 0; + static uint16_t debounce = 0; + static uint8_t error_count = 0; + pimoroni_data_t pimoroni_data = {0}; + static clamp_range_t x_offset = 0, y_offset = 0; if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) { i2c_status_t status = read_pimoroni_trackball(&pimoroni_data); @@ -174,8 +186,8 @@ report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) { if (!debounce) { x_offset += pimoroni_trackball_get_offsets(pimoroni_data.right, pimoroni_data.left, PIMORONI_TRACKBALL_SCALE); y_offset += pimoroni_trackball_get_offsets(pimoroni_data.down, pimoroni_data.up, PIMORONI_TRACKBALL_SCALE); - pimoroni_trackball_adapt_values(&mouse_report.x, &x_offset); - pimoroni_trackball_adapt_values(&mouse_report.y, &y_offset); + mouse_report.x = pimoroni_trackball_adapt_values(&x_offset); + mouse_report.y = pimoroni_trackball_adapt_values(&y_offset); } else { debounce--; } @@ -221,8 +233,8 @@ report_mouse_t pmw3360_get_report(report_mouse_t mouse_report) { # endif MotionStart = timer_read(); } - mouse_report.x = constrain_hid(data.dx); - mouse_report.y = constrain_hid(data.dy); + mouse_report.x = CONSTRAIN_HID_XY(data.dx); + mouse_report.y = CONSTRAIN_HID_XY(data.dy); } return mouse_report; @@ -259,8 +271,8 @@ report_mouse_t pmw3389_get_report(report_mouse_t mouse_report) { # endif MotionStart = timer_read(); } - mouse_report.x = constrain_hid(data.dx); - mouse_report.y = constrain_hid(data.dy); + mouse_report.x = CONSTRAIN_HID_XY(data.dx); + mouse_report.y = CONSTRAIN_HID_XY(data.dy); } return mouse_report; diff --git a/tmk_core/protocol/host.c b/tmk_core/protocol/host.c index 053d2b79e3..3d8604d541 100644 --- a/tmk_core/protocol/host.c +++ b/tmk_core/protocol/host.c @@ -93,6 +93,11 @@ void host_mouse_send(report_mouse_t *report) { if (!driver) return; #ifdef MOUSE_SHARED_EP report->report_id = REPORT_ID_MOUSE; +#endif +#ifdef MOUSE_EXTENDED_REPORT + // clip and copy to Boot protocol XY + report->boot_x = (report->x > 127) ? 127 : ((report->x < -127) ? -127 : report->x); + report->boot_y = (report->y > 127) ? 127 : ((report->y < -127) ? -127 : report->y); #endif (*driver->send_mouse)(report); } diff --git a/tmk_core/protocol/report.h b/tmk_core/protocol/report.h index 7bbeb78af7..735ccdb4a1 100644 --- a/tmk_core/protocol/report.h +++ b/tmk_core/protocol/report.h @@ -201,15 +201,25 @@ typedef struct { uint32_t usage; } __attribute__((packed)) report_programmable_button_t; +#ifdef MOUSE_EXTENDED_REPORT +typedef int16_t mouse_xy_report_t; +#else +typedef int8_t mouse_xy_report_t; +#endif + typedef struct { #ifdef MOUSE_SHARED_EP uint8_t report_id; #endif uint8_t buttons; - int8_t x; - int8_t y; - int8_t v; - int8_t h; +#ifdef MOUSE_EXTENDED_REPORT + int8_t boot_x; + int8_t boot_y; +#endif + mouse_xy_report_t x; + mouse_xy_report_t y; + int8_t v; + int8_t h; } __attribute__((packed)) report_mouse_t; typedef struct { diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c index 063bd2c3f1..52e3276d35 100644 --- a/tmk_core/protocol/usb_descriptor.c +++ b/tmk_core/protocol/usb_descriptor.c @@ -126,14 +126,27 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { HID_RI_REPORT_SIZE(8, 0x01), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - // X/Y position (2 bytes) +# ifdef MOUSE_EXTENDED_REPORT + // Boot protocol XY ignored in Report protocol + HID_RI_REPORT_COUNT(8, 0x02), + HID_RI_REPORT_SIZE(8, 0x08), + HID_RI_INPUT(8, HID_IOF_CONSTANT), +# endif + // X/Y position (2 or 4 bytes) HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop HID_RI_USAGE(8, 0x30), // X HID_RI_USAGE(8, 0x31), // Y +# ifndef MOUSE_EXTENDED_REPORT HID_RI_LOGICAL_MINIMUM(8, -127), HID_RI_LOGICAL_MAXIMUM(8, 127), HID_RI_REPORT_COUNT(8, 0x02), HID_RI_REPORT_SIZE(8, 0x08), +# else + HID_RI_LOGICAL_MINIMUM(16, -32767), + HID_RI_LOGICAL_MAXIMUM(16, 32767), + HID_RI_REPORT_COUNT(8, 0x02), + HID_RI_REPORT_SIZE(8, 0x10), +# endif HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), // Vertical wheel (1 byte) diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c index ebde955d3b..d07cc0d27e 100644 --- a/tmk_core/protocol/vusb/vusb.c +++ b/tmk_core/protocol/vusb/vusb.c @@ -482,14 +482,28 @@ const PROGMEM uchar shared_hid_report[] = { 0x75, 0x01, // Report Size (1) 0x81, 0x02, // Input (Data, Variable, Absolute) - // X/Y position (2 bytes) +# ifdef MOUSE_EXTENDED_REPORT + // Boot protocol XY ignored in Report protocol + 0x95, 0x02, // Report Count (2) + 0x75, 0x08, // Report Size (8) + 0x81, 0x03, // Input (Constant) +# endif + + // X/Y position (2 or 4 bytes) 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) +# ifndef MOUSE_EXTENDED_REPORT 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Logical Maximum (127) 0x95, 0x02, // Report Count (2) 0x75, 0x08, // Report Size (8) +# else + 0x16, 0x01, 0x80, // Logical Minimum (-32767) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x95, 0x02, // Report Count (2) + 0x75, 0x10, // Report Size (16) +# endif 0x81, 0x06, // Input (Data, Variable, Relative) // Vertical wheel (1 byte) -- cgit v1.2.3 From 0fd08da806711112147cd6c3b9bdee0250f9f103 Mon Sep 17 00:00:00 2001 From: yiancar Date: Sat, 11 Jun 2022 01:20:01 +0100 Subject: Scale brigthness for VIA (#17352) Co-authored-by: yiancar --- quantum/via.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'quantum') diff --git a/quantum/via.c b/quantum/via.c index 320bd5546d..a37bd38da8 100644 --- a/quantum/via.c +++ b/quantum/via.c @@ -64,6 +64,7 @@ void via_qmk_rgblight_get_value(uint8_t *data); #endif #if defined(VIA_QMK_RGB_MATRIX_ENABLE) +# include void via_qmk_rgb_matrix_set_value(uint8_t *data); void via_qmk_rgb_matrix_get_value(uint8_t *data); void eeconfig_update_rgb_matrix(void); @@ -421,7 +422,7 @@ void via_qmk_backlight_get_value(uint8_t *data) { switch (*value_id) { case id_qmk_backlight_brightness: { // level / BACKLIGHT_LEVELS * 255 - value_data[0] = ((uint16_t)get_backlight_level()) * 255 / BACKLIGHT_LEVELS; + value_data[0] = ((uint16_t)get_backlight_level() * UINT8_MAX) / BACKLIGHT_LEVELS; break; } case id_qmk_backlight_effect: { @@ -441,7 +442,7 @@ void via_qmk_backlight_set_value(uint8_t *data) { switch (*value_id) { case id_qmk_backlight_brightness: { // level / 255 * BACKLIGHT_LEVELS - backlight_level_noeeprom(((uint16_t)value_data[0]) * BACKLIGHT_LEVELS / 255); + backlight_level_noeeprom(((uint16_t)value_data[0] * BACKLIGHT_LEVELS) / UINT8_MAX); break; } case id_qmk_backlight_effect: { @@ -466,7 +467,7 @@ void via_qmk_rgblight_get_value(uint8_t *data) { uint8_t *value_data = &(data[1]); switch (*value_id) { case id_qmk_rgblight_brightness: { - value_data[0] = rgblight_get_val(); + value_data[0] = ((uint16_t)rgblight_get_val() * UINT8_MAX) / RGBLIGHT_LIMIT_VAL; break; } case id_qmk_rgblight_effect: { @@ -490,7 +491,7 @@ void via_qmk_rgblight_set_value(uint8_t *data) { uint8_t *value_data = &(data[1]); switch (*value_id) { case id_qmk_rgblight_brightness: { - rgblight_sethsv_noeeprom(rgblight_get_hue(), rgblight_get_sat(), value_data[0]); + rgblight_sethsv_noeeprom(rgblight_get_hue(), rgblight_get_sat(), ((uint16_t)value_data[0] * RGBLIGHT_LIMIT_VAL) / UINT8_MAX; break; } case id_qmk_rgblight_effect: { @@ -557,7 +558,7 @@ void via_qmk_rgb_matrix_get_value(uint8_t *data) { uint8_t *value_data = &(data[1]); switch (*value_id) { case id_qmk_rgblight_brightness: - value_data[0] = rgb_matrix_get_val(); + value_data[0] = ((uint16_t)rgb_matrix_get_val() * UINT8_MAX) / RGB_MATRIX_MAXIMUM_BRIGHTNESS; break; case id_qmk_rgblight_effect: value_data[0] = rgb_matrix_get_mode(); @@ -577,7 +578,7 @@ void via_qmk_rgb_matrix_set_value(uint8_t *data) { uint8_t *value_data = &(data[1]); switch (*value_id) { case id_qmk_rgblight_brightness: - rgb_matrix_sethsv_noeeprom(rgb_matrix_get_hue(), rgb_matrix_get_sat(), value_data[0]); + rgb_matrix_sethsv_noeeprom(rgb_matrix_get_hue(), rgb_matrix_get_sat(), scale8(value_data[0], RGB_MATRIX_MAXIMUM_BRIGHTNESS)); break; case id_qmk_rgblight_effect: rgb_matrix_mode_noeeprom(value_data[0]); -- cgit v1.2.3 From 568924c76cb29620e2cb7d2f2f5b1beddf8cf623 Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Sat, 11 Jun 2022 03:07:58 +0100 Subject: Add missing bracket for VIA brightness scaling (#17354) --- quantum/via.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/via.c b/quantum/via.c index a37bd38da8..1ded1f5fe8 100644 --- a/quantum/via.c +++ b/quantum/via.c @@ -491,7 +491,7 @@ void via_qmk_rgblight_set_value(uint8_t *data) { uint8_t *value_data = &(data[1]); switch (*value_id) { case id_qmk_rgblight_brightness: { - rgblight_sethsv_noeeprom(rgblight_get_hue(), rgblight_get_sat(), ((uint16_t)value_data[0] * RGBLIGHT_LIMIT_VAL) / UINT8_MAX; + rgblight_sethsv_noeeprom(rgblight_get_hue(), rgblight_get_sat(), ((uint16_t)value_data[0] * RGBLIGHT_LIMIT_VAL) / UINT8_MAX); break; } case id_qmk_rgblight_effect: { -- cgit v1.2.3 From 80034a847fdfe91cf0d6ef9399d34d90c15d8a54 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Fri, 10 Jun 2022 22:01:46 -0700 Subject: Ensure that rgb+via compiles in all cases (#17355) --- quantum/via.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'quantum') diff --git a/quantum/via.c b/quantum/via.c index 1ded1f5fe8..d2ef0862cc 100644 --- a/quantum/via.c +++ b/quantum/via.c @@ -461,6 +461,9 @@ void via_qmk_backlight_set_value(uint8_t *data) { #endif // #if defined(VIA_QMK_BACKLIGHT_ENABLE) #if defined(VIA_QMK_RGBLIGHT_ENABLE) +# ifndef RGBLIGHT_LIMIT_VAL +# define RGBLIGHT_LIMIT_VAL 255 +# endif void via_qmk_rgblight_get_value(uint8_t *data) { uint8_t *value_id = &(data[0]); @@ -518,6 +521,11 @@ void via_qmk_rgblight_set_value(uint8_t *data) { #if defined(VIA_QMK_RGB_MATRIX_ENABLE) +# if !defined(RGB_MATRIX_MAXIMUM_BRIGHTNESS) || RGB_MATRIX_MAXIMUM_BRIGHTNESS > UINT8_MAX +# undef RGB_MATRIX_MAXIMUM_BRIGHTNESS +# define RGB_MATRIX_MAXIMUM_BRIGHTNESS UINT8_MAX +# endif + // VIA supports only 4 discrete values for effect speed; map these to some // useful speed values for RGB Matrix. enum speed_values { -- cgit v1.2.3 From 1706da9054f8c4aa77493062a8937a7b64970a9e Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Mon, 13 Jun 2022 22:12:55 +0200 Subject: tap-dance: Restructure code and document in more detail (#16394) --- builddefs/build_test.mk | 2 +- docs/feature_tap_dance.md | 143 +++++---- docs/ja/feature_tap_dance.md | 1 - .../basekeys/slice/rev1/keymaps/2moons/keymap.c | 4 +- .../slice/rev1_rgb/keymaps/2moons_rgb/keymap.c | 4 +- .../bpiphany/frosty_flake/keymaps/nikchi/config.h | 1 + .../bpiphany/frosty_flake/keymaps/nikchi/keymap.c | 32 ++- .../keymaps/nikchi/variableTapDance.md | 5 +- keyboards/duck/lightsaver/keymaps/rasmus/keymap.c | 4 +- .../ergodox_ez/keymaps/hacker_dvorak/config.h | 1 + .../hacker_dvorak/tap_dance/tap_dance_actions.c | 38 ++- .../gboards/gergoplex/keymaps/georgepetri/config.h | 2 + .../gboards/gergoplex/keymaps/georgepetri/keymap.c | 11 +- keyboards/handwired/ortho5x14/keymaps/2u/keymap.c | 6 +- .../handwired/ortho5x14/keymaps/split1/keymap.c | 6 +- keyboards/jones/v03/keymaps/default_jp/config.h | 1 + keyboards/jones/v03/keymaps/default_jp/keymap.c | 15 +- .../jones/v03_1/keymaps/default_ansi/config.h | 1 + .../jones/v03_1/keymaps/default_ansi/keymap.c | 15 +- keyboards/jones/v03_1/keymaps/default_jp/config.h | 1 + keyboards/jones/v03_1/keymaps/default_jp/keymap.c | 15 +- keyboards/keyhive/navi10/keymaps/default/keymap.c | 2 +- keyboards/keyhive/navi10/keymaps/devdev/keymap.c | 2 +- .../keyhive/navi10/keymaps/emdarcher/keymap.c | 2 +- .../kprepublic/jj50/keymaps/archetype/config.h | 1 + .../kprepublic/jj50/keymaps/archetype/keymap.c | 11 +- keyboards/planck/keymaps/ariccb/config.h | 1 + keyboards/planck/keymaps/ariccb/keymap.c | 13 +- keyboards/planck/keymaps/rootiest/config.h | 1 + keyboards/planck/keymaps/rootiest/keymap.c | 23 +- .../7skb/keymaps/salicylic/keymap.c | 4 +- .../7splus/keymaps/salicylic/keymap.c | 4 +- .../jisplit89/keymaps/salicylic/keymap.c | 4 +- .../naked60/keymaps/salicylic/keymap.c | 4 +- .../naked60/keymaps/salicylic_with_nafuda/keymap.c | 4 +- .../keymaps/salicylic_with_setta21/keymap.c | 4 +- .../naked64/keymaps/salicylic/keymap.c | 4 +- .../keymaps/salicylic_with_setta21/keymap.c | 4 +- .../thevankeyboards/minivan/keymaps/belak/keymap.c | 21 +- quantum/process_keycode/process_tap_dance.c | 137 ++++----- quantum/process_keycode/process_tap_dance.h | 33 +-- tests/tapdance/config.h | 19 ++ tests/tapdance/examples.c | 199 +++++++++++++ tests/tapdance/examples.h | 33 +++ tests/tapdance/test.mk | 22 ++ tests/tapdance/test_examples.cpp | 319 +++++++++++++++++++++ users/edvorakjp/edvorakjp_tap_dance.c | 13 +- users/gourdo1/gourdo1.c | 2 +- users/mnil/config.h | 1 + users/mnil/mnil.c | 4 +- users/ninjonas/config.h | 3 +- users/ninjonas/tap_dances.c | 16 +- 52 files changed, 972 insertions(+), 246 deletions(-) create mode 100644 tests/tapdance/config.h create mode 100644 tests/tapdance/examples.c create mode 100644 tests/tapdance/examples.h create mode 100644 tests/tapdance/test.mk create mode 100644 tests/tapdance/test_examples.cpp (limited to 'quantum') diff --git a/builddefs/build_test.mk b/builddefs/build_test.mk index 5ad33b19c5..834184f221 100644 --- a/builddefs/build_test.mk +++ b/builddefs/build_test.mk @@ -42,7 +42,7 @@ VPATH += \ all: elf -VPATH += $(COMMON_VPATH) +VPATH += $(TEST_PATH) $(COMMON_VPATH) PLATFORM:=TEST PLATFORM_KEY:=test BOOTLOADER_TYPE:=none diff --git a/docs/feature_tap_dance.md b/docs/feature_tap_dance.md index c055a9989a..05134ec229 100644 --- a/docs/feature_tap_dance.md +++ b/docs/feature_tap_dance.md @@ -14,55 +14,48 @@ Optionally, you might want to set a custom `TAPPING_TERM` time by adding somethi ```c #define TAPPING_TERM 175 +#define TAPPING_TERM_PER_KEY ``` -The `TAPPING_TERM` time is the maximum time allowed between taps of your Tap Dance key, and is measured in milliseconds. For example, if you used the above `#define` statement and set up a Tap Dance key that sends `Space` on single-tap and `Enter` on double-tap, then this key will send `ENT` only if you tap this key twice in less than 175ms. If you tap the key, wait more than 175ms, and tap the key again you'll end up sending `SPC SPC` instead. +The `TAPPING_TERM` time is the maximum time allowed between taps of your Tap Dance key, and is measured in milliseconds. For example, if you used the above `#define` statement and set up a Tap Dance key that sends `Space` on single-tap and `Enter` on double-tap, then this key will send `ENT` only if you tap this key twice in less than 175ms. If you tap the key, wait more than 175ms, and tap the key again you'll end up sending `SPC SPC` instead. The `TAPPING_TERM_PER_KEY` definition is only needed if you control the tapping term through a [custom `get_tapping_term` function](tap_hold.md#tapping_term), which may be needed because `TAPPING_TERM` affects not just tap-dance keys. -Next, you will want to define some tap-dance keys, which is easiest to do with the `TD()` macro, that takes a number which will later be used as an index into the `tap_dance_actions` array. +Next, you will want to define some tap-dance keys, which is easiest to do with the `TD()` macro. That macro takes a number which will later be used as an index into the `tap_dance_actions` array and turns it into a tap-dance keycode. After this, you'll want to use the `tap_dance_actions` array to specify what actions shall be taken when a tap-dance key is in action. Currently, there are five possible options: * `ACTION_TAP_DANCE_DOUBLE(kc1, kc2)`: Sends the `kc1` keycode when tapped once, `kc2` otherwise. When the key is held, the appropriate keycode is registered: `kc1` when pressed and held, `kc2` when tapped once, then pressed and held. * `ACTION_TAP_DANCE_LAYER_MOVE(kc, layer)`: Sends the `kc` keycode when tapped once, or moves to `layer`. (this functions like the `TO` layer keycode). - * This is the same as `ACTION_TAP_DANCE_DUAL_ROLE`, but renamed to something that is clearer about its functionality. Both names will work. * `ACTION_TAP_DANCE_LAYER_TOGGLE(kc, layer)`: Sends the `kc` keycode when tapped once, or toggles the state of `layer`. (this functions like the `TG` layer keycode). * `ACTION_TAP_DANCE_FN(fn)`: Calls the specified function - defined in the user keymap - with the final tap count of the tap dance action. * `ACTION_TAP_DANCE_FN_ADVANCED(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn)`: Calls the first specified function - defined in the user keymap - on every tap, the second function when the dance action finishes (like the previous option), and the last function when the tap dance action resets. -* ~~`ACTION_TAP_DANCE_FN_ADVANCED_TIME(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn, tap_specific_tapping_term)`~~: This functions identically to the `ACTION_TAP_DANCE_FN_ADVANCED` function, but uses a custom tapping term for it, instead of the predefined `TAPPING_TERM`. - * This is deprecated in favor of the Per Key Tapping Term functionality, as outlined [here](tap_hold.md#tapping-term). You'd want to check for the specific `TD()` macro that you want to use (such as `TD(TD_ESC_CAPS)`) instead of using this specific Tap Dance function. The first option is enough for a lot of cases, that just want dual roles. For example, `ACTION_TAP_DANCE_DOUBLE(KC_SPC, KC_ENT)` will result in `Space` being sent on single-tap, `Enter` otherwise. !> Keep in mind that only [basic keycodes](keycodes_basic.md) are supported here. Custom keycodes are not supported. -Similar to the first option, the second option is good for simple layer-switching cases. +Similar to the first option, the second and third option are good for simple layer-switching cases. -For more complicated cases, use the third or fourth options (examples of each are listed below). - -Finally, the fifth option is particularly useful if your non-Tap-Dance keys start behaving weirdly after adding the code for your Tap Dance keys. The likely problem is that you changed the `TAPPING_TERM` time to make your Tap Dance keys easier for you to use, and that this has changed the way your other keys handle interrupts. +For more complicated cases, like blink the LEDs, fiddle with the backlighting, and so on, use the fourth or fifth option. Examples of each are listed below. ## Implementation Details :id=implementation Well, that's the bulk of it! You should now be able to work through the examples below, and to develop your own Tap Dance functionality. But if you want a deeper understanding of what's going on behind the scenes, then read on for the explanation of how it all works! -The main entry point is `process_tap_dance()`, called from `process_record_quantum()`, which is run for every keypress, and our handler gets to run early. This function checks whether the key pressed is a tap-dance key. If it is not, and a tap-dance was in action, we handle that first, and enqueue the newly pressed key. If it is a tap-dance key, then we check if it is the same as the already active one (if there's one active, that is). If it is not, we fire off the old one first, then register the new one. If it was the same, we increment the counter and reset the timer. - -This means that you have `TAPPING_TERM` time to tap the key again; you do not have to input all the taps within a single `TAPPING_TERM` timeframe. This allows for longer tap counts, with minimal impact on responsiveness. +Let's go over the three functions mentioned in `ACTION_TAP_DANCE_FN_ADVANCED` in a little more detail. They all receive the same too arguments: a pointer to a structure that holds all dance related state information, and a pointer to a use case specific state variable. The three functions differ in when they are called. The first, `on_each_tap_fn()`, is called every time the tap dance key is *pressed*. Before it is called, the counter is incremented and the timer is reset. The second function, `on_dance_finished_fn()`, is called when the tap dance is interrupted or ends because `TAPPING_TERM` milliseconds have passed since the last tap. When the `finished` field of the dance state structure is set to `true`, the `on_dance_finished_fn()` is skipped. After `on_dance_finished_fn()` was called or would have been called, but no sooner than when the tap dance key is *released*, `on_dance_reset_fn()` is called. It is possible to end a tap dance immediately, skipping `on_dance_finished_fn()`, but not `on_dance_reset_fn`, by calling `reset_tap_dance(state)`. -Our next stop is `tap_dance_task()`. This handles the timeout of tap-dance keys. +To accomplish this logic, the tap dance mechanics use three entry points. The main entry point is `process_tap_dance()`, called from `process_record_quantum()` *after* `process_record_kb()` and `process_record_user()`. This function is responsible for calling `on_each_tap_fn()` and `on_dance_reset_fn()`. In order to handle interruptions of a tap dance, another entry point, `preprocess_tap_dance()` is run right at the beginning of `process_record_quantum()`. This function checks whether the key pressed is a tap-dance key. If it is not, and a tap-dance was in action, we handle that first, and enqueue the newly pressed key. If it is a tap-dance key, then we check if it is the same as the already active one (if there's one active, that is). If it is not, we fire off the old one first, then register the new one. Finally, `tap_dance_task()` periodically checks whether `TAPPING_TERM` has passed since the last key press and finishes a tap dance if that is the case. -For the sake of flexibility, tap-dance actions can be either a pair of keycodes, or a user function. The latter allows one to handle higher tap counts, or do extra things, like blink the LEDs, fiddle with the backlighting, and so on. This is accomplished by using an union, and some clever macros. +This means that you have `TAPPING_TERM` time to tap the key again; you do not have to input all the taps within a single `TAPPING_TERM` timeframe. This allows for longer tap counts, with minimal impact on responsiveness. ## Examples :id=examples -### Simple Example :id=simple-example +### Simple Example: Send `ESC` on Single Tap, `CAPS_LOCK` on Double Tap :id=simple-example Here's a simple example for a single definition: 1. In your `rules.mk`, add `TAP_DANCE_ENABLE = yes` -2. In your `config.h` (which you can copy from `qmk_firmware/keyboards/planck/config.h` to your keymap directory), add `#define TAPPING_TERM 200` -3. In your `keymap.c` file, define the variables and definitions, then add to your keymap: +2. In your `keymap.c` file, define the variables and definitions, then add to your keymap: ```c // Tap Dance declarations @@ -92,40 +85,15 @@ All the enums used in the examples are declared like this: ```c // Enums defined for all examples: enum { - CT_SE, - CT_CLN, + TD_ESC_CAPS, CT_EGG, CT_FLSH, - X_TAP_DANCE -}; -``` - -#### Example 1: Send `:` on Single Tap, `;` on Double Tap :id=example-1 - -```c -void dance_cln_finished(qk_tap_dance_state_t *state, void *user_data) { - if (state->count == 1) { - register_code16(KC_COLN); - } else { - register_code(KC_SCLN); - } -} - -void dance_cln_reset(qk_tap_dance_state_t *state, void *user_data) { - if (state->count == 1) { - unregister_code16(KC_COLN); - } else { - unregister_code(KC_SCLN); - } -} - -// All tap dance functions would go here. Only showing this one. -qk_tap_dance_action_t tap_dance_actions[] = { - [CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_cln_finished, dance_cln_reset), + CT_CLN, + X_CTL, }; ``` -#### Example 2: Send "Safety Dance!" After 100 Taps :id=example-2 +#### Example 1: Send "Safety Dance!" After 100 Taps :id=example-1 ```c void dance_egg(qk_tap_dance_state_t *state, void *user_data) { @@ -140,7 +108,7 @@ qk_tap_dance_action_t tap_dance_actions[] = { }; ``` -#### Example 3: Turn LED Lights On Then Off, One at a Time :id=example-3 +#### Example 2: Turn LED Lights On Then Off, One at a Time :id=example-2 ```c // On each tap, light up one LED, from right to left @@ -181,15 +149,74 @@ void dance_flsh_reset(qk_tap_dance_state_t *state, void *user_data) { ergodox_right_led_3_off(); } -// All tap dances now put together. Example 3 is "CT_FLASH" +// All tap dances now put together. Example 2 is "CT_FLSH" qk_tap_dance_action_t tap_dance_actions[] = { - [CT_SE] = ACTION_TAP_DANCE_DOUBLE(KC_SPC, KC_ENT), - [CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_cln_finished, dance_cln_reset), + [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS), [CT_EGG] = ACTION_TAP_DANCE_FN(dance_egg), [CT_FLSH] = ACTION_TAP_DANCE_FN_ADVANCED(dance_flsh_each, dance_flsh_finished, dance_flsh_reset) }; ``` +#### Example 3: Send `:` on Tap, `;` on Hold :id=example-3 + +With a little effort, powerful tap-hold configurations can be implemented as tap dances. To emit taps as early as possible, we need to act on releases of the tap dance key. There is no callback for this in the tap dance framework, so we use `process_record_user()`. + +```c +typedef struct { + uint16_t tap; + uint16_t hold; + uint16_t held; +} tap_dance_tap_hold_t; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + qk_tap_dance_action_t *action; + + switch (keycode) { + case TD(CT_CLN): // list all tap dance keycodes with tap-hold configurations + action = &tap_dance_actions[TD_INDEX(keycode)]; + if (!record->event.pressed && action->state.count && !action->state.finished) { + tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data; + tap_code16(tap_hold->tap); + } + } + return true; +} + +void tap_dance_tap_hold_finished(qk_tap_dance_state_t *state, void *user_data) { + tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; + + if (state->pressed) { + if (state->count == 1 +#ifndef PERMISSIVE_HOLD + && !state->interrupted +#endif + ) { + register_code16(tap_hold->hold); + tap_hold->held = tap_hold->hold; + } else { + register_code16(tap_hold->tap); + tap_hold->held = tap_hold->tap; + } + } +} + +void tap_dance_tap_hold_reset(qk_tap_dance_state_t *state, void *user_data) { + tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; + + if (tap_hold->held) { + unregister_code16(tap_hold->held); + tap_hold->held = 0; + } +} + +#define ACTION_TAP_DANCE_TAP_HOLD(tap, hold) \ + { .fn = {NULL, tap_dance_tap_hold_finished, tap_dance_tap_hold_reset}, .user_data = (void *)&((tap_dance_tap_hold_t){tap, hold, 0}), } + +qk_tap_dance_action_t tap_dance_actions[] = { + [CT_CLN] = ACTION_TAP_DANCE_TAP_HOLD(KC_COLN, KC_SCLN), +}; +``` + #### Example 4: 'Quad Function Tap-Dance' :id=example-4 By [DanielGGordon](https://github.com/danielggordon) @@ -329,7 +356,7 @@ And then simply use `TD(X_CTL)` anywhere in your keymap. If you want to implement this in your userspace, then you may want to check out how [DanielGGordon](https://github.com/qmk/qmk_firmware/tree/master/users/gordon) has implemented this in their userspace. -> In this configuration "hold" takes place **after** tap dance timeout (see `ACTION_TAP_DANCE_FN_ADVANCED_TIME`). To achieve instant hold, remove `state->interrupted` checks in conditions. As a result you may use comfortable longer tapping periods to have more time for taps and not to wait too long for holds (try starting with doubled `TAPPING_TERM`). +> In this configuration "hold" takes place **after** tap dance timeout. To achieve instant hold, remove `state->interrupted` checks in conditions. As a result you may use comfortable longer tapping periods to have more time for taps and not to wait too long for holds (try starting with doubled `TAPPING_TERM`). #### Example 5: Using tap dance for advanced mod-tap and layer-tap keys :id=example-5 @@ -511,8 +538,18 @@ void ql_reset(qk_tap_dance_state_t *state, void *user_data) { // Associate our tap dance key with its functionality qk_tap_dance_action_t tap_dance_actions[] = { - [QUOT_LAYR] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, ql_finished, ql_reset, 275) + [QUOT_LAYR] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ql_finished, ql_reset) }; + +// Set a long-ish tapping term for tap-dance keys +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: + return 275; + default: + return TAPPING_TERM; + } +} ``` The above code is similar to that used in previous examples. The one point to note is that we need to be able to check which layers are active at any time so we can toggle them if needed. To do this we use the `layer_state_is(layer)` function which returns `true` if the given `layer` is active. @@ -521,6 +558,6 @@ The use of `cur_dance()` and `ql_tap_state` mirrors the above examples. The `case: TD_SINGLE_TAP` in `ql_finished` is similar to the above examples. The `TD_SINGLE_HOLD` case works in conjunction with `ql_reset()` to switch to `_MY_LAYER` while the tap dance key is held, and to switch away from `_MY_LAYER` when the key is released. This mirrors the use of `MO(_MY_LAYER)`. The `TD_DOUBLE_TAP` case works by checking whether `_MY_LAYER` is the active layer, and toggling it on or off accordingly. This mirrors the use of `TG(_MY_LAYER)`. -`tap_dance_actions[]` works similar to the above examples. Note that I used `ACTION_TAP_DANCE_FN_ADVANCED_TIME()` instead of `ACTION_TAP_DANCE_FN_ADVANCED()`. This is because I like my `TAPPING_TERM` to be short (\~175ms) for my non-tap-dance keys but find that this is too quick for me to reliably complete tap dance actions - thus the increased time of 275ms here. +`tap_dance_actions[]` works similar to the above examples. Note that, additionally, I set a longer tapping term for the tap dance keys. This is because I like my `TAPPING_TERM` to be short (\~175ms) for my non-tap-dance keys but find that this is too quick for me to reliably complete tap dance actions - thus the increased time of 275ms here. In order for the per-key tapping terms to take effect, `TAPPING_TERM_PER_KEY` must be defined in your `config.h`. Finally, to get this tap dance key working, be sure to include `TD(QUOT_LAYR)` in your `keymaps[]`. diff --git a/docs/ja/feature_tap_dance.md b/docs/ja/feature_tap_dance.md index a6d108f1e9..762816f21b 100644 --- a/docs/ja/feature_tap_dance.md +++ b/docs/ja/feature_tap_dance.md @@ -28,7 +28,6 @@ * `ACTION_TAP_DANCE_DOUBLE(kc1, kc2)`: 1回タップすると `kc1` キーコードを送信し、2回タップすると `kc2` キーコードを送信します。キーを押し続けているときは、適切なキーコードが登録されます: キーを押し続けた場合は `kc1`、一度タップしてから続けてもう一度キーを押してそのまま押し続けたときは、 `kc2` が登録されます。 * `ACTION_TAP_DANCE_LAYER_MOVE(kc, layer)`: 1回タップすると `kc` キーコードが送信され、2回タップすると `layer` レイヤーに移動します(これは `TO` レイヤーキーコードのように機能します)。 - * この機能は `ACTION_TAP_DANCE_DUAL_ROLE` と同じですが、機能が明確になるように関数名を変更しました。どちらの関数名でも実行できます。 * `ACTION_TAP_DANCE_LAYER_TOGGLE(kc, layer)`: 1回タップすると `kc` キーコードが送信され、2回タップすると `layer` の状態をトグルします(これは `TG` レイヤーキーコードのように機能します)。 * `ACTION_TAP_DANCE_FN(fn)`: ユーザーキーマップに定義した指定の関数が呼び出されます。タップダンス実行の回数分タップすると、最後の時点で呼び出されます。 * `ACTION_TAP_DANCE_FN_ADVANCED(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn)`: タップする度にユーザーキーマップに定義した最初の関数が呼び出されます。タップダンスの実行が終わった時点で2番目の関数が呼び出され、タップダンスの実行をリセットするときに最後の関数が呼び出されます。 diff --git a/keyboards/basekeys/slice/rev1/keymaps/2moons/keymap.c b/keyboards/basekeys/slice/rev1/keymaps/2moons/keymap.c index 26ca151089..1292f2d2ed 100644 --- a/keyboards/basekeys/slice/rev1/keymaps/2moons/keymap.c +++ b/keyboards/basekeys/slice/rev1/keymaps/2moons/keymap.c @@ -46,8 +46,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/basekeys/slice/rev1_rgb/keymaps/2moons_rgb/keymap.c b/keyboards/basekeys/slice/rev1_rgb/keymaps/2moons_rgb/keymap.c index 05de0e42d0..7e82c7b7d2 100644 --- a/keyboards/basekeys/slice/rev1_rgb/keymaps/2moons_rgb/keymap.c +++ b/keyboards/basekeys/slice/rev1_rgb/keymaps/2moons_rgb/keymap.c @@ -39,8 +39,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/bpiphany/frosty_flake/keymaps/nikchi/config.h b/keyboards/bpiphany/frosty_flake/keymaps/nikchi/config.h index 4bc6d2c3c0..e45034f9a8 100644 --- a/keyboards/bpiphany/frosty_flake/keymaps/nikchi/config.h +++ b/keyboards/bpiphany/frosty_flake/keymaps/nikchi/config.h @@ -2,6 +2,7 @@ // place overrides here #define TAPPING_TERM 200 +#define TAPPING_TERM_PER_KEY #define LEADER_TIMEOUT 800 #define DISABLE_SPACE_CADET_ROLLOVER diff --git a/keyboards/bpiphany/frosty_flake/keymaps/nikchi/keymap.c b/keyboards/bpiphany/frosty_flake/keymaps/nikchi/keymap.c index dd2098d945..6db177c183 100644 --- a/keyboards/bpiphany/frosty_flake/keymaps/nikchi/keymap.c +++ b/keyboards/bpiphany/frosty_flake/keymaps/nikchi/keymap.c @@ -52,17 +52,33 @@ qk_tap_dance_action_t tap_dance_actions[] = { // Tap once for CTRL, twice for Caps Lock [TD_CTCPS] = ACTION_TAP_DANCE_DOUBLE(KC_LCTL, KC_CAPS), [COPA] = ACTION_TAP_DANCE_DOUBLE(LCTL(KC_C), LCTL(KC_V)), - [EMOJIS] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleEmojis, NULL, NULL, 800), - [ANIMAL] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleAnimals, NULL, NULL, 800), - //[SYMBOLS] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleSymbols, NULL, NULL, 800), - [FOODS] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleFoods, NULL, NULL, 800), - [ETC] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleEtc, NULL, NULL, 800), - //[VEHICLES] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleVehicles, NULL, NULL, 800), - //[SUPPLEMENT] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleSupplement, NULL, NULL, 800), - [ALLS] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(cycleAll, NULL, NULL, 800) + [EMOJIS] = ACTION_TAP_DANCE_FN_ADVANCED(cycleEmojis, NULL, NULL), + [ANIMAL] = ACTION_TAP_DANCE_FN_ADVANCED(cycleAnimals, NULL, NULL), + //[SYMBOLS] = ACTION_TAP_DANCE_FN_ADVANCED(cycleSymbols, NULL, NULL), + [FOODS] = ACTION_TAP_DANCE_FN_ADVANCED(cycleFoods, NULL, NULL), + [ETC] = ACTION_TAP_DANCE_FN_ADVANCED(cycleEtc, NULL, NULL), + //[VEHICLES] = ACTION_TAP_DANCE_FN_ADVANCED(cycleVehicles, NULL, NULL), + //[SUPPLEMENT] = ACTION_TAP_DANCE_FN_ADVANCED(cycleSupplement, NULL, NULL), + [ALLS] = ACTION_TAP_DANCE_FN_ADVANCED(cycleAll, NULL, NULL) // Other declarations would go here, separated by commas, if you have them }; +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(EMOJIS): + case TD(ANIMAL): + //case TD(SYMBOLS): + case TD(FOODS): + case TD(ETC): + //case TD(VEHICLES): + //case TD(SUPPLEMENT): + case TD(ALLS): + return 800; + default: + return TAPPING_TERM; + } +} + // macros const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { switch(id) { diff --git a/keyboards/bpiphany/frosty_flake/keymaps/nikchi/variableTapDance.md b/keyboards/bpiphany/frosty_flake/keymaps/nikchi/variableTapDance.md index b2e5041393..c3fce50f2a 100644 --- a/keyboards/bpiphany/frosty_flake/keymaps/nikchi/variableTapDance.md +++ b/keyboards/bpiphany/frosty_flake/keymaps/nikchi/variableTapDance.md @@ -3,7 +3,4 @@ Tap Dance is constrained normally by `TAPPING_TERM` defined in your keyboard's c -- `ACTION_TAP_DANCE_FN_ADVANCED_TIME(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset, tap_specific_tapping_term)` : This works the same as `ACTION_TAP_DANCE_FN_ADVANCED` just with the extra `tap_specific_tapping_term` arguement at the end. This way you can set a specific tap dance to have a longer or shorter tap in between your taps, giving you more, or less, time in between each tap. - - -`tap_specific_tapping_term` should be the same type and range of values that one would put into the `TAPPING_TERM` definition in the config.h file. +- Implementing `uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record)`, you can set a specific tap dance to have a longer or shorter tap in between your taps, giving you more, or less, time in between each tap. The return value should be the same type and range of values that one would put into the `TAPPING_TERM` definition in the config.h file. diff --git a/keyboards/duck/lightsaver/keymaps/rasmus/keymap.c b/keyboards/duck/lightsaver/keymaps/rasmus/keymap.c index 70dc17bb13..65f128a26b 100644 --- a/keyboards/duck/lightsaver/keymaps/rasmus/keymap.c +++ b/keyboards/duck/lightsaver/keymaps/rasmus/keymap.c @@ -34,8 +34,8 @@ enum { //Tap Dance Definitions qk_tap_dance_action_t tap_dance_actions[] = { - [TD_F1_GAME] = ACTION_TAP_DANCE_DUAL_ROLE(KC_F1, GAME), - [TD_CAPS_FN] = ACTION_TAP_DANCE_DUAL_ROLE(KC_CAPS, 5) + [TD_F1_GAME] = ACTION_TAP_DANCE_LAYER_MOVE(KC_F1, GAME), + [TD_CAPS_FN] = ACTION_TAP_DANCE_LAYER_MOVE(KC_CAPS, 5) }; enum macro_id { diff --git a/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h b/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h index da20820787..c35963d842 100644 --- a/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h +++ b/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h @@ -7,6 +7,7 @@ #undef TAPPING_TERM #define TAPPING_TERM 175 +#define TAPPING_TERM_PER_KEY #undef DEBOUNCE #define DEBOUNCE 15 diff --git a/keyboards/ergodox_ez/keymaps/hacker_dvorak/tap_dance/tap_dance_actions.c b/keyboards/ergodox_ez/keymaps/hacker_dvorak/tap_dance/tap_dance_actions.c index 59e3e2b0dc..1d5e1cee00 100644 --- a/keyboards/ergodox_ez/keymaps/hacker_dvorak/tap_dance/tap_dance_actions.c +++ b/keyboards/ergodox_ez/keymaps/hacker_dvorak/tap_dance/tap_dance_actions.c @@ -13,14 +13,32 @@ qk_tap_dance_action_t tap_dance_actions[] = { [RPRN_RBRC] = ACTION_TAP_DANCE_DOUBLE(KC_RPRN, KC_RBRC), [LCBR_LABK] = ACTION_TAP_DANCE_DOUBLE(KC_LCBR, KC_LABK), [RCBR_RABK] = ACTION_TAP_DANCE_DOUBLE(KC_RCBR, KC_RABK), - [SCLN_COLN] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, scln_coln_finished, scln_coln_reset, DANCING_TERM), - [QUOT_DQUO] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, quot_dquot_finished, quot_dquot_reset, DANCING_TERM), - [DOT_COMM] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, dot_comm_finished, dot_comm_reset, DANCING_TERM), - [NONE_LEAD] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, none_lead_finished, none_lead_reset, DANCING_TERM), - [U_ARR_GUI] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, u_arrows_gui_finished, u_arrows_gui_reset, DANCING_TERM), - [H_MOU_GUI] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, h_mouse_gui_finished, h_mouse_gui_reset, DANCING_TERM), - [J_MED_MEH] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, j_media_meh_finished, j_media_meh_reset, DANCING_TERM), - [W_MED_MEH] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, w_media_meh_finished, w_media_meh_reset, DANCING_TERM), - [K_NUM_HYP] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, k_numpad_hyper_finished, k_numpad_hyper_reset, DANCING_TERM), - [M_CHO_HYP] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, m_chords_hyper_finished, m_chords_hyper_reset, DANCING_TERM), + [SCLN_COLN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, scln_coln_finished, scln_coln_reset), + [QUOT_DQUO] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, quot_dquot_finished, quot_dquot_reset), + [DOT_COMM] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dot_comm_finished, dot_comm_reset), + [NONE_LEAD] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, none_lead_finished, none_lead_reset), + [U_ARR_GUI] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, u_arrows_gui_finished, u_arrows_gui_reset), + [H_MOU_GUI] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, h_mouse_gui_finished, h_mouse_gui_reset), + [J_MED_MEH] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, j_media_meh_finished, j_media_meh_reset), + [W_MED_MEH] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, w_media_meh_finished, w_media_meh_reset), + [K_NUM_HYP] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, k_numpad_hyper_finished, k_numpad_hyper_reset), + [M_CHO_HYP] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, m_chords_hyper_finished, m_chords_hyper_reset), }; + +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(SCLN_COLN): + case TD(QUOT_DQUO): + case TD(DOT_COMM): + case TD(NONE_LEAD): + case TD(U_ARR_GUI): + case TD(H_MOU_GUI): + case TD(J_MED_MEH): + case TD(W_MED_MEH): + case TD(K_NUM_HYP): + case TD(M_CHO_HYP): + return DANCING_TERM; + default: + return TAPPING_TERM; + } +} diff --git a/keyboards/gboards/gergoplex/keymaps/georgepetri/config.h b/keyboards/gboards/gergoplex/keymaps/georgepetri/config.h index f66c334b85..e2c27583fa 100644 --- a/keyboards/gboards/gergoplex/keymaps/georgepetri/config.h +++ b/keyboards/gboards/gergoplex/keymaps/georgepetri/config.h @@ -27,3 +27,5 @@ along with this program. If not, see . #define COMBO_ALLOW_ACTION_KEYS #define COMBO_VARIABLE_LEN + +#define TAPPING_TERM_PER_KEY diff --git a/keyboards/gboards/gergoplex/keymaps/georgepetri/keymap.c b/keyboards/gboards/gergoplex/keymaps/georgepetri/keymap.c index e3b8944814..8b832cbac8 100644 --- a/keyboards/gboards/gergoplex/keymaps/georgepetri/keymap.c +++ b/keyboards/gboards/gergoplex/keymaps/georgepetri/keymap.c @@ -199,5 +199,14 @@ void ql_reset(qk_tap_dance_state_t *state, void *user_data) { } qk_tap_dance_action_t tap_dance_actions[] = { - [GAME] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, ql_finished, ql_reset, 275) + [GAME] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ql_finished, ql_reset) }; + +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: + return 275; + default: + return TAPPING_TERM; + } +} diff --git a/keyboards/handwired/ortho5x14/keymaps/2u/keymap.c b/keyboards/handwired/ortho5x14/keymaps/2u/keymap.c index 70a96fac9d..d785825332 100644 --- a/keyboards/handwired/ortho5x14/keymaps/2u/keymap.c +++ b/keyboards/handwired/ortho5x14/keymaps/2u/keymap.c @@ -343,9 +343,9 @@ qk_tap_dance_action_t tap_dance_actions[] = { [TD_PGUP_HOME] = ACTION_TAP_DANCE_DOUBLE(KC_PGUP, KC_HOME), [TD_PGDN_END] = ACTION_TAP_DANCE_DOUBLE(KC_PGDN, KC_END), - [TD_Q_LrALT] = ACTION_TAP_DANCE_DUAL_ROLE(KC_Q, _ALT), - [TD_R_LrKey] = ACTION_TAP_DANCE_DUAL_ROLE(KC_R, _RAISE), - [TD_T_LrMS] = ACTION_TAP_DANCE_DUAL_ROLE(KC_T, _MOUSE), + [TD_Q_LrALT] = ACTION_TAP_DANCE_LAYER_MOVE(KC_Q, _ALT), + [TD_R_LrKey] = ACTION_TAP_DANCE_LAYER_MOVE(KC_R, _RAISE), + [TD_T_LrMS] = ACTION_TAP_DANCE_LAYER_MOVE(KC_T, _MOUSE), [TD_SHIFT_CAPS] = ACTION_TAP_DANCE_FN_ADVANCED(NULL,lshift_finished, lshift_reset), [TD_SPC_ENT] = ACTION_TAP_DANCE_DOUBLE(KC_SPACE, KC_ENT), diff --git a/keyboards/handwired/ortho5x14/keymaps/split1/keymap.c b/keyboards/handwired/ortho5x14/keymaps/split1/keymap.c index b152503aaf..3734510f8c 100644 --- a/keyboards/handwired/ortho5x14/keymaps/split1/keymap.c +++ b/keyboards/handwired/ortho5x14/keymaps/split1/keymap.c @@ -279,9 +279,9 @@ qk_tap_dance_action_t tap_dance_actions[] = { [TD_PGUP_HOME] = ACTION_TAP_DANCE_DOUBLE(KC_PGUP, KC_HOME), [TD_PGDN_END] = ACTION_TAP_DANCE_DOUBLE(KC_PGUP, KC_END), - [TD_Q_LrALT] = ACTION_TAP_DANCE_DUAL_ROLE(KC_Q, _ALT), - [TD_R_LrKey] = ACTION_TAP_DANCE_DUAL_ROLE(KC_R, _RAISE), - [TD_T_LrMS] = ACTION_TAP_DANCE_DUAL_ROLE(KC_T, _MOUSE), + [TD_Q_LrALT] = ACTION_TAP_DANCE_LAYER_MOVE(KC_Q, _ALT), + [TD_R_LrKey] = ACTION_TAP_DANCE_LAYER_MOVE(KC_R, _RAISE), + [TD_T_LrMS] = ACTION_TAP_DANCE_LAYER_MOVE(KC_T, _MOUSE), [TD_SHIFT_CAPS] = ACTION_TAP_DANCE_FN_ADVANCED(NULL,lshift_finished, lshift_reset), [TD_SPC_ENT] = ACTION_TAP_DANCE_DOUBLE(KC_SPACE, KC_ENT), diff --git a/keyboards/jones/v03/keymaps/default_jp/config.h b/keyboards/jones/v03/keymaps/default_jp/config.h index aa06121c1c..7545003ac7 100644 --- a/keyboards/jones/v03/keymaps/default_jp/config.h +++ b/keyboards/jones/v03/keymaps/default_jp/config.h @@ -21,3 +21,4 @@ // time for long press #define TAPPING_TERM 200 +#define TAPPING_TERM_PER_KEY diff --git a/keyboards/jones/v03/keymaps/default_jp/keymap.c b/keyboards/jones/v03/keymaps/default_jp/keymap.c index 3f5b10208c..bdcb9e88b1 100644 --- a/keyboards/jones/v03/keymaps/default_jp/keymap.c +++ b/keyboards/jones/v03/keymaps/default_jp/keymap.c @@ -51,9 +51,18 @@ void ql_reset(qk_tap_dance_state_t *state, void *user_data); // Tap Dance definitions qk_tap_dance_action_t tap_dance_actions[] = { [TD_LSFT_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_LSFT, KC_CAPS), - [TD_ESC_NUM] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, ql_finished, ql_reset, 275), + [TD_ESC_NUM] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ql_finished, ql_reset), }; +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(TD_ESC_NUM): + return 275; + default: + return TAPPING_TERM; + } +} + // Defines the keycodes used by our macros in process_record_user enum custom_keycodes { MAC = SAFE_RANGE, @@ -303,7 +312,7 @@ static tap ql_tap_state = { // Functions that control what our tap dance key does void ql_finished(qk_tap_dance_state_t *state, void *user_data) { ql_tap_state.state = cur_dance(state); - switch(state->keycode) { + switch(TAP_DANCE_KEYCODE(state)) { case TD(TD_ESC_NUM): // ESC key action switch (ql_tap_state.state) { case SINGLE_TAP: @@ -332,7 +341,7 @@ void ql_finished(qk_tap_dance_state_t *state, void *user_data) { } void ql_reset(qk_tap_dance_state_t *state, void *user_data) { - switch(state->keycode) { + switch(TAP_DANCE_KEYCODE(state)) { case TD(TD_ESC_NUM): // If the key was held down and now is released then switch off the layer if (ql_tap_state.state == TAP_HOLD) { diff --git a/keyboards/jones/v03_1/keymaps/default_ansi/config.h b/keyboards/jones/v03_1/keymaps/default_ansi/config.h index 0b51190bbe..ee7b09a90c 100644 --- a/keyboards/jones/v03_1/keymaps/default_ansi/config.h +++ b/keyboards/jones/v03_1/keymaps/default_ansi/config.h @@ -21,6 +21,7 @@ // time for long press #define TAPPING_TERM 200 +#define TAPPING_TERM_PER_KEY // music map for music-mode #define MUSIC_MAP diff --git a/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c b/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c index 5b1486bb86..e86204a3e3 100644 --- a/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c +++ b/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c @@ -50,9 +50,18 @@ void ql_reset(qk_tap_dance_state_t *state, void *user_data); // Tap Dance definitions qk_tap_dance_action_t tap_dance_actions[] = { [TD_LSFT_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_LSFT, KC_CAPS), - [TD_ESC_NUM] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, ql_finished, ql_reset, 275), + [TD_ESC_NUM] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ql_finished, ql_reset), }; +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(TD_ESC_NUM): + return 275; + default: + return TAPPING_TERM; + } +} + // Defines the keycodes used by our macros in process_record_user enum custom_keycodes { MAC = SAFE_RANGE, @@ -322,7 +331,7 @@ static tap ql_tap_state = { // Functions that control what our tap dance key does void ql_finished(qk_tap_dance_state_t *state, void *user_data) { ql_tap_state.state = cur_dance(state); - switch(state->keycode) { + switch(TAP_DANCE_KEYCODE(state)) { case TD(TD_ESC_NUM): // ESC key action switch (ql_tap_state.state) { case SINGLE_TAP: @@ -351,7 +360,7 @@ void ql_finished(qk_tap_dance_state_t *state, void *user_data) { } void ql_reset(qk_tap_dance_state_t *state, void *user_data) { - switch(state->keycode) { + switch(TAP_DANCE_KEYCODE(state)) { case TD(TD_ESC_NUM): // If the key was held down and now is released then switch off the layer if (ql_tap_state.state == TAP_HOLD) { diff --git a/keyboards/jones/v03_1/keymaps/default_jp/config.h b/keyboards/jones/v03_1/keymaps/default_jp/config.h index 0b51190bbe..ee7b09a90c 100644 --- a/keyboards/jones/v03_1/keymaps/default_jp/config.h +++ b/keyboards/jones/v03_1/keymaps/default_jp/config.h @@ -21,6 +21,7 @@ // time for long press #define TAPPING_TERM 200 +#define TAPPING_TERM_PER_KEY // music map for music-mode #define MUSIC_MAP diff --git a/keyboards/jones/v03_1/keymaps/default_jp/keymap.c b/keyboards/jones/v03_1/keymaps/default_jp/keymap.c index 436586a721..9a2663f6d7 100644 --- a/keyboards/jones/v03_1/keymaps/default_jp/keymap.c +++ b/keyboards/jones/v03_1/keymaps/default_jp/keymap.c @@ -51,9 +51,18 @@ void ql_reset(qk_tap_dance_state_t *state, void *user_data); // Tap Dance definitions qk_tap_dance_action_t tap_dance_actions[] = { [TD_LSFT_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_LSFT, KC_CAPS), - [TD_ESC_NUM] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, ql_finished, ql_reset, 275), + [TD_ESC_NUM] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ql_finished, ql_reset), }; +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(TD_ESC_NUM): + return 275; + default: + return TAPPING_TERM; + } +} + // Defines the keycodes used by our macros in process_record_user enum custom_keycodes { MAC = SAFE_RANGE, @@ -324,7 +333,7 @@ static tap ql_tap_state = { // Functions that control what our tap dance key does void ql_finished(qk_tap_dance_state_t *state, void *user_data) { ql_tap_state.state = cur_dance(state); - switch(state->keycode) { + switch(TAP_DANCE_KEYCODE(state)) { case TD(TD_ESC_NUM): // ESC key action switch (ql_tap_state.state) { case SINGLE_TAP: @@ -353,7 +362,7 @@ void ql_finished(qk_tap_dance_state_t *state, void *user_data) { } void ql_reset(qk_tap_dance_state_t *state, void *user_data) { - switch(state->keycode) { + switch(TAP_DANCE_KEYCODE(state)) { case TD(TD_ESC_NUM): // If the key was held down and now is released then switch off the layer if (ql_tap_state.state == TAP_HOLD) { diff --git a/keyboards/keyhive/navi10/keymaps/default/keymap.c b/keyboards/keyhive/navi10/keymaps/default/keymap.c index d1b3127760..c4295b1553 100644 --- a/keyboards/keyhive/navi10/keymaps/default/keymap.c +++ b/keyboards/keyhive/navi10/keymaps/default/keymap.c @@ -127,5 +127,5 @@ void tk_reset(qk_tap_dance_state_t *state, void *user_data){ //associate the tap dance key with its functionality qk_tap_dance_action_t tap_dance_actions[] = { - [TAPPY_KEY] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, tk_finished, tk_reset, 275) + [TAPPY_KEY] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, tk_finished, tk_reset) }; diff --git a/keyboards/keyhive/navi10/keymaps/devdev/keymap.c b/keyboards/keyhive/navi10/keymaps/devdev/keymap.c index b0d43ebc69..0fc20cbbd4 100644 --- a/keyboards/keyhive/navi10/keymaps/devdev/keymap.c +++ b/keyboards/keyhive/navi10/keymaps/devdev/keymap.c @@ -259,5 +259,5 @@ void tk_reset(qk_tap_dance_state_t *state, void *user_data){ //associate the tap dance key with its functionality qk_tap_dance_action_t tap_dance_actions[] = { - [TAPPY_KEY] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, tk_finished, tk_reset, TAPPING_TERM) + [TAPPY_KEY] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, tk_finished, tk_reset) }; diff --git a/keyboards/keyhive/navi10/keymaps/emdarcher/keymap.c b/keyboards/keyhive/navi10/keymaps/emdarcher/keymap.c index 40efed48d5..37850e28f3 100644 --- a/keyboards/keyhive/navi10/keymaps/emdarcher/keymap.c +++ b/keyboards/keyhive/navi10/keymaps/emdarcher/keymap.c @@ -178,5 +178,5 @@ void tk_reset(qk_tap_dance_state_t *state, void *user_data){ //associate the tap dance key with its functionality qk_tap_dance_action_t tap_dance_actions[] = { - [TAPPY_KEY] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, tk_finished, tk_reset, 275) + [TAPPY_KEY] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, tk_finished, tk_reset) }; diff --git a/keyboards/kprepublic/jj50/keymaps/archetype/config.h b/keyboards/kprepublic/jj50/keymaps/archetype/config.h index a12e070b4f..9604ac719c 100644 --- a/keyboards/kprepublic/jj50/keymaps/archetype/config.h +++ b/keyboards/kprepublic/jj50/keymaps/archetype/config.h @@ -6,4 +6,5 @@ #define AUTO_SHIFT_TIMEOUT 150 #define NO_AUTO_SHIFT_ALPHA #define TAPPING_TERM 150 +#define TAPPING_TERM_PER_KEY //#define BOOTMAGIC_KEY_SALT KC_LCTL diff --git a/keyboards/kprepublic/jj50/keymaps/archetype/keymap.c b/keyboards/kprepublic/jj50/keymaps/archetype/keymap.c index 82c615f135..ff59ef43e5 100644 --- a/keyboards/kprepublic/jj50/keymaps/archetype/keymap.c +++ b/keyboards/kprepublic/jj50/keymaps/archetype/keymap.c @@ -167,9 +167,18 @@ qk_tap_dance_action_t tap_dance_actions[] = { // Single tap = ) | Double tap = ] | Triple tap = } | Single hold = KC_LALT [TD_LALT_RBRC] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, right_brackets, right_brackets_reset), // Layer Switcher ESC - [TD_ESC_LAYER] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, layer_switcher, layer_switcher_reset, 100), + [TD_ESC_LAYER] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, layer_switcher, layer_switcher_reset), }; +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(TD_ESC_LAYER): + return 100; + default: + return TAPPING_TERM; + } +} + const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/planck/keymaps/ariccb/config.h b/keyboards/planck/keymaps/ariccb/config.h index 322aa9277f..464a8cd5db 100644 --- a/keyboards/planck/keymaps/ariccb/config.h +++ b/keyboards/planck/keymaps/ariccb/config.h @@ -40,6 +40,7 @@ //#define MIDI_ADVANCED #define TAPPING_TERM 150 +#define TAPPING_TERM_PER_KEY #define IGNORE_MOD_TAP_INTERRUPT // #define IGNORE_MOD_TAP_INTERRUPT // #define HOLD_ON_OTHER_KEY_PRESS diff --git a/keyboards/planck/keymaps/ariccb/keymap.c b/keyboards/planck/keymaps/ariccb/keymap.c index c0b4e490fa..33d0a26273 100644 --- a/keyboards/planck/keymaps/ariccb/keymap.c +++ b/keyboards/planck/keymaps/ariccb/keymap.c @@ -379,9 +379,18 @@ void usl_reset(qk_tap_dance_state_t *state, void *user_data) { // Associate our tap dance key with its functionality qk_tap_dance_action_t tap_dance_actions[] = { - [UNDS_LOWER] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, usl_finished, usl_reset, 175) + [UNDS_LOWER] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, usl_finished, usl_reset) }; +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(UNDS_LOWER): + return 175; + default: + return TAPPING_TERM; + } +} + bool process_record_user(uint16_t keycode, keyrecord_t *record) { if (!process_select_word(keycode, record, SELWORD)) { return false; } if (!process_caps_word(keycode, record)) { return false; } @@ -661,4 +670,4 @@ void process_combo_event(uint16_t combo_index, bool pressed) { } break; } -} \ No newline at end of file +} diff --git a/keyboards/planck/keymaps/rootiest/config.h b/keyboards/planck/keymaps/rootiest/config.h index fc1fc81761..5bb5a73a29 100644 --- a/keyboards/planck/keymaps/rootiest/config.h +++ b/keyboards/planck/keymaps/rootiest/config.h @@ -87,6 +87,7 @@ /* * TAP-DANCE options */ +#define TAPPING_TERM_PER_KEY // Control Tap-Dance time individually by key #define TAPPING_TERM 250 // Default time allowed before resetting a Tap-Dance combo #define ONESHOT_TAP_TOGGLE 5 /* Tapping this number of times holds the key until tapped once again. */ #define ONESHOT_TIMEOUT 5000 /* Time (in ms) before the one shot key is released */ diff --git a/keyboards/planck/keymaps/rootiest/keymap.c b/keyboards/planck/keymaps/rootiest/keymap.c index 634bf2829e..857d7a9e21 100644 --- a/keyboards/planck/keymaps/rootiest/keymap.c +++ b/keyboards/planck/keymaps/rootiest/keymap.c @@ -1656,13 +1656,26 @@ void sml_reset(qk_tap_dance_state_t* state, void* user_data) { sml_state.state = // Tap Dance definitions qk_tap_dance_action_t tap_dance_actions[] = { // Tap once for °, twice for ℉, thrice for ℃ - [TD_DEG_DEGF] = ACTION_TAP_DANCE_FN(send_degree_symbol), // - [TD_LSHFT_CAPS] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, scap_finished, scap_reset, 200), // - [TD_LCTL_STICKY] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, slctl_finished, slctl_reset, 200), // - [TD_LALT_STICKY] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, slalt_finished, slalt_reset, 200), // - [TD_SMILEY] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, sml_finished, sml_reset, 500), + [TD_DEG_DEGF] = ACTION_TAP_DANCE_FN(send_degree_symbol), // + [TD_LSHFT_CAPS] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, scap_finished, scap_reset), // + [TD_LCTL_STICKY] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, slctl_finished, slctl_reset), // + [TD_LALT_STICKY] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, slalt_finished, slalt_reset), // + [TD_SMILEY] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, sml_finished, sml_reset), }; +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(TD_LSHFT_CAPS): + case TD(TD_LCTL_STICKY): + case TD(TD_LALT_STICKY): + return 200; + case TD(TD_SMILEY): + return 500; + default: + return TAPPING_TERM; + } +} + // Dip-Switch controls void dip_switch_update_user(uint8_t index, bool active) { switch (index) { diff --git a/keyboards/salicylic_acid3/7skb/keymaps/salicylic/keymap.c b/keyboards/salicylic_acid3/7skb/keymaps/salicylic/keymap.c index 4e1f2acd05..7221f8c612 100644 --- a/keyboards/salicylic_acid3/7skb/keymaps/salicylic/keymap.c +++ b/keyboards/salicylic_acid3/7skb/keymaps/salicylic/keymap.c @@ -32,8 +32,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/salicylic_acid3/7splus/keymaps/salicylic/keymap.c b/keyboards/salicylic_acid3/7splus/keymaps/salicylic/keymap.c index 06d7972a2e..bea5978c50 100644 --- a/keyboards/salicylic_acid3/7splus/keymaps/salicylic/keymap.c +++ b/keyboards/salicylic_acid3/7splus/keymaps/salicylic/keymap.c @@ -39,8 +39,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESMS] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _MOUSE), - [TD_ESAR] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESMS] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _MOUSE), + [TD_ESAR] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/salicylic_acid3/jisplit89/keymaps/salicylic/keymap.c b/keyboards/salicylic_acid3/jisplit89/keymaps/salicylic/keymap.c index 4e8addf6b7..eba01d4d65 100644 --- a/keyboards/salicylic_acid3/jisplit89/keymaps/salicylic/keymap.c +++ b/keyboards/salicylic_acid3/jisplit89/keymaps/salicylic/keymap.c @@ -39,8 +39,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESMS] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _MOUSE), - [TD_ESAR] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESMS] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _MOUSE), + [TD_ESAR] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/salicylic_acid3/naked60/keymaps/salicylic/keymap.c b/keyboards/salicylic_acid3/naked60/keymaps/salicylic/keymap.c index 8a2dbf051f..b70e68da54 100644 --- a/keyboards/salicylic_acid3/naked60/keymaps/salicylic/keymap.c +++ b/keyboards/salicylic_acid3/naked60/keymaps/salicylic/keymap.c @@ -23,8 +23,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_nafuda/keymap.c b/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_nafuda/keymap.c index 4201d79a2e..c43803be35 100644 --- a/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_nafuda/keymap.c +++ b/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_nafuda/keymap.c @@ -34,8 +34,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_setta21/keymap.c b/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_setta21/keymap.c index 23786da915..6dd2ef8863 100644 --- a/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_setta21/keymap.c +++ b/keyboards/salicylic_acid3/naked60/keymaps/salicylic_with_setta21/keymap.c @@ -32,8 +32,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/salicylic_acid3/naked64/keymaps/salicylic/keymap.c b/keyboards/salicylic_acid3/naked64/keymaps/salicylic/keymap.c index db46075c8f..ae7843341a 100644 --- a/keyboards/salicylic_acid3/naked64/keymaps/salicylic/keymap.c +++ b/keyboards/salicylic_acid3/naked64/keymaps/salicylic/keymap.c @@ -33,8 +33,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/salicylic_acid3/naked64/keymaps/salicylic_with_setta21/keymap.c b/keyboards/salicylic_acid3/naked64/keymaps/salicylic_with_setta21/keymap.c index c91716cdd4..6e2dd0886f 100644 --- a/keyboards/salicylic_acid3/naked64/keymaps/salicylic_with_setta21/keymap.c +++ b/keyboards/salicylic_acid3/naked64/keymaps/salicylic_with_setta21/keymap.c @@ -38,8 +38,8 @@ enum tapdances{ }; qk_tap_dance_action_t tap_dance_actions[] = { - [TD_ESFL] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _FLOCK), - [TD_ESQW] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _QWERTY), + [TD_ESFL] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _FLOCK), + [TD_ESQW] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _QWERTY), }; #define LOWER MO(_LOWER) diff --git a/keyboards/thevankeyboards/minivan/keymaps/belak/keymap.c b/keyboards/thevankeyboards/minivan/keymaps/belak/keymap.c index 437b1881a4..0ed709747a 100644 --- a/keyboards/thevankeyboards/minivan/keymaps/belak/keymap.c +++ b/keyboards/thevankeyboards/minivan/keymaps/belak/keymap.c @@ -22,6 +22,9 @@ #define TD_LCTL TD(BE_TD_CTL) #define TD_LALT TD(BE_TD_ALT) +#define ACTION_TAP_DANCE_MOD_TAP(mod) \ + { .fn = {mod_tap_fn, NULL, mod_reset_fn}, .user_data = (void *)&((uint8_t){mod}), } + enum belak_td { BE_TD_GUI = 0, BE_TD_CTL, @@ -32,15 +35,9 @@ void mod_tap_fn(qk_tap_dance_state_t *state, void *user_data); void mod_reset_fn(qk_tap_dance_state_t *state, void *user_data); qk_tap_dance_action_t tap_dance_actions[] = { - [BE_TD_GUI] = ACTION_TAP_DANCE_FN_ADVANCED(mod_tap_fn, NULL, mod_reset_fn), - [BE_TD_CTL] = ACTION_TAP_DANCE_FN_ADVANCED(mod_tap_fn, NULL, mod_reset_fn), - [BE_TD_ALT] = ACTION_TAP_DANCE_FN_ADVANCED(mod_tap_fn, NULL, mod_reset_fn), -}; - -uint16_t tap_dance_keys[] = { - [BE_TD_GUI] = KC_LGUI, - [BE_TD_CTL] = KC_LCTL, - [BE_TD_ALT] = KC_LALT, + [BE_TD_GUI] = ACTION_TAP_DANCE_MOD_TAP(KC_LGUI), + [BE_TD_CTL] = ACTION_TAP_DANCE_MOD_TAP(KC_LCTL), + [BE_TD_ALT] = ACTION_TAP_DANCE_MOD_TAP(KC_LALT), }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { @@ -74,7 +71,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void mod_tap_fn(qk_tap_dance_state_t *state, void *user_data) { switch (state->count) { case 1: - register_mods(MOD_BIT(tap_dance_keys[state->keycode - QK_TAP_DANCE])); + uint8_t *mod = (uint8_t *)user_data; + register_mods(MOD_BIT(*mod)); send_keyboard_report(); break; case 2: @@ -90,8 +88,9 @@ void mod_tap_fn(qk_tap_dance_state_t *state, void *user_data) { } void mod_reset_fn(qk_tap_dance_state_t *state, void *user_data) { + uint8_t *mod = (uint8_t *)user_data; layer_off(_L1); layer_off(_L2); - unregister_mods(MOD_BIT(tap_dance_keys[state->keycode - QK_TAP_DANCE])); + unregister_mods(MOD_BIT(*mod)); send_keyboard_report(); } diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c index db8df5f870..3270a1b000 100644 --- a/quantum/process_keycode/process_tap_dance.c +++ b/quantum/process_keycode/process_tap_dance.c @@ -15,12 +15,8 @@ */ #include "quantum.h" -#ifndef NO_ACTION_ONESHOT -uint8_t get_oneshot_mods(void); -#endif - -static uint16_t last_td; -static int16_t highest_td = -1; +static uint16_t active_td; +static uint16_t last_tap_time; void qk_tap_dance_pair_on_each_tap(qk_tap_dance_state_t *state, void *user_data) { qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data; @@ -34,18 +30,14 @@ void qk_tap_dance_pair_on_each_tap(qk_tap_dance_state_t *state, void *user_data) void qk_tap_dance_pair_finished(qk_tap_dance_state_t *state, void *user_data) { qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data; - if (state->count == 1) { - register_code16(pair->kc1); - } else if (state->count == 2) { - register_code16(pair->kc2); - } + register_code16(pair->kc1); } void qk_tap_dance_pair_reset(qk_tap_dance_state_t *state, void *user_data) { qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data; - wait_ms(TAP_CODE_DELAY); if (state->count == 1) { + wait_ms(TAP_CODE_DELAY); unregister_code16(pair->kc1); } else if (state->count == 2) { unregister_code16(pair->kc2); @@ -87,23 +79,40 @@ static inline void _process_tap_dance_action_fn(qk_tap_dance_state_t *state, voi } static inline void process_tap_dance_action_on_each_tap(qk_tap_dance_action_t *action) { + action->state.count++; + action->state.weak_mods = get_mods(); + action->state.weak_mods |= get_weak_mods(); +#ifndef NO_ACTION_ONESHOT + action->state.oneshot_mods = get_oneshot_mods(); +#endif _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_each_tap); } -static inline void process_tap_dance_action_on_dance_finished(qk_tap_dance_action_t *action) { - if (action->state.finished) return; - action->state.finished = true; - add_mods(action->state.oneshot_mods); - add_weak_mods(action->state.weak_mods); - send_keyboard_report(); - _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_dance_finished); -} - static inline void process_tap_dance_action_on_reset(qk_tap_dance_action_t *action) { _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_reset); - del_mods(action->state.oneshot_mods); del_weak_mods(action->state.weak_mods); +#ifndef NO_ACTION_ONESHOT + del_mods(action->state.oneshot_mods); +#endif send_keyboard_report(); + action->state = (const qk_tap_dance_state_t){0}; +} + +static inline void process_tap_dance_action_on_dance_finished(qk_tap_dance_action_t *action) { + if (!action->state.finished) { + action->state.finished = true; + add_weak_mods(action->state.weak_mods); +#ifndef NO_ACTION_ONESHOT + add_mods(action->state.oneshot_mods); +#endif + send_keyboard_report(); + _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_dance_finished); + } + active_td = 0; + if (!action->state.pressed) { + // There will not be a key release event, so reset now. + process_tap_dance_action_on_reset(action); + } } void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) { @@ -111,51 +120,33 @@ void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) { if (!record->event.pressed) return; - if (highest_td == -1) return; - - for (int i = 0; i <= highest_td; i++) { - action = &tap_dance_actions[i]; - if (action->state.count) { - if (keycode == action->state.keycode && keycode == last_td) continue; - action->state.interrupted = true; - action->state.interrupting_keycode = keycode; - process_tap_dance_action_on_dance_finished(action); - reset_tap_dance(&action->state); - - // Tap dance actions can leave some weak mods active (e.g., if the tap dance is mapped to a keycode with - // modifiers), but these weak mods should not affect the keypress which interrupted the tap dance. - clear_weak_mods(); - } - } + if (!active_td || keycode == active_td) return; + + action = &tap_dance_actions[TD_INDEX(active_td)]; + action->state.interrupted = true; + action->state.interrupting_keycode = keycode; + process_tap_dance_action_on_dance_finished(action); + + // Tap dance actions can leave some weak mods active (e.g., if the tap dance is mapped to a keycode with + // modifiers), but these weak mods should not affect the keypress which interrupted the tap dance. + clear_weak_mods(); } bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { - uint16_t idx = keycode - QK_TAP_DANCE; qk_tap_dance_action_t *action; switch (keycode) { case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: - if ((int16_t)idx > highest_td) highest_td = idx; - action = &tap_dance_actions[idx]; + action = &tap_dance_actions[TD_INDEX(keycode)]; action->state.pressed = record->event.pressed; if (record->event.pressed) { - action->state.keycode = keycode; - action->state.count++; - action->state.timer = timer_read(); -#ifndef NO_ACTION_ONESHOT - action->state.oneshot_mods = get_oneshot_mods(); -#else - action->state.oneshot_mods = 0; -#endif - action->state.weak_mods = get_mods(); - action->state.weak_mods |= get_weak_mods(); + last_tap_time = timer_read(); process_tap_dance_action_on_each_tap(action); - - last_td = keycode; + active_td = action->state.finished ? 0 : keycode; } else { - if (action->state.count && action->state.finished) { - reset_tap_dance(&action->state); + if (action->state.finished) { + process_tap_dance_action_on_reset(action); } } @@ -166,35 +157,17 @@ bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { } void tap_dance_task() { - if (highest_td == -1) return; - uint16_t tap_user_defined; - - for (uint8_t i = 0; i <= highest_td; i++) { - qk_tap_dance_action_t *action = &tap_dance_actions[i]; - if (action->custom_tapping_term > 0) { - tap_user_defined = action->custom_tapping_term; - } else { - tap_user_defined = GET_TAPPING_TERM(action->state.keycode, &(keyrecord_t){}); - } - if (action->state.count && timer_elapsed(action->state.timer) > tap_user_defined) { - process_tap_dance_action_on_dance_finished(action); - reset_tap_dance(&action->state); - } - } -} - -void reset_tap_dance(qk_tap_dance_state_t *state) { qk_tap_dance_action_t *action; - if (state->pressed) return; + if (!active_td || timer_elapsed(last_tap_time) <= GET_TAPPING_TERM(active_td, &(keyrecord_t){})) return; - action = &tap_dance_actions[state->keycode - QK_TAP_DANCE]; - - process_tap_dance_action_on_reset(action); + action = &tap_dance_actions[TD_INDEX(active_td)]; + if (!action->state.interrupted) { + process_tap_dance_action_on_dance_finished(action); + } +} - state->count = 0; - state->interrupted = false; - state->finished = false; - state->interrupting_keycode = 0; - last_td = 0; +void reset_tap_dance(qk_tap_dance_state_t *state) { + active_td = 0; + process_tap_dance_action_on_reset((qk_tap_dance_action_t *)state); } diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h index d9ffb1e73d..d97900d96b 100644 --- a/quantum/process_keycode/process_tap_dance.h +++ b/quantum/process_keycode/process_tap_dance.h @@ -22,30 +22,27 @@ # include typedef struct { + uint16_t interrupting_keycode; uint8_t count; - uint8_t oneshot_mods; uint8_t weak_mods; - uint16_t keycode; - uint16_t interrupting_keycode; - uint16_t timer; - bool interrupted; - bool pressed; - bool finished; +# ifndef NO_ACTION_ONESHOT + uint8_t oneshot_mods; +# endif + bool pressed : 1; + bool finished : 1; + bool interrupted : 1; } qk_tap_dance_state_t; -# define TD(n) (QK_TAP_DANCE | ((n)&0xFF)) - typedef void (*qk_tap_dance_user_fn_t)(qk_tap_dance_state_t *state, void *user_data); typedef struct { + qk_tap_dance_state_t state; struct { qk_tap_dance_user_fn_t on_each_tap; qk_tap_dance_user_fn_t on_dance_finished; qk_tap_dance_user_fn_t on_reset; } fn; - qk_tap_dance_state_t state; - uint16_t custom_tapping_term; - void * user_data; + void *user_data; } qk_tap_dance_action_t; typedef struct { @@ -62,31 +59,31 @@ typedef struct { # define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) \ { .fn = {qk_tap_dance_pair_on_each_tap, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset}, .user_data = (void *)&((qk_tap_dance_pair_t){kc1, kc2}), } -# define ACTION_TAP_DANCE_DUAL_ROLE(kc, layer) \ +# define ACTION_TAP_DANCE_LAYER_MOVE(kc, layer) \ { .fn = {qk_tap_dance_dual_role_on_each_tap, qk_tap_dance_dual_role_finished, qk_tap_dance_dual_role_reset}, .user_data = (void *)&((qk_tap_dance_dual_role_t){kc, layer, layer_move}), } # define ACTION_TAP_DANCE_LAYER_TOGGLE(kc, layer) \ { .fn = {NULL, qk_tap_dance_dual_role_finished, qk_tap_dance_dual_role_reset}, .user_data = (void *)&((qk_tap_dance_dual_role_t){kc, layer, layer_invert}), } -# define ACTION_TAP_DANCE_LAYER_MOVE(kc, layer) ACTION_TAP_DANCE_DUAL_ROLE(kc, layer) - # define ACTION_TAP_DANCE_FN(user_fn) \ { .fn = {NULL, user_fn, NULL}, .user_data = NULL, } # define ACTION_TAP_DANCE_FN_ADVANCED(user_fn_on_each_tap, 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_data = NULL, } -# define ACTION_TAP_DANCE_FN_ADVANCED_TIME(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset, tap_specific_tapping_term) \ - { .fn = {user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset}, .user_data = NULL, .custom_tapping_term = tap_specific_tapping_term, } +# define TD(n) (QK_TAP_DANCE | TD_INDEX(n)) +# define TD_INDEX(code) ((code)&0xFF) +# define TAP_DANCE_KEYCODE(state) TD(((qk_tap_dance_action_t *)state) - tap_dance_actions) extern qk_tap_dance_action_t tap_dance_actions[]; +void reset_tap_dance(qk_tap_dance_state_t *state); + /* To be used internally */ void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record); bool process_tap_dance(uint16_t keycode, keyrecord_t *record); void tap_dance_task(void); -void reset_tap_dance(qk_tap_dance_state_t *state); void qk_tap_dance_pair_on_each_tap(qk_tap_dance_state_t *state, void *user_data); void qk_tap_dance_pair_finished(qk_tap_dance_state_t *state, void *user_data); diff --git a/tests/tapdance/config.h b/tests/tapdance/config.h new file mode 100644 index 0000000000..6aada3efd3 --- /dev/null +++ b/tests/tapdance/config.h @@ -0,0 +1,19 @@ +/* Copyright 2022 Jouke Witteveen + * + * 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 . + */ + +#pragma once + +#include "test_common.h" diff --git a/tests/tapdance/examples.c b/tests/tapdance/examples.c new file mode 100644 index 0000000000..4a5be41b08 --- /dev/null +++ b/tests/tapdance/examples.c @@ -0,0 +1,199 @@ +/* Copyright 2022 Jouke Witteveen + * + * 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 . + */ + +#include "quantum.h" +#include "examples.h" + +// Example code from the tap dance documentation, adapted for testing + +// clang-format off + +// Example 1 + +void dance_egg(qk_tap_dance_state_t *state, void *user_data) { + if (state->count >= 100) { + // SEND_STRING("Safety dance!"); + tap_code(KC_C); + reset_tap_dance(state); + } +} + + +// Example 2 + +void dance_flsh_each(qk_tap_dance_state_t *state, void *user_data) { + switch (state->count) { + case 1: + register_code(KC_3); + break; + case 2: + register_code(KC_2); + break; + case 3: + register_code(KC_1); + break; + case 4: + unregister_code(KC_3); + // wait_ms(50); + unregister_code(KC_2); + // wait_ms(50); + unregister_code(KC_1); + } +} + +void dance_flsh_finished(qk_tap_dance_state_t *state, void *user_data) { + if (state->count >= 4) { + // reset_keyboard(); + tap_code(KC_R); + } +} + +void dance_flsh_reset(qk_tap_dance_state_t *state, void *user_data) { + unregister_code(KC_1); + // wait_ms(50); + unregister_code(KC_2); + // wait_ms(50); + unregister_code(KC_3); +} + + +// Example 3 + +typedef struct { + uint16_t tap; + uint16_t hold; + uint16_t held; +} tap_dance_tap_hold_t; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + qk_tap_dance_action_t *action; + + switch (keycode) { + case TD(CT_CLN): + action = &tap_dance_actions[TD_INDEX(keycode)]; + if (!record->event.pressed && action->state.count && !action->state.finished) { + tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data; + tap_code16(tap_hold->tap); + } + } + return true; +} + +void tap_dance_tap_hold_finished(qk_tap_dance_state_t *state, void *user_data) { + tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; + + if (state->pressed) { + if (state->count == 1 +#ifndef PERMISSIVE_HOLD + && !state->interrupted +#endif + ) { + register_code16(tap_hold->hold); + tap_hold->held = tap_hold->hold; + } else { + register_code16(tap_hold->tap); + tap_hold->held = tap_hold->tap; + } + } +} + +void tap_dance_tap_hold_reset(qk_tap_dance_state_t *state, void *user_data) { + tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; + + if (tap_hold->held) { + unregister_code16(tap_hold->held); + tap_hold->held = 0; + } +} + +#define ACTION_TAP_DANCE_TAP_HOLD(tap, hold) \ + { .fn = {NULL, tap_dance_tap_hold_finished, tap_dance_tap_hold_reset}, .user_data = (void *)&((tap_dance_tap_hold_t){tap, hold, 0}), } + + +// Example 4 + +typedef enum { + TD_NONE, + TD_UNKNOWN, + TD_SINGLE_TAP, + TD_SINGLE_HOLD, + TD_DOUBLE_TAP, + TD_DOUBLE_HOLD, + TD_DOUBLE_SINGLE_TAP, + TD_TRIPLE_TAP, + TD_TRIPLE_HOLD +} td_state_t; + +typedef struct { + bool is_press_action; + td_state_t state; +} td_tap_t; + +td_state_t cur_dance(qk_tap_dance_state_t *state) { + if (state->count == 1) { + if (state->interrupted || !state->pressed) return TD_SINGLE_TAP; + else return TD_SINGLE_HOLD; + } else if (state->count == 2) { + if (state->interrupted) return TD_DOUBLE_SINGLE_TAP; + else if (state->pressed) return TD_DOUBLE_HOLD; + else return TD_DOUBLE_TAP; + } + + if (state->count == 3) { + if (state->interrupted || !state->pressed) return TD_TRIPLE_TAP; + else return TD_TRIPLE_HOLD; + } else return TD_UNKNOWN; +} + +static td_tap_t xtap_state = { + .is_press_action = true, + .state = TD_NONE +}; + +void x_finished(qk_tap_dance_state_t *state, void *user_data) { + xtap_state.state = cur_dance(state); + switch (xtap_state.state) { + case TD_SINGLE_TAP: register_code(KC_X); break; + case TD_SINGLE_HOLD: register_code(KC_LCTL); break; + case TD_DOUBLE_TAP: register_code(KC_ESC); break; + case TD_DOUBLE_HOLD: register_code(KC_LALT); break; + case TD_DOUBLE_SINGLE_TAP: tap_code(KC_X); register_code(KC_X); + default: break; // Not present in documentation + } +} + +void x_reset(qk_tap_dance_state_t *state, void *user_data) { + switch (xtap_state.state) { + case TD_SINGLE_TAP: unregister_code(KC_X); break; + case TD_SINGLE_HOLD: unregister_code(KC_LCTL); break; + case TD_DOUBLE_TAP: unregister_code(KC_ESC); break; + case TD_DOUBLE_HOLD: unregister_code(KC_LALT); + case TD_DOUBLE_SINGLE_TAP: unregister_code(KC_X); + default: break; // Not present in documentation + } + xtap_state.state = TD_NONE; +} + + +qk_tap_dance_action_t tap_dance_actions[] = { + [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS), + [CT_EGG] = ACTION_TAP_DANCE_FN(dance_egg), + [CT_FLSH] = ACTION_TAP_DANCE_FN_ADVANCED(dance_flsh_each, dance_flsh_finished, dance_flsh_reset), + [CT_CLN] = ACTION_TAP_DANCE_TAP_HOLD(KC_COLN, KC_SCLN), + [X_CTL] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, x_finished, x_reset) +}; + +// clang-format on diff --git a/tests/tapdance/examples.h b/tests/tapdance/examples.h new file mode 100644 index 0000000000..2622af6b2f --- /dev/null +++ b/tests/tapdance/examples.h @@ -0,0 +1,33 @@ +/* Copyright 2022 Jouke Witteveen + * + * 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 . + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + TD_ESC_CAPS, + CT_EGG, + CT_FLSH, + CT_CLN, + X_CTL, +}; + +#ifdef __cplusplus +} +#endif diff --git a/tests/tapdance/test.mk b/tests/tapdance/test.mk new file mode 100644 index 0000000000..041d9b4dc9 --- /dev/null +++ b/tests/tapdance/test.mk @@ -0,0 +1,22 @@ +# Copyright 2022 Jouke Witteveen +# +# 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 . + +# -------------------------------------------------------------------------------- +# Keep this file, even if it is empty, as a marker that this folder contains tests +# -------------------------------------------------------------------------------- + +TAP_DANCE_ENABLE = yes + +SRC += examples.c diff --git a/tests/tapdance/test_examples.cpp b/tests/tapdance/test_examples.cpp new file mode 100644 index 0000000000..e67e6cb907 --- /dev/null +++ b/tests/tapdance/test_examples.cpp @@ -0,0 +1,319 @@ +/* Copyright 2022 Jouke Witteveen + * + * 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 . + */ + +#include "keyboard_report_util.hpp" +#include "keycode.h" +#include "test_common.hpp" +#include "action_tapping.h" +#include "test_keymap_key.hpp" +#include "examples.h" + +using testing::_; +using testing::InSequence; + +class TapDance : public TestFixture {}; + +TEST_F(TapDance, DoubleTap) { + TestDriver driver; + InSequence s; + auto key_esc_caps = KeymapKey{0, 1, 0, TD(TD_ESC_CAPS)}; + + set_keymap({key_esc_caps}); + + /* The tap dance key does nothing on the first press */ + key_esc_caps.press(); + run_one_scan_loop(); + key_esc_caps.release(); + EXPECT_NO_REPORT(driver); + + /* We get the key press and the release on timeout */ + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_ESC)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Double tap gets us the second key */ + tap_key(key_esc_caps); + EXPECT_NO_REPORT(driver); + key_esc_caps.press(); + EXPECT_REPORT(driver, (KC_CAPS)); + run_one_scan_loop(); + key_esc_caps.release(); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); +} + +TEST_F(TapDance, DoubleTapWithMod) { + TestDriver driver; + InSequence s; + auto key_esc_caps = KeymapKey{0, 1, 0, TD(TD_ESC_CAPS)}; + auto key_shift = KeymapKey{0, 2, 0, KC_LSFT}; + + set_keymap({key_esc_caps, key_shift}); + + /* The tap dance key does nothing on the first press */ + key_shift.press(); + EXPECT_REPORT(driver, (KC_LSFT)); + run_one_scan_loop(); + key_esc_caps.press(); + run_one_scan_loop(); + + key_esc_caps.release(); + key_shift.release(); + EXPECT_EMPTY_REPORT(driver); + + /* We get the key press and the release */ + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_LSFT)); + EXPECT_REPORT(driver, (KC_LSFT, KC_ESC)); + EXPECT_REPORT(driver, (KC_LSFT)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Double tap gets us the second key */ + key_shift.press(); + EXPECT_REPORT(driver, (KC_LSFT)); + run_one_scan_loop(); + tap_key(key_esc_caps); + EXPECT_NO_REPORT(driver); + key_shift.release(); + key_esc_caps.press(); + EXPECT_REPORT(driver, (KC_LSFT, KC_CAPS)); + run_one_scan_loop(); + key_esc_caps.release(); + EXPECT_REPORT(driver, (KC_LSFT)); + run_one_scan_loop(); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); +} + +TEST_F(TapDance, DoubleTapInterrupted) { + TestDriver driver; + InSequence s; + auto key_esc_caps = KeymapKey{0, 1, 0, TD(TD_ESC_CAPS)}; + auto regular_key = KeymapKey(0, 2, 0, KC_A); + + set_keymap({key_esc_caps, regular_key}); + + /* Interrupted double tap */ + tap_key(key_esc_caps); + regular_key.press(); + /* Immediate tap of the first key */ + EXPECT_REPORT(driver, (KC_ESC)); + EXPECT_EMPTY_REPORT(driver); + /* Followed by the interrupting key */ + EXPECT_REPORT(driver, (KC_A)); + run_one_scan_loop(); + regular_key.release(); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Second tap after being interrupted acts as a single tap */ + key_esc_caps.press(); + run_one_scan_loop(); + key_esc_caps.release(); + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_ESC)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); +} + +TEST_F(TapDance, DanceFn) { + TestDriver driver; + InSequence s; + auto key_egg = KeymapKey(0, 1, 0, TD(CT_EGG)); + + set_keymap({key_egg}); + + /* 99 taps do nothing */ + for (int i = 0; i < 99; i++) { + run_one_scan_loop(); + key_egg.press(); + run_one_scan_loop(); + key_egg.release(); + } + idle_for(TAPPING_TERM); + EXPECT_NO_REPORT(driver); + run_one_scan_loop(); + + /* 100 taps trigger the action */ + for (int i = 0; i < 100; i++) { + run_one_scan_loop(); + key_egg.press(); + run_one_scan_loop(); + key_egg.release(); + } + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_C)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* 250 taps act the same as 100 taps */ + /* Taps are counted in an uint8_t, so the count overflows after 255 taps */ + for (int i = 0; i < 250; i++) { + run_one_scan_loop(); + key_egg.press(); + run_one_scan_loop(); + key_egg.release(); + } + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_C)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); +} + +TEST_F(TapDance, DanceFnAdvanced) { + TestDriver driver; + InSequence s; + auto key_flsh = KeymapKey(0, 1, 0, TD(CT_FLSH)); + + set_keymap({key_flsh}); + + /* Three taps don't trigger a reset */ + EXPECT_REPORT(driver, (KC_3)); + EXPECT_REPORT(driver, (KC_3, KC_2)); + EXPECT_REPORT(driver, (KC_3, KC_2, KC_1)); + for (int i = 0; i < 3; i++) { + run_one_scan_loop(); + key_flsh.press(); + run_one_scan_loop(); + key_flsh.release(); + } + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_3, KC_2)); + EXPECT_REPORT(driver, (KC_3)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Four taps trigger a reset */ + EXPECT_REPORT(driver, (KC_3)); + EXPECT_REPORT(driver, (KC_3, KC_2)); + EXPECT_REPORT(driver, (KC_3, KC_2, KC_1)); + EXPECT_REPORT(driver, (KC_2, KC_1)); + EXPECT_REPORT(driver, (KC_1)); + EXPECT_EMPTY_REPORT(driver); + for (int i = 0; i < 4; i++) { + run_one_scan_loop(); + key_flsh.press(); + run_one_scan_loop(); + key_flsh.release(); + } + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_R)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); +} + +TEST_F(TapDance, TapHold) { + TestDriver driver; + InSequence s; + auto key_cln = KeymapKey{0, 1, 0, TD(CT_CLN)}; + + set_keymap({key_cln}); + + /* Short taps fire on release */ + key_cln.press(); + run_one_scan_loop(); + key_cln.release(); + EXPECT_REPORT(driver, (KC_LSFT)); + EXPECT_REPORT(driver, (KC_LSFT, KC_SCLN)); + EXPECT_REPORT(driver, (KC_LSFT)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Holds immediate following a tap apply to the tap key */ + key_cln.press(); + EXPECT_REPORT(driver, (KC_LSFT)); + EXPECT_REPORT(driver, (KC_LSFT, KC_SCLN)); + idle_for(TAPPING_TERM * 2); + key_cln.release(); + EXPECT_REPORT(driver, (KC_LSFT)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Holds trigger the hold key */ + key_cln.press(); + idle_for(TAPPING_TERM); + run_one_scan_loop(); + EXPECT_REPORT(driver, (KC_SCLN)); + run_one_scan_loop(); + key_cln.release(); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); +} + +TEST_F(TapDance, QuadFunction) { + TestDriver driver; + InSequence s; + auto key_quad = KeymapKey{0, 1, 0, TD(X_CTL)}; + auto regular_key = KeymapKey(0, 2, 0, KC_A); + + set_keymap({key_quad, regular_key}); + + /* Single tap */ + key_quad.press(); + run_one_scan_loop(); + key_quad.release(); + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_X)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Single hold */ + key_quad.press(); + run_one_scan_loop(); + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_LCTL)); + run_one_scan_loop(); + key_quad.release(); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Double tap */ + tap_key(key_quad); + key_quad.press(); + run_one_scan_loop(); + key_quad.release(); + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_ESC)); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Double tap and hold */ + tap_key(key_quad); + key_quad.press(); + run_one_scan_loop(); + idle_for(TAPPING_TERM); + EXPECT_REPORT(driver, (KC_LALT)); + run_one_scan_loop(); + key_quad.release(); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); + + /* Double single tap */ + tap_key(key_quad); + tap_key(key_quad); + regular_key.press(); + EXPECT_REPORT(driver, (KC_X)); + EXPECT_EMPTY_REPORT(driver); + EXPECT_REPORT(driver, (KC_X)); + EXPECT_EMPTY_REPORT(driver); + EXPECT_REPORT(driver, (KC_A)); + run_one_scan_loop(); + regular_key.release(); + EXPECT_EMPTY_REPORT(driver); + run_one_scan_loop(); +} diff --git a/users/edvorakjp/edvorakjp_tap_dance.c b/users/edvorakjp/edvorakjp_tap_dance.c index cee10de693..69fcbac1ca 100644 --- a/users/edvorakjp/edvorakjp_tap_dance.c +++ b/users/edvorakjp/edvorakjp_tap_dance.c @@ -64,6 +64,15 @@ void td_raise_reset(qk_tap_dance_state_t *state, void *user_data) { } qk_tap_dance_action_t tap_dance_actions[] = { - [TD_EDVORAKJP_LOWER] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, td_lower_finished, td_lower_reset, 150), - [TD_EDVORAKJP_RAISE] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, td_raise_finished, td_raise_reset, 150), + [TD_EDVORAKJP_LOWER] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, td_lower_finished, td_lower_reset), + [TD_EDVORAKJP_RAISE] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, td_raise_finished, td_raise_reset), }; + +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: + return 150; + default: + return TAPPING_TERM; + } +} diff --git a/users/gourdo1/gourdo1.c b/users/gourdo1/gourdo1.c index b964729be9..4e741ccc91 100644 --- a/users/gourdo1/gourdo1.c +++ b/users/gourdo1/gourdo1.c @@ -45,7 +45,7 @@ qk_tap_dance_action_t tap_dance_actions[] = { [TD_LSFT_CAPSLOCK] = ACTION_TAP_DANCE_DOUBLE(KC_LSFT, KC_CAPS), [TD_LSFT_CAPS_WIN] = ACTION_TAP_DANCE_FN_ADVANCED(dance_LSFT_each_tap, NULL, dance_LSFT_reset), // Tap once for Escape, twice to reset to base layer - [TD_ESC_BASELYR] = ACTION_TAP_DANCE_DUAL_ROLE(KC_ESC, _BASE), + [TD_ESC_BASELYR] = ACTION_TAP_DANCE_LAYER_MOVE(KC_ESC, _BASE), }; #endif // TD_LSFT_CAPSLOCK_ENABLE diff --git a/users/mnil/config.h b/users/mnil/config.h index 3547785ff7..b471b9a818 100644 --- a/users/mnil/config.h +++ b/users/mnil/config.h @@ -19,3 +19,4 @@ #define MK_3_SPEED #define MK_MOMENTARY_ACCEL #define PERMISSIVE_HOLD +#define TAPPING_TERM 250 diff --git a/users/mnil/mnil.c b/users/mnil/mnil.c index d5bd0ef0bb..00da6086ef 100644 --- a/users/mnil/mnil.c +++ b/users/mnil/mnil.c @@ -140,7 +140,7 @@ void aa_reset(qk_tap_dance_state_t *state, void *user_data) { // clang-format off qk_tap_dance_action_t tap_dance_actions[] = { - [AAE] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, ae_finished, ae_reset, 250), - [OAA] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, aa_finished, aa_reset, 250) + [AAE] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ae_finished, ae_reset), + [OAA] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, aa_finished, aa_reset) }; // clang-format on diff --git a/users/ninjonas/config.h b/users/ninjonas/config.h index 025dbb541a..565e40e841 100644 --- a/users/ninjonas/config.h +++ b/users/ninjonas/config.h @@ -2,6 +2,7 @@ #undef TAPPING_TERM #define TAPPING_TERM 200 #endif +#define TAPPING_TERM_PER_KEY // Mouse Settings: Smoothing out mouse movement on keypress #ifndef MOUSEKEY_INTERVAL @@ -18,4 +19,4 @@ #undef COMBO_TERM #define COMBO_COUNT 5 #define COMBO_TERM 60 -#endif \ No newline at end of file +#endif diff --git a/users/ninjonas/tap_dances.c b/users/ninjonas/tap_dances.c index 63e4d3ba47..3e4cec9133 100644 --- a/users/ninjonas/tap_dances.c +++ b/users/ninjonas/tap_dances.c @@ -107,6 +107,16 @@ qk_tap_dance_action_t tap_dance_actions[] = { [TD_GUI_GUISPC] = ACTION_TAP_DANCE_DOUBLE(KC_LGUI, LGUI(KC_SPC)), // Advanced Tap Dances - [TD_COPY_PASTE_APP] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, copy_paste_app_finished, copy_paste_app_reset, 300), - [TD_Y_NUMPAD] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, y_numpad_finished, y_numpad_reset, 300), -}; \ No newline at end of file + [TD_COPY_PASTE_APP] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, copy_paste_app_finished, copy_paste_app_reset), + [TD_Y_NUMPAD] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, y_numpad_finished, y_numpad_reset), +}; + +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case TD(TD_COPY_PASTE_APP): + case TD(TD_Y_NUMPAD): + return 300; + default: + return TAPPING_TERM; + } +} -- cgit v1.2.3 From 0da6562c4df570729889690e21061229c5648b73 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sat, 18 Jun 2022 14:37:51 -0700 Subject: Make default layer size 16-bit (#15286) Co-authored-by: James Young <18669334+noroadsleft@users.noreply.github.com> --- docs/zh-cn/custom_quantum_functions.md | 7 +- .../sweet16/keymaps/ridingintraffic/keymap.c | 2 +- .../gherkin/keymaps/itsaferbie/keymap.c | 2 +- .../half_n_half/keymaps/Boy_314/keymap.c | 4 +- keyboards/bandominedoni/keymaps/led/keymap.c | 2 +- keyboards/bandominedoni/keymaps/via/keymap.c | 2 +- keyboards/biacco42/ergo42/keymaps/hdbx/keymap.c | 4 +- .../bpiphany/kitten_paw/keymaps/ickerwx/keymap.c | 4 +- .../bpiphany/pegasushoof/keymaps/blowrak/keymap.c | 2 +- keyboards/cannonkeys/ortho75/ortho75.c | 73 +-- .../cannonkeys/satisfaction75/satisfaction75.c | 2 +- .../ckeys/washington/keymaps/default/keymap.c | 4 +- keyboards/clueboard/66/keymaps/magicmonty/keymap.c | 2 +- keyboards/crkbd/keymaps/dsanchezseco/keymap.c | 2 +- keyboards/crkbd/keymaps/edvorakjp/keymap.c | 4 +- keyboards/crkbd/keymaps/edvorakjp/oled.c | 2 +- keyboards/crkbd/keymaps/jarred/keymap.c | 2 +- keyboards/dichotomy/keymaps/default/keymap.c | 4 +- .../plaid/keymaps/thehalfdeafchef/keymap.c | 2 +- keyboards/dz60/keymaps/iso_split-spacebar/keymap.c | 28 +- keyboards/dz60/keymaps/marianas/customLogic.c | 2 +- keyboards/dz60/keymaps/xtonhasvim/keymap.c | 4 +- .../dztech/dz60rgb/keymaps/matthewrobo/keymap.c | 2 +- keyboards/dztech/dz60rgb/keymaps/mekanist/keymap.c | 4 +- keyboards/dztech/dz60rgb/keymaps/perseid/keymap.c | 4 +- .../dztech/dz65rgb/keymaps/catrielmuller/keymap.c | 4 +- keyboards/dztech/dz65rgb/keymaps/drootz/keymap.c | 156 +++--- .../dztech/dz65rgb/keymaps/matthewrobo/keymap.c | 2 +- .../ergodox_ez/keymaps/bepo_tm_style/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/blakedietz/keymap.c | 3 +- .../ergodox_ez/keymaps/bpruitt-goddard/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/default_osx/keymap.c | 2 +- .../ergodox_ez/keymaps/dvorak_42_key/keymap.c | 2 +- .../hacker_dvorak/user/layer_set_state_user.c | 2 +- .../ergodox_ez/keymaps/heartrobotninja/keymap.c | 4 +- keyboards/ergodox_ez/keymaps/kou/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/lukaus/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/matrixman/keymap.c | 2 +- .../ergodox_ez/keymaps/nathanvercaemert/keymap.c | 3 +- keyboards/ergodox_ez/keymaps/nfriend/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/profet_80/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/pvinis/keymap.c | 6 +- keyboards/ergodox_ez/keymaps/rgb_layer/keymap.c | 3 +- keyboards/ergodox_ez/keymaps/rishka/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/skug/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/smurmann/keymap.c | 8 +- keyboards/ergodox_ez/keymaps/steno/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/testing/keymap.c | 2 +- keyboards/ergodox_ez/keymaps/vim/keymap.c | 2 +- keyboards/ergodox_ez/util/compile_keymap.py | 110 ++-- keyboards/ergoslab/keymaps/default/keymap.c | 2 +- keyboards/exclusive/e65/keymaps/masterzen/keymap.c | 2 +- .../exclusive/e7v1/keymaps/masterzen/keymap.c | 2 +- keyboards/gboards/gergo/keymaps/colemak/keymap.c | 5 +- keyboards/gh60/revc/keymaps/dbroqua/keymap.c | 4 +- keyboards/gh60/revc/keymaps/default/keymap.c | 2 +- keyboards/gh60/revc/keymaps/robotmaxtron/keymap.c | 2 +- keyboards/gh60/satan/keymaps/addcninblue/keymap.c | 2 +- .../chimera_ergo/keymaps/default/keymap.c | 2 +- .../glenpickle/chimera_ls/keymaps/default/keymap.c | 2 +- .../chimera_ortho/keymaps/default/keymap.c | 2 +- keyboards/gon/nerdtkl/keymaps/gam3cat/keymap.c | 2 +- .../handwired/frenchdev/keymaps/default/keymap.c | 2 +- keyboards/handwired/kbod/keymaps/default/keymap.c | 2 +- keyboards/handwired/prime_exl/keymaps/via/keymap.c | 2 +- .../handwired/promethium/keymaps/default/keymap.c | 6 +- .../handwired/promethium/keymaps/priyadi/keymap.c | 8 +- .../handwired/traveller/keymaps/default/keymap.c | 2 +- .../handwired/tritium_numpad/keymaps/blu/keymap.c | 2 +- keyboards/helix/pico/keymaps/mtei/keymap.c | 2 +- .../helix/rev2/keymaps/default/oled_display.c | 2 +- keyboards/helix/rev2/keymaps/edvorakjp/keymap.c | 4 +- keyboards/helix/rev2/keymaps/edvorakjp/oled.c | 2 +- keyboards/helix/rev2/keymaps/five_rows/keymap.c | 4 +- .../helix/rev3_5rows/keymaps/five_rows/keymap.c | 4 +- keyboards/hineybush/h87a/keymaps/gam3cat/keymap.c | 2 +- keyboards/hotdox/keymaps/default/keymap.c | 2 +- keyboards/hotdox/keymaps/eozaki/keymap.c | 2 +- keyboards/hotdox/keymaps/kloki/keymap.c | 2 +- .../ergodox_infinity/keymaps/default/keymap.c | 2 +- .../ergodox_infinity/keymaps/gordon/keymap.c | 2 +- .../ergodox_infinity/keymaps/halfkeyboard/keymap.c | 2 +- .../ergodox_infinity/keymaps/input_club/keymap.c | 2 +- .../ergodox_infinity/keymaps/narze/keymap.c | 2 +- .../ergodox_infinity/keymaps/nordic_ergo/keymap.c | 2 +- .../ergodox_infinity/keymaps/rask/keymap.c | 2 +- .../ergodox_infinity/keymaps/rjhilgefort/keymap.c | 2 +- .../keymaps/trulyergonomic/keymap.c | 2 +- .../infinity60/keymaps/jpetermans/keymap.c | 4 +- keyboards/jc65/v32u4/keymaps/gam3cat/keymap.c | 2 +- .../jones/v03_1/keymaps/default_ansi/keymap.c | 2 +- keyboards/jones/v03_1/keymaps/default_jp/keymap.c | 2 +- .../kakunpc/angel64/alpha/keymaps/default/keymap.c | 2 +- .../kakunpc/angel64/rev1/keymaps/kakunpc/keymap.c | 2 +- .../suihankey/alpha/keymaps/default/keymap.c | 2 +- .../suihankey/rev1/keymaps/default/keymap.c | 2 +- keyboards/kbdfans/kbd6x/keymaps/othi/keymap.c | 3 +- keyboards/kbdfans/kbd75/keymaps/edulpn/keymap.c | 2 +- keyboards/kbdfans/niu_mini/keymaps/tobias/keymap.c | 30 +- .../kbdfans/niu_mini/keymaps/xtonhasvim/keymap.c | 2 +- keyboards/keebio/bdn9/keymaps/vosechu-ksp/keymap.c | 2 +- .../keebio/bfo9000/keymaps/abstractkb/keymap.c | 5 +- keyboards/keebio/iris/keymaps/edvorakjp/keymap.c | 4 +- keyboards/keebio/iris/keymaps/jerryhcooke/keymap.c | 4 +- keyboards/keebio/iris/keymaps/sq5rix/keymap.c | 3 +- .../keebio/levinson/keymaps/issmirnov/keymap.c | 2 +- keyboards/keebio/levinson/keymaps/issmirnov/rgb.c | 2 +- keyboards/keebio/levinson/keymaps/issmirnov/rgb.h | 2 +- .../keebio/levinson/keymaps/xtonhasvim/keymap.c | 2 +- keyboards/keebio/nyquist/keymaps/pitty/keymap.c | 2 +- .../keebio/quefrency/keymaps/georgepetri/keymap.c | 2 +- .../keyhive/honeycomb/keymaps/default/keymap.c | 2 +- keyboards/kinesis/keymaps/milestogo/keymap.c | 2 +- .../kprepublic/cospad/keymaps/detrus/keymap.c | 6 +- .../kprepublic/jj50/keymaps/abstractkb/keymap.c | 2 +- .../jj50/keymaps/abstractkb_gergomatch/keymap.c | 2 +- keyboards/ktec/ergodone/keymaps/eozaki/keymap.c | 2 +- keyboards/ktec/ergodone/keymaps/erovia/keymap.c | 2 +- keyboards/ktec/ergodone/keymaps/kloki/keymap.c | 2 +- keyboards/ktec/ergodone/keymaps/vega/keymap.c | 2 +- .../leeku/finger65/keymaps/madhatter/keymap.c | 2 +- keyboards/lets_split/keymaps/bbaserdem/keymap.c | 2 +- keyboards/lets_split/keymaps/cpeters1982/keymap.c | 2 +- keyboards/lets_split/keymaps/geripgeri/keymap.c | 2 +- keyboards/lets_split/keymaps/pitty/keymap.c | 2 +- keyboards/lily58/lib/layer_state_reader.c | 2 +- keyboards/m10a/keymaps/gam3cat/keymap.c | 2 +- .../lets_split_eh/keymaps/bbaserdem/keymap.c | 2 +- .../lets_split_eh/keymaps/romus/keymap.c | 4 +- .../mechmini/v2/keymaps/wsturgiss/keymap.c | 3 +- keyboards/mechllama/g35/keymaps/default/keymap.c | 2 +- keyboards/mechlovin/hannah910/hannah910.c | 6 +- keyboards/mechlovin/hex4b/keymaps/nazzer/keymap.c | 28 +- keyboards/minimacro5/keymaps/devdev/keymap.c | 2 +- keyboards/mitosis/keymaps/carvac_dv/keymap.c | 3 +- keyboards/mitosis/keymaps/datagrok/keymap.c | 4 +- keyboards/mitosis/keymaps/default/keymap.c | 5 +- keyboards/mitosis/keymaps/mjt/keymap.c | 4 +- keyboards/mitosis/keymaps/nzen/keymap.c | 4 +- keyboards/mschwingen/modelm/modelm.c | 4 +- keyboards/mwstudio/mw65_rgb/keymaps/via/keymap.c | 4 +- keyboards/pearl/keymaps/cijanzen/keymap.c | 2 +- keyboards/pearl/keymaps/jetpacktuxedo/keymap.c | 2 +- keyboards/pearl/keymaps/phil/keymap.c | 2 +- keyboards/pearl/keymaps/rask/keymap.c | 2 +- keyboards/percent/canoe/keymaps/dhertz/keymap.c | 4 +- keyboards/phoenix/phoenix.c | 2 +- keyboards/planck/keymaps/aviator/keymap.c | 8 +- keyboards/planck/keymaps/charlesrocket/keymap.c | 2 +- keyboards/planck/keymaps/grahampheath/keymap.c | 2 +- keyboards/planck/keymaps/oryx/keymap.c | 2 +- keyboards/planck/keymaps/rootiest/keymap.c | 2 +- keyboards/planck/keymaps/tom/keymap.c | 2 +- keyboards/planck/keymaps/tylerwince/keymap.c | 4 +- keyboards/preonic/keymaps/dudeofawesome/keymap.c | 2 +- keyboards/preonic/keymaps/senseored/keymap.c | 2 +- keyboards/primekb/prime_e/keymaps/via/keymap.c | 2 +- keyboards/redox_w/keymaps/italian/keymap.c | 12 +- keyboards/redscarf_i/redscarf_i.c | 2 +- keyboards/rgbkb/pan/keymaps/default/keymap.c | 2 +- keyboards/rgbkb/sol/keymaps/default/keymap.c | 4 +- keyboards/rgbkb/sol/keymaps/xyverz/keymap.c | 4 +- keyboards/rgbkb/zen/rev2/rev2.c | 2 +- .../rgbkb/zygomorph/keymaps/default_oled/keymap.c | 2 +- .../satt/comet46/keymaps/default-rgbled/keymap.c | 2 +- keyboards/satt/comet46/keymaps/default/keymap.c | 4 +- keyboards/satt/comet46/keymaps/satt/keymap.c | 4 +- keyboards/splitkb/kyria/keymaps/j-inc/keymap.c | 2 +- keyboards/splitkb/kyria/keymaps/ninjonas/oled.c | 2 +- .../splitkb/kyria/keymaps/thomasbaart/keymap.c | 4 +- keyboards/splitography/keymaps/jeandeaual/keymap.c | 2 +- keyboards/splitography/keymaps/multi/keymap.c | 2 +- keyboards/tetris/keymaps/default/keymap.c | 4 +- .../roadkit/keymaps/flipphone/keymap.c | 2 +- keyboards/v60_type_r/keymaps/xtonhasvim/keymap.c | 3 +- keyboards/xiudi/xd60/keymaps/birkir/keymap.c | 2 +- keyboards/xiudi/xd60/keymaps/kmontag42/keymap.c | 2 +- keyboards/xiudi/xd75/keymaps/arpinfidel/keymap.c | 2 +- keyboards/xiudi/xd75/keymaps/cbbrowne/keymap.c | 2 +- keyboards/xiudi/xd75/keymaps/kloki/keymap.c | 2 +- keyboards/xiudi/xd75/keymaps/tdl-jturner/keymap.c | 2 +- layouts/community/ergodox/ab/keymap.c | 2 +- layouts/community/ergodox/absenth/keymap.c | 2 +- layouts/community/ergodox/adam/keymap.c | 2 +- layouts/community/ergodox/adnw_k_o_y/keymap.c | 2 +- layouts/community/ergodox/alexjj/keymap.c | 2 +- layouts/community/ergodox/andrew_osx/keymap.c | 2 +- layouts/community/ergodox/berfarah/keymap.c | 4 +- layouts/community/ergodox/bryan/keymap.c | 2 +- layouts/community/ergodox/choromanski/keymap.c | 42 +- layouts/community/ergodox/colemak/keymap.c | 2 +- .../ergodox/colemak_code_friendly/keymap.c | 20 +- .../community/ergodox/colemak_programmer/keymap.c | 8 +- .../community/ergodox/common_nighthawk/keymap.c | 2 +- layouts/community/ergodox/csharp_dev/keymap.c | 40 +- layouts/community/ergodox/dave/keymap.c | 2 +- layouts/community/ergodox/deadcyclo/keymap.c | 16 +- layouts/community/ergodox/dragon788/keymap.c | 2 +- layouts/community/ergodox/dvorak/keymap.c | 2 +- layouts/community/ergodox/dvorak_emacs/keymap.c | 2 +- .../ergodox/dvorak_emacs_software/keymap.c | 2 +- .../ergodox/dvorak_intl_squisher/keymap.c | 2 +- layouts/community/ergodox/dvorak_plover/keymap.c | 2 +- .../community/ergodox/dvorak_programmer/keymap.c | 68 +-- .../ergodox/dvorak_programmer_swe/keymap.c | 2 +- layouts/community/ergodox/dvorak_spanish/keymap.c | 43 +- .../community/ergodox/dvorak_svorak_a5/keymap.c | 2 +- layouts/community/ergodox/emacs_osx_dk/keymap.c | 2 +- layouts/community/ergodox/french_hacker/keymap.c | 2 +- layouts/community/ergodox/galson/keymap.c | 4 +- layouts/community/ergodox/german-kinergo/keymap.c | 2 +- layouts/community/ergodox/german-lukas/keymap.c | 2 +- .../ergodox/german-manuneo/compile_keymap.py | 110 ++-- layouts/community/ergodox/german-manuneo/keymap.c | 2 +- layouts/community/ergodox/german/keymap.c | 2 +- layouts/community/ergodox/haegin/keymap.c | 2 +- layouts/community/ergodox/ishigoya-jp/keymap.c | 78 +-- layouts/community/ergodox/issmirnov/keymap.c | 6 +- layouts/community/ergodox/italian/keymap.c | 4 +- layouts/community/ergodox/j3rn/keymap.c | 2 +- layouts/community/ergodox/jackhumbert/keymap.c | 14 +- layouts/community/ergodox/jacobono/keymap.c | 2 +- layouts/community/ergodox/jafo/keymap.c | 2 +- layouts/community/ergodox/jgarr/keymap.c | 2 +- layouts/community/ergodox/josh/keymap.c | 2 +- layouts/community/ergodox/kastyle/keymap.c | 4 +- layouts/community/ergodox/kejadlen/keymap.c | 2 +- layouts/community/ergodox/kines-ish/keymap.c | 2 +- layouts/community/ergodox/kristian/keymap.c | 2 +- layouts/community/ergodox/maz/keymap.c | 2 +- layouts/community/ergodox/mclennon_osx/keymap.c | 2 +- layouts/community/ergodox/meagerfindings/keymap.c | 2 +- layouts/community/ergodox/msc/keymap.c | 2 +- layouts/community/ergodox/naps62/keymap.c | 2 +- .../ergodox/neo2_on_qwertz_hardware/keymap.c | 4 +- layouts/community/ergodox/osx_de/keymap.c | 197 ++++---- layouts/community/ergodox/osx_de_adnw_koy/keymap.c | 153 +++--- .../community/ergodox/osx_de_experimental/keymap.c | 555 ++++++++++----------- layouts/community/ergodox/osx_fr/keymap.c | 2 +- .../community/ergodox/osx_kinesis_pnut/keymap.c | 2 +- layouts/community/ergodox/osx_neo2/keymap.c | 2 +- layouts/community/ergodox/phoenix/keymap.c | 2 +- layouts/community/ergodox/plover/keymap.c | 2 +- .../ergodox/qwerty_code_friendly/keymap.c | 2 +- layouts/community/ergodox/reset_eeprom/keymap.c | 2 +- .../romanzolotarev-norman-plover-osx-hjkl/keymap.c | 2 +- .../romanzolotarev-norman-plover-osx/keymap.c | 2 +- .../romanzolotarev-norman-qwerty-osx/keymap.c | 2 +- layouts/community/ergodox/sethbc/keymap.c | 2 +- layouts/community/ergodox/siroken3/keymap.c | 2 +- layouts/community/ergodox/sneako/keymap.c | 2 +- layouts/community/ergodox/software_neo2/keymap.c | 2 +- layouts/community/ergodox/swedish-lindhe/keymap.c | 2 +- layouts/community/ergodox/swedish/keymap.c | 2 +- layouts/community/ergodox/swissgerman/keymap.c | 2 +- layouts/community/ergodox/techtomas/keymap.c | 2 +- layouts/community/ergodox/tkuichooseyou/keymap.c | 2 +- layouts/community/ergodox/tonyabra_osx/keymap.c | 2 +- layouts/community/ergodox/townk_osx/keymap.c | 2 +- .../twentylives_dvorak_with_hebrew/keymap.c | 22 +- .../community/ergodox/win10_writers-block/keymap.c | 28 +- layouts/community/ergodox/xyverz/keymap.c | 6 +- .../community/ergodox/zweihander-macos/keymap.c | 2 +- layouts/community/ortho_4x12/peej/keymap.c | 2 +- quantum/action_layer.h | 2 +- tmk_core/protocol/arm_atsam/md_rgb_matrix.c | 2 +- users/333fred/333fred.c | 2 +- users/333fred/rgb.c | 4 +- users/bbaserdem/bbaserdem.c | 4 +- users/billypython/billypython.c | 2 +- users/billypython/billypython.h | 2 +- users/dhertz/dhertz.c | 3 +- users/doogle999/doogle999.c | 6 +- users/edvorakjp/edvorakjp.c | 2 +- users/edvorakjp/edvorakjp.h | 2 +- users/ericgebhart/ericgebhart.c | 2 +- users/ericgebhart/tap_dances.c | 4 +- users/kuchosauronad0/kuchosauronad0.c | 6 +- users/kuchosauronad0/kuchosauronad0.h | 4 +- users/kuchosauronad0/rgblight_user.c | 20 +- users/kuchosauronad0/template.c | 4 +- users/mtdjr/mtdjr.c | 2 +- users/ninjonas/oled.c | 2 +- users/pvinis/pvinis.c | 2 +- users/pvinis/pvinis.h | 2 +- users/romus/romus.c | 4 +- users/sigma/sigma.c | 4 +- users/stanrc85/layer_rgb.c | 2 +- users/talljoe/talljoe.c | 2 +- users/tominabox1/tominabox1.c | 4 +- users/turbomech/backupturbomech.c | 6 +- users/xulkal/custom_oled.c | 2 +- users/zer09/zer09.c | 2 +- 293 files changed, 1249 insertions(+), 1309 deletions(-) (limited to 'quantum') diff --git a/docs/zh-cn/custom_quantum_functions.md b/docs/zh-cn/custom_quantum_functions.md index 29c5089052..dba9e7e7c0 100644 --- a/docs/zh-cn/custom_quantum_functions.md +++ b/docs/zh-cn/custom_quantum_functions.md @@ -240,7 +240,7 @@ void suspend_wakeup_init_user(void) { ```c layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _RAISE: rgblight_setrgb (0x00, 0x00, 0xFF); break; @@ -267,7 +267,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { ### `layer_state_set_*` 函数文档 -* 键盘/各子版本:`uint32_t layer_state_set_kb(uint32_t state)` +* 键盘/各子版本:`layer_state_t layer_state_set_kb(layer_state_t state)` * 布局: `layer_state_t layer_state_set_user(layer_state_t state)` @@ -325,7 +325,7 @@ void keyboard_post_init_user(void) { ```c layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _RAISE: if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_magenta(); rgblight_mode_noeeprom(1); } break; @@ -474,4 +474,3 @@ cancel_deferred_exec(my_token); ```c #define MAX_DEFERRED_EXECUTORS 16 ``` - diff --git a/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/keymap.c b/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/keymap.c index 6b7b36cbb2..eeca552657 100644 --- a/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/keymap.c +++ b/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/keymap.c @@ -196,7 +196,7 @@ void matrix_scan_user(void) { } } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _TAPLAND: rgblight_setrgb(0, 16, 0); //green break; diff --git a/keyboards/40percentclub/gherkin/keymaps/itsaferbie/keymap.c b/keyboards/40percentclub/gherkin/keymaps/itsaferbie/keymap.c index 950b6e86b9..32c074c88f 100644 --- a/keyboards/40percentclub/gherkin/keymaps/itsaferbie/keymap.c +++ b/keyboards/40percentclub/gherkin/keymaps/itsaferbie/keymap.c @@ -105,7 +105,7 @@ void matrix_scan_user(void) { #ifdef RGBLIGHT_ENABLE static uint8_t old_layer = 255; - uint8_t new_layer = biton32(layer_state); + uint8_t new_layer = get_highest_layer(layer_state); // Color of the Icons. if (old_layer != new_layer) { diff --git a/keyboards/40percentclub/half_n_half/keymaps/Boy_314/keymap.c b/keyboards/40percentclub/half_n_half/keymaps/Boy_314/keymap.c index 2eef3dc48b..bd467482fe 100644 --- a/keyboards/40percentclub/half_n_half/keymaps/Boy_314/keymap.c +++ b/keyboards/40percentclub/half_n_half/keymaps/Boy_314/keymap.c @@ -128,10 +128,10 @@ void tap_dance_choose_layer_reset (qk_tap_dance_state_t *state, void *user_data) layer_off(_RAISE); break; case 3: - if (biton32(default_layer_state) == _DVORAK) { + if (get_highest_layer(default_layer_state) == _DVORAK) { set_single_persistent_default_layer(_QWERTY); } - else if (biton32(default_layer_state) == _QWERTY) { + else if (get_highest_layer(default_layer_state) == _QWERTY) { set_single_persistent_default_layer(_DVORAK); } break; diff --git a/keyboards/bandominedoni/keymaps/led/keymap.c b/keyboards/bandominedoni/keymaps/led/keymap.c index 305756b5b1..4a88d33872 100644 --- a/keyboards/bandominedoni/keymaps/led/keymap.c +++ b/keyboards/bandominedoni/keymaps/led/keymap.c @@ -180,7 +180,7 @@ void keyboard_post_init_user(void) { #ifdef RGB_MATRIX_ENABLE void rgb_matrix_indicators_user(void) { if (rgb_matrix_is_enabled()) { // turn the lights on when it is enabled. - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _CLOSE: // rgb_matrix_set_color(pgm_read_byte(&convert_led_location2number[11]), RGB_RED); // RGB_TOG <- too heavy. diff --git a/keyboards/bandominedoni/keymaps/via/keymap.c b/keyboards/bandominedoni/keymaps/via/keymap.c index ad6833d692..342ed1d40c 100644 --- a/keyboards/bandominedoni/keymaps/via/keymap.c +++ b/keyboards/bandominedoni/keymaps/via/keymap.c @@ -118,7 +118,7 @@ void keyboard_post_init_user(void) { #ifdef RGB_MATRIX_ENABLE void rgb_matrix_indicators_user(void) { if (rgb_matrix_is_enabled()) { // turn the lights on when it is enabled. - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _CLOSE: // rgb_matrix_set_color(pgm_read_byte(&convert_led_location2number[11]), RGB_RED); // RGB_TOG <- too heavy. diff --git a/keyboards/biacco42/ergo42/keymaps/hdbx/keymap.c b/keyboards/biacco42/ergo42/keymaps/hdbx/keymap.c index bb3b6fac48..58f01bb322 100644 --- a/keyboards/biacco42/ergo42/keymaps/hdbx/keymap.c +++ b/keyboards/biacco42/ergo42/keymaps/hdbx/keymap.c @@ -134,7 +134,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; // RGB Underglow使用時のレイヤー毎のカラー切り替え -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } @@ -148,7 +148,7 @@ void matrix_init_user(void) { layer_state_t layer_state_set_user(layer_state_t state) { state = update_tri_layer_state(state, _RAISE, _LOWER, _ADJUST); #ifdef RGBLIGHT_ENABLE - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _RAISE: rgblight_setrgb_chartreuse(); // RAISE:シャルトリューズ break; diff --git a/keyboards/bpiphany/kitten_paw/keymaps/ickerwx/keymap.c b/keyboards/bpiphany/kitten_paw/keymaps/ickerwx/keymap.c index cc4d0bca63..4553d4e0e3 100644 --- a/keyboards/bpiphany/kitten_paw/keymaps/ickerwx/keymap.c +++ b/keyboards/bpiphany/kitten_paw/keymaps/ickerwx/keymap.c @@ -89,7 +89,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void matrix_scan_user(void) { uint8_t layer; - layer = biton32(layer_state); + layer = get_highest_layer(layer_state); if (current_layer_global != layer) { current_layer_global = layer; @@ -132,7 +132,7 @@ void tap_helper(keyrecord_t *record, uint16_t orig_mod, uint16_t macro_mod, uint bool process_record_user(uint16_t keycode, keyrecord_t *record) { uint8_t layer; - layer = biton32(layer_state); + layer = get_highest_layer(layer_state); if (layer == PROG2) { if (keycode >= KC_A && keycode <= KC_EXSEL && \ !( // do not send LSFT + these keycodes, they are needed for emulating the US layout diff --git a/keyboards/bpiphany/pegasushoof/keymaps/blowrak/keymap.c b/keyboards/bpiphany/pegasushoof/keymaps/blowrak/keymap.c index 7884462021..dc55cdf9fd 100644 --- a/keyboards/bpiphany/pegasushoof/keymaps/blowrak/keymap.c +++ b/keyboards/bpiphany/pegasushoof/keymaps/blowrak/keymap.c @@ -77,7 +77,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case KM_BLOWRAK: ph_caps_led_on(); diff --git a/keyboards/cannonkeys/ortho75/ortho75.c b/keyboards/cannonkeys/ortho75/ortho75.c index 7c722d7156..58b7396a1b 100644 --- a/keyboards/cannonkeys/ortho75/ortho75.c +++ b/keyboards/cannonkeys/ortho75/ortho75.c @@ -5,47 +5,48 @@ uint8_t layer = 0; -uint32_t layer_state_set_kb(uint32_t state) { - state = layer_state_set_user(state); - layer = biton32(state); - return state; +layer_state_t layer_state_set_kb(layer_state_t state) { + state = layer_state_set_user(state); + layer = get_highest_layer(state); + return state; } bool encoder_update_kb(uint8_t index, bool clockwise) { if (!encoder_update_user(index, clockwise)) return false; - uint16_t mapped_code = 0; - if (index == 0) { - if (clockwise) { - switch(layer){ - case 0: - default: - mapped_code = KC_VOLU; - break; - case 1: - mapped_code = KC_MEDIA_NEXT_TRACK; - break; - case 2: - mapped_code = KC_PGDN; - break; + uint16_t mapped_code = 0; + if (index == 0) { + if (clockwise) { + switch (layer) { + case 0: + default: + mapped_code = KC_VOLU; + break; + case 1: + mapped_code = KC_MEDIA_NEXT_TRACK; + break; + case 2: + mapped_code = KC_PGDN; + break; + } + } else { + switch (layer) { + case 0: + default: + mapped_code = KC_VOLD; + break; + case 1: + mapped_code = KC_MEDIA_PREV_TRACK; + break; + case 2: + mapped_code = KC_PGUP; + break; + } } - } else { - switch(layer){ - case 0: - default: - mapped_code = KC_VOLD; - break; - case 1: - mapped_code = KC_MEDIA_PREV_TRACK; - break; - case 2: - mapped_code = KC_PGUP; - break; + uint16_t held_keycode_timer = timer_read(); + register_code(mapped_code); + while (timer_elapsed(held_keycode_timer) < MEDIA_KEY_DELAY) { /* no-op */ } + unregister_code(mapped_code); } - uint16_t held_keycode_timer = timer_read(); - register_code(mapped_code); - while (timer_elapsed(held_keycode_timer) < MEDIA_KEY_DELAY){ /* no-op */ } - unregister_code(mapped_code); - } - return true; + return true; } diff --git a/keyboards/cannonkeys/satisfaction75/satisfaction75.c b/keyboards/cannonkeys/satisfaction75/satisfaction75.c index bd7eaf1885..9435377839 100644 --- a/keyboards/cannonkeys/satisfaction75/satisfaction75.c +++ b/keyboards/cannonkeys/satisfaction75/satisfaction75.c @@ -240,7 +240,7 @@ void read_host_led_state(void) { layer_state_t layer_state_set_kb(layer_state_t state) { state = layer_state_set_user(state); - layer = biton32(state); + layer = get_highest_layer(state); oled_request_wakeup(); return state; } diff --git a/keyboards/ckeys/washington/keymaps/default/keymap.c b/keyboards/ckeys/washington/keymaps/default/keymap.c index 95e0f3ab59..9ce0181fe4 100644 --- a/keyboards/ckeys/washington/keymaps/default/keymap.c +++ b/keyboards/ckeys/washington/keymaps/default/keymap.c @@ -40,7 +40,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; bool encoder_update_user(uint8_t index, bool clockwise) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _BASE: if (clockwise) { tap_code(KC_VOLU); @@ -62,7 +62,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { bool oled_task_user(void) { // Host Keyboard Layer Status oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _BASE: oled_write_P(PSTR("Default\n"), false); break; diff --git a/keyboards/clueboard/66/keymaps/magicmonty/keymap.c b/keyboards/clueboard/66/keymaps/magicmonty/keymap.c index 56d4c47071..7b7d2bdce0 100644 --- a/keyboards/clueboard/66/keymaps/magicmonty/keymap.c +++ b/keyboards/clueboard/66/keymaps/magicmonty/keymap.c @@ -199,7 +199,7 @@ void matrix_scan_user(void) { if (!rgblight_config.enable || rgblight_config.mode != 1) { return; } - uint32_t layer = layer_state; + layer_state_t layer = layer_state; uint8_t val = rgblight_config.val; if (layer & (1<<_FL)) { diff --git a/keyboards/crkbd/keymaps/dsanchezseco/keymap.c b/keyboards/crkbd/keymaps/dsanchezseco/keymap.c index 6ef428a11f..ab84e5c580 100644 --- a/keyboards/crkbd/keymaps/dsanchezseco/keymap.c +++ b/keyboards/crkbd/keymaps/dsanchezseco/keymap.c @@ -84,7 +84,7 @@ oled_rotation_t oled_init_user(oled_rotation_t rotation) { const char *read_logo(void); bool oled_task_user(void){ - switch (biton32(layer_state)){ + switch (get_highest_layer(layer_state)){ case _DVORAK: oled_write_ln_P(PSTR("DVRK"), false); break; diff --git a/keyboards/crkbd/keymaps/edvorakjp/keymap.c b/keyboards/crkbd/keymaps/edvorakjp/keymap.c index 5e56da61a9..f3b801da68 100644 --- a/keyboards/crkbd/keymaps/edvorakjp/keymap.c +++ b/keyboards/crkbd/keymaps/edvorakjp/keymap.c @@ -54,9 +54,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // clang-format on #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT -uint32_t layer_state_set_keymap(uint32_t state) { +layer_state_t layer_state_set_keymap(layer_state_t state) { rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case L_EDVORAKJP_LOWER: rgblight_sethsv_noeeprom_red(); break; diff --git a/keyboards/crkbd/keymaps/edvorakjp/oled.c b/keyboards/crkbd/keymaps/edvorakjp/oled.c index e5ff029565..cd75f8e277 100644 --- a/keyboards/crkbd/keymaps/edvorakjp/oled.c +++ b/keyboards/crkbd/keymaps/edvorakjp/oled.c @@ -9,7 +9,7 @@ void render_layer_state(void) { char layer_name[17]; oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case L_EDVORAKJP_BASE: oled_write_ln_P(PSTR("Default"), false); break; diff --git a/keyboards/crkbd/keymaps/jarred/keymap.c b/keyboards/crkbd/keymaps/jarred/keymap.c index b938636c2a..3784eff2b8 100644 --- a/keyboards/crkbd/keymaps/jarred/keymap.c +++ b/keyboards/crkbd/keymaps/jarred/keymap.c @@ -84,7 +84,7 @@ const char *read_keylogs(void); char matrix_line_str[24]; const char *read_layer_state(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); strcpy(matrix_line_str, "Layer: "); diff --git a/keyboards/dichotomy/keymaps/default/keymap.c b/keyboards/dichotomy/keymaps/default/keymap.c index b8c7ef4274..80fc4d89bc 100755 --- a/keyboards/dichotomy/keymaps/default/keymap.c +++ b/keyboards/dichotomy/keymaps/default/keymap.c @@ -109,7 +109,7 @@ report_mouse_t currentReport = {}; bool process_record_user(uint16_t keycode, keyrecord_t *record) { //uint8_t layer; - //layer = biton32(layer_state); // get the current layer //Or don't, I didn't use it. + //layer = get_highest_layer(layer_state); // get the current layer //Or don't, I didn't use it. bool returnVal = true; //this is to determine if more key processing is needed. //custom layer handling for tri_layer, @@ -437,7 +437,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { }; void matrix_scan_user(void) { - //uint8_t layer = biton32(layer_state); + //uint8_t layer = get_highest_layer(layer_state); for (uint8_t i = 0; i= CUSTOM_LONGPRESS) && (!special_key_states[i]) && special_key_pressed[i]){ switch (i + SAFE_RANGE){ diff --git a/keyboards/dm9records/plaid/keymaps/thehalfdeafchef/keymap.c b/keyboards/dm9records/plaid/keymaps/thehalfdeafchef/keymap.c index 6dcabb160e..e617d0dd5f 100644 --- a/keyboards/dm9records/plaid/keymaps/thehalfdeafchef/keymap.c +++ b/keyboards/dm9records/plaid/keymaps/thehalfdeafchef/keymap.c @@ -129,7 +129,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { return update_tri_laye // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _LOWER: diff --git a/keyboards/dz60/keymaps/iso_split-spacebar/keymap.c b/keyboards/dz60/keymaps/iso_split-spacebar/keymap.c index a9e811f9a4..d3956ce3f0 100644 --- a/keyboards/dz60/keymaps/iso_split-spacebar/keymap.c +++ b/keyboards/dz60/keymaps/iso_split-spacebar/keymap.c @@ -4,12 +4,12 @@ // thanks to atlacat, hailbreno, itsaferbie and weeheavy... // and special thanks to AGausmann and drashna for the layer-activated RGB underglow -// https://www.reddit.com/r/olkb/comments/6t1vdu/update_layeractivated_rgb_underglow/ +// https://www.reddit.com/r/olkb/comments/6t1vdu/update_layeractivated_rgb_underglow/ // https://github.com/AGausmann/qmk_firmware/blob/agausmann-v3.x/keyboards/nyquist/keymaps/agausmann/keymap.c #include QMK_KEYBOARD_H -/* +/* * Each layer gets a name for readability. * The underscores don't mean anything - you can * have a layer called STUFF or any other name. @@ -23,8 +23,8 @@ #define NL 2 // Numpad Layer #define RL 3 // RGB Layer -/* -* Let's give an easier name to the RGB modes +/* +* Let's give an easier name to the RGB modes * and assign the ones we want to the different layer * these will then be used by the function below * @@ -49,10 +49,10 @@ // #define RGB_RL_MODE rgblight_mode_noeeprom(22) //rgb mode for RL layer #define RGB_RL_LIGHT rgblight_sethsv_noeeprom_red() //rgb light for RL layer - + const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - + /* Keymap BL: Base Layer (Default Layer) * * ,-----------------------------------------------------------. @@ -140,7 +140,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { _______, RGB_STA, RGB_BRE, RGB_RAI, RGB_SWI, _______, _______, RGB_SNA, RGB_KNI, RGB_GRA, RGB_XMS, _______, _______, _______, _______, BL_DEC, BL_TOGG, BL_INC, BL_STEP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, MO(FL), _______, _______, _______, TO(BL), _______), - + }; @@ -175,25 +175,25 @@ void matrix_scan_user(void) { #ifdef RGBLIGHT_ENABLE static uint8_t old_layer = 1; - uint8_t new_layer = biton32(layer_state); + uint8_t new_layer = get_highest_layer(layer_state); if (old_layer != new_layer) { switch (new_layer) { case BL: RGB_BL_MODE; - RGB_BL_LIGHT; + RGB_BL_LIGHT; break; case FL: RGB_FL_MODE; - RGB_FL_LIGHT; + RGB_FL_LIGHT; break; case NL: - RGB_NL_MODE; - RGB_NL_LIGHT; + RGB_NL_MODE; + RGB_NL_LIGHT; break; case RL: - RGB_RL_MODE; - RGB_RL_LIGHT; + RGB_RL_MODE; + RGB_RL_LIGHT; break; } diff --git a/keyboards/dz60/keymaps/marianas/customLogic.c b/keyboards/dz60/keymaps/marianas/customLogic.c index f22bd882e9..03ba92fe92 100644 --- a/keyboards/dz60/keymaps/marianas/customLogic.c +++ b/keyboards/dz60/keymaps/marianas/customLogic.c @@ -11,7 +11,7 @@ static int16_t fnTimer = 0; layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) + switch (get_highest_layer(state)) { case QWERTY: rgblight_mode(9); diff --git a/keyboards/dz60/keymaps/xtonhasvim/keymap.c b/keyboards/dz60/keymaps/xtonhasvim/keymap.c index 9a482686d8..49bc20b576 100644 --- a/keyboards/dz60/keymaps/xtonhasvim/keymap.c +++ b/keyboards/dz60/keymaps/xtonhasvim/keymap.c @@ -73,7 +73,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { static uint32_t last_state = 0; if(last_state != state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _CMD: user_led_on(); break; @@ -85,5 +85,3 @@ layer_state_t layer_state_set_user(layer_state_t state) { } return state; } - - diff --git a/keyboards/dztech/dz60rgb/keymaps/matthewrobo/keymap.c b/keyboards/dztech/dz60rgb/keymaps/matthewrobo/keymap.c index a12358c8d9..287496e17f 100644 --- a/keyboards/dztech/dz60rgb/keymaps/matthewrobo/keymap.c +++ b/keyboards/dztech/dz60rgb/keymaps/matthewrobo/keymap.c @@ -96,7 +96,7 @@ void rgb_matrix_indicators_user(void) uint8_t this_led = host_keyboard_leds(); if (!g_suspend_state && rgb_matrix_config.enable) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _NAV: if (this_led & (1 << USB_LED_NUM_LOCK)) { rgb_matrix_set_color(13, 0xFF, 0x00, 0x00); diff --git a/keyboards/dztech/dz60rgb/keymaps/mekanist/keymap.c b/keyboards/dztech/dz60rgb/keymaps/mekanist/keymap.c index a7c6360568..6af35cf779 100644 --- a/keyboards/dztech/dz60rgb/keymaps/mekanist/keymap.c +++ b/keyboards/dztech/dz60rgb/keymaps/mekanist/keymap.c @@ -62,7 +62,7 @@ void rgb_matrix_indicators_user(void) uint8_t this_led = host_keyboard_leds(); if (!g_suspend_state && rgb_matrix_config.enable) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _LAYER1: rgb_matrix_layer_helper(0xFF, 0x00, 0x00); break; @@ -78,7 +78,7 @@ void rgb_matrix_indicators_user(void) rgb_matrix_set_color(40, 0xFF, 0xFF, 0xFF); } - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _LAYER3: if (this_led & (1 << USB_LED_NUM_LOCK)) { rgb_matrix_set_color(13, 0xFF, 0x00, 0x00); diff --git a/keyboards/dztech/dz60rgb/keymaps/perseid/keymap.c b/keyboards/dztech/dz60rgb/keymaps/perseid/keymap.c index c13fcc1d35..daef7b271d 100644 --- a/keyboards/dztech/dz60rgb/keymaps/perseid/keymap.c +++ b/keyboards/dztech/dz60rgb/keymaps/perseid/keymap.c @@ -37,7 +37,7 @@ void rgb_matrix_layer_helper (uint8_t red, uint8_t green, uint8_t blue) { void rgb_matrix_indicators_user(void) { if (!g_suspend_state) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _QWERTY: rgb_matrix_layer_helper(0x00, 0x0F, 0xFF); break; @@ -46,7 +46,7 @@ void rgb_matrix_indicators_user(void) } } - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _FNM: rgb_matrix_set_color(0, 0x00, 0xFF, 0x00); rgb_matrix_set_color(1, 0x00, 0x00, 0x00); diff --git a/keyboards/dztech/dz65rgb/keymaps/catrielmuller/keymap.c b/keyboards/dztech/dz65rgb/keymaps/catrielmuller/keymap.c index 8bd6069107..817c0fd2ff 100644 --- a/keyboards/dztech/dz65rgb/keymaps/catrielmuller/keymap.c +++ b/keyboards/dztech/dz65rgb/keymaps/catrielmuller/keymap.c @@ -238,5 +238,5 @@ void rgb_matrix_indicators_user(void) { } // Show Selected Layer - rgb_matrix_set_color(layers_leds_map[biton32(layer_state)], MAIN_COLOR[0], MAIN_COLOR[1], MAIN_COLOR[2]); -} \ No newline at end of file + rgb_matrix_set_color(layers_leds_map[get_highest_layer(layer_state)], MAIN_COLOR[0], MAIN_COLOR[1], MAIN_COLOR[2]); +} diff --git a/keyboards/dztech/dz65rgb/keymaps/drootz/keymap.c b/keyboards/dztech/dz65rgb/keymaps/drootz/keymap.c index c313f467e3..2ebbddcef7 100644 --- a/keyboards/dztech/dz65rgb/keymaps/drootz/keymap.c +++ b/keyboards/dztech/dz65rgb/keymaps/drootz/keymap.c @@ -1,20 +1,20 @@ #include QMK_KEYBOARD_H /**************** SOME GLOBALS *********************/ - + bool onMac = false; bool isLeader = false; bool isBlinking = false; bool isRecording = false; bool isPlaying = false; -const float led_dim_ratio = 0.50; -static uint16_t blink_cycle_timer, - blink_fade_in_timer, - blink_fade_out_timer, +const float led_dim_ratio = 0.50; +static uint16_t blink_cycle_timer, + blink_fade_in_timer, + blink_fade_out_timer, macro_one_play_timer, macro_two_play_timer, macro_play_blink_timer = 2000; -static uint8_t fade_in_step_counter, +static uint8_t fade_in_step_counter, fade_out_step_counter, blink_hsv_value; @@ -26,13 +26,13 @@ Function to set color with hsv arguments - "val_ratio" is used to adjust brightness ratio */ void rgb_matrix_set_color_hsv(uint8_t led, uint16_t hue, uint16_t sat, uint16_t val, float val_ratio) { - const uint8_t h = hue <= 255 ? hue : rgb_matrix_config.hsv.h; + const uint8_t h = hue <= 255 ? hue : rgb_matrix_config.hsv.h; const uint8_t s = sat <= 255 ? sat : rgb_matrix_config.hsv.s; const uint8_t v = val <= 255 ? val * val_ratio : rgb_matrix_config.hsv.v * val_ratio; HSV hsv_in = {h, s, v}; RGB rgb_out = hsv_to_rgb(hsv_in); rgb_matrix_set_color(led, rgb_out.r, rgb_out.g, rgb_out.b); -} +} void reset_blink_cycle(void) { blink_cycle_timer = timer_read(); @@ -110,31 +110,31 @@ const layers_leds_map[] = { const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [_MAIN] = LAYOUT_65_ansi( - KC_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_INS, - KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP, - KC_LEAD, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGDN, - KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_DEL, + KC_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_INS, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP, + KC_LEAD, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGDN, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_DEL, KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT ), [_MAC] = LAYOUT_65_ansi( - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_LALT, KC_LGUI, KC_TRNS, KC_TRNS, MO(_FN), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS ), [_FN] = LAYOUT_65_ansi( - DYN_REC_STOP, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NO, KC_NO, - KC_TRNS, KC_MUTE, KC_VOLU, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, RGB_SAD, RGB_SAI, DYN_MACRO_PLAY2, DYN_REC_START2, - KC_TRNS, KC_BRID, KC_VOLD, KC_BRIU, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, RGB_HUD, RGB_HUI, DYN_MACRO_PLAY1, DYN_REC_START1, - KC_TRNS, TO(_MAIN), TO(_MAC), KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, RGB_SPD, RGB_SPI, KC_TRNS, RGB_VAI, KC_NO, + DYN_REC_STOP, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NO, KC_NO, + KC_TRNS, KC_MUTE, KC_VOLU, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, RGB_SAD, RGB_SAI, DYN_MACRO_PLAY2, DYN_REC_START2, + KC_TRNS, KC_BRID, KC_VOLD, KC_BRIU, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, RGB_HUD, RGB_HUI, DYN_MACRO_PLAY1, DYN_REC_START1, + KC_TRNS, TO(_MAIN), TO(_MAC), KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, RGB_SPD, RGB_SPI, KC_TRNS, RGB_VAI, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_RMOD, RGB_VAD, RGB_MOD ), -}; +}; //**************** MATRIX SCANS *********************// -void rgb_matrix_indicators_user(void) { +void rgb_matrix_indicators_user(void) { #ifdef RGB_MATRIX_ENABLE @@ -144,7 +144,7 @@ void rgb_matrix_indicators_user(void) { /* CapsLock LED indicator */ if (IS_HOST_LED_ON(USB_LED_CAPS_LOCK)) { rgb_matrix_set_color_hsv(30, 999, 0, led_constant_val, 0.75); // WHITE - } + } /* Current layer LED indicator */ rgb_matrix_set_color_hsv(layers_leds_map[get_highest_layer(layer_state)], 999, 0, led_constant_val, led_dim_ratio); // WHITE @@ -155,7 +155,7 @@ void rgb_matrix_indicators_user(void) { rgb_matrix_set_color_hsv(30, 999, 999, 999, 1); // CONFIG } else { rgb_matrix_set_color_hsv(14, 999, 999, 999, led_dim_ratio); // CONFIG - } + } /* Blinking LED indicator when recording Dynamic Macro */ if (isRecording && isBlinking) { @@ -174,7 +174,7 @@ void rgb_matrix_indicators_user(void) { } } - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _FN: /* Dynamic Macro LED indicator */ if (isRecording) { @@ -188,12 +188,12 @@ void rgb_matrix_indicators_user(void) { /* Layer LED indicators */ rgb_matrix_set_color_hsv(45, 999, 0, led_constant_val, led_dim_ratio); /* WHITE Layer _MAIN */ rgb_matrix_set_color_hsv(46, 999, 0, led_constant_val, led_dim_ratio); /* WHITE Layer _MAC */ - break; + break; } #endif /* RGB_MATRIX */ } - + bool process_record_user(uint16_t keycode, keyrecord_t *record) { bool pressed = record->event.pressed; if (pressed) { @@ -202,12 +202,12 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { onMac = true; break; case TO(_MAIN): - onMac = false; + onMac = false; break; } } return true; -} +} //**************** LEADER *********************// @@ -244,7 +244,7 @@ const uint8_t french_accent_index[3] = { [_ACUTE] = 2 }; -/* +/* This represent unicode decimal values Each index will be mapped to numpad keycode to out put the correct sequence All codes in this array should be of size 3 @@ -272,8 +272,8 @@ const uint8_t french_decimal_unicodes[5][3][2] = { /*[Letter][Accent][Case]*/ } },{ { - 140, // î - 206 // Î + 140, // î + 206 // Î } },{ { @@ -306,7 +306,7 @@ This is designed and work on an English language keyboard setting on both Window => accept french_letter and french_accent enum's as argument */ void send_french_accent(uint8_t letter, uint8_t accent) { - + bool isCaps; uint8_t decimal_unicode_in; uint8_t decimal_unicode_size = 3; @@ -330,7 +330,7 @@ void send_french_accent(uint8_t letter, uint8_t accent) { }; /* - Function to tap the correct keycodes in sequence for the + Function to tap the correct keycodes in sequence for the "Windows Alt Code" requested, aka Decimal Unicodes */ void tap_win_alt_code(void) { @@ -341,7 +341,7 @@ void send_french_accent(uint8_t letter, uint8_t accent) { tap_code(numpad_key_map[decimal_unicode_out[i]]); } } - + isCaps = IS_HOST_LED_ON(USB_LED_CAPS_LOCK) ? true : false; if (onMac) { @@ -372,7 +372,7 @@ void send_french_accent(uint8_t letter, uint8_t accent) { /*Couple functions used to output the same macro on two different sequences*/ -/* (|) */ +/* (|) */ void ldrkey_send_paranthesis_wrap_ini(void) { SEND_STRING("()" SS_TAP(X_LEFT)); } @@ -382,7 +382,7 @@ void ldrkey_send_paranthesis_wrap_word(void) { onMac ? SEND_STRING(SS_LALT(SS_TAP(X_LEFT)) "(" SS_LALT(SS_TAP(X_RIGHT)) ")") : SEND_STRING(SS_LCTL(SS_TAP(X_LEFT)) "(" SS_LCTL(SS_TAP(X_RIGHT)) ")"); } -/* (selection) */ +/* (selection) */ void ldrkey_send_paranthesis_wrap_selection(void) { onMac ? SEND_STRING(SS_LGUI(SS_TAP(X_X)) "()" SS_TAP(X_LEFT) SS_LGUI(SS_TAP(X_V)) SS_TAP(X_RIGHT)) : SEND_STRING(SS_LCTL(SS_TAP(X_X)) "()" SS_TAP(X_LEFT) SS_LCTL(SS_TAP(X_V)) SS_TAP(X_RIGHT)); } @@ -419,9 +419,9 @@ void ldrkey_send_curlybrace_wrap_selection(void) { LEADER_EXTERNS(); -void matrix_scan_user(void) +void matrix_scan_user(void) { - LEADER_DICTIONARY() + LEADER_DICTIONARY() { leading = false; leader_end(); @@ -476,49 +476,49 @@ void matrix_scan_user(void) tap_code(KC_CAPS); } /* ± => LdrKey > = > - */ - SEQ_TWO_KEYS(KC_EQL, KC_MINS) { - onMac ? SEND_STRING(SS_LALT(SS_LSFT(SS_TAP(X_EQL)))) : SEND_STRING(SS_DOWN(X_LALT) SS_TAP(X_P2) SS_TAP(X_P4) SS_TAP(X_P1) SS_UP(X_LALT)); + SEQ_TWO_KEYS(KC_EQL, KC_MINS) { + onMac ? SEND_STRING(SS_LALT(SS_LSFT(SS_TAP(X_EQL)))) : SEND_STRING(SS_DOWN(X_LALT) SS_TAP(X_P2) SS_TAP(X_P4) SS_TAP(X_P1) SS_UP(X_LALT)); } /* ≤ => LdrKey > - > = */ - SEQ_TWO_KEYS(KC_MINS, KC_EQL) { - onMac ? SEND_STRING(SS_LALT(SS_TAP(X_COMM))) : SEND_STRING(SS_DOWN(X_LALT) SS_TAP(X_P2) SS_TAP(X_P4) SS_TAP(X_P3) SS_UP(X_LALT)); + SEQ_TWO_KEYS(KC_MINS, KC_EQL) { + onMac ? SEND_STRING(SS_LALT(SS_TAP(X_COMM))) : SEND_STRING(SS_DOWN(X_LALT) SS_TAP(X_P2) SS_TAP(X_P4) SS_TAP(X_P3) SS_UP(X_LALT)); } /* ≥ => LdrKey > = > = */ - SEQ_TWO_KEYS(KC_EQL, KC_EQL) { - onMac ? SEND_STRING(SS_LALT(SS_TAP(X_DOT))) : SEND_STRING(SS_DOWN(X_LALT) SS_TAP(X_P2) SS_TAP(X_P4) SS_TAP(X_P2) SS_UP(X_LALT)); + SEQ_TWO_KEYS(KC_EQL, KC_EQL) { + onMac ? SEND_STRING(SS_LALT(SS_TAP(X_DOT))) : SEND_STRING(SS_DOWN(X_LALT) SS_TAP(X_P2) SS_TAP(X_P4) SS_TAP(X_P2) SS_UP(X_LALT)); } /* <= => LdrKey > , > , */ - SEQ_TWO_KEYS(KC_COMM, KC_COMM) { - SEND_STRING(SS_LSFT(SS_TAP(X_COMM)) SS_TAP(X_SPC) SS_TAP(X_EQL) SS_TAP(X_LEFT) SS_TAP(X_BSPC) SS_TAP(X_RIGHT)); + SEQ_TWO_KEYS(KC_COMM, KC_COMM) { + SEND_STRING(SS_LSFT(SS_TAP(X_COMM)) SS_TAP(X_SPC) SS_TAP(X_EQL) SS_TAP(X_LEFT) SS_TAP(X_BSPC) SS_TAP(X_RIGHT)); } /* => => LdrKey > . > . */ - SEQ_TWO_KEYS(KC_DOT, KC_DOT) { - SEND_STRING("=>"); + SEQ_TWO_KEYS(KC_DOT, KC_DOT) { + SEND_STRING("=>"); } /* ", " => LdrKey > " " */ - SEQ_ONE_KEY(KC_SPC) { - SEND_STRING(", "); + SEQ_ONE_KEY(KC_SPC) { + SEND_STRING(", "); } /* ". " => LdrKey > " " > " " */ - SEQ_TWO_KEYS(KC_SPC, KC_SPC) { - SEND_STRING(". "); + SEQ_TWO_KEYS(KC_SPC, KC_SPC) { + SEND_STRING(". "); } /* Backward delete current word (on cursor) */ - SEQ_TWO_KEYS(KC_BSPC, KC_BSPC) { - onMac ? SEND_STRING(SS_LALT(SS_TAP(X_RIGHT)) SS_LALT(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)) : SEND_STRING(SS_LCTL(SS_TAP(X_RIGHT)) SS_LCTL(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)); + SEQ_TWO_KEYS(KC_BSPC, KC_BSPC) { + onMac ? SEND_STRING(SS_LALT(SS_TAP(X_RIGHT)) SS_LALT(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)) : SEND_STRING(SS_LCTL(SS_TAP(X_RIGHT)) SS_LCTL(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)); } /* Previous word delete */ - SEQ_ONE_KEY(KC_BSPC) { - onMac ? SEND_STRING(SS_LALT(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)) : SEND_STRING(SS_LCTL(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)); + SEQ_ONE_KEY(KC_BSPC) { + onMac ? SEND_STRING(SS_LALT(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)) : SEND_STRING(SS_LCTL(SS_LSFT(SS_TAP(X_LEFT))) SS_TAP(X_BSPC)); } /* Forward delete current word (on cursor) */ - SEQ_TWO_KEYS(KC_DEL, KC_DEL) { + SEQ_TWO_KEYS(KC_DEL, KC_DEL) { - onMac ? SEND_STRING(SS_LALT(SS_TAP(X_LEFT)) SS_LALT(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)) : SEND_STRING(SS_LCTL(SS_TAP(X_LEFT)) SS_LCTL(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)); + onMac ? SEND_STRING(SS_LALT(SS_TAP(X_LEFT)) SS_LALT(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)) : SEND_STRING(SS_LCTL(SS_TAP(X_LEFT)) SS_LCTL(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)); } /* Next word delete */ - SEQ_ONE_KEY(KC_DEL) { - onMac ? SEND_STRING(SS_LALT(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)): SEND_STRING(SS_LCTL(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)); + SEQ_ONE_KEY(KC_DEL) { + onMac ? SEND_STRING(SS_LALT(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)): SEND_STRING(SS_LCTL(SS_LSFT(SS_TAP(X_RIGHT))) SS_TAP(X_DEL)); } /* ` => LdrKey > Escape */ SEQ_ONE_KEY(KC_GESC) { @@ -548,7 +548,7 @@ void matrix_scan_user(void) SEQ_ONE_KEY(KC_Q) { onMac ? SEND_STRING(SS_LGUI(SS_TAP(X_Q))) : SEND_STRING(SS_LALT(SS_TAP(X_F4))); } - /* " => LdrKey > ' */ + /* " => LdrKey > ' */ SEQ_ONE_KEY(KC_QUOT) { SEND_STRING("\""); } @@ -657,48 +657,48 @@ void matrix_scan_user(void) ldrkey_send_curlybrace_wrap_selection(); } /* Select everything on this line before cursor => LdrKey > Left */ - SEQ_ONE_KEY(KC_LEFT) { + SEQ_ONE_KEY(KC_LEFT) { onMac ? SEND_STRING(SS_LSFT(SS_LGUI(SS_TAP(X_LEFT)))) : SEND_STRING(SS_LSFT(SS_TAP(X_HOME))); } /* Select everything on this line after cursor => LdrKey > Right */ - SEQ_ONE_KEY(KC_RIGHT) { + SEQ_ONE_KEY(KC_RIGHT) { onMac ? SEND_STRING(SS_LSFT(SS_LGUI(SS_TAP(X_RIGHT)))) : SEND_STRING(SS_LSFT(SS_TAP(X_END))); } /* Select everything on this line before cursor and bring on previous line => LdrKey > Left > Left */ - SEQ_TWO_KEYS(KC_LEFT, KC_LEFT) { - onMac ? SEND_STRING(SS_LSFT(SS_TAP(X_UP) SS_LGUI(SS_TAP(X_RIGHT)))) : SEND_STRING(SS_LSFT(SS_TAP(X_UP) SS_TAP(X_END))); + SEQ_TWO_KEYS(KC_LEFT, KC_LEFT) { + onMac ? SEND_STRING(SS_LSFT(SS_TAP(X_UP) SS_LGUI(SS_TAP(X_RIGHT)))) : SEND_STRING(SS_LSFT(SS_TAP(X_UP) SS_TAP(X_END))); } /* Select everything on this line => LdrKey > Right > Left */ - SEQ_TWO_KEYS(KC_RIGHT, KC_LEFT) { - onMac ? SEND_STRING(SS_LGUI(SS_TAP(X_RIGHT) SS_LSFT(SS_LGUI(SS_TAP(X_LEFT))))) : SEND_STRING(SS_TAP(X_END) SS_LSFT(SS_TAP(X_HOME))); + SEQ_TWO_KEYS(KC_RIGHT, KC_LEFT) { + onMac ? SEND_STRING(SS_LGUI(SS_TAP(X_RIGHT) SS_LSFT(SS_LGUI(SS_TAP(X_LEFT))))) : SEND_STRING(SS_TAP(X_END) SS_LSFT(SS_TAP(X_HOME))); } /* Select 1x Page Up on the page before the cursor => LdrKey > Up */ - SEQ_ONE_KEY(KC_UP) { + SEQ_ONE_KEY(KC_UP) { SEND_STRING(SS_LSFT(SS_TAP(X_PGUP))); } /* Select 1x Page Down on the page after the cursor => LdrKey > Down */ - SEQ_ONE_KEY(KC_DOWN) { - SEND_STRING(SS_LSFT(SS_TAP(X_PGDN))); + SEQ_ONE_KEY(KC_DOWN) { + SEND_STRING(SS_LSFT(SS_TAP(X_PGDN))); } /* Select everything on the page before the cursor => LdrKey > Up > Up */ - SEQ_TWO_KEYS(KC_UP, KC_UP) { + SEQ_TWO_KEYS(KC_UP, KC_UP) { onMac ? SEND_STRING(SS_LSFT(SS_LGUI(SS_TAP(X_UP)))) : SEND_STRING(SS_LSFT(SS_LCTL(SS_TAP(X_HOME)))); } /* Select everything on the page after the cursor => LdrKey > Down > Down */ - SEQ_TWO_KEYS(KC_DOWN, KC_DOWN) { + SEQ_TWO_KEYS(KC_DOWN, KC_DOWN) { onMac ? SEND_STRING(SS_LSFT(SS_LGUI(SS_TAP(X_DOWN)))) : SEND_STRING(SS_LSFT(SS_LCTL(SS_TAP(X_END)))); } /* HELPER => spit out the url of the layout description page on github */ - SEQ_FIVE_KEYS(KC_GESC, KC_GESC, KC_GESC, KC_GESC, KC_GESC) { + SEQ_FIVE_KEYS(KC_GESC, KC_GESC, KC_GESC, KC_GESC, KC_GESC) { SEND_STRING("https://github.com/qmk/qmk_firmware/tree/master/keyboards/dztech/dz65rgb/keymaps/drootz"); } /* google.ca => LdrKey > G > G */ - SEQ_TWO_KEYS(KC_G, KC_G) { - SEND_STRING("https://google.ca" SS_TAP(X_ENT)); + SEQ_TWO_KEYS(KC_G, KC_G) { + SEND_STRING("https://google.ca" SS_TAP(X_ENT)); } /* @gmail => LdrKey > M > L > T */ - SEQ_THREE_KEYS(KC_M, KC_L, KC_T) { - SEND_STRING("mailto." SS_TAP(X_D) SS_TAP(X_A) SS_TAP(X_N) SS_TAP(X_I) SS_TAP(X_E) SS_TAP(X_L) SS_TAP(X_R) SS_TAP(X_A) SS_TAP(X_C) SS_TAP(X_I) SS_TAP(X_N) SS_TAP(X_E) "@gmail.com"); + SEQ_THREE_KEYS(KC_M, KC_L, KC_T) { + SEND_STRING("mailto." SS_TAP(X_D) SS_TAP(X_A) SS_TAP(X_N) SS_TAP(X_I) SS_TAP(X_E) SS_TAP(X_L) SS_TAP(X_R) SS_TAP(X_A) SS_TAP(X_C) SS_TAP(X_I) SS_TAP(X_N) SS_TAP(X_E) "@gmail.com"); } /* Show Desktop => LdrKey > D */ SEQ_ONE_KEY(KC_D) { diff --git a/keyboards/dztech/dz65rgb/keymaps/matthewrobo/keymap.c b/keyboards/dztech/dz65rgb/keymaps/matthewrobo/keymap.c index 00915a9b4f..0c7bfbbb48 100644 --- a/keyboards/dztech/dz65rgb/keymaps/matthewrobo/keymap.c +++ b/keyboards/dztech/dz65rgb/keymaps/matthewrobo/keymap.c @@ -91,7 +91,7 @@ void rgb_matrix_indicators_user(void) uint8_t this_led = host_keyboard_leds(); if (!g_suspend_state && rgb_matrix_config.enable) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _NAV: if (IS_LED_ON(this_led, USB_LED_NUM_LOCK)) { rgb_matrix_set_color(17, 0xFF, 0x00, 0x00); diff --git a/keyboards/ergodox_ez/keymaps/bepo_tm_style/keymap.c b/keyboards/ergodox_ez/keymaps/bepo_tm_style/keymap.c index a5b107baae..91798ab188 100755 --- a/keyboards/ergodox_ez/keymaps/bepo_tm_style/keymap.c +++ b/keyboards/ergodox_ez/keymaps/bepo_tm_style/keymap.c @@ -190,7 +190,7 @@ static bool is_macro1_recording = false; // The current set of active layers (as a bitmask). // There is a global 'layer_state' variable but it is set after the call // to layer_state_set_user(). -static uint32_t current_layer_state = 0; +static layer_state_t current_layer_state = 0; layer_state_t layer_state_set_user(layer_state_t state); // Method called at the end of the tap dance on the TAP_MACRO key. That key is diff --git a/keyboards/ergodox_ez/keymaps/blakedietz/keymap.c b/keyboards/ergodox_ez/keymaps/blakedietz/keymap.c index 5c08d30727..67c50eb129 100644 --- a/keyboards/ergodox_ez/keymaps/blakedietz/keymap.c +++ b/keyboards/ergodox_ez/keymaps/blakedietz/keymap.c @@ -200,7 +200,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -262,4 +262,3 @@ void matrix_scan_user(void) { // } // return true; //} - diff --git a/keyboards/ergodox_ez/keymaps/bpruitt-goddard/keymap.c b/keyboards/ergodox_ez/keymaps/bpruitt-goddard/keymap.c index 229ece0d74..eff7f111b4 100644 --- a/keyboards/ergodox_ez/keymaps/bpruitt-goddard/keymap.c +++ b/keyboards/ergodox_ez/keymaps/bpruitt-goddard/keymap.c @@ -98,7 +98,7 @@ static bool is_macro1_recording = false; // The current set of active layers (as a bitmask). // There is a global 'layer_state' variable but it is set after the call // to layer_state_set_user(). -static uint32_t current_layer_state = 0; +static layer_state_t current_layer_state = 0; layer_state_t layer_state_set_user(layer_state_t state); // Method called at the end of the tap dance on the TAP_MACRO key. That key is diff --git a/keyboards/ergodox_ez/keymaps/default_osx/keymap.c b/keyboards/ergodox_ez/keymaps/default_osx/keymap.c index 73b1077b83..3ab66078fe 100644 --- a/keyboards/ergodox_ez/keymaps/default_osx/keymap.c +++ b/keyboards/ergodox_ez/keymaps/default_osx/keymap.c @@ -141,7 +141,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c b/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c index fab2977356..ff9ae77bdd 100644 --- a/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c +++ b/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c @@ -725,7 +725,7 @@ void led_set_user(uint8_t usb_led) { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_2_off(); diff --git a/keyboards/ergodox_ez/keymaps/hacker_dvorak/user/layer_set_state_user.c b/keyboards/ergodox_ez/keymaps/hacker_dvorak/user/layer_set_state_user.c index fd022681b0..ed407def79 100644 --- a/keyboards/ergodox_ez/keymaps/hacker_dvorak/user/layer_set_state_user.c +++ b/keyboards/ergodox_ez/keymaps/hacker_dvorak/user/layer_set_state_user.c @@ -1,6 +1,6 @@ layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); switch (layer) { case DVORAK: diff --git a/keyboards/ergodox_ez/keymaps/heartrobotninja/keymap.c b/keyboards/ergodox_ez/keymaps/heartrobotninja/keymap.c index b6edc17532..91884c8e76 100644 --- a/keyboards/ergodox_ez/keymaps/heartrobotninja/keymap.c +++ b/keyboards/ergodox_ez/keymaps/heartrobotninja/keymap.c @@ -370,7 +370,7 @@ LEADER_EXTERNS(); void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (keyboard_report->mods & MOD_BIT(KC_LSFT) || ((get_oneshot_mods() & MOD_BIT(KC_LSFT)) && @@ -677,4 +677,4 @@ void matrix_init_user(void) wait_ms(1000); rgblight_effect_knight(50); -} \ No newline at end of file +} diff --git a/keyboards/ergodox_ez/keymaps/kou/keymap.c b/keyboards/ergodox_ez/keymaps/kou/keymap.c index c8d0a6b5dd..01427c2d2d 100644 --- a/keyboards/ergodox_ez/keymaps/kou/keymap.c +++ b/keyboards/ergodox_ez/keymaps/kou/keymap.c @@ -284,7 +284,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/lukaus/keymap.c b/keyboards/ergodox_ez/keymaps/lukaus/keymap.c index 5d797beb18..542e123db3 100644 --- a/keyboards/ergodox_ez/keymaps/lukaus/keymap.c +++ b/keyboards/ergodox_ez/keymaps/lukaus/keymap.c @@ -813,7 +813,7 @@ case RU_7: layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); // ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/matrixman/keymap.c b/keyboards/ergodox_ez/keymaps/matrixman/keymap.c index 10b6567cdb..bb6ba5ae34 100644 --- a/keyboards/ergodox_ez/keymaps/matrixman/keymap.c +++ b/keyboards/ergodox_ez/keymaps/matrixman/keymap.c @@ -165,7 +165,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/nathanvercaemert/keymap.c b/keyboards/ergodox_ez/keymaps/nathanvercaemert/keymap.c index e31391a674..a3c2176951 100644 --- a/keyboards/ergodox_ez/keymaps/nathanvercaemert/keymap.c +++ b/keyboards/ergodox_ez/keymaps/nathanvercaemert/keymap.c @@ -218,7 +218,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); ergodox_board_led_off(); ergodox_right_led_1_off(); ergodox_right_led_2_off(); @@ -431,4 +431,3 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } return true; } - diff --git a/keyboards/ergodox_ez/keymaps/nfriend/keymap.c b/keyboards/ergodox_ez/keymaps/nfriend/keymap.c index 1d12093bab..ba578dd1c5 100644 --- a/keyboards/ergodox_ez/keymaps/nfriend/keymap.c +++ b/keyboards/ergodox_ez/keymaps/nfriend/keymap.c @@ -1057,7 +1057,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/profet_80/keymap.c b/keyboards/ergodox_ez/keymaps/profet_80/keymap.c index 85455fa9d9..6f602e828e 100644 --- a/keyboards/ergodox_ez/keymaps/profet_80/keymap.c +++ b/keyboards/ergodox_ez/keymaps/profet_80/keymap.c @@ -157,7 +157,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/pvinis/keymap.c b/keyboards/ergodox_ez/keymaps/pvinis/keymap.c index 024cefd270..c69621ab98 100644 --- a/keyboards/ergodox_ez/keymaps/pvinis/keymap.c +++ b/keyboards/ergodox_ez/keymaps/pvinis/keymap.c @@ -245,11 +245,11 @@ void keyboard_post_init_user_keymap(void) { } // light up leds based on the layer -uint32_t layer_state_set_user_keymap(uint32_t state) { +layer_state_t layer_state_set_user_keymap(layer_state_t state) { ergodox_right_led_1_off(); ergodox_right_led_2_off(); ergodox_right_led_3_off(); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case LR_SYSCTL: ergodox_right_led_3_on(); // blue break; @@ -306,7 +306,7 @@ uint32_t layer_state_set_user_keymap(uint32_t state) { // SYSCTL on first tap, MOUSE ON second tap // void layers_dance_finished(qk_tap_dance_state_t *state, void *user_data) { -// uint8_t layer = biton32(layer_state); +// uint8_t layer = get_highest_layer(layer_state); // switch(state->count) { // case 1: diff --git a/keyboards/ergodox_ez/keymaps/rgb_layer/keymap.c b/keyboards/ergodox_ez/keymaps/rgb_layer/keymap.c index 3e607edb39..595f3b4ee1 100644 --- a/keyboards/ergodox_ez/keymaps/rgb_layer/keymap.c +++ b/keyboards/ergodox_ez/keymaps/rgb_layer/keymap.c @@ -228,7 +228,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { ergodox_right_led_1_off(); ergodox_right_led_2_off(); ergodox_right_led_3_off(); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case SYMB: ergodox_right_led_1_on(); if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_red(); rgblight_mode_noeeprom(1); } @@ -268,4 +268,3 @@ layer_state_t layer_state_set_user(layer_state_t state) { } return state; } - diff --git a/keyboards/ergodox_ez/keymaps/rishka/keymap.c b/keyboards/ergodox_ez/keymaps/rishka/keymap.c index 102803e512..0d6ac9fe95 100644 --- a/keyboards/ergodox_ez/keymaps/rishka/keymap.c +++ b/keyboards/ergodox_ez/keymaps/rishka/keymap.c @@ -138,7 +138,7 @@ void keyboard_post_init_user(void) { }; // Runs whenever there is a layer state change. -uint32_t layer_state_set_user(layer_state_t state) { +layer_state_t layer_state_set_user(layer_state_t state) { ergodox_board_led_off(); ergodox_right_led_1_off(); ergodox_right_led_2_off(); diff --git a/keyboards/ergodox_ez/keymaps/skug/keymap.c b/keyboards/ergodox_ez/keymaps/skug/keymap.c index 1446ea7466..04aa6a99fd 100644 --- a/keyboards/ergodox_ez/keymaps/skug/keymap.c +++ b/keyboards/ergodox_ez/keymaps/skug/keymap.c @@ -228,7 +228,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/smurmann/keymap.c b/keyboards/ergodox_ez/keymaps/smurmann/keymap.c index 42ac13775f..c8ddc23a8b 100644 --- a/keyboards/ergodox_ez/keymaps/smurmann/keymap.c +++ b/keyboards/ergodox_ez/keymaps/smurmann/keymap.c @@ -139,7 +139,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if(layer == 1) { @@ -157,7 +157,7 @@ void matrix_scan_user(void) { } if(keyboard_report->mods & MOD_BIT(KC_LSFT)) - { + { ergodox_right_led_1_set (LED_BRIGHTNESS_HI); ergodox_right_led_1_on (); } else { @@ -182,7 +182,7 @@ void matrix_scan_user(void) { } if(keyboard_report->mods & MOD_BIT(KC_LCTRL)) - { + { ergodox_right_led_3_set (LED_BRIGHTNESS_HI); ergodox_right_led_3_on (); } else { @@ -195,7 +195,7 @@ void matrix_scan_user(void) { }; void led_set_user(uint8_t usb_led){ - if (usb_led & (1 << USB_LED_CAPS_LOCK)) + if (usb_led & (1 << USB_LED_CAPS_LOCK)) { capsOn = true; }else { diff --git a/keyboards/ergodox_ez/keymaps/steno/keymap.c b/keyboards/ergodox_ez/keymaps/steno/keymap.c index 080d3f6cef..96218bbe99 100644 --- a/keyboards/ergodox_ez/keymaps/steno/keymap.c +++ b/keyboards/ergodox_ez/keymaps/steno/keymap.c @@ -228,7 +228,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/testing/keymap.c b/keyboards/ergodox_ez/keymaps/testing/keymap.c index 5c1fc4af28..3aee63ddf1 100644 --- a/keyboards/ergodox_ez/keymaps/testing/keymap.c +++ b/keyboards/ergodox_ez/keymaps/testing/keymap.c @@ -62,7 +62,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/keymaps/vim/keymap.c b/keyboards/ergodox_ez/keymaps/vim/keymap.c index 948f2b4794..c1c037ef23 100644 --- a/keyboards/ergodox_ez/keymaps/vim/keymap.c +++ b/keyboards/ergodox_ez/keymaps/vim/keymap.c @@ -330,7 +330,7 @@ void matrix_init_user(void) { }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ergodox_ez/util/compile_keymap.py b/keyboards/ergodox_ez/util/compile_keymap.py index b447ecaf5c..310512c920 100755 --- a/keyboards/ergodox_ez/util/compile_keymap.py +++ b/keyboards/ergodox_ez/util/compile_keymap.py @@ -27,29 +27,34 @@ PY2 = sys.version_info.major == 2 if PY2: chr = unichr - KEYBOARD_LAYOUTS = { # These map positions in the parsed layout to # positions in the KEYMAP MATRIX 'ergodox_ez': [ - [ 0, 1, 2, 3, 4, 5, 6], [38, 39, 40, 41, 42, 43, 44], - [ 7, 8, 9, 10, 11, 12, 13], [45, 46, 47, 48, 49, 50, 51], - [14, 15, 16, 17, 18, 19 ], [ 52, 53, 54, 55, 56, 57], - [20, 21, 22, 23, 24, 25, 26], [58, 59, 60, 61, 62, 63, 64], - [27, 28, 29, 30, 31 ], [ 65, 66, 67, 68, 69], - [ 32, 33], [70, 71 ], - [ 34], [72 ], - [ 35, 36, 37], [73, 74, 75 ], + [0, 1, 2, 3, 4, 5, 6], + [38, 39, 40, 41, 42, 43, 44], + [7, 8, 9, 10, 11, 12, 13], + [45, 46, 47, 48, 49, 50, 51], + [14, 15, 16, 17, 18, 19], + [52, 53, 54, 55, 56, 57], + [20, 21, 22, 23, 24, 25, 26], + [58, 59, 60, 61, 62, 63, 64], + [27, 28, 29, 30, 31], + [65, 66, 67, 68, 69], + [32, 33], + [70, 71], + [34], + [72], + [35, 36, 37], + [73, 74, 75], ] } -ROW_INDENTS = { - 'ergodox_ez': [0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 5, 0, 6, 0, 4, 0] -} +ROW_INDENTS = {'ergodox_ez': [0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 5, 0, 6, 0, 4, 0]} BLANK_LAYOUTS = [ -# Compact Layout -""" + # Compact Layout + """ .------------------------------------.------------------------------------. | | | | | | | | | | | | | | | !-----+----+----+----+----+----------!-----+----+----+----+----+----+-----! @@ -70,8 +75,8 @@ BLANK_LAYOUTS = [ '-----------------' '-----------------' """, -# Wide Layout -""" + # Wide Layout + """ .---------------------------------------------. .---------------------------------------------. | | | | | | | | ! | | | | | | | !-------+-----+-----+-----+-----+-------------! !-------+-----+-----+-----+-----+-----+-------! @@ -93,26 +98,22 @@ BLANK_LAYOUTS = [ """, ] - DEFAULT_CONFIG = { - "keymaps_includes": [ - "keymap_common.h", - ], + "keymaps_includes": ["keymap_common.h",], 'filler': "-+.'!:x", 'separator': "|", 'default_key_prefix': ["KC_"], } - SECTIONS = [ 'layout_config', 'layers', ] - # Markdown Parsing -ONELINE_COMMENT_RE = re.compile(r""" +ONELINE_COMMENT_RE = re.compile( + r""" ^ # comment must be at the start of the line \s* # arbitrary whitespace // # start of the comment @@ -121,22 +122,26 @@ ONELINE_COMMENT_RE = re.compile(r""" """, re.MULTILINE | re.VERBOSE ) -INLINE_COMMENT_RE = re.compile(r""" +INLINE_COMMENT_RE = re.compile( + r""" ([\,\"\[\]\{\}\d]) # anythig that might end a expression \s+ # comment must be preceded by whitespace // # start of the comment \s # and succeded by whitespace (?:[^\"\]\}\{\[]*) # the comment (except things which might be json) $ # until the end of line -""", re.MULTILINE | re.VERBOSE) +""", re.MULTILINE | re.VERBOSE +) -TRAILING_COMMA_RE = re.compile(r""" +TRAILING_COMMA_RE = re.compile( + r""" , # the comma (?:\s*) # arbitrary whitespace $ # only works if the trailing comma is followed by newline (\s*) # arbitrary whitespace ([\]\}]) # end of an array or object -""", re.MULTILINE | re.VERBOSE) +""", re.MULTILINE | re.VERBOSE +) def loads(raw_data): @@ -178,9 +183,7 @@ def parse_config(path): def end_section(): if section['start_line'] >= 0: if section['name'] == 'layout_config': - config.update(loads("\n".join( - section['code_lines'] - ))) + config.update(loads("\n".join(section['code_lines']))) elif section['sub_name'].startswith('layer'): layer_name = section['sub_name'] config['layer_lines'][layer_name] = section['code_lines'] @@ -215,6 +218,7 @@ def parse_config(path): assert 'layout' in config return config + # header file parsing IF0_RE = re.compile(r""" @@ -224,7 +228,6 @@ IF0_RE = re.compile(r""" #endif """, re.MULTILINE | re.DOTALL | re.VERBOSE) - COMMENT_RE = re.compile(r""" /\* .*? @@ -244,6 +247,7 @@ def regex_partial(re_str_fmt, flags): def partial(*args, **kwargs): re_str = re_str_fmt.format(*args, **kwargs) return re.compile(re_str, flags) + return partial @@ -256,7 +260,6 @@ KEYDEF_REP = regex_partial(r""" ) # capture group end """, re.MULTILINE | re.DOTALL | re.VERBOSE) - ENUM_RE = re.compile(r""" ( enum @@ -268,7 +271,6 @@ ENUM_RE = re.compile(r""" ) # capture group end """, re.MULTILINE | re.DOTALL | re.VERBOSE) - ENUM_KEY_REP = regex_partial(r""" ( {} # the prefixes @@ -309,14 +311,13 @@ def parse_valid_keys(config, out_path): include_path = os.path.join(dirpath, include) if os.path.exists(include_path): header_data = read_header_file(include_path) - valid_keycodes.update( - parse_keydefs(config, header_data) - ) + valid_keycodes.update(parse_keydefs(config, header_data)) return valid_keycodes # Keymap Parsing + def iter_raw_codes(layer_lines, filler, separator): filler_re = re.compile("[" + filler + " ]") for line in layer_lines: @@ -346,28 +347,21 @@ LAYER_CHANGE_RE = re.compile(r""" (DF|TG|MO)\(\d+\) """, re.VERBOSE) - MACRO_RE = re.compile(r""" M\(\w+\) """, re.VERBOSE) - UNICODE_RE = re.compile(r""" U[0-9A-F]{4} """, re.VERBOSE) - NON_CODE = re.compile(r""" ^[^A-Z0-9_]$ """, re.VERBOSE) def parse_uni_code(raw_code): - macro_id = "UC_" + ( - unicodedata.name(raw_code) - .replace(" ", "_") - .replace("-", "_") - ) + macro_id = "UC_" + (unicodedata.name(raw_code).replace(" ", "_").replace("-", "_")) code = "M({})".format(macro_id) uc_hex = "{:04X}".format(ord(raw_code)) return code, macro_id, uc_hex @@ -407,19 +401,13 @@ def parse_code(raw_code, key_prefixes, valid_keycodes): def parse_keymap(config, key_indexes, layer_lines, valid_keycodes): keymap = {} - raw_codes = list(iter_raw_codes( - layer_lines, config['filler'], config['separator'] - )) + raw_codes = list(iter_raw_codes(layer_lines, config['filler'], config['separator'])) indexed_codes = iter_indexed_codes(raw_codes, key_indexes) key_prefixes = config['key_prefixes'] for raw_code, key_index, row_index in indexed_codes: - code, macro_id, uc_hex = parse_code( - raw_code, key_prefixes, valid_keycodes - ) + code, macro_id, uc_hex = parse_code(raw_code, key_prefixes, valid_keycodes) # TODO: line numbers for invalid codes - err_msg = "Could not parse key '{}' on row {}".format( - raw_code, row_index - ) + err_msg = "Could not parse key '{}' on row {}".format(raw_code, row_index) assert code is not None, err_msg # print(repr(raw_code), repr(code), macro_id, uc_hex) if macro_id: @@ -432,17 +420,14 @@ def parse_keymap(config, key_indexes, layer_lines, valid_keycodes): def parse_keymaps(config, valid_keycodes): keymaps = collections.OrderedDict() - key_indexes = config.get( - 'key_indexes', KEYBOARD_LAYOUTS[config['layout']] - ) + key_indexes = config.get('key_indexes', KEYBOARD_LAYOUTS[config['layout']]) # TODO: maybe validate key_indexes for layer_name, layer_lines, in config['layer_lines'].items(): - keymaps[layer_name] = parse_keymap( - config, key_indexes, layer_lines, valid_keycodes - ) + keymaps[layer_name] = parse_keymap(config, key_indexes, layer_lines, valid_keycodes) return keymaps + # keymap.c output USERCODE = """ @@ -453,7 +438,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -572,7 +557,6 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {{ }}; """ - UNICODE_MACRO_TEMPLATE = """ case {macro_id}: unicode_action_function(0x{hi:02x}, 0x{lo:02x}); @@ -584,9 +568,7 @@ def unicode_macro_cases(config): for macro_id, uc_hex in config['unicode_macros'].items(): hi = int(uc_hex, 16) >> 8 lo = int(uc_hex, 16) & 0xFF - yield UNICODE_MACRO_TEMPLATE.format( - macro_id=macro_id, hi=hi, lo=lo - ) + yield UNICODE_MACRO_TEMPLATE.format(macro_id=macro_id, hi=hi, lo=lo) def iter_keymap_lines(keymap, row_indents=None): diff --git a/keyboards/ergoslab/keymaps/default/keymap.c b/keyboards/ergoslab/keymaps/default/keymap.c index 59415618a8..093d586eba 100644 --- a/keyboards/ergoslab/keymaps/default/keymap.c +++ b/keyboards/ergoslab/keymaps/default/keymap.c @@ -51,7 +51,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { #ifdef RGBLIGHT_ENABLE layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); switch (layer) { case BASE: rgblight_sethsv(HSV_ERGOSLAB_ORANGE); diff --git a/keyboards/exclusive/e65/keymaps/masterzen/keymap.c b/keyboards/exclusive/e65/keymaps/masterzen/keymap.c index 156832de4e..898a294f7e 100644 --- a/keyboards/exclusive/e65/keymaps/masterzen/keymap.c +++ b/keyboards/exclusive/e65/keymaps/masterzen/keymap.c @@ -102,7 +102,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { edit = false; } - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _ADJUST: temp_config.mode = rgblight_get_mode(); rgblight_mode_noeeprom(1); diff --git a/keyboards/exclusive/e7v1/keymaps/masterzen/keymap.c b/keyboards/exclusive/e7v1/keymaps/masterzen/keymap.c index 6987e84021..2793cffe93 100644 --- a/keyboards/exclusive/e7v1/keymaps/masterzen/keymap.c +++ b/keyboards/exclusive/e7v1/keymaps/masterzen/keymap.c @@ -121,7 +121,7 @@ layer_state_t layer_state_set_user(layer_state_t state) edit = false; } - switch (biton32(state)) + switch (get_highest_layer(state)) { case _ADJUST: mode = rgblight_get_mode(); diff --git a/keyboards/gboards/gergo/keymaps/colemak/keymap.c b/keyboards/gboards/gergo/keymaps/colemak/keymap.c index b2e79114f2..35b1e0b653 100644 --- a/keyboards/gboards/gergo/keymaps/colemak/keymap.c +++ b/keyboards/gboards/gergo/keymaps/colemak/keymap.c @@ -146,8 +146,8 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - //uint8_t layer = biton32(layer_state); - biton32(layer_state); + //uint8_t layer = get_highest_layer(layer_state); + get_highest_layer(layer_state); }; @@ -171,4 +171,3 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } return true; }; - diff --git a/keyboards/gh60/revc/keymaps/dbroqua/keymap.c b/keyboards/gh60/revc/keymaps/dbroqua/keymap.c index 964f40f1c0..ffb87ef009 100644 --- a/keyboards/gh60/revc/keymaps/dbroqua/keymap.c +++ b/keyboards/gh60/revc/keymaps/dbroqua/keymap.c @@ -101,7 +101,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; void matrix_scan_user(void) { - uint32_t layer = layer_state; + layer_state_t layer = layer_state; if (layer & (1<<1)) { gh60_fn_led_on(); @@ -120,4 +120,4 @@ void matrix_scan_user(void) { } else { gh60_esc_led_off(); } -}; \ No newline at end of file +}; diff --git a/keyboards/gh60/revc/keymaps/default/keymap.c b/keyboards/gh60/revc/keymaps/default/keymap.c index a8fd4f3c22..4ebc71ff4b 100644 --- a/keyboards/gh60/revc/keymaps/default/keymap.c +++ b/keyboards/gh60/revc/keymaps/default/keymap.c @@ -31,7 +31,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void matrix_scan_user(void) { //Layer LED indicators - uint32_t layer = layer_state; + layer_state_t layer = layer_state; if (layer & (1<<1)) { gh60_wasd_leds_on(); diff --git a/keyboards/gh60/revc/keymaps/robotmaxtron/keymap.c b/keyboards/gh60/revc/keymaps/robotmaxtron/keymap.c index b84e7564fc..77bf54de63 100644 --- a/keyboards/gh60/revc/keymaps/robotmaxtron/keymap.c +++ b/keyboards/gh60/revc/keymaps/robotmaxtron/keymap.c @@ -97,7 +97,7 @@ void matrix_scan_user(void) { // Layer LED indicators // ESC led on when in function layer, WASD cluster leds enabled when on arrow cluster - uint32_t layer = layer_state; + layer_state_t layer = layer_state; if (layer & (1<<1)) { gh60_wasd_leds_on(); } else { diff --git a/keyboards/gh60/satan/keymaps/addcninblue/keymap.c b/keyboards/gh60/satan/keymaps/addcninblue/keymap.c index 5012fee56b..2b1a417fb5 100644 --- a/keyboards/gh60/satan/keymaps/addcninblue/keymap.c +++ b/keyboards/gh60/satan/keymaps/addcninblue/keymap.c @@ -177,7 +177,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (old_layer != layer) { switch (layer) { diff --git a/keyboards/glenpickle/chimera_ergo/keymaps/default/keymap.c b/keyboards/glenpickle/chimera_ergo/keymaps/default/keymap.c index 51ab0e92cd..dd7e32f7dc 100644 --- a/keyboards/glenpickle/chimera_ergo/keymaps/default/keymap.c +++ b/keyboards/glenpickle/chimera_ergo/keymaps/default/keymap.c @@ -131,7 +131,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _QWERTY: diff --git a/keyboards/glenpickle/chimera_ls/keymaps/default/keymap.c b/keyboards/glenpickle/chimera_ls/keymaps/default/keymap.c index 0affeef389..1ae70e6245 100644 --- a/keyboards/glenpickle/chimera_ls/keymaps/default/keymap.c +++ b/keyboards/glenpickle/chimera_ls/keymaps/default/keymap.c @@ -158,7 +158,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _QWERTY: diff --git a/keyboards/glenpickle/chimera_ortho/keymaps/default/keymap.c b/keyboards/glenpickle/chimera_ortho/keymaps/default/keymap.c index 6a676493dd..bc783f540c 100644 --- a/keyboards/glenpickle/chimera_ortho/keymaps/default/keymap.c +++ b/keyboards/glenpickle/chimera_ortho/keymaps/default/keymap.c @@ -151,7 +151,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _QWERTY: diff --git a/keyboards/gon/nerdtkl/keymaps/gam3cat/keymap.c b/keyboards/gon/nerdtkl/keymaps/gam3cat/keymap.c index c4294c812e..bda83bb5da 100644 --- a/keyboards/gon/nerdtkl/keymaps/gam3cat/keymap.c +++ b/keyboards/gon/nerdtkl/keymaps/gam3cat/keymap.c @@ -241,7 +241,7 @@ void matrix_scan_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _BL: custom_backlight_level(0); break; diff --git a/keyboards/handwired/frenchdev/keymaps/default/keymap.c b/keyboards/handwired/frenchdev/keymaps/default/keymap.c index 2d917b412e..11463a0162 100644 --- a/keyboards/handwired/frenchdev/keymaps/default/keymap.c +++ b/keyboards/handwired/frenchdev/keymaps/default/keymap.c @@ -209,7 +209,7 @@ void press_underscore(void) { uint8_t old_layer=_BASE; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); frenchdev_led_1_off(); frenchdev_led_2_off(); diff --git a/keyboards/handwired/kbod/keymaps/default/keymap.c b/keyboards/handwired/kbod/keymaps/default/keymap.c index 333f8a769f..0ffc3e9d97 100644 --- a/keyboards/handwired/kbod/keymaps/default/keymap.c +++ b/keyboards/handwired/kbod/keymaps/default/keymap.c @@ -89,7 +89,7 @@ void matrix_init_user(void) { } void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (layer) { PORTC |= _BV(PC7); } else { diff --git a/keyboards/handwired/prime_exl/keymaps/via/keymap.c b/keyboards/handwired/prime_exl/keymaps/via/keymap.c index 0e6802996d..b5b616d55b 100644 --- a/keyboards/handwired/prime_exl/keymaps/via/keymap.c +++ b/keyboards/handwired/prime_exl/keymaps/via/keymap.c @@ -87,7 +87,7 @@ void led_set_user(uint8_t usb_led) { //function for layer indicator LED layer_state_t layer_state_set_user(layer_state_t state) { - if (biton32(state) == 1) { + if (get_highest_layer(state) == 1) { writePinHigh(C6); } else { writePinLow(C6); diff --git a/keyboards/handwired/promethium/keymaps/default/keymap.c b/keyboards/handwired/promethium/keymaps/default/keymap.c index 1903b2f9ba..77f83361e6 100644 --- a/keyboards/handwired/promethium/keymaps/default/keymap.c +++ b/keyboards/handwired/promethium/keymaps/default/keymap.c @@ -529,7 +529,7 @@ void led_reset(void) { } void led_set_default_layer_indicator(void) { - uint8_t default_layer = biton32(default_layer_state); + uint8_t default_layer = get_highest_layer(default_layer_state); if (default_layer == _QWERTY) { rgbsps_set(LED_IND_QWERTY, THEME_COLOR_QWERTY); rgbsps_set(LED_IND_ALT, COLOR_BLANK); @@ -553,7 +553,7 @@ void led_set_layer_indicator(void) { rgbsps_set(LED_IND_GREEK, COLOR_BLANK); rgbsps_set(LED_IND_EMOJI, COLOR_BLANK); - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (oldlayer == layer) { return; } @@ -1014,7 +1014,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { lshift = keyboard_report->mods & MOD_BIT(KC_LSFT); rshift = keyboard_report->mods & MOD_BIT(KC_RSFT); - layer = biton32(layer_state); + layer = get_highest_layer(layer_state); #ifdef DOUBLESPACE_LAYER_ENABLE // double-space: send space immediately if any other key depressed before space is released diff --git a/keyboards/handwired/promethium/keymaps/priyadi/keymap.c b/keyboards/handwired/promethium/keymaps/priyadi/keymap.c index 94b505aa2c..faa096ce08 100644 --- a/keyboards/handwired/promethium/keymaps/priyadi/keymap.c +++ b/keyboards/handwired/promethium/keymaps/priyadi/keymap.c @@ -532,7 +532,7 @@ void led_reset(void) { } void led_set_default_layer_indicator(void) { - uint8_t default_layer = biton32(default_layer_state); + uint8_t default_layer = get_highest_layer(default_layer_state); if (default_layer == _QWERTY) { rgbsps_set(LED_IND_QWERTY, THEME_COLOR_QWERTY); rgbsps_set(LED_IND_ALT, COLOR_BLANK); @@ -556,7 +556,7 @@ void led_set_layer_indicator(void) { rgbsps_set(LED_IND_GREEK, COLOR_BLANK); rgbsps_set(LED_IND_EMOJI, COLOR_BLANK); - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (oldlayer == layer) { return; } @@ -989,7 +989,7 @@ void process_doublespace(bool pressed, bool *isactive, bool *otheractive, bool * } #endif -uint32_t layer_state_set_kb(uint32_t state) +layer_state_t layer_state_set_kb(layer_state_t state) { // turn on punc layer if both fun & num are on if ((state & ((1UL<<_NUM) | (1UL<<_FUN))) == ((1UL<<_NUM) | (1UL<<_FUN))) { @@ -1017,7 +1017,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { lshift = keyboard_report->mods & MOD_BIT(KC_LSFT); rshift = keyboard_report->mods & MOD_BIT(KC_RSFT); - layer = biton32(layer_state); + layer = get_highest_layer(layer_state); #ifdef DOUBLESPACE_LAYER_ENABLE // double-space: send space immediately if any other key depressed before space is released diff --git a/keyboards/handwired/traveller/keymaps/default/keymap.c b/keyboards/handwired/traveller/keymaps/default/keymap.c index 288acbe108..2cd57db35f 100644 --- a/keyboards/handwired/traveller/keymaps/default/keymap.c +++ b/keyboards/handwired/traveller/keymaps/default/keymap.c @@ -219,7 +219,7 @@ void LayerLEDSet(uint8_t layr) { uint8_t old_layer = _QW; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (old_layer != layer) { LayerLEDSet(layer); diff --git a/keyboards/handwired/tritium_numpad/keymaps/blu/keymap.c b/keyboards/handwired/tritium_numpad/keymaps/blu/keymap.c index b618675295..50bbf232b5 100644 --- a/keyboards/handwired/tritium_numpad/keymaps/blu/keymap.c +++ b/keyboards/handwired/tritium_numpad/keymaps/blu/keymap.c @@ -9,7 +9,7 @@ void keyboard_pre_init_user(void) layer_state_t layer_state_set_user(layer_state_t state) { // Switch layer LED accordingly - switch (biton32(state)) { + switch (get_highest_layer(state)) { case 0: writePinHigh(B0); break; diff --git a/keyboards/helix/pico/keymaps/mtei/keymap.c b/keyboards/helix/pico/keymaps/mtei/keymap.c index b703ca376d..f641829292 100644 --- a/keyboards/helix/pico/keymaps/mtei/keymap.c +++ b/keyboards/helix/pico/keymaps/mtei/keymap.c @@ -242,7 +242,7 @@ float music_scale[][2] = SONG(MUSIC_SCALE_SOUND); static int current_default_layer; -uint32_t default_layer_state_set_kb(uint32_t state) { +layer_state_t default_layer_state_set_kb(layer_state_t state) { // 1<<_QWERTY - 1 == 1 - 1 == _QWERTY (=0) // 1<<_COLEMAK - 1 == 2 - 1 == _COLEMAK (=1) current_default_layer = state - 1; diff --git a/keyboards/helix/rev2/keymaps/default/oled_display.c b/keyboards/helix/rev2/keymaps/default/oled_display.c index ad5558869f..384356bd14 100644 --- a/keyboards/helix/rev2/keymaps/default/oled_display.c +++ b/keyboards/helix/rev2/keymaps/default/oled_display.c @@ -86,7 +86,7 @@ static void render_layer_status(void) { break; default: oled_write_P(PSTR("Undef-"), false); - snprintf(buf,sizeof(buf), "%ld", layer_state); + snprintf(buf,sizeof(buf), "%u", layer_state); oled_write(buf, false); } oled_write_P(PSTR("\n"), false); diff --git a/keyboards/helix/rev2/keymaps/edvorakjp/keymap.c b/keyboards/helix/rev2/keymaps/edvorakjp/keymap.c index 5de00cb14c..80d0392ffb 100644 --- a/keyboards/helix/rev2/keymaps/edvorakjp/keymap.c +++ b/keyboards/helix/rev2/keymaps/edvorakjp/keymap.c @@ -5,9 +5,9 @@ // keymaps definitions are moved to keymap_Xrows.c. #ifdef RGBLIGHT_ENABLE -uint32_t layer_state_set_keymap(uint32_t state) { +layer_state_t layer_state_set_keymap(layer_state_t state) { rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case L_EDVORAKJP_LOWER: rgblight_sethsv_noeeprom_red(); break; diff --git a/keyboards/helix/rev2/keymaps/edvorakjp/oled.c b/keyboards/helix/rev2/keymaps/edvorakjp/oled.c index 207aebc423..14e3e5533b 100644 --- a/keyboards/helix/rev2/keymaps/edvorakjp/oled.c +++ b/keyboards/helix/rev2/keymaps/edvorakjp/oled.c @@ -19,7 +19,7 @@ void render_layer_state(void) { char layer_name[17]; oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case L_EDVORAKJP_BASE: oled_write_ln_P(PSTR("Default"), false); break; diff --git a/keyboards/helix/rev2/keymaps/five_rows/keymap.c b/keyboards/helix/rev2/keymaps/five_rows/keymap.c index d992425de7..4d9dc16a9e 100644 --- a/keyboards/helix/rev2/keymaps/five_rows/keymap.c +++ b/keyboards/helix/rev2/keymaps/five_rows/keymap.c @@ -379,8 +379,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { int current_default_layer; -uint32_t default_layer_state_set_user(uint32_t state) { - current_default_layer = biton32(state); +layer_state_t default_layer_state_set_user(layer_state_t state) { + current_default_layer = get_highest_layer(state); return state; } diff --git a/keyboards/helix/rev3_5rows/keymaps/five_rows/keymap.c b/keyboards/helix/rev3_5rows/keymaps/five_rows/keymap.c index d992425de7..4d9dc16a9e 100644 --- a/keyboards/helix/rev3_5rows/keymaps/five_rows/keymap.c +++ b/keyboards/helix/rev3_5rows/keymaps/five_rows/keymap.c @@ -379,8 +379,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { int current_default_layer; -uint32_t default_layer_state_set_user(uint32_t state) { - current_default_layer = biton32(state); +layer_state_t default_layer_state_set_user(layer_state_t state) { + current_default_layer = get_highest_layer(state); return state; } diff --git a/keyboards/hineybush/h87a/keymaps/gam3cat/keymap.c b/keyboards/hineybush/h87a/keymaps/gam3cat/keymap.c index d59438f6b3..d505d5171d 100644 --- a/keyboards/hineybush/h87a/keymaps/gam3cat/keymap.c +++ b/keyboards/hineybush/h87a/keymaps/gam3cat/keymap.c @@ -245,7 +245,7 @@ void matrix_scan_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _BL: custom_backlight_level(0); rgblight_sethsv_noeeprom(180,100,255); diff --git a/keyboards/hotdox/keymaps/default/keymap.c b/keyboards/hotdox/keymaps/default/keymap.c index fe07e6f91d..eb4692a4c2 100644 --- a/keyboards/hotdox/keymaps/default/keymap.c +++ b/keyboards/hotdox/keymaps/default/keymap.c @@ -163,7 +163,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_right_led_1_off(); ergodox_right_led_2_off(); diff --git a/keyboards/hotdox/keymaps/eozaki/keymap.c b/keyboards/hotdox/keymaps/eozaki/keymap.c index 3516f20303..d4b8f491fd 100644 --- a/keyboards/hotdox/keymaps/eozaki/keymap.c +++ b/keyboards/hotdox/keymaps/eozaki/keymap.c @@ -170,7 +170,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/hotdox/keymaps/kloki/keymap.c b/keyboards/hotdox/keymaps/kloki/keymap.c index f858effd54..2550b68978 100644 --- a/keyboards/hotdox/keymaps/kloki/keymap.c +++ b/keyboards/hotdox/keymaps/kloki/keymap.c @@ -189,7 +189,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/default/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/default/keymap.c index cd65001803..6f9967b46e 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/default/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/default/keymap.c @@ -167,7 +167,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/gordon/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/gordon/keymap.c index c321d546fb..50e3238a7d 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/gordon/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/gordon/keymap.c @@ -335,7 +335,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_on(); ergodox_led_all_on(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/halfkeyboard/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/halfkeyboard/keymap.c index 3870dd8ffd..c8498fe9e9 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/halfkeyboard/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/halfkeyboard/keymap.c @@ -492,7 +492,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/input_club/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/input_club/keymap.c index 545429fca0..e941cee154 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/input_club/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/input_club/keymap.c @@ -223,7 +223,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/narze/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/narze/keymap.c index dd721e9a78..184eb638c9 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/narze/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/narze/keymap.c @@ -659,7 +659,7 @@ void matrix_setup(void) { } void matrix_scan_user(void) { - // uint8_t layer = biton32(layer_state); + // uint8_t layer = get_highest_layer(layer_state); // ergodox_board_led_off(); // ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/nordic_ergo/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/nordic_ergo/keymap.c index d08b96cc6e..70f49bb5c9 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/nordic_ergo/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/nordic_ergo/keymap.c @@ -221,7 +221,7 @@ void matrix_init_user(void){ // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/rask/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/rask/keymap.c index e31c1c5d6b..b202823c77 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/rask/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/rask/keymap.c @@ -179,7 +179,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/rjhilgefort/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/rjhilgefort/keymap.c index 31d218ebfb..c322222baf 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/rjhilgefort/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/rjhilgefort/keymap.c @@ -309,7 +309,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/ergodox_infinity/keymaps/trulyergonomic/keymap.c b/keyboards/input_club/ergodox_infinity/keymaps/trulyergonomic/keymap.c index 02f409ad9e..bbc24ea27f 100644 --- a/keyboards/input_club/ergodox_infinity/keymaps/trulyergonomic/keymap.c +++ b/keyboards/input_club/ergodox_infinity/keymaps/trulyergonomic/keymap.c @@ -137,7 +137,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/input_club/infinity60/keymaps/jpetermans/keymap.c b/keyboards/input_club/infinity60/keymaps/jpetermans/keymap.c index 3c2e0d4da8..a19be6664c 100644 --- a/keyboards/input_club/infinity60/keymaps/jpetermans/keymap.c +++ b/keyboards/input_club/infinity60/keymaps/jpetermans/keymap.c @@ -239,7 +239,7 @@ void matrix_scan_user(void) { //Turn on layer indicator or page depending on mode switch(led_mode_global) { case MODE_FLASH: //flash preset page leds then single indicator - page = biton32(layer_state) > max_pages ? 7 : biton32(layer_state); + page = get_highest_layer(layer_state) > max_pages ? 7 : get_highest_layer(layer_state); msg=(page << 8) | DISPLAY_PAGE; chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); chThdSleepMilliseconds(500); @@ -254,7 +254,7 @@ void matrix_scan_user(void) { break; case MODE_PAGE: //display pre-defined led page - page = biton32(layer_state) > max_pages ? 7 : biton32(layer_state); + page = get_highest_layer(layer_state) > max_pages ? 7 : get_highest_layer(layer_state); msg=(page << 8) | DISPLAY_PAGE; chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); break; diff --git a/keyboards/jc65/v32u4/keymaps/gam3cat/keymap.c b/keyboards/jc65/v32u4/keymaps/gam3cat/keymap.c index 7572b9e073..453cd2360d 100644 --- a/keyboards/jc65/v32u4/keymaps/gam3cat/keymap.c +++ b/keyboards/jc65/v32u4/keymaps/gam3cat/keymap.c @@ -224,7 +224,7 @@ void matrix_scan_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _BL: custom_backlight_level(0); rgblight_sethsv_noeeprom(180,100,255); diff --git a/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c b/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c index e86204a3e3..a592418c4d 100644 --- a/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c +++ b/keyboards/jones/v03_1/keymaps/default_ansi/keymap.c @@ -253,7 +253,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { } } if (index == 1) { /* Second encoder, Left side */ - switch(biton32(layer_state)) { + switch(get_highest_layer(layer_state)) { case _LOWER: if (clockwise) { rgblight_decrease_hue(); diff --git a/keyboards/jones/v03_1/keymaps/default_jp/keymap.c b/keyboards/jones/v03_1/keymaps/default_jp/keymap.c index 9a2663f6d7..56f51d56ce 100644 --- a/keyboards/jones/v03_1/keymaps/default_jp/keymap.c +++ b/keyboards/jones/v03_1/keymaps/default_jp/keymap.c @@ -255,7 +255,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { } } if (index == 1) { /* Second encoder, Left side */ - switch(biton32(layer_state)) { + switch(get_highest_layer(layer_state)) { case _LOWER: if (clockwise) { rgblight_decrease_hue(); diff --git a/keyboards/kakunpc/angel64/alpha/keymaps/default/keymap.c b/keyboards/kakunpc/angel64/alpha/keymaps/default/keymap.c index 0f2a8dada1..92dfa7da6e 100644 --- a/keyboards/kakunpc/angel64/alpha/keymaps/default/keymap.c +++ b/keyboards/kakunpc/angel64/alpha/keymaps/default/keymap.c @@ -40,7 +40,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { #ifdef OLED_ENABLE bool oled_task_user(void) { oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case BASE: oled_write_P(PSTR("Default\n"), false); break; diff --git a/keyboards/kakunpc/angel64/rev1/keymaps/kakunpc/keymap.c b/keyboards/kakunpc/angel64/rev1/keymaps/kakunpc/keymap.c index 6c5184c1b3..601bf5f02f 100644 --- a/keyboards/kakunpc/angel64/rev1/keymaps/kakunpc/keymap.c +++ b/keyboards/kakunpc/angel64/rev1/keymaps/kakunpc/keymap.c @@ -175,7 +175,7 @@ void matrix_scan_user(void) { #ifdef OLED_ENABLE bool oled_task_user(void) { oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case BASE: oled_write_P(PSTR("Default\n"), false); break; diff --git a/keyboards/kakunpc/suihankey/alpha/keymaps/default/keymap.c b/keyboards/kakunpc/suihankey/alpha/keymaps/default/keymap.c index b682f0f15d..d937b68813 100644 --- a/keyboards/kakunpc/suihankey/alpha/keymaps/default/keymap.c +++ b/keyboards/kakunpc/suihankey/alpha/keymaps/default/keymap.c @@ -58,7 +58,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { #ifdef OLED_ENABLE bool oled_task_user(void) { oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case BASE: oled_write_P(PSTR("Default\n"), false); break; diff --git a/keyboards/kakunpc/suihankey/rev1/keymaps/default/keymap.c b/keyboards/kakunpc/suihankey/rev1/keymaps/default/keymap.c index b682f0f15d..d937b68813 100644 --- a/keyboards/kakunpc/suihankey/rev1/keymaps/default/keymap.c +++ b/keyboards/kakunpc/suihankey/rev1/keymaps/default/keymap.c @@ -58,7 +58,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { #ifdef OLED_ENABLE bool oled_task_user(void) { oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case BASE: oled_write_P(PSTR("Default\n"), false); break; diff --git a/keyboards/kbdfans/kbd6x/keymaps/othi/keymap.c b/keyboards/kbdfans/kbd6x/keymaps/othi/keymap.c index 6bbbdd87c1..ce341509a6 100644 --- a/keyboards/kbdfans/kbd6x/keymaps/othi/keymap.c +++ b/keyboards/kbdfans/kbd6x/keymaps/othi/keymap.c @@ -38,7 +38,7 @@ void eeconfig_init_user(void) { #define DE_UDIA_CAP UC(0x00DC) layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case NM_MODE: rgblight_setrgb (0x00, 0x66, 0x00); break; @@ -187,4 +187,3 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { _______, _______, _______, _______, _______, _______, _______ ), }; - diff --git a/keyboards/kbdfans/kbd75/keymaps/edulpn/keymap.c b/keyboards/kbdfans/kbd75/keymaps/edulpn/keymap.c index 998f1a25d2..5a6d760355 100644 --- a/keyboards/kbdfans/kbd75/keymaps/edulpn/keymap.c +++ b/keyboards/kbdfans/kbd75/keymaps/edulpn/keymap.c @@ -45,7 +45,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case WINDOWS_LAYER: rgblight_setrgb_blue(); break; diff --git a/keyboards/kbdfans/niu_mini/keymaps/tobias/keymap.c b/keyboards/kbdfans/niu_mini/keymaps/tobias/keymap.c index 935dd5c506..8c03ae2df2 100644 --- a/keyboards/kbdfans/niu_mini/keymaps/tobias/keymap.c +++ b/keyboards/kbdfans/niu_mini/keymaps/tobias/keymap.c @@ -8,7 +8,7 @@ * 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. + * 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 . @@ -103,8 +103,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_EQL, S(KC_EQL), RALT(KC_2), RALT(KC_3), RALT(KC_4), RALT(KC_E), KC_RBRC, RALT(KC_7), RALT(KC_8), RALT(KC_9), RALT(KC_0), RALT(KC_MINS), KC_LSFT, KC_NUBS, RALT(KC_NUBS), S(KC_NUBS), DGRMCRO, XXXXXXX, XXXXXXX, RALT(KC_M), KC_RBRC, S(KC_RBRC), RALT(KC_RBRC), _______, _______, _______, KC_RALT, _______,TO(_ADJUST), _______, _______, _______, _______, _______, _______, TO(_QWERTY) -), - +), + /* Lower * ,-----------------------------------------------------------------------------------. @@ -257,10 +257,10 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } else { workmode = false; - return false; - } + return false; + } } - + } return true; } @@ -293,7 +293,7 @@ void rgbflag(uint8_t r, uint8_t g, uint8_t b) { layer_state_t layer_state_set_user(layer_state_t state) { // if(rgblight_get_mode() == 1) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _QWERTY: if(!workmode){ rgblight_mode(9); @@ -312,7 +312,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { tap_code(KC_NLCK); } rgbflag(0xFF, 0x00, 0x00); - + break; case _ADJUST: rgblight_mode(1); @@ -350,7 +350,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { rgblight_mode(1); if(bnumlock) { tap_code(KC_NLCK); - } + } rgbflag(0xFF, 0xFF, 0xFF); break; } @@ -363,8 +363,8 @@ layer_state_t layer_state_set_user(layer_state_t state) { //Layer LED indicators uint32_t layer = layer_state; - - + + if (layer & (1<<2)) { if(!bnumlock) { numlock_changed = true; @@ -373,10 +373,10 @@ layer_state_t layer_state_set_user(layer_state_t state) { bnumlock = true; } } -} +} */ - - + + void led_set_user(uint8_t usb_led) { if (usb_led & (1 << USB_LED_NUM_LOCK)) { @@ -410,4 +410,4 @@ void led_set_user(uint8_t usb_led) { } -} \ No newline at end of file +} diff --git a/keyboards/kbdfans/niu_mini/keymaps/xtonhasvim/keymap.c b/keyboards/kbdfans/niu_mini/keymaps/xtonhasvim/keymap.c index bfda812738..d3c6102b16 100644 --- a/keyboards/kbdfans/niu_mini/keymaps/xtonhasvim/keymap.c +++ b/keyboards/kbdfans/niu_mini/keymaps/xtonhasvim/keymap.c @@ -187,7 +187,7 @@ void rgbflag(uint8_t r, uint8_t g, uint8_t b, uint8_t rr, uint8_t gg, uint8_t bb void set_state_leds(void) { if (rgblight_get_mode() == 1) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _RAISE: rgbflag(C_BLU, C_GRN); break; diff --git a/keyboards/keebio/bdn9/keymaps/vosechu-ksp/keymap.c b/keyboards/keebio/bdn9/keymaps/vosechu-ksp/keymap.c index a449c3ec3d..3b92657d4d 100644 --- a/keyboards/keebio/bdn9/keymaps/vosechu-ksp/keymap.c +++ b/keyboards/keebio/bdn9/keymaps/vosechu-ksp/keymap.c @@ -64,7 +64,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { flight_mode = false; rcs_mode = false; - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _PANIC: panic_mode = true; // For use in encoder evaluation rgblight_sethsv_noeeprom(HSV_RED); diff --git a/keyboards/keebio/bfo9000/keymaps/abstractkb/keymap.c b/keyboards/keebio/bfo9000/keymaps/abstractkb/keymap.c index 29531b9973..ad56226ac6 100644 --- a/keyboards/keebio/bfo9000/keymaps/abstractkb/keymap.c +++ b/keyboards/keebio/bfo9000/keymaps/abstractkb/keymap.c @@ -42,7 +42,7 @@ void matrix_post_init_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _LIST: rgblight_sethsv_noeeprom(0,255,255); rgblight_mode_noeeprom(RGBLIGHT_MODE_RAINBOW_SWIRL); @@ -87,6 +87,3 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { return true; } } - - - diff --git a/keyboards/keebio/iris/keymaps/edvorakjp/keymap.c b/keyboards/keebio/iris/keymaps/edvorakjp/keymap.c index 0c0fc5a746..013d6c00a5 100644 --- a/keyboards/keebio/iris/keymaps/edvorakjp/keymap.c +++ b/keyboards/keebio/iris/keymaps/edvorakjp/keymap.c @@ -59,9 +59,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void matrix_init_keymap() {} #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT -uint32_t layer_state_set_keymap(uint32_t state) { +layer_state_t layer_state_set_keymap(layer_state_t state) { rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case L_EDVORAKJP_LOWER: rgblight_sethsv_noeeprom_red(); break; diff --git a/keyboards/keebio/iris/keymaps/jerryhcooke/keymap.c b/keyboards/keebio/iris/keymaps/jerryhcooke/keymap.c index e0c09638b2..bc04f9fbfd 100644 --- a/keyboards/keebio/iris/keymaps/jerryhcooke/keymap.c +++ b/keyboards/keebio/iris/keymaps/jerryhcooke/keymap.c @@ -11,7 +11,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {[0] = LAYOUT(KC_GE #ifdef ENCODER_ENABLE bool encoder_update_user(uint8_t index, bool clockwise) { if (index == 0) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _LOWER: clockwise ? tap_code(KC_MS_WH_UP) : tap_code(KC_MS_WH_DOWN); break; @@ -23,7 +23,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { break; } } else if (index == 1) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _LOWER: clockwise ? tap_code(KC_UP) : tap_code(KC_DOWN); break; diff --git a/keyboards/keebio/iris/keymaps/sq5rix/keymap.c b/keyboards/keebio/iris/keymaps/sq5rix/keymap.c index 19a939a55b..d3e0d680a1 100644 --- a/keyboards/keebio/iris/keymaps/sq5rix/keymap.c +++ b/keyboards/keebio/iris/keymaps/sq5rix/keymap.c @@ -134,7 +134,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { } // tmux screen else if (index == 1) { - switch(biton32(layer_state)){ + switch(get_highest_layer(layer_state)){ case 0: if (clockwise) { send_string(SS_LCTL("B")"p"); @@ -182,4 +182,3 @@ layer_state_t layer_state_set_user(layer_state_t state) { rgblight_set_layer_state(2, layer_state_cmp(state, 4)); return state; } - diff --git a/keyboards/keebio/levinson/keymaps/issmirnov/keymap.c b/keyboards/keebio/levinson/keymaps/issmirnov/keymap.c index d9edfebaa0..6de2279be4 100644 --- a/keyboards/keebio/levinson/keymaps/issmirnov/keymap.c +++ b/keyboards/keebio/levinson/keymaps/issmirnov/keymap.c @@ -91,7 +91,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { #ifdef RGBLIGHT_ENABLE layer_state_set_rgb(state); #endif - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); combo_enable(); // by default, enable combos. switch (layer) { case 0: diff --git a/keyboards/keebio/levinson/keymaps/issmirnov/rgb.c b/keyboards/keebio/levinson/keymaps/issmirnov/rgb.c index de3a5342c0..3695731353 100644 --- a/keyboards/keebio/levinson/keymaps/issmirnov/rgb.c +++ b/keyboards/keebio/levinson/keymaps/issmirnov/rgb.c @@ -45,7 +45,7 @@ void matrix_scan_rgb(void) { } void set_rgb_indicators(uint8_t this_mod, uint8_t this_osm) { - if (biton32(layer_state) == _QWERTY) { + if (get_highest_layer(layer_state) == _QWERTY) { if ((this_mod | this_osm) & MOD_MASK_SHIFT) { rgblight_setrgb_gold_at(SHFT_LED1); } else { diff --git a/keyboards/keebio/levinson/keymaps/issmirnov/rgb.h b/keyboards/keebio/levinson/keymaps/issmirnov/rgb.h index 254d3cbac0..8b14d8571d 100644 --- a/keyboards/keebio/levinson/keymaps/issmirnov/rgb.h +++ b/keyboards/keebio/levinson/keymaps/issmirnov/rgb.h @@ -6,7 +6,7 @@ void keyboard_post_init_rgb(void); // If rgb enabled, set underglow for layer -uint32_t layer_state_set_rgb(uint32_t state); +layer_state_t layer_state_set_rgb(layer_state_t state); // Enhance matrix scan code. Note: keep this light, since it runs every 100ms void matrix_scan_rgb(void); diff --git a/keyboards/keebio/levinson/keymaps/xtonhasvim/keymap.c b/keyboards/keebio/levinson/keymaps/xtonhasvim/keymap.c index 16aa965d7d..014e6c9c23 100644 --- a/keyboards/keebio/levinson/keymaps/xtonhasvim/keymap.c +++ b/keyboards/keebio/levinson/keymaps/xtonhasvim/keymap.c @@ -182,7 +182,7 @@ void rgbflag(uint8_t r, uint8_t g, uint8_t b, uint8_t rr, uint8_t gg, uint8_t bb void set_state_leds(void) { if (rgblight_get_mode() == 1) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _RAISE: rgbflag(C_BLU, C_GRN); break; diff --git a/keyboards/keebio/nyquist/keymaps/pitty/keymap.c b/keyboards/keebio/nyquist/keymaps/pitty/keymap.c index 31912bb63e..2016cd1c46 100644 --- a/keyboards/keebio/nyquist/keymaps/pitty/keymap.c +++ b/keyboards/keebio/nyquist/keymaps/pitty/keymap.c @@ -143,7 +143,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { #ifdef RGBLIGHT_ENABLE uint8_t default_layer = eeconfig_read_default_layer(); if (rgb_layer_change) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _LOWER: rgblight_set_purple; rgblight_mode(5); diff --git a/keyboards/keebio/quefrency/keymaps/georgepetri/keymap.c b/keyboards/keebio/quefrency/keymaps/georgepetri/keymap.c index a367e877fe..7d6f9da30e 100644 --- a/keyboards/keebio/quefrency/keymaps/georgepetri/keymap.c +++ b/keyboards/keebio/quefrency/keymaps/georgepetri/keymap.c @@ -64,7 +64,7 @@ void keyboard_post_init_user(void) { } void update_led(void) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _BASE: rgblight_sethsv_noeeprom(HSV_BLUE); break; diff --git a/keyboards/keyhive/honeycomb/keymaps/default/keymap.c b/keyboards/keyhive/honeycomb/keymaps/default/keymap.c index d0a5961873..429624822e 100755 --- a/keyboards/keyhive/honeycomb/keymaps/default/keymap.c +++ b/keyboards/keyhive/honeycomb/keymaps/default/keymap.c @@ -37,7 +37,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { report_mouse_t currentReport = {}; bool process_record_user(uint16_t keycode, keyrecord_t *record) { - //uint8_t layer = biton32(layer_state); // get the current layer + //uint8_t layer = get_highest_layer(layer_state); // get the current layer // Basic example functions switch (keycode) { diff --git a/keyboards/kinesis/keymaps/milestogo/keymap.c b/keyboards/kinesis/keymaps/milestogo/keymap.c index 8c01bcb83d..72687195ef 100644 --- a/keyboards/kinesis/keymaps/milestogo/keymap.c +++ b/keyboards/kinesis/keymaps/milestogo/keymap.c @@ -330,7 +330,7 @@ void matrix_init_user(void) { void matrix_scan_user(void) { #ifdef ALVICSTEP_CONFIG_H - int8_t layer = biton32(layer_state); + int8_t layer = get_highest_layer(layer_state); switch (layer) { case 1: diff --git a/keyboards/kprepublic/cospad/keymaps/detrus/keymap.c b/keyboards/kprepublic/cospad/keymaps/detrus/keymap.c index af56305e5c..84324c6e0d 100644 --- a/keyboards/kprepublic/cospad/keymaps/detrus/keymap.c +++ b/keyboards/kprepublic/cospad/keymaps/detrus/keymap.c @@ -271,7 +271,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Makes sure to update the good tri-layer if a layer changes layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(default_layer_state)) { + switch (get_highest_layer(default_layer_state)) { case _QWERTY_LAYER: state = update_tri_layer_state(state, _RAISE_LAYER, _QWERTY_LOWER_LAYER, _ALTER_LAYER); break; @@ -289,8 +289,8 @@ layer_state_t layer_state_set_user(layer_state_t state) { } // Makes the tri-layer -uint32_t default_layer_state_set_kb(uint32_t state) { - switch (biton32(state)) { +layer_state_t default_layer_state_set_kb(layer_state_t state) { + switch (get_highest_layer(state)) { case _QWERTY_LAYER: state = update_tri_layer_state(state, _RAISE_LAYER, _QWERTZ_LOWER_LAYER, _ALTER_LAYER); state = update_tri_layer_state(state, _RAISE_LAYER, _COLEMA_LOWER_LAYER, _ALTER_LAYER); diff --git a/keyboards/kprepublic/jj50/keymaps/abstractkb/keymap.c b/keyboards/kprepublic/jj50/keymaps/abstractkb/keymap.c index e257649369..c096aaea10 100644 --- a/keyboards/kprepublic/jj50/keymaps/abstractkb/keymap.c +++ b/keyboards/kprepublic/jj50/keymaps/abstractkb/keymap.c @@ -42,7 +42,7 @@ void keyboard_post_init_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _RAISE: rgblight_sethsv_noeeprom(170,255,255); rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); diff --git a/keyboards/kprepublic/jj50/keymaps/abstractkb_gergomatch/keymap.c b/keyboards/kprepublic/jj50/keymaps/abstractkb_gergomatch/keymap.c index baedbb4dd2..af4c3c84bb 100644 --- a/keyboards/kprepublic/jj50/keymaps/abstractkb_gergomatch/keymap.c +++ b/keyboards/kprepublic/jj50/keymaps/abstractkb_gergomatch/keymap.c @@ -42,7 +42,7 @@ void keyboard_post_init_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _FUNC: rgblight_sethsv_noeeprom(170,255,255); rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); diff --git a/keyboards/ktec/ergodone/keymaps/eozaki/keymap.c b/keyboards/ktec/ergodone/keymaps/eozaki/keymap.c index 09854ee89c..3910756f81 100644 --- a/keyboards/ktec/ergodone/keymaps/eozaki/keymap.c +++ b/keyboards/ktec/ergodone/keymaps/eozaki/keymap.c @@ -179,7 +179,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ktec/ergodone/keymaps/erovia/keymap.c b/keyboards/ktec/ergodone/keymaps/erovia/keymap.c index 279c8a57c1..502c0dafe6 100644 --- a/keyboards/ktec/ergodone/keymaps/erovia/keymap.c +++ b/keyboards/ktec/ergodone/keymaps/erovia/keymap.c @@ -204,7 +204,7 @@ void matrix_init_user(void) { layer_state_t layer_state_set_user(layer_state_t state) { ergodox_led_all_off(); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case FN: // Red led on Pro Micro for Fn layer ergodox_board_led_on(); diff --git a/keyboards/ktec/ergodone/keymaps/kloki/keymap.c b/keyboards/ktec/ergodone/keymaps/kloki/keymap.c index 87e96d20fd..1347f8f501 100644 --- a/keyboards/ktec/ergodone/keymaps/kloki/keymap.c +++ b/keyboards/ktec/ergodone/keymaps/kloki/keymap.c @@ -198,7 +198,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/ktec/ergodone/keymaps/vega/keymap.c b/keyboards/ktec/ergodone/keymaps/vega/keymap.c index ee6c56bf95..21db785345 100644 --- a/keyboards/ktec/ergodone/keymaps/vega/keymap.c +++ b/keyboards/ktec/ergodone/keymaps/vega/keymap.c @@ -534,7 +534,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/keyboards/leeku/finger65/keymaps/madhatter/keymap.c b/keyboards/leeku/finger65/keymaps/madhatter/keymap.c index a69fe69153..f73b0371a1 100644 --- a/keyboards/leeku/finger65/keymaps/madhatter/keymap.c +++ b/keyboards/leeku/finger65/keymaps/madhatter/keymap.c @@ -40,7 +40,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; // layer_state_t layer_state_set_user(layer_state_t state) { -// switch(biton32(state)) { +// switch(get_highest_layer(state)) { // case _FNMS: // led_off(); // rgb_on(); diff --git a/keyboards/lets_split/keymaps/bbaserdem/keymap.c b/keyboards/lets_split/keymaps/bbaserdem/keymap.c index f9eab059ef..296b3ccd23 100755 --- a/keyboards/lets_split/keymaps/bbaserdem/keymap.c +++ b/keyboards/lets_split/keymaps/bbaserdem/keymap.c @@ -13,7 +13,7 @@ void matrix_init_keymap (void) { } -uint32_t layer_state_set_keymap(uint32_t state) { +layer_state_t layer_state_set_keymap(layer_state_t state) { return state; } diff --git a/keyboards/lets_split/keymaps/cpeters1982/keymap.c b/keyboards/lets_split/keymaps/cpeters1982/keymap.c index c4c26d56bc..27cd9db8b4 100644 --- a/keyboards/lets_split/keymaps/cpeters1982/keymap.c +++ b/keyboards/lets_split/keymaps/cpeters1982/keymap.c @@ -183,7 +183,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { #ifdef RGBLIGHT_ENABLE uint8_t default_layer = eeconfig_read_default_layer(); if (rgb_layer_change) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _RAISE: rgblight_set_orange; rgblight_mode(5); diff --git a/keyboards/lets_split/keymaps/geripgeri/keymap.c b/keyboards/lets_split/keymaps/geripgeri/keymap.c index 62e3570468..eb22a1509e 100644 --- a/keyboards/lets_split/keymaps/geripgeri/keymap.c +++ b/keyboards/lets_split/keymaps/geripgeri/keymap.c @@ -255,7 +255,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { state = update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST); writePin(B0, !(state & (1UL << (_NUMPAD)))); - switch(biton32(state)) { + switch(get_highest_layer(state)) { case _RAISE: rgblight_setrgb_at(255, 255, 255, RGBLED_NUM / 2); rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); diff --git a/keyboards/lets_split/keymaps/pitty/keymap.c b/keyboards/lets_split/keymaps/pitty/keymap.c index d723e0c026..8bc32a1eb7 100644 --- a/keyboards/lets_split/keymaps/pitty/keymap.c +++ b/keyboards/lets_split/keymaps/pitty/keymap.c @@ -128,7 +128,7 @@ void persistent_default_layer_set(uint16_t default_layer) { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _NAV: if (RGB_INIT) {} else { diff --git a/keyboards/lily58/lib/layer_state_reader.c b/keyboards/lily58/lib/layer_state_reader.c index 0e9dd7039b..868d8e5cb4 100644 --- a/keyboards/lily58/lib/layer_state_reader.c +++ b/keyboards/lily58/lib/layer_state_reader.c @@ -28,7 +28,7 @@ const char *read_layer_state(void) { snprintf(layer_state_str, sizeof(layer_state_str), "Layer: Adjust"); break; default: - snprintf(layer_state_str, sizeof(layer_state_str), "Layer: Undef-%ld", layer_state); + snprintf(layer_state_str, sizeof(layer_state_str), "Layer: Undef-%u", layer_state); } return layer_state_str; diff --git a/keyboards/m10a/keymaps/gam3cat/keymap.c b/keyboards/m10a/keymaps/gam3cat/keymap.c index f962246ef3..86231f8406 100644 --- a/keyboards/m10a/keymaps/gam3cat/keymap.c +++ b/keyboards/m10a/keymaps/gam3cat/keymap.c @@ -115,7 +115,7 @@ void matrix_scan_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _L0: custom_backlight_level(0); break; diff --git a/keyboards/maple_computing/lets_split_eh/keymaps/bbaserdem/keymap.c b/keyboards/maple_computing/lets_split_eh/keymaps/bbaserdem/keymap.c index 92e72bbf1c..73329c3114 100755 --- a/keyboards/maple_computing/lets_split_eh/keymaps/bbaserdem/keymap.c +++ b/keyboards/maple_computing/lets_split_eh/keymaps/bbaserdem/keymap.c @@ -5,7 +5,7 @@ void matrix_init_keymap (void) { } -uint32_t layer_state_set_keymap(uint32_t state) { +layer_state_t layer_state_set_keymap(layer_state_t state) { return state; } diff --git a/keyboards/maple_computing/lets_split_eh/keymaps/romus/keymap.c b/keyboards/maple_computing/lets_split_eh/keymaps/romus/keymap.c index ba5b75a5cf..398a324a0f 100644 --- a/keyboards/maple_computing/lets_split_eh/keymaps/romus/keymap.c +++ b/keyboards/maple_computing/lets_split_eh/keymaps/romus/keymap.c @@ -5,8 +5,8 @@ void matrix_init_keymap (void) { } -uint32_t layer_state_set_keymap(uint32_t state) { - +layer_state_t layer_state_set_keymap(layer_state_t state) { + return state; } diff --git a/keyboards/mechkeys/mechmini/v2/keymaps/wsturgiss/keymap.c b/keyboards/mechkeys/mechmini/v2/keymaps/wsturgiss/keymap.c index 218936a19b..689a9ce36e 100644 --- a/keyboards/mechkeys/mechmini/v2/keymaps/wsturgiss/keymap.c +++ b/keyboards/mechkeys/mechmini/v2/keymaps/wsturgiss/keymap.c @@ -87,7 +87,7 @@ void matrix_scan_user(void) { //change colors and rgb modes on layer change layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case raise: rgblight_mode_noeeprom(1); rgblight_setrgb(0xc7, 0x00, 0xf4); @@ -103,4 +103,3 @@ layer_state_t layer_state_set_user(layer_state_t state) { } return state; }; - diff --git a/keyboards/mechllama/g35/keymaps/default/keymap.c b/keyboards/mechllama/g35/keymaps/default/keymap.c index 4568f54f54..09d7afe171 100644 --- a/keyboards/mechllama/g35/keymaps/default/keymap.c +++ b/keyboards/mechllama/g35/keymaps/default/keymap.c @@ -67,7 +67,7 @@ const char* get_layer_name(uint8_t layer) { } bool oled_task_user(void) { - oled_write_ln_P(get_layer_name(biton32(layer_state)), false); + oled_write_ln_P(get_layer_name(get_highest_layer(layer_state)), false); return false; } #endif diff --git a/keyboards/mechlovin/hannah910/hannah910.c b/keyboards/mechlovin/hannah910/hannah910.c index 3237636be2..70c1a7b8e3 100644 --- a/keyboards/mechlovin/hannah910/hannah910.c +++ b/keyboards/mechlovin/hannah910/hannah910.c @@ -34,20 +34,20 @@ void led_set_kb(uint8_t usb_led) { layer_state_t layer_state_set_user(layer_state_t state) { // if on layer 1, turn on D2 LED, otherwise off. - if (biton32(state) == 1) { + if (get_highest_layer(state) == 1) { writePinHigh(D2); } else { writePinLow(D2); } // if on layer 2, turn on D1 LED, otherwise off. - if (biton32(state) == 2) { + if (get_highest_layer(state) == 2) { writePinHigh(D1); } else { writePinLow(D1); } // if on layer 3, turn on D0 LED, otherwise off. - if (biton32(state) == 3) { + if (get_highest_layer(state) == 3) { writePinHigh(D0); } else { writePinLow(D0); diff --git a/keyboards/mechlovin/hex4b/keymaps/nazzer/keymap.c b/keyboards/mechlovin/hex4b/keymaps/nazzer/keymap.c index 437233be52..e0634d85dc 100644 --- a/keyboards/mechlovin/hex4b/keymaps/nazzer/keymap.c +++ b/keyboards/mechlovin/hex4b/keymaps/nazzer/keymap.c @@ -53,9 +53,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; bool led_update_user(led_t led_state) { - + // Toggle CAPS_LOCK LED normally - + # if LED_PIN_ON_STATE == 0 // invert the whole thing to avoid having to conditionally !led_state.x later led_state.raw = ~led_state.raw; @@ -69,30 +69,30 @@ bool led_update_user(led_t led_state) { } layer_state_t layer_state_set_user(layer_state_t state) { - - uint8_t layer = biton32(state); - + + uint8_t layer = get_highest_layer(state); + #if defined(LED_NUM_LOCK_PIN) && defined(LED_SCROLL_LOCK_PIN) switch (layer) { case 0: - writePin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE); - writePin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE); + writePin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE); + writePin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE); break; case 1: - writePin(LED_SCROLL_LOCK_PIN, LED_PIN_ON_STATE); - writePin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE); + writePin(LED_SCROLL_LOCK_PIN, LED_PIN_ON_STATE); + writePin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE); break; case 2: - writePin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE); - writePin(LED_NUM_LOCK_PIN, LED_PIN_ON_STATE); + writePin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE); + writePin(LED_NUM_LOCK_PIN, LED_PIN_ON_STATE); break; case 3: - writePin(LED_SCROLL_LOCK_PIN, LED_PIN_ON_STATE); - writePin(LED_NUM_LOCK_PIN, LED_PIN_ON_STATE); + writePin(LED_SCROLL_LOCK_PIN, LED_PIN_ON_STATE); + writePin(LED_NUM_LOCK_PIN, LED_PIN_ON_STATE); break; } #endif - return state; + return state; } diff --git a/keyboards/minimacro5/keymaps/devdev/keymap.c b/keyboards/minimacro5/keymaps/devdev/keymap.c index d7f998fa3a..3c203fcc37 100644 --- a/keyboards/minimacro5/keymaps/devdev/keymap.c +++ b/keyboards/minimacro5/keymaps/devdev/keymap.c @@ -37,7 +37,7 @@ enum tap_dances{ bool encoder_update_user(uint8_t index, bool clockwise) { if (index == 0) { /* First encoder*/ - switch(biton32(layer_state)){ + switch(get_highest_layer(layer_state)){ case _MAIN: if (clockwise) { tap_code(KC_VOLU); diff --git a/keyboards/mitosis/keymaps/carvac_dv/keymap.c b/keyboards/mitosis/keymaps/carvac_dv/keymap.c index c67f2e387c..842556324f 100644 --- a/keyboards/mitosis/keymaps/carvac_dv/keymap.c +++ b/keyboards/mitosis/keymaps/carvac_dv/keymap.c @@ -105,7 +105,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _STD: @@ -121,4 +121,3 @@ void matrix_scan_user(void) { break; } }; - diff --git a/keyboards/mitosis/keymaps/datagrok/keymap.c b/keyboards/mitosis/keymaps/datagrok/keymap.c index 220c140af0..2611e1194c 100644 --- a/keyboards/mitosis/keymaps/datagrok/keymap.c +++ b/keyboards/mitosis/keymaps/datagrok/keymap.c @@ -102,7 +102,7 @@ const size_t defaultlayers_n = sizeof(defaultlayers) / sizeof(defaultlayers[0]); // New keycode KC_LAYO rotates between available default layers (for e.g., // selecting a base layout). Shift+KC_LAYO makes the current one persistent. bool process_record_layout(uint16_t keycode, keyrecord_t *record) { - uint32_t default_layer; + uint8_t default_layer; uint8_t i; #if defined(AUDIO_ENABLE) float saved_song[][2] = SONG(COIN_SOUND); @@ -121,7 +121,7 @@ bool process_record_layout(uint16_t keycode, keyrecord_t *record) { } else { // rotate default layer. // find the current default layer - default_layer = biton32(default_layer_state); + default_layer = get_highest_layer(default_layer_state); // find next valid default layer for (i = 1; i < defaultlayers_n; i++) { if (defaultlayers[(default_layer + i) % defaultlayers_n]) { diff --git a/keyboards/mitosis/keymaps/default/keymap.c b/keyboards/mitosis/keymaps/default/keymap.c index 6132ad6f78..27b2eb2525 100644 --- a/keyboards/mitosis/keymaps/default/keymap.c +++ b/keyboards/mitosis/keymaps/default/keymap.c @@ -77,7 +77,7 @@ static bool singular_key = false; bool process_record_user(uint16_t keycode, keyrecord_t *record) { uint8_t layer; - layer = biton32(layer_state); // get the current layer + layer = get_highest_layer(layer_state); // get the current layer //custom layer handling for tri_layer, switch (keycode) { @@ -174,7 +174,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _MALT: @@ -193,4 +193,3 @@ void matrix_scan_user(void) { break; } }; - diff --git a/keyboards/mitosis/keymaps/mjt/keymap.c b/keyboards/mitosis/keymaps/mjt/keymap.c index f00bf59556..0946e40b8e 100644 --- a/keyboards/mitosis/keymaps/mjt/keymap.c +++ b/keyboards/mitosis/keymaps/mjt/keymap.c @@ -181,7 +181,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { return false; } uint8_t layer; - layer = biton32(layer_state); // get the current layer + layer = get_highest_layer(layer_state); // get the current layer //custom layer handling for tri_layer, switch (keycode) { @@ -310,7 +310,7 @@ void music_scale_user(void) #endif void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _QWERTY: diff --git a/keyboards/mitosis/keymaps/nzen/keymap.c b/keyboards/mitosis/keymaps/nzen/keymap.c index d9fd3641bc..c981441bc9 100644 --- a/keyboards/mitosis/keymaps/nzen/keymap.c +++ b/keyboards/mitosis/keymaps/nzen/keymap.c @@ -175,7 +175,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _QWERTY: @@ -205,5 +205,3 @@ void matrix_scan_user(void) { void matrix_init_user(void) { set_unicode_input_mode(UC_LNX); // or UC_WINC }; - - diff --git a/keyboards/mschwingen/modelm/modelm.c b/keyboards/mschwingen/modelm/modelm.c index 7dcd4ac024..0ff58f4be3 100644 --- a/keyboards/mschwingen/modelm/modelm.c +++ b/keyboards/mschwingen/modelm/modelm.c @@ -163,8 +163,8 @@ void update_layer_leds(void) { static uint8_t old_layer = 255; static uint8_t old_default_layer = 255; - layer = biton32(layer_state); - default_layer = biton32(default_layer_state); + layer = get_highest_layer(layer_state); + default_layer = get_highest_layer(default_layer_state); if (isRecording && timer_elapsed(blink_cycle_timer) > 150) { blink_state = !blink_state; diff --git a/keyboards/mwstudio/mw65_rgb/keymaps/via/keymap.c b/keyboards/mwstudio/mw65_rgb/keymaps/via/keymap.c index 78a17233e3..ddcd3f6642 100644 --- a/keyboards/mwstudio/mw65_rgb/keymaps/via/keymap.c +++ b/keyboards/mwstudio/mw65_rgb/keymaps/via/keymap.c @@ -95,9 +95,9 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { bool encoder_update_user(uint8_t index, bool clockwise) { if (index == 0) { if (clockwise) { - tap_code(dynamic_keymap_get_keycode(biton32(layer_state), 4, 3)); + tap_code(dynamic_keymap_get_keycode(get_highest_layer(layer_state), 4, 3)); } else { - tap_code(dynamic_keymap_get_keycode(biton32(layer_state), 4, 4)); + tap_code(dynamic_keymap_get_keycode(get_highest_layer(layer_state), 4, 4)); } } return true; diff --git a/keyboards/pearl/keymaps/cijanzen/keymap.c b/keyboards/pearl/keymaps/cijanzen/keymap.c index 896e157fd6..5a3f1eb1cd 100644 --- a/keyboards/pearl/keymaps/cijanzen/keymap.c +++ b/keyboards/pearl/keymaps/cijanzen/keymap.c @@ -46,7 +46,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /** * Status LED layer indicators courtesy of jetpacktuxedo's firmware */ -uint32_t layer_state_set_kb(uint32_t state) +layer_state_t layer_state_set_kb(layer_state_t state) { if (state & (1<<1)) { // if we are on layer 1 PORTD |= (1 << PD0); // light num lock led diff --git a/keyboards/pearl/keymaps/jetpacktuxedo/keymap.c b/keyboards/pearl/keymaps/jetpacktuxedo/keymap.c index 759c6fdc7d..4fd35f63ce 100644 --- a/keyboards/pearl/keymaps/jetpacktuxedo/keymap.c +++ b/keyboards/pearl/keymaps/jetpacktuxedo/keymap.c @@ -27,7 +27,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { ), }; -uint32_t layer_state_set_kb(uint32_t state) { +layer_state_t layer_state_set_kb(layer_state_t state) { // if we are on layer 1 if (state & (1<<1)){ // light num lock led diff --git a/keyboards/pearl/keymaps/phil/keymap.c b/keyboards/pearl/keymaps/phil/keymap.c index 56326d423f..492c4cb0c5 100755 --- a/keyboards/pearl/keymaps/phil/keymap.c +++ b/keyboards/pearl/keymaps/phil/keymap.c @@ -64,7 +64,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { ), }; -uint32_t layer_state_set_kb(uint32_t state) { +layer_state_t layer_state_set_kb(layer_state_t state) { if (state & (1<event.pressed) { layer_on(_LOWER); - uint8_t default_layer = biton32(default_layer_state); + uint8_t default_layer = get_highest_layer(default_layer_state); if (default_layer == _QWERTY) { #ifdef BACKLIGHT_BREATHING breathing_enable(); @@ -151,7 +151,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { update_tri_layer(_LOWER, _RAISE, _ADJUST); } else { layer_off(_LOWER); - uint8_t default_layer = biton32(default_layer_state); + uint8_t default_layer = get_highest_layer(default_layer_state); if (default_layer == _QWERTY) { #ifdef BACKLIGHT_BREATHING breathing_self_disable(); @@ -164,7 +164,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { case RAISE: if (record->event.pressed) { layer_on(_RAISE); - uint8_t default_layer = biton32(default_layer_state); + uint8_t default_layer = get_highest_layer(default_layer_state); if (default_layer == _QWERTY) { #ifdef BACKLIGHT_BREATHING breathing_enable(); @@ -173,7 +173,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { update_tri_layer(_LOWER, _RAISE, _ADJUST); } else { layer_off(_RAISE); - uint8_t default_layer = biton32(default_layer_state); + uint8_t default_layer = get_highest_layer(default_layer_state); if (default_layer == _QWERTY) { #ifdef BACKLIGHT_BREATHING breathing_self_disable(); diff --git a/keyboards/planck/keymaps/charlesrocket/keymap.c b/keyboards/planck/keymaps/charlesrocket/keymap.c index cec3f0186a..bfe61294af 100644 --- a/keyboards/planck/keymaps/charlesrocket/keymap.c +++ b/keyboards/planck/keymaps/charlesrocket/keymap.c @@ -101,7 +101,7 @@ void set_layer_color(int layer) { void rgb_matrix_indicators_user(void) { if (g_suspend_state || keyboard_config.disable_layer_led) { return; } - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case 0: set_layer_color(0); break; diff --git a/keyboards/planck/keymaps/grahampheath/keymap.c b/keyboards/planck/keymaps/grahampheath/keymap.c index babe67c442..eb5401eabd 100644 --- a/keyboards/planck/keymaps/grahampheath/keymap.c +++ b/keyboards/planck/keymaps/grahampheath/keymap.c @@ -231,7 +231,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { bool has_layer_changed = true; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); static uint8_t old_layer = 0; if (old_layer != layer) { diff --git a/keyboards/planck/keymaps/oryx/keymap.c b/keyboards/planck/keymaps/oryx/keymap.c index 0368c98420..fae5a94713 100644 --- a/keyboards/planck/keymaps/oryx/keymap.c +++ b/keyboards/planck/keymaps/oryx/keymap.c @@ -94,7 +94,7 @@ void rgb_matrix_indicators_user(void) { if (keyboard_config.disable_layer_led) { return; } - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case 1: set_layer_color(0); break; diff --git a/keyboards/planck/keymaps/rootiest/keymap.c b/keyboards/planck/keymaps/rootiest/keymap.c index 857d7a9e21..c289c50e5b 100644 --- a/keyboards/planck/keymaps/rootiest/keymap.c +++ b/keyboards/planck/keymaps/rootiest/keymap.c @@ -502,7 +502,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { } else { if (index == 0) { /* First encoder */ uint16_t held_keycode_timer = timer_read(); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case 0: // Base Layer if ((get_mods() & MOD_MASK_GUI)) { // GUI-ed if (clockwise) { diff --git a/keyboards/planck/keymaps/tom/keymap.c b/keyboards/planck/keymaps/tom/keymap.c index 66beaf33b7..d888fb7b05 100644 --- a/keyboards/planck/keymaps/tom/keymap.c +++ b/keyboards/planck/keymaps/tom/keymap.c @@ -228,7 +228,7 @@ bool music_mask_user(uint16_t keycode) { void rgb_matrix_indicators_user(void) { #ifdef RGB_MATRIX_ENABLE - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _RAISE: for (int i = 0; i < DRIVER_LED_TOTAL; i++) { if (HAS_FLAGS(g_led_config.flags[i], LED_FLAG_MODIFIER)) { diff --git a/keyboards/planck/keymaps/tylerwince/keymap.c b/keyboards/planck/keymaps/tylerwince/keymap.c index 5cbc47b2fb..b4c0f9af52 100644 --- a/keyboards/planck/keymaps/tylerwince/keymap.c +++ b/keyboards/planck/keymaps/tylerwince/keymap.c @@ -168,7 +168,7 @@ void set_layer_color(int layer) { void rgb_matrix_indicators_user(void) { if (g_suspend_state || disable_layer_color) { return; } - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case 0: set_layer_color(0); break; @@ -276,7 +276,7 @@ bool music_mask_user(uint16_t keycode) { layer_state_t layer_state_set_user(layer_state_t state) { palClearPad(GPIOB, 8); palClearPad(GPIOB, 9); - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); switch (layer) { case _LOWER: palSetPad(GPIOB, 9); diff --git a/keyboards/preonic/keymaps/dudeofawesome/keymap.c b/keyboards/preonic/keymaps/dudeofawesome/keymap.c index 2d2a252b23..812bf35a20 100644 --- a/keyboards/preonic/keymaps/dudeofawesome/keymap.c +++ b/keyboards/preonic/keymaps/dudeofawesome/keymap.c @@ -275,7 +275,7 @@ bool numpadActive = false; float tone_numpad_on[][2] = SONG(NUMPAD_ON_SOUND); void matrix_scan_user (void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _NUMPAD: diff --git a/keyboards/preonic/keymaps/senseored/keymap.c b/keyboards/preonic/keymaps/senseored/keymap.c index e152507835..0f896700e6 100644 --- a/keyboards/preonic/keymaps/senseored/keymap.c +++ b/keyboards/preonic/keymaps/senseored/keymap.c @@ -367,7 +367,7 @@ bool dip_switch_update_user(uint8_t index, bool active) { layer_state_t layer_state_set_user(layer_state_t state) { // if(rgblight_get_mode() == 1) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _QWERTY: if(bnumlock) { tap_code(KC_NLCK); diff --git a/keyboards/primekb/prime_e/keymaps/via/keymap.c b/keyboards/primekb/prime_e/keymaps/via/keymap.c index 195f845cc2..2d1d003d51 100644 --- a/keyboards/primekb/prime_e/keymaps/via/keymap.c +++ b/keyboards/primekb/prime_e/keymaps/via/keymap.c @@ -108,7 +108,7 @@ void led_set_user(uint8_t usb_led) { //function for layer indicator LED layer_state_t layer_state_set_user(layer_state_t state) { - if (biton32(state) == 1) { + if (get_highest_layer(state) == 1) { writePinHigh(B3); } else { writePinLow(B3); diff --git a/keyboards/redox_w/keymaps/italian/keymap.c b/keyboards/redox_w/keymaps/italian/keymap.c index e67742c6a1..b4c815e4f5 100644 --- a/keyboards/redox_w/keymaps/italian/keymap.c +++ b/keyboards/redox_w/keymaps/italian/keymap.c @@ -53,7 +53,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //├────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┐ ┌────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┤ KC_LSFT ,KC_Z ,KC_X ,KC_C ,KC_V ,KC_B ,KC_ADPU ,KC_PGDN , KC_HOME ,KC_ADEN ,KC_N ,KC_M ,KC_COMM ,KC_DOT ,IT_UGRV ,IT_SHSL , //├────────┼────────┼────────┼────────┼────┬───┴────┬───┼────────┼────────┤ ├────────┼────────┼───┬────┴───┬────┼────────┼────────┼────────┼────────┤ - GUI_LESS,KC_PPLS ,KC_PMNS ,KC_ALAS , KC_CTPL , KC_BSPC ,KC_DEL , KC_ENT ,KC_SPC , ALT_IACC, KC_LEFT ,KC_DOWN ,KC_UP ,KC_RGHT + GUI_LESS,KC_PPLS ,KC_PMNS ,KC_ALAS , KC_CTPL , KC_BSPC ,KC_DEL , KC_ENT ,KC_SPC , ALT_IACC, KC_LEFT ,KC_DOWN ,KC_UP ,KC_RGHT //└────────┴────────┴────────┴────────┘ └────────┘ └────────┴────────┘ └────────┴────────┘ └────────┘ └────────┴────────┴────────┴────────┘ ), @@ -67,7 +67,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //├────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┐ ┌────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┤ _______ ,IT_PERC ,IT_CIRC ,IT_LPRN ,IT_RPRN ,IT_TILD ,_______ ,_______ , _______ ,_______ ,XXXXXXX ,KC_KP_1 ,KC_KP_2 ,KC_KP_3 ,XXXXXXX ,XXXXXXX , //├────────┼────────┼────────┼────────┼────┬───┴────┬───┼────────┼────────┤ ├────────┼────────┼───┬────┴───┬────┼────────┼────────┼────────┼────────┤ - _______ ,_______ ,_______ ,_______ , _______ , _______ ,_______ , _______ ,_______ , KC_KP_0 , KC_KP_0 ,KC_PDOT ,XXXXXXX ,XXXXXXX + _______ ,_______ ,_______ ,_______ , _______ , _______ ,_______ , _______ ,_______ , KC_KP_0 , KC_KP_0 ,KC_PDOT ,XXXXXXX ,XXXXXXX //└────────┴────────┴────────┴────────┘ └────────┘ └────────┴────────┘ └────────┴────────┘ └────────┘ └────────┴────────┴────────┴────────┘ ), @@ -81,7 +81,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //├────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┐ ┌────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┤ XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,_______ ,_______ , _______ ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX , //├────────┼────────┼────────┼────────┼────┬───┴────┬───┼────────┼────────┤ ├────────┼────────┼───┬────┴───┬────┼────────┼────────┼────────┼────────┤ - XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX , KC_BTN1 , KC_BTN2 ,_______ , _______ ,_______ , XXXXXXX , XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX + XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX , KC_BTN1 , KC_BTN2 ,_______ , _______ ,_______ , XXXXXXX , XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX //└────────┴────────┴────────┴────────┘ └────────┘ └────────┴────────┘ └────────┴────────┘ └────────┘ └────────┴────────┴────────┴────────┘ ), @@ -95,14 +95,14 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //├────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┐ ┌────────┼────────┼────────┼────────┼────────┼────────┼────────┼────────┤ XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,_______ ,XXXXXXX , XXXXXXX ,_______ ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX , //├────────┼────────┼────────┼────────┼────┬───┴────┬───┼────────┼────────┤ ├────────┼────────┼───┬────┴───┬────┼────────┼────────┼────────┼────────┤ - XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX , XXXXXXX , XXXXXXX ,XXXXXXX , XXXXXXX ,XXXXXXX , XXXXXXX , XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX + XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX , XXXXXXX , XXXXXXX ,XXXXXXX , XXXXXXX ,XXXXXXX , XXXXXXX , XXXXXXX ,XXXXXXX ,XXXXXXX ,XXXXXXX //└────────┴────────┴────────┴────────┘ └────────┘ └────────┴────────┘ └────────┴────────┘ └────────┘ └────────┴────────┴────────┴────────┘ ) }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case _QWERTY: @@ -121,5 +121,3 @@ void matrix_scan_user(void) { break; } }; - - diff --git a/keyboards/redscarf_i/redscarf_i.c b/keyboards/redscarf_i/redscarf_i.c index a8a685b13b..039e20664d 100644 --- a/keyboards/redscarf_i/redscarf_i.c +++ b/keyboards/redscarf_i/redscarf_i.c @@ -36,7 +36,7 @@ bool led_update_kb(led_t led_state) { } layer_state_t layer_state_set_kb(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case 1: writePinHigh(F6); writePinLow(F5); diff --git a/keyboards/rgbkb/pan/keymaps/default/keymap.c b/keyboards/rgbkb/pan/keymaps/default/keymap.c index dbc127616a..dcafeec765 100644 --- a/keyboards/rgbkb/pan/keymaps/default/keymap.c +++ b/keyboards/rgbkb/pan/keymaps/default/keymap.c @@ -75,7 +75,7 @@ bool oled_task_user(void) { // Host Keyboard Layer Status oled_write_P(PSTR("RGBKB Pan\n"), false); oled_write_P(PSTR("Layer: "), false); - uint8_t layer = layer_state ? biton(layer_state) : biton32(default_layer_state); + uint8_t layer = get_highest_layer(layer_state|default_layer_state); switch (layer) { case _QWERTY: oled_write_P(PSTR("Default\n"), false); diff --git a/keyboards/rgbkb/sol/keymaps/default/keymap.c b/keyboards/rgbkb/sol/keymaps/default/keymap.c index c82259f5ee..1ce18bc1ab 100644 --- a/keyboards/rgbkb/sol/keymaps/default/keymap.c +++ b/keyboards/rgbkb/sol/keymaps/default/keymap.c @@ -233,7 +233,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { } else #endif { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); uint16_t keycode = pgm_read_word(&encoders[layer][index][clockwise]); while (keycode == KC_TRANSPARENT && layer > 0) { @@ -325,7 +325,7 @@ static void render_status(void) { // Define layers here oled_write_P(PSTR("Layer"), false); - uint8_t layer = layer_state ? biton(layer_state) : biton32(default_layer_state); + uint8_t layer = get_highest_layer(layer_state|default_layer_state); switch (layer) { case _QWERTY: oled_write_P(PSTR("BASE "), false); diff --git a/keyboards/rgbkb/sol/keymaps/xyverz/keymap.c b/keyboards/rgbkb/sol/keymaps/xyverz/keymap.c index bdcfbb1b93..bc0884c8e4 100644 --- a/keyboards/rgbkb/sol/keymaps/xyverz/keymap.c +++ b/keyboards/rgbkb/sol/keymaps/xyverz/keymap.c @@ -263,7 +263,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { } else #endif { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); uint16_t keycode = encoders[layer][index][clockwise]; while (keycode == KC_TRANSPARENT && layer > 0) { @@ -306,7 +306,7 @@ static void render_status(void) { // Define layers here oled_write_P(PSTR(" Layer-----"), false); - uint8_t layer = layer_state ? biton(layer_state) : biton32(default_layer_state); + uint8_t layer = layer_state ? get_highest_layer(layer_state) : get_highest_layer(default_layer_state); switch (layer) { case _DVORAK: oled_write_P(PSTR("DVRAK"), false); diff --git a/keyboards/rgbkb/zen/rev2/rev2.c b/keyboards/rgbkb/zen/rev2/rev2.c index 5461890272..70e5531673 100644 --- a/keyboards/rgbkb/zen/rev2/rev2.c +++ b/keyboards/rgbkb/zen/rev2/rev2.c @@ -37,7 +37,7 @@ void render_status(void) { // Define layers here, Have not worked out how to have text displayed for each layer. Copy down the number you see and add a case for it below oled_set_cursor(0, 3); // Line 3 oled_write_P(PSTR("Layer"), false); // Line 4 - oled_write_P(layer_name_user(biton32(layer_state)), false); + oled_write_P(layer_name_user(get_highest_layer(layer_state)), false); // Host Keyboard LED Status uint8_t led_usb_state = host_keyboard_leds(); diff --git a/keyboards/rgbkb/zygomorph/keymaps/default_oled/keymap.c b/keyboards/rgbkb/zygomorph/keymaps/default_oled/keymap.c index 48bd1a33f7..f4d5c82a71 100644 --- a/keyboards/rgbkb/zygomorph/keymaps/default_oled/keymap.c +++ b/keyboards/rgbkb/zygomorph/keymaps/default_oled/keymap.c @@ -198,7 +198,7 @@ static void render_status(void) { // Define layers here, Have not worked out how to have text displayed for each layer. Copy down the number you see and add a case for it below oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _QWERTY: oled_write_ln_P(PSTR("QWERTY"), false); break; diff --git a/keyboards/satt/comet46/keymaps/default-rgbled/keymap.c b/keyboards/satt/comet46/keymaps/default-rgbled/keymap.c index 6c88b70bfe..1e96bd7fbc 100644 --- a/keyboards/satt/comet46/keymaps/default-rgbled/keymap.c +++ b/keyboards/satt/comet46/keymaps/default-rgbled/keymap.c @@ -173,7 +173,7 @@ void matrix_init_user(void) { } void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); uint8_t default_layer = biton32(eeconfig_read_default_layer()); switch (layer) { case _LOWER: diff --git a/keyboards/satt/comet46/keymaps/default/keymap.c b/keyboards/satt/comet46/keymaps/default/keymap.c index cf2c911d4c..bccca0a091 100644 --- a/keyboards/satt/comet46/keymaps/default/keymap.c +++ b/keyboards/satt/comet46/keymaps/default/keymap.c @@ -176,8 +176,8 @@ void render_status(struct CharacterMatrix *matrix) { // Layer state char layer_str[22]; matrix_write(matrix, "Layer: "); - uint8_t layer = biton32(layer_state); - uint8_t default_layer = biton32(eeconfig_read_default_layer()); + uint8_t layer = get_highest_layer(layer_state); + uint8_t default_layer = get_highest_layer(eeconfig_read_default_layer()); switch (layer) { case _QWERTY: switch (default_layer) { diff --git a/keyboards/satt/comet46/keymaps/satt/keymap.c b/keyboards/satt/comet46/keymaps/satt/keymap.c index cdd094f747..54d1d791d7 100644 --- a/keyboards/satt/comet46/keymaps/satt/keymap.c +++ b/keyboards/satt/comet46/keymaps/satt/keymap.c @@ -165,7 +165,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _PSEUDO_US_LOWER: case _PSEUDO_US_RAISE: return update_tri_layer_state(state, _PSEUDO_US_RAISE, _PSEUDO_US_LOWER, _ADJUST); @@ -204,7 +204,7 @@ void render_status(struct CharacterMatrix *matrix) { // Layer state char layer_str[22]; matrix_write(matrix, "Layer: "); - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); uint8_t default_layer = biton32(eeconfig_read_default_layer()); switch (layer) { case _QWERTY: diff --git a/keyboards/splitkb/kyria/keymaps/j-inc/keymap.c b/keyboards/splitkb/kyria/keymaps/j-inc/keymap.c index af583a607f..f193c6e00c 100644 --- a/keyboards/splitkb/kyria/keymaps/j-inc/keymap.c +++ b/keyboards/splitkb/kyria/keymaps/j-inc/keymap.c @@ -341,7 +341,7 @@ bool oled_task_user(void) { #ifdef ENCODER_ENABLE bool encoder_update_user(uint8_t index, bool clockwise) { - switch(biton32(layer_state)){ + switch(get_highest_layer(layer_state)){ case 1: if (clockwise) { tap_code16(C(KC_TAB)); diff --git a/keyboards/splitkb/kyria/keymaps/ninjonas/oled.c b/keyboards/splitkb/kyria/keymaps/ninjonas/oled.c index 813328aa0c..d0f2a1b6cd 100644 --- a/keyboards/splitkb/kyria/keymaps/ninjonas/oled.c +++ b/keyboards/splitkb/kyria/keymaps/ninjonas/oled.c @@ -111,7 +111,7 @@ void oled_slash_separator(void){ void render_layout_state(void) { oled_write_P(PSTR("Layout: "), false); - switch (biton32(default_layer_state)) { + switch (get_highest_layer(default_layer_state)) { case _COLEMAK: oled_write_P(PSTR("Colemak"), false); break; diff --git a/keyboards/splitkb/kyria/keymaps/thomasbaart/keymap.c b/keyboards/splitkb/kyria/keymaps/thomasbaart/keymap.c index 0a4f1887c3..3cd9df27fb 100644 --- a/keyboards/splitkb/kyria/keymaps/thomasbaart/keymap.c +++ b/keyboards/splitkb/kyria/keymaps/thomasbaart/keymap.c @@ -311,7 +311,7 @@ bool oled_task_user(void) { #ifdef ENCODER_ENABLE bool encoder_update_user(uint8_t index, bool clockwise) { if (index == 0) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case QWERTY: // History scrubbing. For Adobe products, hold shift while moving // backward to go forward instead. @@ -336,7 +336,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) { break; } } else if (index == 1) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case QWERTY: // Scrolling with PageUp and PgDn. if (clockwise) { diff --git a/keyboards/splitography/keymaps/jeandeaual/keymap.c b/keyboards/splitography/keymaps/jeandeaual/keymap.c index 6679d835f2..87c4159443 100644 --- a/keyboards/splitography/keymaps/jeandeaual/keymap.c +++ b/keyboards/splitography/keymaps/jeandeaual/keymap.c @@ -225,7 +225,7 @@ bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { } return false; case KC_QUOT: - if ((base_layer != dvorak) || (biton32(layer_state) != _BLUE)) { + if ((base_layer != dvorak) || (get_highest_layer(layer_state) != _BLUE)) { break; } if (record->event.pressed) { diff --git a/keyboards/splitography/keymaps/multi/keymap.c b/keyboards/splitography/keymaps/multi/keymap.c index af1cc1a801..7d847e40b6 100644 --- a/keyboards/splitography/keymaps/multi/keymap.c +++ b/keyboards/splitography/keymaps/multi/keymap.c @@ -331,7 +331,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } return false; case KC_QUOT: - if ((base_layer != dvorak) || (biton32(layer_state) != _BLUE)) { + if ((base_layer != dvorak) || (get_highest_layer(layer_state) != _BLUE)) { break; } if (record->event.pressed) { diff --git a/keyboards/tetris/keymaps/default/keymap.c b/keyboards/tetris/keymaps/default/keymap.c index 1b53ea80b9..9e2a96ffc3 100755 --- a/keyboards/tetris/keymaps/default/keymap.c +++ b/keyboards/tetris/keymaps/default/keymap.c @@ -37,7 +37,7 @@ void matrix_init_user(void) { } void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (RGB_encoder_dir != 0) { if (timer_elapsed(RGB_encoder_timer) > 1400) { @@ -152,7 +152,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t * record) { bool encoder_update_user(uint8_t index, bool clockwise) { RGB_encoder_timer = timer_read(); RGB_encoder_timer2 = timer_read(); - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (clockwise) { RGB_encoder_dir = 1; } else { diff --git a/keyboards/thevankeyboards/roadkit/keymaps/flipphone/keymap.c b/keyboards/thevankeyboards/roadkit/keymaps/flipphone/keymap.c index b00cf80f5c..a6fa5ed722 100644 --- a/keyboards/thevankeyboards/roadkit/keymaps/flipphone/keymap.c +++ b/keyboards/thevankeyboards/roadkit/keymaps/flipphone/keymap.c @@ -147,7 +147,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { return false; } uint8_t layer; - layer = biton32(layer_state); + layer = get_highest_layer(layer_state); switch (keycode) { case FPH_1 ... FPH_9: diff --git a/keyboards/v60_type_r/keymaps/xtonhasvim/keymap.c b/keyboards/v60_type_r/keymaps/xtonhasvim/keymap.c index 82a7e52808..8927a8ee0a 100644 --- a/keyboards/v60_type_r/keymaps/xtonhasvim/keymap.c +++ b/keyboards/v60_type_r/keymaps/xtonhasvim/keymap.c @@ -104,7 +104,7 @@ void rgbflag(uint8_t r, uint8_t g, uint8_t b) { } void set_state_leds(void) { - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _MOVE: rgbflag(C_BLU); break; @@ -192,4 +192,3 @@ void suspend_wakeup_init_user(void) backlight_set(backlight_config.level); rgblight_set(); } - diff --git a/keyboards/xiudi/xd60/keymaps/birkir/keymap.c b/keyboards/xiudi/xd60/keymaps/birkir/keymap.c index fe7cd60662..ab129332c9 100644 --- a/keyboards/xiudi/xd60/keymaps/birkir/keymap.c +++ b/keyboards/xiudi/xd60/keymaps/birkir/keymap.c @@ -47,7 +47,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { edit = false; } - switch (biton32(state)) { + switch (get_highest_layer(state)) { case 1: rgblight_mode(1); rgblight_setrgb(0xD3, 0x7F, 0xED); diff --git a/keyboards/xiudi/xd60/keymaps/kmontag42/keymap.c b/keyboards/xiudi/xd60/keymaps/kmontag42/keymap.c index 8e081c6731..d17fc2f35d 100644 --- a/keyboards/xiudi/xd60/keymaps/kmontag42/keymap.c +++ b/keyboards/xiudi/xd60/keymaps/kmontag42/keymap.c @@ -25,7 +25,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Loop void matrix_scan_user(void) { static uint8_t old_layer = 255; - uint8_t new_layer = biton32(layer_state); + uint8_t new_layer = get_highest_layer(layer_state); if (old_layer != new_layer) { switch (new_layer) { diff --git a/keyboards/xiudi/xd75/keymaps/arpinfidel/keymap.c b/keyboards/xiudi/xd75/keymaps/arpinfidel/keymap.c index 5f7337d68b..c278df1b21 100644 --- a/keyboards/xiudi/xd75/keymaps/arpinfidel/keymap.c +++ b/keyboards/xiudi/xd75/keymaps/arpinfidel/keymap.c @@ -100,7 +100,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { // Runs whenever there is a layer state change. layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); gp100_led_off(); gp103_led_off(); diff --git a/keyboards/xiudi/xd75/keymaps/cbbrowne/keymap.c b/keyboards/xiudi/xd75/keymaps/cbbrowne/keymap.c index 1b29686cff..a0295f2f45 100644 --- a/keyboards/xiudi/xd75/keymaps/cbbrowne/keymap.c +++ b/keyboards/xiudi/xd75/keymaps/cbbrowne/keymap.c @@ -286,7 +286,7 @@ void matrix_init_user(void) { } layer_state_t layer_state_set_user(layer_state_t state) { - switch(biton32(state)) { + switch(get_highest_layer(state)) { case _QWERTY: rgblight_sethsv_white(); break; diff --git a/keyboards/xiudi/xd75/keymaps/kloki/keymap.c b/keyboards/xiudi/xd75/keymaps/kloki/keymap.c index a630019347..d25a16fbb6 100644 --- a/keyboards/xiudi/xd75/keymaps/kloki/keymap.c +++ b/keyboards/xiudi/xd75/keymaps/kloki/keymap.c @@ -70,7 +70,7 @@ bool WINDOWN = false; bool SHIFTDOWN = false; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { case 0: diff --git a/keyboards/xiudi/xd75/keymaps/tdl-jturner/keymap.c b/keyboards/xiudi/xd75/keymaps/tdl-jturner/keymap.c index b7b98cd4c5..f48eb94214 100644 --- a/keyboards/xiudi/xd75/keymaps/tdl-jturner/keymap.c +++ b/keyboards/xiudi/xd75/keymaps/tdl-jturner/keymap.c @@ -180,7 +180,7 @@ void matrix_init_user(void) { //Set a color based on the layer layer_state_t layer_state_set_user(layer_state_t state) { - switch(biton32(state)) { + switch(get_highest_layer(state)) { case _LYFK: rgblight_setrgb_user_LYFK(); break; diff --git a/layouts/community/ergodox/ab/keymap.c b/layouts/community/ergodox/ab/keymap.c index 001123e286..e85d5d528c 100644 --- a/layouts/community/ergodox/ab/keymap.c +++ b/layouts/community/ergodox/ab/keymap.c @@ -130,7 +130,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/absenth/keymap.c b/layouts/community/ergodox/absenth/keymap.c index d84b68f0ef..884167aa31 100644 --- a/layouts/community/ergodox/absenth/keymap.c +++ b/layouts/community/ergodox/absenth/keymap.c @@ -157,7 +157,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/adam/keymap.c b/layouts/community/ergodox/adam/keymap.c index 50270838aa..9dd611e03e 100644 --- a/layouts/community/ergodox/adam/keymap.c +++ b/layouts/community/ergodox/adam/keymap.c @@ -129,7 +129,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { // TODO: Make this relevant to the ErgoDox EZ. diff --git a/layouts/community/ergodox/adnw_k_o_y/keymap.c b/layouts/community/ergodox/adnw_k_o_y/keymap.c index 589a9ea873..6aa309c2cc 100644 --- a/layouts/community/ergodox/adnw_k_o_y/keymap.c +++ b/layouts/community/ergodox/adnw_k_o_y/keymap.c @@ -139,7 +139,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/alexjj/keymap.c b/layouts/community/ergodox/alexjj/keymap.c index 64e7c94433..c9adf7af63 100644 --- a/layouts/community/ergodox/alexjj/keymap.c +++ b/layouts/community/ergodox/alexjj/keymap.c @@ -206,7 +206,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/andrew_osx/keymap.c b/layouts/community/ergodox/andrew_osx/keymap.c index 990fea4f45..4f3f6ef0cb 100644 --- a/layouts/community/ergodox/andrew_osx/keymap.c +++ b/layouts/community/ergodox/andrew_osx/keymap.c @@ -141,7 +141,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/berfarah/keymap.c b/layouts/community/ergodox/berfarah/keymap.c index 164d026ef3..7dc09e7543 100644 --- a/layouts/community/ergodox/berfarah/keymap.c +++ b/layouts/community/ergodox/berfarah/keymap.c @@ -219,7 +219,7 @@ static inline void mod_layer_with_rgb(keyrecord_t *record, uint8_t layer) { bf_set_led(layer); } else { layer_off(layer); - uint8_t currentLayer = biton32(layer_state); + uint8_t currentLayer = get_highest_layer(layer_state); bf_set_led(currentLayer); }; }; @@ -266,7 +266,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_right_led_1_off(); ergodox_right_led_2_off(); diff --git a/layouts/community/ergodox/bryan/keymap.c b/layouts/community/ergodox/bryan/keymap.c index acae77d5fc..ab301e8922 100644 --- a/layouts/community/ergodox/bryan/keymap.c +++ b/layouts/community/ergodox/bryan/keymap.c @@ -200,7 +200,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/choromanski/keymap.c b/layouts/community/ergodox/choromanski/keymap.c index 8be3c7ea7e..933f13b25f 100644 --- a/layouts/community/ergodox/choromanski/keymap.c +++ b/layouts/community/ergodox/choromanski/keymap.c @@ -30,15 +30,15 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { OSL(3), TG(2), TO(5), TO(1), KC_CAPS, KC_LCTL, KC_LALT, KC_MUTE, - KC_BSPC, KC_DEL, KC_LGUI, + KC_BSPC, KC_DEL, KC_LGUI, - KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, + KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_RPRN, KC_J, KC_L, KC_U, KC_Y, KC_SCLN, KC_BSLS, - KC_H, KC_N, KC_E, KC_I, KC_O, KC_QUOT, + KC_H, KC_N, KC_E, KC_I, KC_O, KC_QUOT, KC_RBRC, KC_K, KC_M, KC_COMM, ALT_T(KC_DOT), CTL_T(KC_SLSH), KC_RSFT, - KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, TG(4), - KC_RALT, KC_RCTL, - KC_WH_U, + KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, TG(4), + KC_RALT, KC_RCTL, + KC_WH_U, KC_WH_D, KC_ENT, KC_SPC ), @@ -106,22 +106,22 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { */ [2] = LAYOUT_ergodox( KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, + KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS ), /* Keymap 3: Symbols @@ -147,9 +147,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { */ [3] = LAYOUT_ergodox( KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, - KC_TRNS, KC_PIPE, KC_PLUS, KC_LABK, KC_RABK, KC_HASH, KC_TRNS, - KC_TRNS, KC_EXLM, KC_MINS, KC_EQL, KC_PERC, KC_AT, - KC_TRNS, KC_ASTR, KC_AMPR, KC_SLSH, KC_DLR, KC_CIRC, KC_TRNS, + KC_TRNS, KC_PIPE, KC_PLUS, KC_LABK, KC_RABK, KC_HASH, KC_TRNS, + KC_TRNS, KC_EXLM, KC_MINS, KC_EQL, KC_PERC, KC_AT, + KC_TRNS, KC_ASTR, KC_AMPR, KC_SLSH, KC_DLR, KC_CIRC, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, @@ -229,8 +229,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [5] = LAYOUT_ergodox( KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_TRNS, - KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, - KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_MPLY, + KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_MPLY, KC_LCTL, LALT(KC_TAB), TO(0), KC_LALT, KC_SPC, KC_MPRV, KC_MNXT, KC_VOLU, @@ -249,7 +249,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/colemak/keymap.c b/layouts/community/ergodox/colemak/keymap.c index 54b0c5834a..db2addd6d9 100644 --- a/layouts/community/ergodox/colemak/keymap.c +++ b/layouts/community/ergodox/colemak/keymap.c @@ -138,7 +138,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/colemak_code_friendly/keymap.c b/layouts/community/ergodox/colemak_code_friendly/keymap.c index 936ddbc2a5..6350bd9ee2 100644 --- a/layouts/community/ergodox/colemak_code_friendly/keymap.c +++ b/layouts/community/ergodox/colemak_code_friendly/keymap.c @@ -59,7 +59,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_ESC, KC_A, KC_R, KC_S, KC_T, KC_D, KC_LSFT, LCTL_T(KC_Z), LGUI_T(KC_X), KC_C, KC_V, RALT_T(KC_B), KC_LCBR, KC_LCTL, KC_LGUI, KC_LALT, KC_LBRC, KC_RBRC, - + KC_HOME, KC_END, KC_PSCR, MO(LAYER_LNUM), KC_ENT, KC_LGUI, @@ -101,7 +101,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_F8, KC_F7, KC_F6, KC_F5, M_IN_PRN, KC_TRNS, KC_F4, KC_F3, KC_F2, KC_F1, M_IN_BRC, KC_TRNS, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, - + KC_TRNS, KC_TRNS, DYN_REC_START1, KC_TRNS, KC_TRNS, DYN_MACRO_PLAY1, @@ -126,8 +126,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * |--------+------+------+------+------+------| | | } |------+------+------+------+------+--------| * | | F4 | F3 | F2 | F1 | [] | | | |K/RAlt| M | , |./Supe|/ RCtl| RShift | * '--------+------+------+------+------+-------------' '-------------+------+------+------+------+--------' - * | MUTE | VOLD | VOLU | | | | Left | Down | Up |Right | Del | - * '----------------------------------' '----------------------------------' + * | MUTE | VOLD | VOLU | | | | Left | Down | Up |Right | Del | + * '----------------------------------' '----------------------------------' * .-------------. .-------------. * | | | | Ins |ScrLck| * .------+------+------| |------+------+------. @@ -143,7 +143,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_F8, KC_F7, KC_F6, KC_F5, M_IN_PRN, KC_TRNS, KC_F4, KC_F3, KC_F2, KC_F1, M_IN_BRC, KC_TRNS, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, - + KC_TRNS, KC_TRNS, DYN_REC_START1, KC_TRNS, KC_TRNS, DYN_MACRO_PLAY1, @@ -185,7 +185,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { S(KC_ESC), S(KC_A), S(KC_R), S(KC_S), S(KC_T), S(KC_D), KC_LSFT, S(KC_Z), S(KC_X), S(KC_C), S(KC_V), S(KC_B), KC_LCBR, S(KC_LCTL), S(KC_LGUI), S(KC_LALT), S(KC_LBRC), S(KC_RBRC), - + S(KC_HOME), S(KC_END), S(KC_PSCR), KC_CAPS, S(KC_ENT), S(KC_LGUI), @@ -227,7 +227,7 @@ static bool process_record_dynamic_macro_wrapper(uint16_t keycode, keyrecord_t * } bool process_record_user(uint16_t keycode, keyrecord_t *record) { - + /* the purpose of the ..._wrapper is to detect START/ST0P keys to light the blue led during recording */ if (!process_record_dynamic_macro_wrapper(keycode, record)) { @@ -308,19 +308,19 @@ void matrix_init_user(void) { /* Runs constantly in the background, in a loop. */ void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); //led 1, RED, Caps-Lock ON //if (host_keyboard_leds() & (1<event.pressed) { return MACRO( T(P), T(U), T(B), T(L), T(I), T(C), T(SPACE),END); - } + } break; case MACRO_PRIVATE: if (record->event.pressed) { return MACRO( T(P), T(R), T(I), T(V), T(A), T(T), T(E), T(SPACE),END); - } + } break; case MACRO_STATIC: if (record->event.pressed) { return MACRO( T(S), T(T), T(A), T(T), T(I), T(C), T(SPACE), END); - } + } break; case MACRO_CONST: if (record->event.pressed) { return MACRO( T(C), T(O), T(N), T(S), T(T), T(SPACE), END); - } + } break; case MACRO_VOID: if (record->event.pressed) { return MACRO( T(V), T(O), T(I), T(D), T(SPACE), END); - } + } break; case MACRO_VAR: if (record->event.pressed) { return MACRO( T(V), T(A), T(R), T(SPACE), END); - } + } break; case MACRO_STRING: if (record->event.pressed) { return MACRO( T(S), T(T), T(R), T(I), T(N), T(G), T(SPACE), END); - } - break; + } + break; case MACRO_BOOL: if (record->event.pressed) { return MACRO( T(B), T(O), T(O), T(L), T(SPACE), END); - } - break; + } + break; case MACRO_INT: if (record->event.pressed) { return MACRO( T(I), T(N), T(T), T(SPACE), END); - } + } break; case MACRO_FLOAT: if (record->event.pressed) { return MACRO( T(F), T(L), T(O), T(A),T(T),T(SPACE), END); - } + } break; case MACRO_RETURN: if (record->event.pressed) { return MACRO( T(R), T(E), T(T), T(U),T(R),T(N), END); - } + } break; case MACRO_NULL: if (record->event.pressed) { return MACRO( T(N), T(U), T(L), T(L), END); - } + } case MACRO_BREAK: if (record->event.pressed) { return MACRO( T(B), T(R), T(E), T(A), T(K), T(SCOLON), END); - } + } break; case MACRO_TODO: if (record->event.pressed) { return MACRO( T(SLASH), T(SLASH), D(LSHIFT) ,T(T), T(O), T(D), T(O),U(LSHIFT), T(SPACE),END); - } + } break; case MACRO_NEW: if (record->event.pressed) { return MACRO( T(N), T(E), T(W), T(SPACE), END); - } + } break; case MACRO_PARENTHESE: if (record->event.pressed) { return MACRO( D(LSHIFT),T(9), T(0),U(LSHIFT), T(SCOLON), END); - } + } break; } return MACRO_NONE; @@ -213,7 +213,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dave/keymap.c b/layouts/community/ergodox/dave/keymap.c index efa270c406..c54e50ba98 100644 --- a/layouts/community/ergodox/dave/keymap.c +++ b/layouts/community/ergodox/dave/keymap.c @@ -147,7 +147,7 @@ void matrix_scan_user(void) { */ static uint8_t leds[4]; uint8_t led; - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); diff --git a/layouts/community/ergodox/deadcyclo/keymap.c b/layouts/community/ergodox/deadcyclo/keymap.c index 345e25e03e..76f5279257 100644 --- a/layouts/community/ergodox/deadcyclo/keymap.c +++ b/layouts/community/ergodox/deadcyclo/keymap.c @@ -90,10 +90,10 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_LALT, KC_RALT,KC_LEAD,LCTL(LSFT(KC_U)), LT(SYMB,KC_TILD), KC_PGUP, KC_INS, KC_PGDN, - KC_RBRC,KC_BSPC, KC_ENT + KC_RBRC,KC_BSPC, KC_ENT ), -/* Keymap 1: Symbol Layer LCTL(LSFT(KC_U)) - * +/* Keymap 1: Symbol Layer LCTL(LSFT(KC_U)) + * * ,--------------------------------------------------. ,--------------------------------------------------. * | | F1 | F2 | F3 | F4 | F5 | F6 | | F6 | F7 | F8 | F9 | F10 | F11 | F12 | * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| @@ -192,7 +192,7 @@ KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_U, I3_RUN, KC_TRNS, KC_TRNS, * ,-------------. ,-------------. * | | | | ▒ | ▓ | * ,------|------|------| |------+------+------. - * | | | | | | | | + * | | | | | | | | * | | |------| |------| | | * | | | | | | | | * `--------------------' `--------------------' @@ -218,7 +218,7 @@ KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_U, I3_RUN, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS ), -/* Keymap 4: Unicode 2 +/* Keymap 4: Unicode 2 * * ,--------------------------------------------------. ,--------------------------------------------------. * | | ¹ | ² | ³ | ⁴ | ⁵ | ⁶ | | ⁶ | ⁷ | ⁸ | ⁹ | ⁰ | ℃ | ™ | @@ -234,12 +234,12 @@ KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_U, I3_RUN, KC_TRNS, KC_TRNS, * ,-------------. ,-------------. * | | | | | | * ,------|------|------| |------+------+------. - * | | | | | | | | + * | | | | | | | | * | | |------| |------| | | * | | | | | | | | * `--------------------' `--------------------' */ -// Unicode 2 +// Unicode 2 [UNI2] = LAYOUT_ergodox( KC_TRNS, UC(0x00b9), UC(0x00b2), UC(0x00b3), UC(0x2074), UC(0x2075), UC(0x2076), KC_TRNS, UC(0x2081), UC(0x2082), UC(0x2083), UC(0x2084), UC(0x2085), UC(0x2086), @@ -346,7 +346,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dragon788/keymap.c b/layouts/community/ergodox/dragon788/keymap.c index 956a592b6d..b32346a9df 100644 --- a/layouts/community/ergodox/dragon788/keymap.c +++ b/layouts/community/ergodox/dragon788/keymap.c @@ -183,7 +183,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dvorak/keymap.c b/layouts/community/ergodox/dvorak/keymap.c index 68b575fd68..664d8055a4 100644 --- a/layouts/community/ergodox/dvorak/keymap.c +++ b/layouts/community/ergodox/dvorak/keymap.c @@ -138,7 +138,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dvorak_emacs/keymap.c b/layouts/community/ergodox/dvorak_emacs/keymap.c index 6055fd770d..14c592f27f 100644 --- a/layouts/community/ergodox/dvorak_emacs/keymap.c +++ b/layouts/community/ergodox/dvorak_emacs/keymap.c @@ -120,7 +120,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dvorak_emacs_software/keymap.c b/layouts/community/ergodox/dvorak_emacs_software/keymap.c index 4f90f193c6..c2bc1ef8f2 100644 --- a/layouts/community/ergodox/dvorak_emacs_software/keymap.c +++ b/layouts/community/ergodox/dvorak_emacs_software/keymap.c @@ -121,7 +121,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dvorak_intl_squisher/keymap.c b/layouts/community/ergodox/dvorak_intl_squisher/keymap.c index 3ebbd2df09..2d3ec3806b 100644 --- a/layouts/community/ergodox/dvorak_intl_squisher/keymap.c +++ b/layouts/community/ergodox/dvorak_intl_squisher/keymap.c @@ -139,7 +139,7 @@ LAYOUT_ergodox( // layer 0 : default // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dvorak_plover/keymap.c b/layouts/community/ergodox/dvorak_plover/keymap.c index 989aafb90a..51f7e61203 100644 --- a/layouts/community/ergodox/dvorak_plover/keymap.c +++ b/layouts/community/ergodox/dvorak_plover/keymap.c @@ -181,7 +181,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dvorak_programmer/keymap.c b/layouts/community/ergodox/dvorak_programmer/keymap.c index 33115d21f3..a8acee119a 100644 --- a/layouts/community/ergodox/dvorak_programmer/keymap.c +++ b/layouts/community/ergodox/dvorak_programmer/keymap.c @@ -45,7 +45,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TAB, KC_QUOT, KC_COMM, KC_DOT, KC_P, KC_Y, MO(KEY_SEL), MO(BRACKETS), KC_A, KC_O, KC_E, KC_U, KC_I, MO(SHELL_NAV), KC_SCLN, KC_Q, KC_J, KC_K, KC_X, MO(KEY_NAV), - OSL(SHORTCUTS),OSM(MOD_LCTL), OSM(MOD_LALT),OSL(SYMBOL),MO(NUMBER), + OSL(SHORTCUTS),OSM(MOD_LCTL), OSM(MOD_LALT),OSL(SYMBOL),MO(NUMBER), // thumb cluster OSM(MOD_LSFT), RCTL(KC_S), RCTL(KC_DEL), @@ -62,10 +62,10 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_UP, KC_DOWN,KC_ENT, KC_SPC ), - - - + + + // shell navigation layer [SHELL_NAV] = LAYOUT_ergodox( // left hand @@ -92,7 +92,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_TRNS, KC_TRNS ), - + // key navigation layer [KEY_NAV] = LAYOUT_ergodox( // left hand @@ -177,7 +177,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, - KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, + KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS, KC_TRNS, @@ -187,7 +187,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_PLUS, KC_AMPR, KC_ASTR, KC_GRAVE,KC_TILD, KC_TRNS, KC_MINS, KC_DLR, KC_PERC, KC_CIRC, KC_PIPE, KC_TRNS, KC_TRNS, KC_EQUAL,KC_EXLM, KC_AT, KC_HASH, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, M(SEMICOLON_NEWLINE), M(END_NEWLINE), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS @@ -198,7 +198,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS,M(OPEN_CLOSE_CURLY), M(OPEN_CLOSE_PAREN),M(OPEN_CLOSE_BRACKET), KC_TRNS,KC_TRNS, KC_TRNS,KC_LPRN, KC_RPRN, KC_LBRC, KC_RBRC, KC_TRNS, - KC_TRNS,KC_TRNS,KC_TRNS, KC_LCBR, KC_RCBR, KC_TRNS,KC_TRNS, + KC_TRNS,KC_TRNS,KC_TRNS, KC_LCBR, KC_RCBR, KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS, KC_TRNS, @@ -207,8 +207,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS, KC_TRNS, M(OPEN_CLOSE_BRACKET),M(OPEN_CLOSE_PAREN),M(OPEN_CLOSE_CURLY),KC_TRNS,KC_TRNS, KC_TRNS, KC_LBRC, KC_RBRC, KC_LPRN, KC_RPRN, KC_TRNS, - KC_TRNS, KC_TRNS, KC_LCBR, KC_RCBR, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_LCBR, KC_RCBR, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS @@ -219,7 +219,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_NO, MEH(KC_F1), MEH(KC_F2), MEH(KC_F3), MEH(KC_F4), MEH(KC_F5), MEH(KC_F6), KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, - KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, + KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, MEH(KC_0),MEH(KC_1), MEH(KC_2), @@ -272,12 +272,12 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) case MC_CUT_LINE: if (record->event.pressed) { return MACRO( T(HOME), D(LSFT), T(END), U(LSFT), D(LCTL), T(X), U(LCTL), END); - } + } break; case MC_PASTE_LINE: if (record->event.pressed) { return MACRO( T(END), T(ENTER), D(LCTL), T(V), U(LCTL), END); - } + } break; case MC_NEW_SEARCH_TAB: if (record->event.pressed) { @@ -287,17 +287,17 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) case SCREEN_TAB_LEFT: if (record->event.pressed) { return MACRO( D(LCTL), T(A), U(LCTL), T(P), END); - } + } break; case SCREEN_TAB_RIGHT: if (record->event.pressed) { return MACRO( D(LCTL), T(A), U(LCTL), T(N), END); - } + } break; case SCREEN_NEW_TAB: if (record->event.pressed) { return MACRO( D(LCTL), T(A), U(LCTL), T(C), END); - } + } break; case SCREEN_COPY_MODE: if (record->event.pressed) { @@ -306,14 +306,14 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) break; case SCREEN_PASTE: if (record->event.pressed) { - return MACRO( D(LCTL), T(A), U(LCTL), T(RBRC), END); + return MACRO( D(LCTL), T(A), U(LCTL), T(RBRC), END); } - break; + break; case SWITCH_NDS: if (record->event.pressed) { return MACRO( D(LSFT), T(F11), U(LSFT), W(255), D(LALT), T(TAB), U(LALT), END); - } - break; + } + break; case OPEN_CLOSE_PAREN: if (record->event.pressed) { return MACRO( D(LSFT), T(9), T(0), U(LSFT), T(LEFT), END); @@ -323,39 +323,39 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) if (record->event.pressed) { return MACRO( T(LBRC), T(RBRC), T(LEFT), END); } - break; + break; case OPEN_CLOSE_CURLY: if (record->event.pressed) { return MACRO( D(LSFT), T(LBRC), T(RBRC), U(LSFT), T(LEFT), END); } - break; + break; case OPEN_CLOSE_SINGLE_QUOTE: if (record->event.pressed) { return MACRO( T(QUOT), T(QUOT), T(LEFT), END); } - break; + break; case OPEN_CLOSE_DOUBLE_QUOTE: if (record->event.pressed) { return MACRO( D(LSFT), T(QUOT), T(QUOT), U(LSFT), T(LEFT), END); } - break; + break; case SHELL_RECALL_LAST_ARG_REMOVE_FIRST_COMMAND: if (record->event.pressed) { return MACRO( T(UP), T(HOME), D(LALT), T(D), U(LALT), END); } - break; + break; case SEMICOLON_NEWLINE: if (record->event.pressed) { return MACRO( T(END), T(SCLN), T(ENTER), END); - } + } break; case END_NEWLINE: if (record->event.pressed) { return MACRO( T(END), T(ENTER), END); - } - break; - - + } + break; + + } return MACRO_NONE; }; @@ -378,7 +378,7 @@ void led_set_user(uint8_t usb_led) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_2_off(); @@ -387,13 +387,13 @@ void matrix_scan_user(void) { case NUMBER: case SYMBOL: case BRACKETS: - //case SHELL_LAYER: + //case SHELL_LAYER: ergodox_right_led_2_on(); break; case KEY_NAV: case KEY_SEL: ergodox_right_led_3_on(); - break; + break; case SHORTCUTS: ergodox_right_led_2_on(); ergodox_right_led_3_on(); @@ -401,6 +401,6 @@ void matrix_scan_user(void) { default: // none break; - } + } return; }; diff --git a/layouts/community/ergodox/dvorak_programmer_swe/keymap.c b/layouts/community/ergodox/dvorak_programmer_swe/keymap.c index a8a428a04b..2578547f17 100644 --- a/layouts/community/ergodox/dvorak_programmer_swe/keymap.c +++ b/layouts/community/ergodox/dvorak_programmer_swe/keymap.c @@ -306,7 +306,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/dvorak_spanish/keymap.c b/layouts/community/ergodox/dvorak_spanish/keymap.c index 98aa638a0f..805abb0b77 100644 --- a/layouts/community/ergodox/dvorak_spanish/keymap.c +++ b/layouts/community/ergodox/dvorak_spanish/keymap.c @@ -192,13 +192,13 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) if (record->event.pressed) { key_timer = timer_read(); register_code(KC_RSFT); - } else { + } else { unregister_code(KC_RSFT); - if (timer_elapsed(key_timer) < KEY_TAP_SLOW) { - register_code(KC_RALT); - register_code(KC_BSLS); - unregister_code(KC_BSLS); - unregister_code(KC_RALT); + if (timer_elapsed(key_timer) < KEY_TAP_SLOW) { + register_code(KC_RALT); + register_code(KC_BSLS); + unregister_code(KC_BSLS); + unregister_code(KC_RALT); } } break; @@ -207,13 +207,13 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) if (record->event.pressed) { key_timer = timer_read(); register_code(KC_LALT); - } else { + } else { unregister_code(KC_LALT); - if (timer_elapsed(key_timer) < KEY_TAP_SLOW) { - register_code(KC_RALT); - register_code(KC_LBRACKET); - unregister_code(KC_LBRACKET); - unregister_code(KC_RALT); + if (timer_elapsed(key_timer) < KEY_TAP_SLOW) { + register_code(KC_RALT); + register_code(KC_LBRACKET); + unregister_code(KC_LBRACKET); + unregister_code(KC_RALT); } } break; @@ -222,13 +222,13 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) if (record->event.pressed) { key_timer = timer_read(); register_code(KC_LALT); - } else { + } else { unregister_code(KC_LALT); - if (timer_elapsed(key_timer) < KEY_TAP_SLOW) { - register_code(KC_RALT); - register_code(KC_RBRACKET); - unregister_code(KC_RBRACKET); - unregister_code(KC_RALT); + if (timer_elapsed(key_timer) < KEY_TAP_SLOW) { + register_code(KC_RALT); + register_code(KC_RBRACKET); + unregister_code(KC_RBRACKET); + unregister_code(KC_RALT); } } break; @@ -236,7 +236,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) case CAPS: { if (record->event.pressed) { register_code(KC_CAPSLOCK); - } else { + } else { unregister_code(KC_CAPSLOCK); } break; @@ -253,7 +253,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -270,11 +270,10 @@ void matrix_scan_user(void) { // none break; } - + // Turn the caps lock led on if (host_keyboard_leds() & (1<= 0: if section['name'] == 'layout_config': - config.update(loads("\n".join( - section['code_lines'] - ))) + config.update(loads("\n".join(section['code_lines']))) elif section['sub_name'].startswith('layer'): layer_name = section['sub_name'] config['layer_lines'][layer_name] = section['code_lines'] @@ -215,6 +218,7 @@ def parse_config(path): assert 'layout' in config return config + # header file parsing IF0_RE = re.compile(r""" @@ -224,7 +228,6 @@ IF0_RE = re.compile(r""" #endif """, re.MULTILINE | re.DOTALL | re.VERBOSE) - COMMENT_RE = re.compile(r""" /\* .*? @@ -244,6 +247,7 @@ def regex_partial(re_str_fmt, flags): def partial(*args, **kwargs): re_str = re_str_fmt.format(*args, **kwargs) return re.compile(re_str, flags) + return partial @@ -256,7 +260,6 @@ KEYDEF_REP = regex_partial(r""" ) # capture group end """, re.MULTILINE | re.DOTALL | re.VERBOSE) - ENUM_RE = re.compile(r""" ( enum @@ -268,7 +271,6 @@ ENUM_RE = re.compile(r""" ) # capture group end """, re.MULTILINE | re.DOTALL | re.VERBOSE) - ENUM_KEY_REP = regex_partial(r""" ( {} # the prefixes @@ -309,14 +311,13 @@ def parse_valid_keys(config, out_path): include_path = os.path.join(dirpath, include) if os.path.exists(include_path): header_data = read_header_file(include_path) - valid_keycodes.update( - parse_keydefs(config, header_data) - ) + valid_keycodes.update(parse_keydefs(config, header_data)) return valid_keycodes # Keymap Parsing + def iter_raw_codes(layer_lines, filler, separator): filler_re = re.compile("[" + filler + " ]") for line in layer_lines: @@ -346,28 +347,21 @@ LAYER_CHANGE_RE = re.compile(r""" (DF|TG|MO)\(\d+\) """, re.VERBOSE) - MACRO_RE = re.compile(r""" M\(\w+\) """, re.VERBOSE) - UNICODE_RE = re.compile(r""" U[0-9A-F]{4} """, re.VERBOSE) - NON_CODE = re.compile(r""" ^[^A-Z0-9_]$ """, re.VERBOSE) def parse_uni_code(raw_code): - macro_id = "UC_" + ( - unicodedata.name(raw_code) - .replace(" ", "_") - .replace("-", "_") - ) + macro_id = "UC_" + (unicodedata.name(raw_code).replace(" ", "_").replace("-", "_")) code = "M({})".format(macro_id) uc_hex = "{:04X}".format(ord(raw_code)) return code, macro_id, uc_hex @@ -407,19 +401,13 @@ def parse_code(raw_code, key_prefixes, valid_keycodes): def parse_keymap(config, key_indexes, layer_lines, valid_keycodes): keymap = {} - raw_codes = list(iter_raw_codes( - layer_lines, config['filler'], config['separator'] - )) + raw_codes = list(iter_raw_codes(layer_lines, config['filler'], config['separator'])) indexed_codes = iter_indexed_codes(raw_codes, key_indexes) key_prefixes = config['key_prefixes'] for raw_code, key_index, row_index in indexed_codes: - code, macro_id, uc_hex = parse_code( - raw_code, key_prefixes, valid_keycodes - ) + code, macro_id, uc_hex = parse_code(raw_code, key_prefixes, valid_keycodes) # TODO: line numbers for invalid codes - err_msg = "Could not parse key '{}' on row {}".format( - raw_code, row_index - ) + err_msg = "Could not parse key '{}' on row {}".format(raw_code, row_index) assert code is not None, err_msg # print(repr(raw_code), repr(code), macro_id, uc_hex) if macro_id: @@ -432,17 +420,14 @@ def parse_keymap(config, key_indexes, layer_lines, valid_keycodes): def parse_keymaps(config, valid_keycodes): keymaps = collections.OrderedDict() - key_indexes = config.get( - 'key_indexes', KEYBOARD_LAYOUTS[config['layout']] - ) + key_indexes = config.get('key_indexes', KEYBOARD_LAYOUTS[config['layout']]) # TODO: maybe validate key_indexes for layer_name, layer_lines, in config['layer_lines'].items(): - keymaps[layer_name] = parse_keymap( - config, key_indexes, layer_lines, valid_keycodes - ) + keymaps[layer_name] = parse_keymap(config, key_indexes, layer_lines, valid_keycodes) return keymaps + # keymap.c output USERCODE = """ @@ -453,7 +438,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -572,7 +557,6 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {{ }}; """ - UNICODE_MACRO_TEMPLATE = """ case {macro_id}: unicode_action_function(0x{hi:02x}, 0x{lo:02x}); @@ -584,9 +568,7 @@ def unicode_macro_cases(config): for macro_id, uc_hex in config['unicode_macros'].items(): hi = int(uc_hex, 16) >> 8 lo = int(uc_hex, 16) & 0xFF - yield UNICODE_MACRO_TEMPLATE.format( - macro_id=macro_id, hi=hi, lo=lo - ) + yield UNICODE_MACRO_TEMPLATE.format(macro_id=macro_id, hi=hi, lo=lo) def iter_keymap_lines(keymap, row_indents=None): diff --git a/layouts/community/ergodox/german-manuneo/keymap.c b/layouts/community/ergodox/german-manuneo/keymap.c index 9b24df83db..b6217800c3 100644 --- a/layouts/community/ergodox/german-manuneo/keymap.c +++ b/layouts/community/ergodox/german-manuneo/keymap.c @@ -741,7 +741,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/german/keymap.c b/layouts/community/ergodox/german/keymap.c index 99dda5185c..150aaf3a73 100644 --- a/layouts/community/ergodox/german/keymap.c +++ b/layouts/community/ergodox/german/keymap.c @@ -140,7 +140,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/haegin/keymap.c b/layouts/community/ergodox/haegin/keymap.c index c3c2afecb8..cf5db6333b 100644 --- a/layouts/community/ergodox/haegin/keymap.c +++ b/layouts/community/ergodox/haegin/keymap.c @@ -226,7 +226,7 @@ qk_tap_dance_action_t tap_dance_actions[] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/ishigoya-jp/keymap.c b/layouts/community/ergodox/ishigoya-jp/keymap.c index e9d89d1bbc..8fe2b7e415 100644 --- a/layouts/community/ergodox/ishigoya-jp/keymap.c +++ b/layouts/community/ergodox/ishigoya-jp/keymap.c @@ -109,7 +109,7 @@ static uint16_t start; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* Keymap 0: Basic layer * - * + * * ,----------------------------------------------------. ,--------------------------------------------------. * | En / 和 | | ^ | % | | |Selall| | Undo | | $ | @ | LT | UP | RT | * |----------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| @@ -129,9 +129,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * | | | Num | | Esc | | | * `--------------------' `----------------------' * - * + * * tmux prefix set to C-b - * + * */ // If it accepts an argument (i.e, is a function), it doesn't need KC_. // Otherwise, it needs KC_* @@ -175,9 +175,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * | shift| fn |------| |------| |kazari| * | | | Num | | | | | * `--------------------' `--------------------' - * - * - * + * + * + * */ [JP] = LAYOUT_ergodox( KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, @@ -218,14 +218,14 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * | | |------| |------| | | * | | | | | | | | * `--------------------' `--------------------' - * - * - * + * + * + * */ [JPXON] = LAYOUT_ergodox( KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, M(JPXE), KC_NO, M(JPXKE), KC_NO, KC_NO, - KC_NO, KC_NO, KC_NO, M(JPXKA), KC_NO, KC_NO, + KC_NO, KC_NO, KC_NO, M(JPXKA), KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, @@ -261,14 +261,14 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * | | |------| |------| | | * | | | | | | | | * `--------------------' `--------------------' - * - * - * + * + * + * */ [JPKAZARI] = LAYOUT_ergodox( KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, M(JPGO), M(JPZA), M(JPBE), M(JPGE), KC_NO, - KC_NO, M(JPDO), M(JPJI), M(JPGA), M(JPGI), M(JPZU), + KC_NO, M(JPDO), M(JPJI), M(JPGA), M(JPGI), M(JPZU), KC_NO, KC_NO, M(JPZO), M(JPBI), M(JPDI), KC_NO, KC_NO, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, @@ -304,14 +304,14 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * | | |------| |------| | | * | | | | | | | | * `--------------------' `--------------------' - * - * - * + * + * + * */ [JPTOPROW] = LAYOUT_ergodox( KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_E, KC_MINS, M(JPRE), KC_NO, KC_NO, - KC_NO, M(JPRA), M(JPRI), M(JPNA), M(JPNO), M(JPMI), + KC_NO, M(JPRA), M(JPRI), M(JPNA), M(JPNO), M(JPMI), KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, @@ -348,14 +348,14 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * | | |------| |------| | | * | | | | | | | | * `--------------------' `--------------------' - * - * - * + * + * + * */ [JPTRKZ] = LAYOUT_ergodox( KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, M(JPPE),KC_NO, KC_NO, - KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, + KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, M(JPPI), KC_NO, KC_NO, KC_NO, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, @@ -397,7 +397,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // left hand KC_NO, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_NO, KC_NO, KC_NO, KC_NO, JP_DQUO, KC_RBRACKET, KC_BSPC, KC_SCLN, - KC_NO, KC_NO, KC_SLSH, JP_PLUS, LSFT(KC_RBRACKET), JP_RCBR, + KC_NO, KC_NO, KC_SLSH, JP_PLUS, LSFT(KC_RBRACKET), JP_RCBR, KC_NO, KC_NO, JP_ASTR, KC_MINS, LSFT(KC_8), LSFT(KC_9), JP_COLN, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_HASH, KC_NO, KC_NO, @@ -417,7 +417,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { - + // MACRO only works in this function switch(id) { case 0: @@ -445,9 +445,9 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) } } break; - + // kana macros start here - + case JPVU: if (record->event.pressed) { return MACRO( I(1), T(V), T(U), END); @@ -641,7 +641,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) case JPDI: if (record->event.pressed) { return MACRO( I(1), T(D), T(I), END); - } + } break; case JPZE: if (record->event.pressed) { @@ -838,9 +838,9 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) return MACRO( I(1), T(B), T(U), END); } break; - + // kana macros end here - + break; case SHIFT: if (record->event.pressed) { @@ -848,8 +848,8 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) if (layer_state == (1<event.pressed) { start = timer_read(); @@ -917,7 +917,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) break; */ } - return MACRO_NONE; + return MACRO_NONE; }; // Runs just one time when the keyboard initializes. @@ -927,15 +927,15 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); - uint8_t deflayer = biton32(default_layer_state); + uint8_t layer = get_highest_layer(layer_state); + uint8_t deflayer = get_highest_layer(default_layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); ergodox_right_led_2_off(); ergodox_right_led_3_off(); - - + + switch (layer) { case 0: //none diff --git a/layouts/community/ergodox/issmirnov/keymap.c b/layouts/community/ergodox/issmirnov/keymap.c index b129148b08..2743a04e93 100644 --- a/layouts/community/ergodox/issmirnov/keymap.c +++ b/layouts/community/ergodox/issmirnov/keymap.c @@ -125,7 +125,7 @@ _______, _______, KC_LGUI // called by QMK during key processing before the actual key event is handled. Useful for macros. bool process_record_user(uint16_t keycode, keyrecord_t *record) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (keycode) { case TAP_TOG_LAYER: process_tap_tog(_SYMB,record); @@ -157,7 +157,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { // Runs constantly in the background, in a loop every 100ms or so. // Best used for LED status output triggered when user isn't actively typing. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); if (layer == 0) { // Set up LED indicators for stuck modifier keys. // https://github.com/qmk/qmk_firmware/blob/master/tmk_core/common/report.h#L118 @@ -202,7 +202,7 @@ void matrix_scan_user(void) { // only runs when when the layer is changed, good for updating LED's and clearing sticky state layer_state_t layer_state_set_user(layer_state_t state) { - uint8_t layer = biton32(state); + uint8_t layer = get_highest_layer(state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/italian/keymap.c b/layouts/community/ergodox/italian/keymap.c index 64dd51db67..3a81cc213b 100644 --- a/layouts/community/ergodox/italian/keymap.c +++ b/layouts/community/ergodox/italian/keymap.c @@ -43,7 +43,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_ESC, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, TT(SYMB), KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, - KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_LALT, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_LALT, MT(MOD_LGUI,KC_NONUS_BSLASH),KC_PPLS, KC_PMNS,KC_PAST,MT(MOD_LCTL,KC_PSLS), KC_INS, KC_LGUI, KC_HOME, @@ -197,7 +197,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/j3rn/keymap.c b/layouts/community/ergodox/j3rn/keymap.c index 5081ddf527..8ff8db2381 100644 --- a/layouts/community/ergodox/j3rn/keymap.c +++ b/layouts/community/ergodox/j3rn/keymap.c @@ -141,7 +141,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/jackhumbert/keymap.c b/layouts/community/ergodox/jackhumbert/keymap.c index 9d357881e2..b6d1b33e33 100644 --- a/layouts/community/ergodox/jackhumbert/keymap.c +++ b/layouts/community/ergodox/jackhumbert/keymap.c @@ -23,7 +23,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_NO, RGB_TOG, RGB_MOD, RGB_HUI, RGB_HUD, KC_P, KC_BSPC, RGB_SAI, RGB_SAD, RGB_VAI, RGB_VAD, KC_SCLN, KC_QUOT, KC_NO, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_ENT, - MO(1), KC_LEFT,KC_DOWN,KC_UP, KC_RGHT, + MO(1), KC_LEFT,KC_DOWN,KC_UP, KC_RGHT, RGB_TOG, RGB_HUI, RGB_MOD, M(2), KC_SPC,KC_SPC @@ -32,7 +32,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // left hand KC_TRNS,KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_TRNS, - KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS,KC_TRNS, @@ -43,7 +43,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS, KC_TRNS, KC_F12, KC_NO, KC_NO, KC_NO, RESET, KC_TRNS, - KC_TRNS, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY, + KC_TRNS, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS @@ -51,9 +51,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [MDIA] = LAYOUT_ergodox( KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_TRNS, - KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, @@ -62,7 +62,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE, KC_TRNS, KC_F12, KC_NO, KC_NO, KC_NO, RESET, KC_TRNS, - KC_TRNS, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY, + KC_TRNS, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS @@ -97,7 +97,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/jacobono/keymap.c b/layouts/community/ergodox/jacobono/keymap.c index e97209fc84..7c5b914872 100644 --- a/layouts/community/ergodox/jacobono/keymap.c +++ b/layouts/community/ergodox/jacobono/keymap.c @@ -227,7 +227,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/jafo/keymap.c b/layouts/community/ergodox/jafo/keymap.c index b8b8e63517..28c95d6540 100644 --- a/layouts/community/ergodox/jafo/keymap.c +++ b/layouts/community/ergodox/jafo/keymap.c @@ -139,7 +139,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/jgarr/keymap.c b/layouts/community/ergodox/jgarr/keymap.c index ac4e562263..38eaa5fca0 100644 --- a/layouts/community/ergodox/jgarr/keymap.c +++ b/layouts/community/ergodox/jgarr/keymap.c @@ -138,7 +138,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/josh/keymap.c b/layouts/community/ergodox/josh/keymap.c index 07ee97ec82..3f9d8779e1 100644 --- a/layouts/community/ergodox/josh/keymap.c +++ b/layouts/community/ergodox/josh/keymap.c @@ -188,7 +188,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/kastyle/keymap.c b/layouts/community/ergodox/kastyle/keymap.c index c9789955b3..268080c7dc 100644 --- a/layouts/community/ergodox/kastyle/keymap.c +++ b/layouts/community/ergodox/kastyle/keymap.c @@ -1,5 +1,5 @@ /* Setup to approximate a Kinesis Advantage with an eye to use in a - * Mac/OSX environment + * Mac/OSX environment * This version adds a hand swap feature to flip the keyboard */ #include QMK_KEYBOARD_H #include "debug.h" @@ -143,7 +143,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/kejadlen/keymap.c b/layouts/community/ergodox/kejadlen/keymap.c index 6ce209f806..92a667dec0 100644 --- a/layouts/community/ergodox/kejadlen/keymap.c +++ b/layouts/community/ergodox/kejadlen/keymap.c @@ -74,7 +74,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/kines-ish/keymap.c b/layouts/community/ergodox/kines-ish/keymap.c index 2d1513667f..718bf6cee1 100644 --- a/layouts/community/ergodox/kines-ish/keymap.c +++ b/layouts/community/ergodox/kines-ish/keymap.c @@ -138,7 +138,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/kristian/keymap.c b/layouts/community/ergodox/kristian/keymap.c index 3fdccb790a..3f84823b99 100644 --- a/layouts/community/ergodox/kristian/keymap.c +++ b/layouts/community/ergodox/kristian/keymap.c @@ -35,7 +35,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/maz/keymap.c b/layouts/community/ergodox/maz/keymap.c index 3244f2152d..4d313dee43 100644 --- a/layouts/community/ergodox/maz/keymap.c +++ b/layouts/community/ergodox/maz/keymap.c @@ -183,7 +183,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/mclennon_osx/keymap.c b/layouts/community/ergodox/mclennon_osx/keymap.c index 72e9d505a1..ae67d8fb40 100644 --- a/layouts/community/ergodox/mclennon_osx/keymap.c +++ b/layouts/community/ergodox/mclennon_osx/keymap.c @@ -98,7 +98,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/meagerfindings/keymap.c b/layouts/community/ergodox/meagerfindings/keymap.c index f4340b8e1b..c780c1a9fb 100644 --- a/layouts/community/ergodox/meagerfindings/keymap.c +++ b/layouts/community/ergodox/meagerfindings/keymap.c @@ -538,7 +538,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { }; void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/msc/keymap.c b/layouts/community/ergodox/msc/keymap.c index 5d9de3239b..62d18798dd 100644 --- a/layouts/community/ergodox/msc/keymap.c +++ b/layouts/community/ergodox/msc/keymap.c @@ -138,7 +138,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/naps62/keymap.c b/layouts/community/ergodox/naps62/keymap.c index 230b3376b2..fe6289097b 100644 --- a/layouts/community/ergodox/naps62/keymap.c +++ b/layouts/community/ergodox/naps62/keymap.c @@ -141,7 +141,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/neo2_on_qwertz_hardware/keymap.c b/layouts/community/ergodox/neo2_on_qwertz_hardware/keymap.c index 7c91b3fbb0..7c57820c43 100644 --- a/layouts/community/ergodox/neo2_on_qwertz_hardware/keymap.c +++ b/layouts/community/ergodox/neo2_on_qwertz_hardware/keymap.c @@ -5,7 +5,7 @@ #define UM 0 #define L0 0 // layer_0 -#define L1 1 // layer_1 +#define L1 1 // layer_1 #define L2 2 // layer_2 #define L3 3 // layer_3 #define L4 4 // layer_4 @@ -344,7 +344,7 @@ void unicode_action_function(uint16_t hi, uint16_t lo) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/osx_de/keymap.c b/layouts/community/ergodox/osx_de/keymap.c index 5c3d7e49ea..cbbfc42280 100644 --- a/layouts/community/ergodox/osx_de/keymap.c +++ b/layouts/community/ergodox/osx_de/keymap.c @@ -31,117 +31,117 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [BASE]=LAYOUT_ergodox( //left half - KC_ESC, DE_1, DE_2, DE_3, DE_4, DE_5, M(M_CTL_SFT_HASH), - KC_TAB, DE_Q, DE_W, DE_E, DE_R, DE_T, KC_LGUI, - KC_LALT, DE_A, DE_S, DE_D, DE_F, DE_G, - KC_LSFT, CTL_T(DE_Y), DE_X, DE_C, DE_V, DE_B, KC_LALT, - LT(SYMB,DE_LABK), M(M_DE_CIRC_CTRLCMD), M(M_DE_PLUS_CTRLALT), KC_UP, KC_DOWN, - M(M_MEH_SH_ACUT), TG(MDIA), - KC_HOME, - KC_BSPC, KC_DEL, LT(SMLY,KC_END), + KC_ESC, DE_1, DE_2, DE_3, DE_4, DE_5, M(M_CTL_SFT_HASH), + KC_TAB, DE_Q, DE_W, DE_E, DE_R, DE_T, KC_LGUI, + KC_LALT, DE_A, DE_S, DE_D, DE_F, DE_G, + KC_LSFT, CTL_T(DE_Y), DE_X, DE_C, DE_V, DE_B, KC_LALT, + LT(SYMB,DE_LABK), M(M_DE_CIRC_CTRLCMD), M(M_DE_PLUS_CTRLALT), KC_UP, KC_DOWN, + M(M_MEH_SH_ACUT), TG(MDIA), + KC_HOME, + KC_BSPC, KC_DEL, LT(SMLY,KC_END), //right half - M(M_CTL_SFT_HASH), DE_6, DE_7, DE_8, DE_9, DE_0, DE_SS, - KC_RGUI, DE_Z, DE_U, DE_I, DE_O, DE_P, DE_UDIA, - DE_H, DE_J, DE_K, DE_L, DE_ODIA, ALT_T(DE_ADIA), - KC_RALT, DE_N, DE_M, DE_COMM, DE_DOT, CTL_T(DE_MINS), KC_RSFT, - KC_LEFT, KC_RIGHT, LGUI(KC_LSFT), LALT(KC_LSFT), LT(SYMB,DE_PLUS), - TG(NUMB), ALL_T(DE_ACUT), - KC_PGUP, + M(M_CTL_SFT_HASH), DE_6, DE_7, DE_8, DE_9, DE_0, DE_SS, + KC_RGUI, DE_Z, DE_U, DE_I, DE_O, DE_P, DE_UDIA, + DE_H, DE_J, DE_K, DE_L, DE_ODIA, ALT_T(DE_ADIA), + KC_RALT, DE_N, DE_M, DE_COMM, DE_DOT, CTL_T(DE_MINS), KC_RSFT, + KC_LEFT, KC_RIGHT, LGUI(KC_LSFT), LALT(KC_LSFT), LT(SYMB,DE_PLUS), + TG(NUMB), ALL_T(DE_ACUT), + KC_PGUP, KC_PGDN, KC_ENT, KC_SPC), [SYMB]=LAYOUT_ergodox( //left half - KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, - KC_TRNS, DE_LABK, DE_RABK, DE_EXLM, DE_QUES, KC_TRNS, KC_TRNS, - KC_TRNS, DE_HASH, DE_DLR, DE_BSLS, DE_SLSH, KC_DOT, - KC_TRNS, KC_TRNS, DE_LABK, DE_PERC, DE_PIPE, DE_TILD, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_DEL, KC_TRNS, + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, + KC_TRNS, DE_LABK, DE_RABK, DE_EXLM, DE_QUES, KC_TRNS, KC_TRNS, + KC_TRNS, DE_HASH, DE_DLR, DE_BSLS, DE_SLSH, KC_DOT, + KC_TRNS, KC_TRNS, DE_LABK, DE_PERC, DE_PIPE, DE_TILD, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_DEL, KC_TRNS, //right half - M(M_TOGGLE_5), KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, - KC_TRNS, LALT(LSFT(KC_7)), LALT(KC_5), LALT(KC_6), DE_LABK, DE_RABK, DE_EXLM, - DE_SLSH, DE_LPRN, DE_RPRN, LALT(KC_8), LALT(KC_9), DE_HASH, - KC_TRNS, DE_PIPE, DE_TILD, DE_CIRC, KC_UP, DE_MINS, LSFT(KC_4), - DE_QUOT, KC_LEFT, KC_DOWN, KC_RIGHT, KC_TRNS, - KC_F13, KC_F12, - KC_F14, + M(M_TOGGLE_5), KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, + KC_TRNS, LALT(LSFT(KC_7)), LALT(KC_5), LALT(KC_6), DE_LABK, DE_RABK, DE_EXLM, + DE_SLSH, DE_LPRN, DE_RPRN, LALT(KC_8), LALT(KC_9), DE_HASH, + KC_TRNS, DE_PIPE, DE_TILD, DE_CIRC, KC_UP, DE_MINS, LSFT(KC_4), + DE_QUOT, KC_LEFT, KC_DOWN, KC_RIGHT, KC_TRNS, + KC_F13, KC_F12, + KC_F14, KC_F15, KC_TRNS, KC_TRNS), [MDIA]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_BTN1, KC_MS_U, KC_BTN2, KC_WH_U, KC_TRNS, - KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_WH_D, - KC_TRNS, KC_TRNS, KC_WH_L, KC_WH_D, KC_WH_R, KC_BTN3, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_BTN1, KC_MS_U, KC_BTN2, KC_WH_U, KC_TRNS, + KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_WH_D, + KC_TRNS, KC_TRNS, KC_WH_L, KC_WH_D, KC_WH_R, KC_BTN3, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - KC_MUTE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MPLY, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_VOLU, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_VOLD, KC_TRNS, KC_MPRV, KC_MNXT, KC_UP, KC_TRNS, - KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RIGHT, - KC_TRNS, KC_TRNS, - KC_TRNS, + KC_MUTE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MPLY, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_VOLU, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_VOLD, KC_TRNS, KC_MPRV, KC_MNXT, KC_UP, KC_TRNS, + KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RIGHT, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_WBAK), [SMLY]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - M(SM_SMILE), M(SM_SMIRK), M(SM_LAUGH), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, M(SM_FROWN), M(SM_SAD), M(SM_CRY), KC_TRNS, KC_TRNS, KC_TRNS, - M(SM_HEART), M(SM_KISS), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + M(SM_SMILE), M(SM_SMIRK), M(SM_LAUGH), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, M(SM_FROWN), M(SM_SAD), M(SM_CRY), KC_TRNS, KC_TRNS, KC_TRNS, + M(SM_HEART), M(SM_KISS), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), [NUMB]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, - KC_TRNS, KC_UP, KC_7, KC_8, KC_9, LSFT(KC_RBRC), KC_F12, - KC_DOWN, KC_4, KC_5, KC_6, KC_RBRC, DE_MINS, - KC_TRNS, LSFT(KC_6), KC_1, KC_2, KC_3, LSFT(KC_7), KC_TRNS, - KC_0, KC_DOT, KC_COMM, DE_EQL, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, + KC_TRNS, KC_UP, KC_7, KC_8, KC_9, LSFT(KC_RBRC), KC_F12, + KC_DOWN, KC_4, KC_5, KC_6, KC_RBRC, DE_MINS, + KC_TRNS, LSFT(KC_6), KC_1, KC_2, KC_3, LSFT(KC_7), KC_TRNS, + KC_0, KC_DOT, KC_COMM, DE_EQL, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), [EGOS]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_LSFT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_LCTL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_F1, KC_F2, - KC_F3, - KC_SPC, KC_LCTL, KC_F4, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_LSFT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_LCTL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_F1, KC_F2, + KC_F3, + KC_SPC, KC_LCTL, KC_F4, //right half - M(M_TOGGLE_5), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + M(M_TOGGLE_5), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), }; @@ -318,7 +318,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { -uint8_t layer = biton32(layer_state); +uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -328,22 +328,22 @@ switch (layer) { case SYMB: ergodox_right_led_1_on(); - - + + break; case MDIA: - + ergodox_right_led_2_on(); - + break; case SMLY: - - + + ergodox_right_led_3_on(); break; case NUMB: ergodox_right_led_1_on(); - + ergodox_right_led_3_on(); break; case EGOS: @@ -357,4 +357,3 @@ break; } }; - diff --git a/layouts/community/ergodox/osx_de_adnw_koy/keymap.c b/layouts/community/ergodox/osx_de_adnw_koy/keymap.c index b8ffc2e51f..cd09d066a6 100644 --- a/layouts/community/ergodox/osx_de_adnw_koy/keymap.c +++ b/layouts/community/ergodox/osx_de_adnw_koy/keymap.c @@ -27,105 +27,105 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [BASE]=LAYOUT_ergodox( //left half - KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LCTL, - KC_TAB, KC_K, KC_DOT, KC_O, KC_COMM, KC_Z, KC_LGUI, - TG(QWERTZ), KC_H, KC_A, KC_E, KC_I, KC_U, - KC_LSFT, CTL_T(KC_X), KC_Q, DE_ADIA, DE_UDIA, DE_ODIA, KC_LALT, - LT(SYMB,KC_GRV), DE_LABK, LALT(KC_LSFT), KC_LEFT, KC_RGHT, - TG(MDIA), MEH_T(LSFT(DE_ACUT)), - KC_HOME, - KC_BSPC, KC_DEL, KC_END, + KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LCTL, + KC_TAB, KC_K, KC_DOT, KC_O, KC_COMM, KC_Z, KC_LGUI, + TG(QWERTZ), KC_H, KC_A, KC_E, KC_I, KC_U, + KC_LSFT, CTL_T(KC_X), KC_Q, DE_ADIA, DE_UDIA, DE_ODIA, KC_LALT, + LT(SYMB,KC_GRV), DE_LABK, LALT(KC_LSFT), KC_LEFT, KC_RGHT, + TG(MDIA), MEH_T(LSFT(DE_ACUT)), + KC_HOME, + KC_BSPC, KC_DEL, KC_END, //right half - KC_RCTL, KC_6, KC_7, KC_8, KC_9, KC_0, DE_MINS, - KC_RGUI, KC_V, KC_G, KC_C, KC_L, KC_MINS, KC_Y, - KC_D, KC_T, KC_R, KC_N, KC_S, LT(MDIA,KC_F), - KC_RALT, KC_B, KC_P, KC_W, KC_M, CTL_T(KC_J), KC_RSFT, - KC_UP, KC_DOWN, LGUI(KC_LSFT), KC_RBRC, LT(SYMB,KC_BSLS), - ALL_T(DE_ACUT), TG(NUMB), - KC_PGUP, + KC_RCTL, KC_6, KC_7, KC_8, KC_9, KC_0, DE_MINS, + KC_RGUI, KC_V, KC_G, KC_C, KC_L, KC_MINS, KC_Y, + KC_D, KC_T, KC_R, KC_N, KC_S, LT(MDIA,KC_F), + KC_RALT, KC_B, KC_P, KC_W, KC_M, CTL_T(KC_J), KC_RSFT, + KC_UP, KC_DOWN, LGUI(KC_LSFT), KC_RBRC, LT(SYMB,KC_BSLS), + ALL_T(DE_ACUT), TG(NUMB), + KC_PGUP, KC_PGDN, KC_ENT, KC_SPC), [SYMB]=LAYOUT_ergodox( //left half - KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, - KC_TRNS, KC_GRV, LSFT(KC_GRV), DE_EXLM, DE_QUES, KC_TRNS, KC_TRNS, - KC_TRNS, DE_HASH, DE_DLR, LALT(LSFT(KC_7)), DE_SLSH, KC_DOT, - KC_TRNS, KC_TRNS, DE_LABK, DE_PERC, LALT(KC_7), LALT(KC_N), KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_DEL, KC_TRNS, + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, + KC_TRNS, KC_GRV, LSFT(KC_GRV), DE_EXLM, DE_QUES, KC_TRNS, KC_TRNS, + KC_TRNS, DE_HASH, DE_DLR, LALT(LSFT(KC_7)), DE_SLSH, KC_DOT, + KC_TRNS, KC_TRNS, DE_LABK, DE_PERC, LALT(KC_7), LALT(KC_N), KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_DEL, KC_TRNS, //right half - KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, - KC_TRNS, LALT(LSFT(KC_7)), LALT(KC_5), LALT(KC_6), LALT(KC_7), DE_HASH, KC_F12, - DE_SLSH, DE_LPRN, DE_RPRN, LALT(KC_8), LALT(KC_9), KC_TRNS, - KC_TRNS, DE_AMPR, KC_GRV, LSFT(KC_GRV), DE_DQUO, DE_QUOT, DE_QUES, - KC_TRNS, KC_DOT, KC_EXLM, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, + KC_TRNS, LALT(LSFT(KC_7)), LALT(KC_5), LALT(KC_6), LALT(KC_7), DE_HASH, KC_F12, + DE_SLSH, DE_LPRN, DE_RPRN, LALT(KC_8), LALT(KC_9), KC_TRNS, + KC_TRNS, DE_AMPR, KC_GRV, LSFT(KC_GRV), DE_DQUO, DE_QUOT, DE_QUES, + KC_TRNS, KC_DOT, KC_EXLM, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), [MDIA]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_U, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_TRNS, - KC_TRNS, KC_WH_L, KC_WH_U, KC_WH_D, KC_WH_R, KC_BTN3, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN1, KC_BTN2, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_U, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_TRNS, + KC_TRNS, KC_WH_L, KC_WH_U, KC_WH_D, KC_WH_R, KC_BTN3, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN1, KC_BTN2, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MPLY, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_MUTE, KC_MPRV, KC_MNXT, KC_UP, KC_TRNS, - KC_VOLU, KC_VOLD, KC_LEFT, KC_DOWN, KC_RIGHT, - KC_TRNS, KC_TRNS, - KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MPLY, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_MUTE, KC_MPRV, KC_MNXT, KC_UP, KC_TRNS, + KC_VOLU, KC_VOLD, KC_LEFT, KC_DOWN, KC_RIGHT, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_WBAK), [QWERTZ]=LAYOUT_ergodox( //left half - KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, LGUI(KC_V), - KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_LGUI, - KC_TRNS, KC_A, KC_S, KC_D, KC_F, KC_G, - KC_LSFT, CTL_T(KC_Z), KC_X, KC_C, KC_V, KC_B, KC_LALT, - LT(SYMB,KC_GRV), DE_LABK, LALT(KC_LSFT), KC_LEFT, KC_RGHT, - KC_TRNS, MEH_T(LSFT(DE_ACUT)), - KC_HOME, - KC_BSPC, KC_DEL, KC_END, + KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, LGUI(KC_V), + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_LGUI, + KC_TRNS, KC_A, KC_S, KC_D, KC_F, KC_G, + KC_LSFT, CTL_T(KC_Z), KC_X, KC_C, KC_V, KC_B, KC_LALT, + LT(SYMB,KC_GRV), DE_LABK, LALT(KC_LSFT), KC_LEFT, KC_RGHT, + KC_TRNS, MEH_T(LSFT(DE_ACUT)), + KC_HOME, + KC_BSPC, KC_DEL, KC_END, //right half - LGUI(KC_C), KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, - KC_RGUI, KC_Y, KC_U, KC_I, KC_O, KC_P, DE_UDIA, - KC_H, KC_J, KC_K, KC_L, KC_SCLN, LT(MDIA,DE_ADIA), - KC_RALT, KC_N, KC_M, KC_COMM, KC_DOT, CTL_T(KC_SLSH), KC_RSFT, - KC_UP, KC_DOWN, LGUI(KC_LSFT), KC_RBRC, LT(SYMB,KC_BSLS), - ALL_T(DE_ACUT), KC_TRNS, - KC_PGUP, + LGUI(KC_C), KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, + KC_RGUI, KC_Y, KC_U, KC_I, KC_O, KC_P, DE_UDIA, + KC_H, KC_J, KC_K, KC_L, KC_SCLN, LT(MDIA,DE_ADIA), + KC_RALT, KC_N, KC_M, KC_COMM, KC_DOT, CTL_T(KC_SLSH), KC_RSFT, + KC_UP, KC_DOWN, LGUI(KC_LSFT), KC_RBRC, LT(SYMB,KC_BSLS), + ALL_T(DE_ACUT), KC_TRNS, + KC_PGUP, KC_PGDN, KC_ENT, KC_SPC), [NUMB]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, - KC_TRNS, KC_UP, KC_7, KC_8, KC_9, LSFT(KC_RBRC), KC_F12, - KC_DOWN, KC_4, KC_5, KC_6, KC_RBRC, KC_TRNS, - KC_TRNS, LSFT(KC_6), KC_1, KC_2, KC_3, LSFT(KC_7), KC_TRNS, - KC_0, KC_DOT, KC_0, KC_EQL, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, + KC_TRNS, KC_UP, KC_7, KC_8, KC_9, LSFT(KC_RBRC), KC_F12, + KC_DOWN, KC_4, KC_5, KC_6, KC_RBRC, KC_TRNS, + KC_TRNS, LSFT(KC_6), KC_1, KC_2, KC_3, LSFT(KC_7), KC_TRNS, + KC_0, KC_DOT, KC_0, KC_EQL, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), }; // Runs constantly in the background, in a loop. void matrix_scan_user(void) { -uint8_t layer = biton32(layer_state); +uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -139,4 +139,3 @@ break; } }; - diff --git a/layouts/community/ergodox/osx_de_experimental/keymap.c b/layouts/community/ergodox/osx_de_experimental/keymap.c index 8228b5e371..faf238726f 100644 --- a/layouts/community/ergodox/osx_de_experimental/keymap.c +++ b/layouts/community/ergodox/osx_de_experimental/keymap.c @@ -66,315 +66,315 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /** * Layer: BASE -* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ -* | ESC | 1 | 2 | 3 | 4 | 5 | Hold or toggle | | Hold or toggle | 6 | 7 | 8 | 9 | 0 | ß | -* | | | | | | | Layer NUMB | | Layer MDIA | | | | | | | -* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ -* | TAB | Q | W | E | R | T | Cmd | | Cmd | Z | U | I | O | P | Ü | -* | | | | | | | | | | | | | | | | -* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/\-------------------\ \-------------------\/-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ -* | Alt | A | S | D | F | G | | H | J | K | L | Ö | Ä | -* | | | | | | | | | | | | | ALT | -* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ -* | Shift | Y | X | C | V | B | Alt | | Alt | N | M | , | . | - | Shift | -* | | Ctrl | | | | | | | | | | | | Ctrl | | -* \-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\ \-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\ -* -* -* /-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------/ -* | < | LongPress / Type | LongPress / Type | Shift+Ctrl | Type | | # | ACUT | CMD+Shift | ALT+Shift | + | -* | SYMB | DE_CIRC_CTRLCMD | DE_PLUS_CTRAlt | | Toggle SMLY | | Meh | Hyper | | | SYMB | -* \-------------------\\-------------------\\-------------------\\-------------------\/-------------------//-------------------/ /-------------------//-------------------/ \-------------------\\-------------------\\-------------------\\-------------------\\-------------------\ -* | HOME | END | | LEFT | RIGHT | -* | | | | | | -* \-------------------\/-------------------/ /-------------------/\-------------------\ -* | PGUP | | UP | -* | | | | -* /-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------/ -* | BSPC | DEL | PGDN | | DOWN | ENT | SPC | -* | | | | | | | | -* \-------------------\\-------------------\\-------------------\ \-------------------\\-------------------\\-------------------\ -* -* +* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ +* | ESC | 1 | 2 | 3 | 4 | 5 | Hold or toggle | | Hold or toggle | 6 | 7 | 8 | 9 | 0 | ß | +* | | | | | | | Layer NUMB | | Layer MDIA | | | | | | | +* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ +* | TAB | Q | W | E | R | T | Cmd | | Cmd | Z | U | I | O | P | Ü | +* | | | | | | | | | | | | | | | | +* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/\-------------------\ \-------------------\/-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ +* | Alt | A | S | D | F | G | | H | J | K | L | Ö | Ä | +* | | | | | | | | | | | | | ALT | +* /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------//-------------------//-------------------/ +* | Shift | Y | X | C | V | B | Alt | | Alt | N | M | , | . | - | Shift | +* | | Ctrl | | | | | | | | | | | | Ctrl | | +* \-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\ \-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\\-------------------\ +* +* +* /-------------------//-------------------//-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------//-------------------//-------------------/ +* | < | LongPress / Type | LongPress / Type | Shift+Ctrl | Type | | # | ACUT | CMD+Shift | ALT+Shift | + | +* | SYMB | DE_CIRC_CTRLCMD | DE_PLUS_CTRAlt | | Toggle SMLY | | Meh | Hyper | | | SYMB | +* \-------------------\\-------------------\\-------------------\\-------------------\/-------------------//-------------------/ /-------------------//-------------------/ \-------------------\\-------------------\\-------------------\\-------------------\\-------------------\ +* | HOME | END | | LEFT | RIGHT | +* | | | | | | +* \-------------------\/-------------------/ /-------------------/\-------------------\ +* | PGUP | | UP | +* | | | | +* /-------------------//-------------------//-------------------/ /-------------------//-------------------//-------------------/ +* | BSPC | DEL | PGDN | | DOWN | ENT | SPC | +* | | | | | | | | +* \-------------------\\-------------------\\-------------------\ \-------------------\\-------------------\\-------------------\ +* +* **/ [BASE]=LAYOUT_ergodox( //left half - KC_ESC, DE_1, DE_2, DE_3, DE_4, DE_5, M(TGH_NUM), - KC_TAB, DE_Q, DE_W, DE_E, DE_R, DE_T, KC_LGUI, - KC_LALT, DE_A, DE_S, DE_D, DE_F, DE_G, - KC_LSFT, CTL_T(DE_Y), DE_X, DE_C, DE_V, DE_B, KC_LALT, - LT(SYMB,DE_LABK), M(M_DE_CIRC_CTRLCMD), M(M_DE_PLUS_CTRLALT), LSFT(KC_LCTRL), M(SMLY_TOG_QUOT), - KC_HOME, KC_END, - KC_PGUP, - KC_BSPC, KC_DEL, KC_PGDN, + KC_ESC, DE_1, DE_2, DE_3, DE_4, DE_5, M(TGH_NUM), + KC_TAB, DE_Q, DE_W, DE_E, DE_R, DE_T, KC_LGUI, + KC_LALT, DE_A, DE_S, DE_D, DE_F, DE_G, + KC_LSFT, CTL_T(DE_Y), DE_X, DE_C, DE_V, DE_B, KC_LALT, + LT(SYMB,DE_LABK), M(M_DE_CIRC_CTRLCMD), M(M_DE_PLUS_CTRLALT), LSFT(KC_LCTRL), M(SMLY_TOG_QUOT), + KC_HOME, KC_END, + KC_PGUP, + KC_BSPC, KC_DEL, KC_PGDN, //right half - M(TOG_HLD_MDIA), DE_6, DE_7, DE_8, DE_9, DE_0, DE_SS, - KC_RGUI, DE_Z, DE_U, DE_I, DE_O, DE_P, DE_UDIA, - DE_H, DE_J, DE_K, DE_L, DE_ODIA, ALT_T(DE_ADIA), - KC_RALT, DE_N, DE_M, DE_COMM, DE_DOT, CTL_T(DE_MINS), KC_RSFT, - MEH_T(DE_HASH), ALL_T(DE_ACUT), LGUI(KC_LSFT), LALT(KC_LSFT), LT(SYMB,DE_PLUS), - KC_LEFT, KC_RIGHT, - KC_UP, + M(TOG_HLD_MDIA), DE_6, DE_7, DE_8, DE_9, DE_0, DE_SS, + KC_RGUI, DE_Z, DE_U, DE_I, DE_O, DE_P, DE_UDIA, + DE_H, DE_J, DE_K, DE_L, DE_ODIA, ALT_T(DE_ADIA), + KC_RALT, DE_N, DE_M, DE_COMM, DE_DOT, CTL_T(DE_MINS), KC_RSFT, + MEH_T(DE_HASH), ALL_T(DE_ACUT), LGUI(KC_LSFT), LALT(KC_LSFT), LT(SYMB,DE_PLUS), + KC_LEFT, KC_RIGHT, + KC_UP, KC_DOWN, KC_ENT, KC_SPC), /** * Layer: SYMB -* /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ -* | APPLICATION| F1 | F2 | F3 | F4 | F5 | F5 | | F6 | F6 | F7 | F8 | F9 | F10 | F11 | -* | | | | | | | | | | | | | | | | -* /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ -* | | < | > | ! | ? | | | | | \ | [ | ] | < | > | ! | -* | | | | | | | | | | | | | | | | -* /-----------//-----------//-----------//-----------//-----------//-----------/\-----------\ \-----------\/-----------//-----------//-----------//-----------//-----------//-----------/ -* | | # | $ | \ | / | . | | / | ( | ) | { | } | # | -* | | | | | | | | | | | | | | -* /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ -* | | | < | % | | | ~ | | | | | | ~ | | | | | -* | | | | | | | | | | | | | | | | -* \-----------\\-----------\\-----------\\-----------\\-----------\\-----------\\-----------\ \-----------\\-----------\\-----------\\-----------\\-----------\\-----------\\-----------\ -* -* -* /-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------/ -* | | | | | | | ' | DQOT | | Toggle 5 | | -* | | | | | | | | | | | | -* \-----------\\-----------\\-----------\\-----------\/-----------//-----------/ /-----------//-----------/ \-----------\\-----------\\-----------\\-----------\\-----------\ -* | | | | F13 | F12 | -* | | | | | | -* \-----------\/-----------/ /-----------/\-----------\ -* | | | F14 | -* | | | | -* /-----------//-----------//-----------/ /-----------//-----------//-----------/ -* | | DEL | | | F15 | | | -* | | | | | | | | -* \-----------\\-----------\\-----------\ \-----------\\-----------\\-----------\ -* -* +* /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ +* | APPLICATION| F1 | F2 | F3 | F4 | F5 | F5 | | F6 | F6 | F7 | F8 | F9 | F10 | F11 | +* | | | | | | | | | | | | | | | | +* /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ +* | | < | > | ! | ? | | | | | \ | [ | ] | < | > | ! | +* | | | | | | | | | | | | | | | | +* /-----------//-----------//-----------//-----------//-----------//-----------/\-----------\ \-----------\/-----------//-----------//-----------//-----------//-----------//-----------/ +* | | # | $ | \ | / | . | | / | ( | ) | { | } | # | +* | | | | | | | | | | | | | | +* /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------//-----------//-----------/ +* | | | < | % | | | ~ | | | | | | ~ | | | | | +* | | | | | | | | | | | | | | | | +* \-----------\\-----------\\-----------\\-----------\\-----------\\-----------\\-----------\ \-----------\\-----------\\-----------\\-----------\\-----------\\-----------\\-----------\ +* +* +* /-----------//-----------//-----------//-----------//-----------/ /-----------//-----------//-----------//-----------//-----------/ +* | | | | | | | ' | DQOT | | Toggle 5 | | +* | | | | | | | | | | | | +* \-----------\\-----------\\-----------\\-----------\/-----------//-----------/ /-----------//-----------/ \-----------\\-----------\\-----------\\-----------\\-----------\ +* | | | | F13 | F12 | +* | | | | | | +* \-----------\/-----------/ /-----------/\-----------\ +* | | | F14 | +* | | | | +* /-----------//-----------//-----------/ /-----------//-----------//-----------/ +* | | DEL | | | F15 | | | +* | | | | | | | | +* \-----------\\-----------\\-----------\ \-----------\\-----------\\-----------\ +* +* **/ [SYMB]=LAYOUT_ergodox( //left half - KC_APPLICATION, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F5, - KC_TRNS, DE_LABK, DE_RABK, DE_EXLM, DE_QST, KC_TRNS, KC_TRNS, - KC_TRNS, DE_HASH, DE_DLR, DE_BSLS, DE_SLSH, KC_DOT, - KC_TRNS, KC_TRNS, DE_LABK, DE_PERC, DE_PIPE, DE_TILD, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_DEL, KC_TRNS, + KC_APPLICATION, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F5, + KC_TRNS, DE_LABK, DE_RABK, DE_EXLM, DE_QST, KC_TRNS, KC_TRNS, + KC_TRNS, DE_HASH, DE_DLR, DE_BSLS, DE_SLSH, KC_DOT, + KC_TRNS, KC_TRNS, DE_LABK, DE_PERC, DE_PIPE, DE_TILD, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_DEL, KC_TRNS, //right half - KC_F6, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, - KC_TRNS, DE_BSLS, DE_LBRC, DE_RBRC, DE_LABK, DE_RABK, DE_EXLM, - DE_SLSH, DE_LPRN, DE_RPRN, DE_LCBR, DE_RCBR, DE_HASH, - KC_TRNS, DE_PIPE, DE_TILD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - DE_QUOT, DE_DQUO, KC_TRNS, M(M_TOGGLE_5), KC_TRNS, - KC_F13, KC_F12, - KC_F14, + KC_F6, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, + KC_TRNS, DE_BSLS, DE_LBRC, DE_RBRC, DE_LABK, DE_RABK, DE_EXLM, + DE_SLSH, DE_LPRN, DE_RPRN, DE_LCBR, DE_RCBR, DE_HASH, + KC_TRNS, DE_PIPE, DE_TILD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + DE_QUOT, DE_DQUO, KC_TRNS, M(M_TOGGLE_5), KC_TRNS, + KC_F13, KC_F12, + KC_F14, KC_F15, KC_TRNS, KC_TRNS), /** * Layer: MDIA -* /-----//-----//-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----//-----//-----/ -* | | | | | | | | | | | | | | | | -* | | | | | | | | | | | | | | | | -* /-----//-----//-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----//-----//-----/ -* | | | BTN1 | U | BTN2 | U | | | | | | | | | | -* | | | | | | | | | | | | | | | | -* /-----//-----//-----//-----//-----//-----/\-----\ \-----\/-----//-----//-----//-----//-----//-----/ -* | | | L | D | R | D | | | | | | | | -* | | | | | | | | | | | | | | -* /-----//-----//-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----//-----//-----/ -* | | | L | D | R | BTN3 | | | | | | | | UP | | -* | | | | | | | | | | | | | | | | -* \-----\\-----\\-----\\-----\\-----\\-----\\-----\ \-----\\-----\\-----\\-----\\-----\\-----\\-----\ -* -* -* /-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----/ -* | | | | | | | | | LEFT | DOWN | RIGHT| -* | | | | | | | | | | | | -* \-----\\-----\\-----\\-----\/-----//-----/ /-----//-----/ \-----\\-----\\-----\\-----\\-----\ -* | | | | MPRV | MNXT | -* | | | | | | -* \-----\/-----/ /-----/\-----\ -* | | | VOLU | -* | | | | -* /-----//-----//-----/ /-----//-----//-----/ -* | | | | | VOLD | MUTE | MPLY | -* | | | | | | | | -* \-----\\-----\\-----\ \-----\\-----\\-----\ -* -* +* /-----//-----//-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----//-----//-----/ +* | | | | | | | | | | | | | | | | +* | | | | | | | | | | | | | | | | +* /-----//-----//-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----//-----//-----/ +* | | | BTN1 | U | BTN2 | U | | | | | | | | | | +* | | | | | | | | | | | | | | | | +* /-----//-----//-----//-----//-----//-----/\-----\ \-----\/-----//-----//-----//-----//-----//-----/ +* | | | L | D | R | D | | | | | | | | +* | | | | | | | | | | | | | | +* /-----//-----//-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----//-----//-----/ +* | | | L | D | R | BTN3 | | | | | | | | UP | | +* | | | | | | | | | | | | | | | | +* \-----\\-----\\-----\\-----\\-----\\-----\\-----\ \-----\\-----\\-----\\-----\\-----\\-----\\-----\ +* +* +* /-----//-----//-----//-----//-----/ /-----//-----//-----//-----//-----/ +* | | | | | | | | | LEFT | DOWN | RIGHT| +* | | | | | | | | | | | | +* \-----\\-----\\-----\\-----\/-----//-----/ /-----//-----/ \-----\\-----\\-----\\-----\\-----\ +* | | | | MPRV | MNXT | +* | | | | | | +* \-----\/-----/ /-----/\-----\ +* | | | VOLU | +* | | | | +* /-----//-----//-----/ /-----//-----//-----/ +* | | | | | VOLD | MUTE | MPLY | +* | | | | | | | | +* \-----\\-----\\-----\ \-----\\-----\\-----\ +* +* **/ [MDIA]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_BTN1, KC_MS_U, KC_BTN2, KC_WH_U, KC_TRNS, - KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_WH_D, - KC_TRNS, KC_TRNS, KC_WH_L, KC_WH_D, KC_WH_R, KC_BTN3, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_BTN1, KC_MS_U, KC_BTN2, KC_WH_U, KC_TRNS, + KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_WH_D, + KC_TRNS, KC_TRNS, KC_WH_L, KC_WH_D, KC_WH_R, KC_BTN3, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, - KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RIGHT, - KC_MPRV, KC_MNXT, - KC_VOLU, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, + KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RIGHT, + KC_MPRV, KC_MNXT, + KC_VOLU, KC_VOLD, KC_MUTE, KC_MPLY), /** * Layer: SMLY -* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ -* | | | | | | | | | Typing | Typing | Typing | | | | | -* | | | | | | | | | SM_SMILE| SM_SMIRK| SM_LAUGH| | | | | -* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ -* | | | | | | | | | | Typing | Typing | Typing | | | | -* | | | | | | | | | | SM_FROWN| SM_SAD | SM_CRY | | | | -* /--------//--------//--------//--------//--------//--------/\--------\ \--------\/--------//--------//--------//--------//--------//--------/ -* | | | | | | | | Typing | Typing | | | | | -* | | | | | | | | SM_HEART| SM_KISS | | | | | -* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ -* | | | | | | | | | | | | | | | | -* | | | | | | | | | | | | | | | | -* \--------\\--------\\--------\\--------\\--------\\--------\\--------\ \--------\\--------\\--------\\--------\\--------\\--------\\--------\ -* -* -* /--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------/ -* | | | | | | | | | | | | -* | | | | | | | | | | | | -* \--------\\--------\\--------\\--------\/--------//--------/ /--------//--------/ \--------\\--------\\--------\\--------\\--------\ -* | | | | | | -* | | | | | | -* \--------\/--------/ /--------/\--------\ -* | | | | -* | | | | -* /--------//--------//--------/ /--------//--------//--------/ -* | | | | | | | | -* | | | | | | | | -* \--------\\--------\\--------\ \--------\\--------\\--------\ -* -* +* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ +* | | | | | | | | | Typing | Typing | Typing | | | | | +* | | | | | | | | | SM_SMILE| SM_SMIRK| SM_LAUGH| | | | | +* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ +* | | | | | | | | | | Typing | Typing | Typing | | | | +* | | | | | | | | | | SM_FROWN| SM_SAD | SM_CRY | | | | +* /--------//--------//--------//--------//--------//--------/\--------\ \--------\/--------//--------//--------//--------//--------//--------/ +* | | | | | | | | Typing | Typing | | | | | +* | | | | | | | | SM_HEART| SM_KISS | | | | | +* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ +* | | | | | | | | | | | | | | | | +* | | | | | | | | | | | | | | | | +* \--------\\--------\\--------\\--------\\--------\\--------\\--------\ \--------\\--------\\--------\\--------\\--------\\--------\\--------\ +* +* +* /--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------/ +* | | | | | | | | | | | | +* | | | | | | | | | | | | +* \--------\\--------\\--------\\--------\/--------//--------/ /--------//--------/ \--------\\--------\\--------\\--------\\--------\ +* | | | | | | +* | | | | | | +* \--------\/--------/ /--------/\--------\ +* | | | | +* | | | | +* /--------//--------//--------/ /--------//--------//--------/ +* | | | | | | | | +* | | | | | | | | +* \--------\\--------\\--------\ \--------\\--------\\--------\ +* +* **/ [SMLY]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - M(SM_SMILE), M(SM_SMIRK), M(SM_LAUGH), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, M(SM_FROWN), M(SM_SAD), M(SM_CRY), KC_TRNS, KC_TRNS, KC_TRNS, - M(SM_HEART), M(SM_KISS), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + M(SM_SMILE), M(SM_SMIRK), M(SM_LAUGH), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, M(SM_FROWN), M(SM_SAD), M(SM_CRY), KC_TRNS, KC_TRNS, KC_TRNS, + M(SM_HEART), M(SM_KISS), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), /** * Layer: NUMB -* /----//----//----//----//----//----//----/ /----//----//----//----//----//----//----/ -* | | | | | | | | | | F6 | F7 | F8 | F9 | F10 | F11 | -* | | | | | | | | | | | | | | | | -* /----//----//----//----//----//----//----/ /----//----//----//----//----//----//----/ -* | | | | UP | | | | | | / | 7 | 8 | 9 | * | F12 | -* | | | | | | | | | | | | | | | | -* /----//----//----//----//----//----/\----\ \----\/----//----//----//----//----//----/ -* | | | LEFT| DOWN| RGHT| | | / | 4 | 5 | 6 | + | - | -* | | | | | | | | | | | | | | -* /----//----//----//----//----//----//----/ /----//----//----//----//----//----//----/ -* | | | | | | | | | | % | 1 | 2 | 3 | | | -* | | | | | | | | | | | | | | | | -* \----\\----\\----\\----\\----\\----\\----\ \----\\----\\----\\----\\----\\----\\----\ -* -* -* /----//----//----//----//----/ /----//----//----//----//----/ -* | | | | | | | 0 | . | , | = | | -* | | | | | | | | | | | | -* \----\\----\\----\\----\/----//----/ /----//----/ \----\\----\\----\\----\\----\ -* | | | | | | -* | | | | | | -* \----\/----/ /----/\----\ -* | | | | -* | | | | -* /----//----//----/ /----//----//----/ -* | | | | | | | | -* | | | | | | | | -* \----\\----\\----\ \----\\----\\----\ -* -* +* /----//----//----//----//----//----//----/ /----//----//----//----//----//----//----/ +* | | | | | | | | | | F6 | F7 | F8 | F9 | F10 | F11 | +* | | | | | | | | | | | | | | | | +* /----//----//----//----//----//----//----/ /----//----//----//----//----//----//----/ +* | | | | UP | | | | | | / | 7 | 8 | 9 | * | F12 | +* | | | | | | | | | | | | | | | | +* /----//----//----//----//----//----/\----\ \----\/----//----//----//----//----//----/ +* | | | LEFT| DOWN| RGHT| | | / | 4 | 5 | 6 | + | - | +* | | | | | | | | | | | | | | +* /----//----//----//----//----//----//----/ /----//----//----//----//----//----//----/ +* | | | | | | | | | | % | 1 | 2 | 3 | | | +* | | | | | | | | | | | | | | | | +* \----\\----\\----\\----\\----\\----\\----\ \----\\----\\----\\----\\----\\----\\----\ +* +* +* /----//----//----//----//----/ /----//----//----//----//----/ +* | | | | | | | 0 | . | , | = | | +* | | | | | | | | | | | | +* \----\\----\\----\\----\/----//----/ /----//----/ \----\\----\\----\\----\\----\ +* | | | | | | +* | | | | | | +* \----\/----/ /----/\----\ +* | | | | +* | | | | +* /----//----//----/ /----//----//----/ +* | | | | | | | | +* | | | | | | | | +* \----\\----\\----\ \----\\----\\----\ +* +* **/ [NUMB]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, //right half - KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, - KC_TRNS, DE_SLSH, KC_7, KC_8, KC_9, DE_ASTR, KC_F12, - DE_SLSH, KC_4, KC_5, KC_6, DE_PLUS, DE_MINS, - KC_TRNS, DE_PERC, KC_1, KC_2, KC_3, KC_TRNS, KC_TRNS, - KC_0, KC_DOT, KC_COMM, DE_EQL, KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, + KC_TRNS, DE_SLSH, KC_7, KC_8, KC_9, DE_ASTR, KC_F12, + DE_SLSH, KC_4, KC_5, KC_6, DE_PLUS, DE_MINS, + KC_TRNS, DE_PERC, KC_1, KC_2, KC_3, KC_TRNS, KC_TRNS, + KC_0, KC_DOT, KC_COMM, DE_EQL, KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), /** * Layer: EGOS -* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ -* | | | | | | | | | | | | | | | | -* | | | | | | | | | | | | | | | | -* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ -* | | | | | | | | | | | | | | | | -* | | | | | | | | | | | | | | | | -* /--------//--------//--------//--------//--------//--------/\--------\ \--------\/--------//--------//--------//--------//--------//--------/ -* | Shift | | | | | | | | | | | | | -* | | | | | | | | | | | | | | -* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ -* | | | | | | | | | | | | | | | | -* | | | | | | | | | | | | | | | | -* \--------\\--------\\--------\\--------\\--------\\--------\\--------\ \--------\\--------\\--------\\--------\\--------\\--------\\--------\ -* -* -* /--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------/ -* | Ctrl | | | | | | | | | Toggle 5| | -* | | | | | | | | | | | | -* \--------\\--------\\--------\\--------\/--------//--------/ /--------//--------/ \--------\\--------\\--------\\--------\\--------\ -* | F1 | F2 | | | | -* | | | | | | -* \--------\/--------/ /--------/\--------\ -* | F3 | | | -* | | | | -* /--------//--------//--------/ /--------//--------//--------/ -* | SPC | Ctrl | F4 | | | | | -* | | | | | | | | -* \--------\\--------\\--------\ \--------\\--------\\--------\ -* -* +* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ +* | | | | | | | | | | | | | | | | +* | | | | | | | | | | | | | | | | +* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ +* | | | | | | | | | | | | | | | | +* | | | | | | | | | | | | | | | | +* /--------//--------//--------//--------//--------//--------/\--------\ \--------\/--------//--------//--------//--------//--------//--------/ +* | Shift | | | | | | | | | | | | | +* | | | | | | | | | | | | | | +* /--------//--------//--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------//--------//--------/ +* | | | | | | | | | | | | | | | | +* | | | | | | | | | | | | | | | | +* \--------\\--------\\--------\\--------\\--------\\--------\\--------\ \--------\\--------\\--------\\--------\\--------\\--------\\--------\ +* +* +* /--------//--------//--------//--------//--------/ /--------//--------//--------//--------//--------/ +* | Ctrl | | | | | | | | | Toggle 5| | +* | | | | | | | | | | | | +* \--------\\--------\\--------\\--------\/--------//--------/ /--------//--------/ \--------\\--------\\--------\\--------\\--------\ +* | F1 | F2 | | | | +* | | | | | | +* \--------\/--------/ /--------/\--------\ +* | F3 | | | +* | | | | +* /--------//--------//--------/ /--------//--------//--------/ +* | SPC | Ctrl | F4 | | | | | +* | | | | | | | | +* \--------\\--------\\--------\ \--------\\--------\\--------\ +* +* **/ [EGOS]=LAYOUT_ergodox( //left half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_LSFT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_LCTL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_F1, KC_F2, - KC_F3, - KC_SPC, KC_LCTL, KC_F4, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_LSFT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_LCTL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_F1, KC_F2, + KC_F3, + KC_SPC, KC_LCTL, KC_F4, //right half - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, M(M_TOGGLE_5), KC_TRNS, - KC_TRNS, KC_TRNS, - KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, M(M_TOGGLE_5), KC_TRNS, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), }; @@ -556,7 +556,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { -uint8_t layer = biton32(layer_state); +uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -566,17 +566,17 @@ switch (layer) { case SYMB: ergodox_right_led_1_on(); - - + + break; case MDIA: - + ergodox_right_led_2_on(); - + break; case NUMB: - - + + ergodox_right_led_3_on(); break; case EGOS: @@ -590,4 +590,3 @@ break; } }; - diff --git a/layouts/community/ergodox/osx_fr/keymap.c b/layouts/community/ergodox/osx_fr/keymap.c index 886e54208a..22451c1a30 100644 --- a/layouts/community/ergodox/osx_fr/keymap.c +++ b/layouts/community/ergodox/osx_fr/keymap.c @@ -141,7 +141,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/osx_kinesis_pnut/keymap.c b/layouts/community/ergodox/osx_kinesis_pnut/keymap.c index ad6ea27364..fb50a3407e 100644 --- a/layouts/community/ergodox/osx_kinesis_pnut/keymap.c +++ b/layouts/community/ergodox/osx_kinesis_pnut/keymap.c @@ -145,7 +145,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/osx_neo2/keymap.c b/layouts/community/ergodox/osx_neo2/keymap.c index 3dbfceabc4..125cc43a8f 100644 --- a/layouts/community/ergodox/osx_neo2/keymap.c +++ b/layouts/community/ergodox/osx_neo2/keymap.c @@ -704,7 +704,7 @@ void matrix_init_user(void){ // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/phoenix/keymap.c b/layouts/community/ergodox/phoenix/keymap.c index a66462e3a8..4371e5f2e7 100644 --- a/layouts/community/ergodox/phoenix/keymap.c +++ b/layouts/community/ergodox/phoenix/keymap.c @@ -138,7 +138,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/plover/keymap.c b/layouts/community/ergodox/plover/keymap.c index ffb869309a..7b34dde2ed 100644 --- a/layouts/community/ergodox/plover/keymap.c +++ b/layouts/community/ergodox/plover/keymap.c @@ -182,7 +182,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/qwerty_code_friendly/keymap.c b/layouts/community/ergodox/qwerty_code_friendly/keymap.c index 6e285d5613..ed06446907 100644 --- a/layouts/community/ergodox/qwerty_code_friendly/keymap.c +++ b/layouts/community/ergodox/qwerty_code_friendly/keymap.c @@ -662,7 +662,7 @@ void matrix_init_user(void) { /* Runs constantly in the background, in a loop. */ void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/reset_eeprom/keymap.c b/layouts/community/ergodox/reset_eeprom/keymap.c index 83c252a9a1..726447cbd0 100644 --- a/layouts/community/ergodox/reset_eeprom/keymap.c +++ b/layouts/community/ergodox/reset_eeprom/keymap.c @@ -96,7 +96,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/romanzolotarev-norman-plover-osx-hjkl/keymap.c b/layouts/community/ergodox/romanzolotarev-norman-plover-osx-hjkl/keymap.c index 819944121e..6eb319ca63 100644 --- a/layouts/community/ergodox/romanzolotarev-norman-plover-osx-hjkl/keymap.c +++ b/layouts/community/ergodox/romanzolotarev-norman-plover-osx-hjkl/keymap.c @@ -88,7 +88,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); ergodox_right_led_2_off(); diff --git a/layouts/community/ergodox/romanzolotarev-norman-plover-osx/keymap.c b/layouts/community/ergodox/romanzolotarev-norman-plover-osx/keymap.c index a0964fac77..adf420daa0 100644 --- a/layouts/community/ergodox/romanzolotarev-norman-plover-osx/keymap.c +++ b/layouts/community/ergodox/romanzolotarev-norman-plover-osx/keymap.c @@ -88,7 +88,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); ergodox_right_led_2_off(); diff --git a/layouts/community/ergodox/romanzolotarev-norman-qwerty-osx/keymap.c b/layouts/community/ergodox/romanzolotarev-norman-qwerty-osx/keymap.c index 6aca3a6d5f..cf3941ee1d 100644 --- a/layouts/community/ergodox/romanzolotarev-norman-qwerty-osx/keymap.c +++ b/layouts/community/ergodox/romanzolotarev-norman-qwerty-osx/keymap.c @@ -48,7 +48,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); ergodox_right_led_2_off(); diff --git a/layouts/community/ergodox/sethbc/keymap.c b/layouts/community/ergodox/sethbc/keymap.c index 26d3106ec4..f3a1f64309 100644 --- a/layouts/community/ergodox/sethbc/keymap.c +++ b/layouts/community/ergodox/sethbc/keymap.c @@ -77,7 +77,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/siroken3/keymap.c b/layouts/community/ergodox/siroken3/keymap.c index fed8b4a0c8..dd5125d20e 100644 --- a/layouts/community/ergodox/siroken3/keymap.c +++ b/layouts/community/ergodox/siroken3/keymap.c @@ -141,7 +141,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/sneako/keymap.c b/layouts/community/ergodox/sneako/keymap.c index 9d3cdd5a11..dffe797ab0 100644 --- a/layouts/community/ergodox/sneako/keymap.c +++ b/layouts/community/ergodox/sneako/keymap.c @@ -141,7 +141,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/software_neo2/keymap.c b/layouts/community/ergodox/software_neo2/keymap.c index 5f600a5ab5..c191a034f2 100644 --- a/layouts/community/ergodox/software_neo2/keymap.c +++ b/layouts/community/ergodox/software_neo2/keymap.c @@ -98,7 +98,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/swedish-lindhe/keymap.c b/layouts/community/ergodox/swedish-lindhe/keymap.c index 368e216cdc..b0abff9ec6 100644 --- a/layouts/community/ergodox/swedish-lindhe/keymap.c +++ b/layouts/community/ergodox/swedish-lindhe/keymap.c @@ -162,7 +162,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/swedish/keymap.c b/layouts/community/ergodox/swedish/keymap.c index 90218aa886..5e2d47de57 100644 --- a/layouts/community/ergodox/swedish/keymap.c +++ b/layouts/community/ergodox/swedish/keymap.c @@ -203,7 +203,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/swissgerman/keymap.c b/layouts/community/ergodox/swissgerman/keymap.c index 8ba9582934..8766d16ae0 100644 --- a/layouts/community/ergodox/swissgerman/keymap.c +++ b/layouts/community/ergodox/swissgerman/keymap.c @@ -222,7 +222,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); switch (layer) { // TODO: Make this relevant to the ErgoDox EZ. diff --git a/layouts/community/ergodox/techtomas/keymap.c b/layouts/community/ergodox/techtomas/keymap.c index 742eca03a4..bdbb50be42 100644 --- a/layouts/community/ergodox/techtomas/keymap.c +++ b/layouts/community/ergodox/techtomas/keymap.c @@ -180,7 +180,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/tkuichooseyou/keymap.c b/layouts/community/ergodox/tkuichooseyou/keymap.c index ea6c8f259f..08f1cfc9ab 100644 --- a/layouts/community/ergodox/tkuichooseyou/keymap.c +++ b/layouts/community/ergodox/tkuichooseyou/keymap.c @@ -138,7 +138,7 @@ LAYOUT_ergodox( // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/tonyabra_osx/keymap.c b/layouts/community/ergodox/tonyabra_osx/keymap.c index 741a6396e8..9b8048dda3 100644 --- a/layouts/community/ergodox/tonyabra_osx/keymap.c +++ b/layouts/community/ergodox/tonyabra_osx/keymap.c @@ -138,7 +138,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/townk_osx/keymap.c b/layouts/community/ergodox/townk_osx/keymap.c index 6799ad7460..c79d74d6eb 100644 --- a/layouts/community/ergodox/townk_osx/keymap.c +++ b/layouts/community/ergodox/townk_osx/keymap.c @@ -229,7 +229,7 @@ uint8_t current_layer = BASE; // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_led_all_off(); ergodox_led_all_set(LED_BRIGHTNESS_LO); diff --git a/layouts/community/ergodox/twentylives_dvorak_with_hebrew/keymap.c b/layouts/community/ergodox/twentylives_dvorak_with_hebrew/keymap.c index 4b5181a70d..12548ae0ea 100644 --- a/layouts/community/ergodox/twentylives_dvorak_with_hebrew/keymap.c +++ b/layouts/community/ergodox/twentylives_dvorak_with_hebrew/keymap.c @@ -36,7 +36,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_DELETE, KC_TRNS, KC_LGUI, KC_BSPACE,CTL_T(KC_NO),KC_LALT, - + KC_TILD, KC_6, KC_7, KC_8, KC_9, KC_0, KC_EQUAL, KC_TRNS, KC_F, KC_G, KC_C, KC_R, KC_L, KC_SLASH, KC_D, KC_H, KC_T, KC_N, KC_S, KC_MINUS, @@ -77,7 +77,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_Y, KC_U, KC_E, KC_O, KC_P, KC_TRNS, KC_H, KC_J, KC_K, KC_L, KC_SCOLON, KC_TRNS, @@ -110,9 +110,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * `--------------------' `--------------------' */ [2] = LAYOUT_ergodox( - KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_UP, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_TRNS, + KC_TRNS, KC_TRNS, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, @@ -120,12 +120,12 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_TRNS, - KC_F11, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, + KC_F11, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RIGHT, KC_TRNS, KC_TRNS, KC_F12, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_BTN1, KC_MS_BTN2, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS ), @@ -154,19 +154,19 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Left Hand KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS, // Right Hand - KC_TRNS, KC_TRNS, KC_LOCKING_NUM, KC_KP_SLASH, KC_KP_ASTERISK, KC_KP_MINUS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_LOCKING_NUM, KC_KP_SLASH, KC_KP_ASTERISK, KC_KP_MINUS, KC_TRNS, KC_TRNS, KC_TRNS, KC_KP_7, KC_KP_8, KC_KP_9, KC_KP_PLUS, KC_TRNS, - KC_TRNS, KC_KP_4, KC_KP_5, KC_KP_6, KC_KP_PLUS, KC_TRNS, + KC_TRNS, KC_KP_4, KC_KP_5, KC_KP_6, KC_KP_PLUS, KC_TRNS, KC_TRNS, KC_TRNS, KC_KP_1, KC_KP_2, KC_KP_3, KC_ENTER, KC_TRNS, KC_KP_0, KC_KP_0, KC_KP_DOT, KC_ENTER, KC_TRNS, - KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS ), @@ -175,7 +175,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/win10_writers-block/keymap.c b/layouts/community/ergodox/win10_writers-block/keymap.c index 05adaed759..443e403b18 100644 --- a/layouts/community/ergodox/win10_writers-block/keymap.c +++ b/layouts/community/ergodox/win10_writers-block/keymap.c @@ -4,8 +4,8 @@ #include "version.h" #include "wait.h" -#define BASE 0 // default layer - helpful for writing in Office-style word processors. -#define SYMB 1 // symbol layer - NumPad, etc. - same as Ergodox EZ default but no EEPROM or Version key +#define BASE 0 // default layer - helpful for writing in Office-style word processors. +#define SYMB 1 // symbol layer - NumPad, etc. - same as Ergodox EZ default but no EEPROM or Version key #define RIMW 2 // rimworld layer - made for the game RimWorld, by Tynan Sylvester | feel free to remap for your favorite game! #define MDIA 3 // media layer - mouse and music - close to Ergodox EZ default media layer @@ -27,19 +27,19 @@ enum { }; void cake_count (qk_tap_dance_state_t *state, void *user_data) { - if (state->count == 2) { + if (state->count == 2) { layer_on (SYMB); //define double tap here layer_off (MDIA); - } - else { + } + else { layer_off (SYMB); //define single tap or hold here layer_off (MDIA); } - if (state->count == 3) { + if (state->count == 3) { layer_on (RIMW); //define triple tap here layer_off (MDIA); - } - else { + } + else { layer_off (RIMW); //define single tap or hold here layer_off (MDIA); reset_tap_dance (state); @@ -83,7 +83,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * ,--------------------------------------------------. ,--------------------------------------------------. * | ` | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 7 | 8 | 9 | 0 | - | = | * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| - * | F12/L1 | Q | W | E | R | T | {/[ | |TD(L0 | Y | U | I | O | P | \ | + * | F12/L1 | Q | W | E | R | T | {/[ | |TD(L0 | Y | U | I | O | P | \ | * |--------+------+------+------+------+------| | |L1 L2)|------+------+------+------+------+--------| * |Caps/Win| A | S | D | F | G |------| |------| H | J | K | L | ; | ' | * |--------+------+------+------+------+------| }/] | TD(ctrl|------+------+------+------+------+--------| @@ -163,8 +163,8 @@ LT(SYMB, KC_F12), KC_Q, KC_W, KC_E, KC_R, KC_T, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS -), - +), + /* Keymap 2: RimWorld Layer * * ,--------------------------------------------------. ,--------------------------------------------------. @@ -186,7 +186,7 @@ LT(SYMB, KC_F12), KC_Q, KC_W, KC_E, KC_R, KC_T, * | | | Q | | | | | * `--------------------' `--------------------' */ -// RIMWORLD +// RIMWORLD [RIMW] = LAYOUT_ergodox( // left hand KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, @@ -300,7 +300,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); @@ -315,7 +315,7 @@ void matrix_scan_user(void) { break; case 3: ergodox_right_led_3_on(); - break; + break; default: // none break; diff --git a/layouts/community/ergodox/xyverz/keymap.c b/layouts/community/ergodox/xyverz/keymap.c index c77920bb13..f348736c6e 100644 --- a/layouts/community/ergodox/xyverz/keymap.c +++ b/layouts/community/ergodox/xyverz/keymap.c @@ -1,6 +1,6 @@ /* * About this keymap: - * + * * The Dvorak layout shown here stems from my early Kinesis years, using the Contour PS/2 with a Dvorak * software layout. Because of this, the RBRC and LBRC were on opposite sides of the board in the corner * keys. When I originally set up this keymap, I'd decided to continue using this layout with my ErgoDox. @@ -14,7 +14,7 @@ * layouts. * * What's New: - * + * * I've overhauled this Dvorak layout a bit to more match what I've got on my other Ortho boards. For * some keys, I'm moving away from my old Kinesis keymap and adding the brackets and braces to the * inner column vertical keys. I figure this will help me have better ease of use. In this update, I @@ -246,7 +246,7 @@ void matrix_init_user(void) { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ergodox/zweihander-macos/keymap.c b/layouts/community/ergodox/zweihander-macos/keymap.c index b2ddeb0d6b..0aecc24e67 100644 --- a/layouts/community/ergodox/zweihander-macos/keymap.c +++ b/layouts/community/ergodox/zweihander-macos/keymap.c @@ -140,7 +140,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // Runs constantly in the background, in a loop. void matrix_scan_user(void) { - uint8_t layer = biton32(layer_state); + uint8_t layer = get_highest_layer(layer_state); ergodox_board_led_off(); ergodox_right_led_1_off(); diff --git a/layouts/community/ortho_4x12/peej/keymap.c b/layouts/community/ortho_4x12/peej/keymap.c index d78f03da41..1e2874ac99 100644 --- a/layouts/community/ortho_4x12/peej/keymap.c +++ b/layouts/community/ortho_4x12/peej/keymap.c @@ -56,7 +56,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { writePinLow(LED_RED); writePinLow(LED_GREEN); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _FUNCTION: writePinHigh(LED_RED); break; diff --git a/quantum/action_layer.h b/quantum/action_layer.h index b87d096eed..bd1085a70f 100644 --- a/quantum/action_layer.h +++ b/quantum/action_layer.h @@ -41,7 +41,7 @@ along with this program. If not, see . #endif #if !defined(LAYER_STATE_8BIT) && !defined(LAYER_STATE_16BIT) && !defined(LAYER_STATE_32BIT) -# define LAYER_STATE_32BIT +# define LAYER_STATE_16BIT #endif #if defined(LAYER_STATE_8BIT) diff --git a/tmk_core/protocol/arm_atsam/md_rgb_matrix.c b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c index 3ed83a44a6..52fe86d297 100644 --- a/tmk_core/protocol/arm_atsam/md_rgb_matrix.c +++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c @@ -450,7 +450,7 @@ static void md_rgb_matrix_config_override(int i) { float bo = 0; float po; - uint8_t highest_active_layer = biton32(layer_state); + uint8_t highest_active_layer = get_highest_layer(layer_state); if (led_animation_circular) { // TODO: should use min/max values from LED configuration instead of diff --git a/users/333fred/333fred.c b/users/333fred/333fred.c index 99f4e01685..ea7b904403 100644 --- a/users/333fred/333fred.c +++ b/users/333fred/333fred.c @@ -115,7 +115,7 @@ void tap_dance_process_keycode(uint16_t keycode) { } __attribute__ ((weak)) -void layer_state_set_rgb(uint32_t state) {} +void layer_state_set_rgb(layer_state_t state) {} layer_state_t layer_state_set_user(layer_state_t state) { layer_state_set_rgb(state); diff --git a/users/333fred/rgb.c b/users/333fred/rgb.c index d287143302..ae21702030 100644 --- a/users/333fred/rgb.c +++ b/users/333fred/rgb.c @@ -23,8 +23,8 @@ #include "quantum.h" #include "333fred.h" -void layer_state_set_rgb(uint32_t state) { - switch (biton32(state)) { +void layer_state_set_rgb(layer_state_t state) { + switch (get_highest_layer(state)) { case BASE: // purple rgblight_sethsv_noeeprom(210, 255, 20); diff --git a/users/bbaserdem/bbaserdem.c b/users/bbaserdem/bbaserdem.c index cdacda12ee..e0cf3d81d1 100644 --- a/users/bbaserdem/bbaserdem.c +++ b/users/bbaserdem/bbaserdem.c @@ -59,7 +59,7 @@ __attribute__ ((weak)) void matrix_scan_keymap(void) { } __attribute__ ((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; } -__attribute__ ((weak)) uint32_t layer_state_set_keymap (uint32_t state) { +__attribute__ ((weak)) layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } __attribute__ ((weak)) void led_set_keymap(uint8_t usb_led) { } @@ -627,7 +627,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { state = layer_state_set_keymap (state); #ifdef RGBLIGHT_ENABLE // Change RGB lighting depending on the last layer activated - rgblight_change( biton32(state) ); + rgblight_change( get_highest_layer(state) ); #endif return state; } diff --git a/users/billypython/billypython.c b/users/billypython/billypython.c index 180b478d7a..f165d2e260 100644 --- a/users/billypython/billypython.c +++ b/users/billypython/billypython.c @@ -23,7 +23,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } __attribute__((weak)) -uint32_t layer_state_set_keymap(uint32_t state) { +layer_state_t layer_state_set_keymap(layer_state_t state) { return state; } diff --git a/users/billypython/billypython.h b/users/billypython/billypython.h index 4a444e9787..cdf5121f2f 100644 --- a/users/billypython/billypython.h +++ b/users/billypython/billypython.h @@ -31,4 +31,4 @@ enum layers_user { }; bool process_record_keymap(uint16_t keycode, keyrecord_t *record); -uint32_t layer_state_set_keymap(uint32_t state); +layer_state_t layer_state_set_keymap(layer_state_t state); diff --git a/users/dhertz/dhertz.c b/users/dhertz/dhertz.c index 163b1cb644..1a2b6e38f1 100644 --- a/users/dhertz/dhertz.c +++ b/users/dhertz/dhertz.c @@ -18,7 +18,7 @@ bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; } __attribute__ ((weak)) -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } __attribute__ ((weak)) @@ -107,4 +107,3 @@ layer_state_t layer_state_set_user (layer_state_t state) { void led_set_user(uint8_t usb_led) { led_set_keymap(usb_led); } - diff --git a/users/doogle999/doogle999.c b/users/doogle999/doogle999.c index 320de7cff8..c9ee125741 100644 --- a/users/doogle999/doogle999.c +++ b/users/doogle999/doogle999.c @@ -382,7 +382,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t* record) static char text[CALC_BUFFER_SIZE + 1]; // Used to store input and then output when ready to print static char backspaceText[CALC_BUFFER_SIZE + 1]; // Pretty dumb waste of memory because only backspace characters, used with send_string to backspace and remove input - if((biton32(layer_state) == CALC_LAYER && CALC_FORCE_NUM_LOCK_INSIDE_CALC) || (biton32(layer_state) != CALC_LAYER && CALC_FORCE_NUM_LOCK_OUTSIDE_CALC)) + if((get_highest_layer(layer_state) == CALC_LAYER && CALC_FORCE_NUM_LOCK_INSIDE_CALC) || (get_highest_layer(layer_state) != CALC_LAYER && CALC_FORCE_NUM_LOCK_OUTSIDE_CALC)) { bool numpadKeyPressed = record->event.pressed && !(get_mods() & MODS_SHIFT_MASK) && @@ -397,7 +397,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t* record) } } - if(biton32(layer_state) != CALC_LAYER) { return true; } + if(get_highest_layer(layer_state) != CALC_LAYER) { return true; } int action = process_input(keycode, get_mods(), record->event); switch(action) @@ -457,4 +457,4 @@ bool process_record_user(uint16_t keycode, keyrecord_t* record) send_string(characterToSend); } return false; -} \ No newline at end of file +} diff --git a/users/edvorakjp/edvorakjp.c b/users/edvorakjp/edvorakjp.c index c44d8bb440..c95b03d981 100644 --- a/users/edvorakjp/edvorakjp.c +++ b/users/edvorakjp/edvorakjp.c @@ -12,7 +12,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { return layer_state_set_keymap(state); } -__attribute__((weak)) uint32_t layer_state_set_keymap(uint32_t state) { return state; } +__attribute__((weak)) layer_state_t layer_state_set_keymap(layer_state_t state) { return state; } bool process_record_user(uint16_t keycode, keyrecord_t *record) { bool process_record_user_result = process_record_keymap(keycode, record) && process_record_edvorakjp_swap_scln(keycode, record) && process_record_edvorakjp_config(keycode, record) && process_record_layer(keycode, record) && process_record_ime(keycode, record); diff --git a/users/edvorakjp/edvorakjp.h b/users/edvorakjp/edvorakjp.h index 93cd9851b7..a878f71ca8 100644 --- a/users/edvorakjp/edvorakjp.h +++ b/users/edvorakjp/edvorakjp.h @@ -68,7 +68,7 @@ enum tap_dance_code { void matrix_init_user(void); void matrix_init_keymap(void); layer_state_t layer_state_set_user(layer_state_t state); -uint32_t layer_state_set_keymap(uint32_t state); +layer_state_t layer_state_set_keymap(layer_state_t state); bool process_record_user(uint16_t keycode, keyrecord_t *record); bool process_record_keymap(uint16_t keycode, keyrecord_t *record); diff --git a/users/ericgebhart/ericgebhart.c b/users/ericgebhart/ericgebhart.c index 2a34110ae2..a071fb8c2e 100755 --- a/users/ericgebhart/ericgebhart.c +++ b/users/ericgebhart/ericgebhart.c @@ -40,7 +40,7 @@ __attribute__ ((weak)) void matrix_scan_keymap(void) {} __attribute__ ((weak)) -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } diff --git a/users/ericgebhart/tap_dances.c b/users/ericgebhart/tap_dances.c index 9f344986aa..8f9503a261 100755 --- a/users/ericgebhart/tap_dances.c +++ b/users/ericgebhart/tap_dances.c @@ -47,7 +47,7 @@ void tap_dance_mouse_btns (qk_tap_dance_state_t *state, void *user_data) { // counting on all the qwerty layers to be less than dvorak_on_bepo int on_qwerty(){ - uint8_t deflayer = (biton32(default_layer_state)); + uint8_t deflayer = (get_highest_layer(default_layer_state)); return (deflayer < _DVORAK_BP); } @@ -58,7 +58,7 @@ static void switch_default_layer(uint8_t layer) { // so the keyboard remembers which layer it's in after power disconnect. /* - uint32_t default_layer_state_set_kb(uint32_t state) { + layer_state_t default_layer_state_set_kb(layer_state_t state) { eeconfig_update_default_layer(state); return state; } diff --git a/users/kuchosauronad0/kuchosauronad0.c b/users/kuchosauronad0/kuchosauronad0.c index a8f17b08ee..820d84daad 100644 --- a/users/kuchosauronad0/kuchosauronad0.c +++ b/users/kuchosauronad0/kuchosauronad0.c @@ -117,7 +117,7 @@ void matrix_scan_user(void){ } __attribute__ ((weak)) -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } @@ -133,12 +133,12 @@ layer_state_t layer_state_set_user(layer_state_t state) { __attribute__ ((weak)) -uint32_t default_layer_state_set_keymap (uint32_t state) { +layer_state_t default_layer_state_set_keymap (layer_state_t state) { return state; } // Runs state check and changes underglow color and animation -uint32_t default_layer_state_set_user(uint32_t state) { +layer_state_t default_layer_state_set_user(layer_state_t state) { state = default_layer_state_set_keymap(state); #if 0 #ifdef RGBLIGHT_ENABLE diff --git a/users/kuchosauronad0/kuchosauronad0.h b/users/kuchosauronad0/kuchosauronad0.h index da996457c6..5cbd517d67 100644 --- a/users/kuchosauronad0/kuchosauronad0.h +++ b/users/kuchosauronad0/kuchosauronad0.h @@ -65,8 +65,8 @@ void shutdown_keymap(void); void suspend_power_down_keymap(void); void suspend_wakeup_init_keymap(void); void matrix_scan_keymap(void); -uint32_t layer_state_set_keymap (uint32_t state); -uint32_t default_layer_state_set_keymap (uint32_t state); +layer_state_t layer_state_set_keymap (layer_state_t state); +layer_state_t default_layer_state_set_keymap (layer_state_t state); void led_set_keymap(uint8_t usb_led); void eeconfig_init_keymap(void); diff --git a/users/kuchosauronad0/rgblight_user.c b/users/kuchosauronad0/rgblight_user.c index 63e412c557..feea0c412f 100644 --- a/users/kuchosauronad0/rgblight_user.c +++ b/users/kuchosauronad0/rgblight_user.c @@ -84,7 +84,7 @@ void matrix_scan_rgb(void) { layer_state_t layer_state_set_rgb(layer_state_t state) { # ifdef RGBLIGHT_ENABLE if (userspace_config.rgb_layer_change) { - switch (biton32(state)) { // _RAISE, _LOWER and _ADJUST use a custom color and the breathing effect + switch (get_highest_layer(state)) { // _RAISE, _LOWER and _ADJUST use a custom color and the breathing effect case _RAISE: rgblight_sethsv_noeeprom_green(); rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3); @@ -98,7 +98,7 @@ layer_state_t layer_state_set_rgb(layer_state_t state) { rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 2); break; default: // Use a solid color for normal layers - switch (biton32(default_layer_state)) { + switch (get_highest_layer(default_layer_state)) { case _QWERTY: rgblight_sethsv_noeeprom_magenta(); break; @@ -118,7 +118,7 @@ layer_state_t layer_state_set_rgb(layer_state_t state) { rgblight_sethsv_noeeprom_white(); break; } - biton32(state) == _MODS ? rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING) : rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); // if _MODS layer is on, then breath to denote it + get_highest_layer(state) == _MODS ? rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING) : rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); // if _MODS layer is on, then breath to denote it break; } } @@ -135,7 +135,7 @@ void matrix_scan_indicator(void) { #endif // !INDICATOR_LIGHTS void rgblight_fade_helper(bool direction){ - // true: increase val = fade in + // true: increase val = fade in // false: decrease val = fade out for (uint8_t index = 0; index < RGBLIGHT_VAL_STEP ; index++) { direction ? rgblight_increase_val() : rgblight_decrease_val(); @@ -147,10 +147,10 @@ void fadeflash_leds(uint8_t hue, uint8_t sat, uint8_t val){ // fade out, set new hue and saturation, fade in, fade out, set old color, fade in // this is used in leader.c // TODO: come up with a better name maybe - rgblight_fade_helper(false); - rgblight_sethsv_noeeprom(hue, sat, 0); - rgblight_fade_helper(true); - rgblight_fade_helper(false); - rgblight_sethsv_noeeprom(base_hue, base_sat, 0); - rgblight_fade_helper(true); + rgblight_fade_helper(false); + rgblight_sethsv_noeeprom(hue, sat, 0); + rgblight_fade_helper(true); + rgblight_fade_helper(false); + rgblight_sethsv_noeeprom(base_hue, base_sat, 0); + rgblight_fade_helper(true); } diff --git a/users/kuchosauronad0/template.c b/users/kuchosauronad0/template.c index 475e45d391..76cc572be3 100644 --- a/users/kuchosauronad0/template.c +++ b/users/kuchosauronad0/template.c @@ -63,11 +63,11 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { __attribute__ ((weak)) -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } -uint32_t layer_state_set_user (uint32_t state) { +layer_state_t layer_state_set_user (layer_state_t state) { return layer_state_set_keymap (state); } diff --git a/users/mtdjr/mtdjr.c b/users/mtdjr/mtdjr.c index 9c6c26bc86..cd67bf3b5f 100644 --- a/users/mtdjr/mtdjr.c +++ b/users/mtdjr/mtdjr.c @@ -137,7 +137,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { }; layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _RAISE: #ifdef RGBLIGHT_ENABLE rgblight_sethsv_noeeprom (240, 255, 255); diff --git a/users/ninjonas/oled.c b/users/ninjonas/oled.c index 55eaf88ccb..463c6dfebb 100644 --- a/users/ninjonas/oled.c +++ b/users/ninjonas/oled.c @@ -23,7 +23,7 @@ bool process_record_oled(uint16_t keycode, keyrecord_t *record) { void render_layout_state(void) { oled_write_P(PSTR("Layout: "), false); - switch (biton32(default_layer_state)) { + switch (get_highest_layer(default_layer_state)) { case _COLEMAK: oled_write_P(PSTR("Colemak"), false); break; diff --git a/users/pvinis/pvinis.c b/users/pvinis/pvinis.c index 71f9210aec..96b01bb461 100644 --- a/users/pvinis/pvinis.c +++ b/users/pvinis/pvinis.c @@ -95,4 +95,4 @@ void keyboard_post_init_user(void) { // Default functions. __attribute__((weak)) void keyboard_post_init_user_keymap(void) {} -__attribute__((weak)) uint32_t layer_state_set_user_keymap(uint32_t state) { return state; } +__attribute__((weak)) layer_state_t layer_state_set_user_keymap(layer_state_t state) { return state; } diff --git a/users/pvinis/pvinis.h b/users/pvinis/pvinis.h index c50033a440..5a11a6cb6f 100644 --- a/users/pvinis/pvinis.h +++ b/users/pvinis/pvinis.h @@ -169,4 +169,4 @@ enum { // Extra stuff that might be needed. void keyboard_post_init_user_keymap(void); -uint32_t layer_state_set_user_keymap(uint32_t state); +layer_state_t layer_state_set_user_keymap(layer_state_t state); diff --git a/users/romus/romus.c b/users/romus/romus.c index f707bb8843..a41a6df578 100644 --- a/users/romus/romus.c +++ b/users/romus/romus.c @@ -59,7 +59,7 @@ __attribute__ ((weak)) void matrix_scan_keymap(void) { } __attribute__ ((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; } -__attribute__ ((weak)) uint32_t layer_state_set_keymap (uint32_t state) { +__attribute__ ((weak)) layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } __attribute__ ((weak)) void led_set_keymap(uint8_t usb_led) { } @@ -551,7 +551,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { state = layer_state_set_keymap (state); #ifdef RGBLIGHT_ENABLE // Change RGB lighting depending on the last layer activated - rgblight_change( biton32(state) ); + rgblight_change( get_highest_layer(state) ); #endif return state; } diff --git a/users/sigma/sigma.c b/users/sigma/sigma.c index 527925a63f..8470060a53 100644 --- a/users/sigma/sigma.c +++ b/users/sigma/sigma.c @@ -49,12 +49,12 @@ bool process_record_secrets(uint16_t keycode, keyrecord_t *record) { __attribute__ ((weak)) -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } __attribute__ ((weak)) -uint32_t default_layer_state_set_keymap (uint32_t state) { +layer_state_t default_layer_state_set_keymap (layer_state_t state) { return state; } diff --git a/users/stanrc85/layer_rgb.c b/users/stanrc85/layer_rgb.c index 6d57198f3b..ad30c2ee65 100644 --- a/users/stanrc85/layer_rgb.c +++ b/users/stanrc85/layer_rgb.c @@ -5,7 +5,7 @@ void matrix_init_user(void) { }; layer_state_t layer_state_set_user(layer_state_t state) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case 0: rgblight_setrgb (0xFF, 0x00, 0x00); break; diff --git a/users/talljoe/talljoe.c b/users/talljoe/talljoe.c index 517f712ec8..6655170d4a 100644 --- a/users/talljoe/talljoe.c +++ b/users/talljoe/talljoe.c @@ -138,7 +138,7 @@ void matrix_init_user(void) { } } -uint32_t default_layer_state_set_kb(uint32_t state) { +layer_state_t default_layer_state_set_kb(layer_state_t state) { // persist changes to default layers eeconfig_update_default_layer(state); return state; diff --git a/users/tominabox1/tominabox1.c b/users/tominabox1/tominabox1.c index 7322ead0dc..b4ec224d07 100644 --- a/users/tominabox1/tominabox1.c +++ b/users/tominabox1/tominabox1.c @@ -128,7 +128,7 @@ layer_state_t layer_state_set_keymap (layer_state_t state) { layer_state_t layer_state_set_user(layer_state_t state) { state = update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST); - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _LOWER: break; case _RAISE: @@ -231,7 +231,7 @@ void render_status_main(void) { // Host Keyboard Layer Status oled_write_P(PSTR("Layer: "), false); - switch (biton32(layer_state)) { + switch (get_highest_layer(layer_state)) { case _BASE: oled_write_P(PSTR("Colemak\n"), false); break; diff --git a/users/turbomech/backupturbomech.c b/users/turbomech/backupturbomech.c index aaea05df96..3671d27ab4 100644 --- a/users/turbomech/backupturbomech.c +++ b/users/turbomech/backupturbomech.c @@ -31,7 +31,7 @@ bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; } __attribute__ ((weak)) -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } __attribute__ ((weak)) @@ -300,7 +300,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { #ifdef RGBLIGHT_ENABLE uint8_t default_layer = eeconfig_read_default_layer(); if (rgb_layer_change) { - switch (biton32(state)) { + switch (get_highest_layer(state)) { case _FUNCTION: rgblight_set_blue; rgblight_mode(1); @@ -377,7 +377,7 @@ bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; } __attribute__ ((weak)) -uint32_t layer_state_set_keymap (uint32_t state) { +layer_state_t layer_state_set_keymap (layer_state_t state) { return state; } __attribute__ ((weak)) diff --git a/users/xulkal/custom_oled.c b/users/xulkal/custom_oled.c index 7fe8040927..fd03033ad6 100644 --- a/users/xulkal/custom_oled.c +++ b/users/xulkal/custom_oled.c @@ -37,7 +37,7 @@ static void render_icon(void) static void render_layer(void) { - uint8_t layer = layer_state ? biton(layer_state) : biton32(default_layer_state); + uint8_t layer = layer_state ? get_highest_layer(layer_state) : get_highest_layer(default_layer_state); #ifdef OLED_90ROTATION oled_write_P(PSTR("Layer"), false); #else diff --git a/users/zer09/zer09.c b/users/zer09/zer09.c index a6768f0a1a..78433b4c20 100644 --- a/users/zer09/zer09.c +++ b/users/zer09/zer09.c @@ -43,7 +43,7 @@ void matrix_init_user(void) { void matrix_scan_user(void) { static uint8_t is_leds_changes = 1; - c_lyr = biton32(layer_state); + c_lyr = get_highest_layer(layer_state); is_leds_changes = is_leds_changes << set_layer_led(c_lyr); is_leds_changes = is_leds_changes << shifted_layer(); -- cgit v1.2.3 From c725b6bf89878aebe9c5ffa2f6c05abd9ea98117 Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Mon, 20 Jun 2022 02:15:55 +0800 Subject: [Core] Mouse key kinetic mode fix (#17176) Co-authored-by: Drashna Jaelre --- docs/feature_mouse_keys.md | 6 +++--- quantum/mousekey.c | 27 ++++++++++++++++----------- quantum/mousekey.h | 4 ++-- 3 files changed, 21 insertions(+), 16 deletions(-) (limited to 'quantum') diff --git a/docs/feature_mouse_keys.md b/docs/feature_mouse_keys.md index 905da36e43..8e474c4245 100644 --- a/docs/feature_mouse_keys.md +++ b/docs/feature_mouse_keys.md @@ -87,9 +87,9 @@ This is an extension of the accelerated mode. The kinetic mode uses a quadratic |`MK_KINETIC_SPEED` |undefined|Enable kinetic mode | |`MOUSEKEY_DELAY` |5 |Delay between pressing a movement key and cursor movement | |`MOUSEKEY_INTERVAL` |10 |Time between cursor movements in milliseconds | -|`MOUSEKEY_MOVE_DELTA` |5 |Step size for accelerating from initial to base speed | +|`MOUSEKEY_MOVE_DELTA` |16 |Step size for accelerating from initial to base speed | |`MOUSEKEY_INITIAL_SPEED` |100 |Initial speed of the cursor in pixel per second | -|`MOUSEKEY_BASE_SPEED` |1000 |Maximum cursor speed at which acceleration stops | +|`MOUSEKEY_BASE_SPEED` |5000 |Maximum cursor speed at which acceleration stops | |`MOUSEKEY_DECELERATED_SPEED` |400 |Decelerated cursor speed | |`MOUSEKEY_ACCELERATED_SPEED` |3000 |Accelerated cursor speed | |`MOUSEKEY_WHEEL_INITIAL_MOVEMENTS` |16 |Initial number of movements of the mouse wheel | @@ -100,7 +100,7 @@ This is an extension of the accelerated mode. The kinetic mode uses a quadratic Tips: * The smoothness of the cursor movement depends on the `MOUSEKEY_INTERVAL` setting. The shorter the interval is set the smoother the movement will be. Setting the value too low makes the cursor unresponsive. Lower settings are possible if the micro processor is fast enough. For example: At an interval of `8` milliseconds, `125` movements per second will be initiated. With a base speed of `1000` each movement will move the cursor by `8` pixels. -* Mouse wheel movements are implemented differently from cursor movements. While it's okay for the cursor to move multiple pixels at once for the mouse wheel this would lead to jerky movements. Instead, the mouse wheel operates at step size `1`. Setting mouse wheel speed is done by adjusting the number of wheel movements per second. +* Mouse wheel movements are implemented differently from cursor movements. While it's okay for the cursor to move multiple pixels at once for the mouse wheel this would lead to jerky movements. Instead, the mouse wheel operates at step size `2`. Setting mouse wheel speed is done by adjusting the number of wheel movements per second. ### Constant mode diff --git a/quantum/mousekey.c b/quantum/mousekey.c index 64d0e66682..81e887d529 100644 --- a/quantum/mousekey.c +++ b/quantum/mousekey.c @@ -66,11 +66,18 @@ uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX; /* milliseconds between the initial key press and first repeated motion event (0-2550) */ uint8_t mk_wheel_delay = MOUSEKEY_WHEEL_DELAY / 10; /* milliseconds between repeated motion events (0-255) */ -uint8_t mk_wheel_interval = MOUSEKEY_WHEEL_INTERVAL; +# ifdef MK_KINETIC_SPEED +float mk_wheel_interval = 1000.0f / MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; +# else +uint8_t mk_wheel_interval = MOUSEKEY_WHEEL_INTERVAL; +# endif uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED; uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX; # ifndef MK_COMBINED +# ifndef MK_KINETIC_SPEED + +/* Default accelerated mode */ static uint8_t move_unit(void) { uint16_t unit; @@ -108,8 +115,7 @@ static uint8_t wheel_unit(void) { return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); } -# else /* #ifndef MK_COMBINED */ -# ifdef MK_KINETIC_SPEED +# else /* #ifndef MK_KINETIC_SPEED */ /* * Kinetic movement acceleration algorithm @@ -147,27 +153,27 @@ static uint8_t move_unit(void) { return speed > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : speed; } -float mk_wheel_interval = 1000.0f / MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; - static uint8_t wheel_unit(void) { float speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; if (mousekey_accel & ((1 << 0) | (1 << 2))) { speed = mousekey_accel & (1 << 2) ? MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS : MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS; - } else if (mousekey_repeat && mouse_timer) { + } else if (mousekey_wheel_repeat && mouse_timer) { if (mk_wheel_interval != MOUSEKEY_WHEEL_BASE_MOVEMENTS) { const float time_elapsed = timer_elapsed(mouse_timer) / 50; speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS + 1 * time_elapsed + 1 * 0.5 * time_elapsed * time_elapsed; } speed = speed > MOUSEKEY_WHEEL_BASE_MOVEMENTS ? MOUSEKEY_WHEEL_BASE_MOVEMENTS : speed; } - mk_wheel_interval = 1000.0f / speed; - return 1; + return (uint8_t)speed > MOUSEKEY_WHEEL_INITIAL_MOVEMENTS ? 2 : 1; } -# else /* #ifndef MK_KINETIC_SPEED */ +# endif /* #ifndef MK_KINETIC_SPEED */ +# else /* #ifndef MK_COMBINED */ + +/* Combined mode */ static uint8_t move_unit(void) { uint16_t unit; @@ -205,8 +211,7 @@ static uint8_t wheel_unit(void) { return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); } -# endif /* #ifndef MK_KINETIC_SPEED */ -# endif /* #ifndef MK_COMBINED */ +# endif /* #ifndef MK_COMBINED */ void mousekey_task(void) { // report cursor and scroll movement independently diff --git a/quantum/mousekey.h b/quantum/mousekey.h index 03da5f282a..d44f47fc1f 100644 --- a/quantum/mousekey.h +++ b/quantum/mousekey.h @@ -39,7 +39,7 @@ along with this program. If not, see . # ifndef MK_KINETIC_SPEED # define MOUSEKEY_MOVE_DELTA 8 # else -# define MOUSEKEY_MOVE_DELTA 5 +# define MOUSEKEY_MOVE_DELTA 16 # endif # endif # ifndef MOUSEKEY_WHEEL_DELTA @@ -82,7 +82,7 @@ along with this program. If not, see . # define MOUSEKEY_INITIAL_SPEED 100 # endif # ifndef MOUSEKEY_BASE_SPEED -# define MOUSEKEY_BASE_SPEED 1000 +# define MOUSEKEY_BASE_SPEED 5000 # endif # ifndef MOUSEKEY_DECELERATED_SPEED # define MOUSEKEY_DECELERATED_SPEED 400 -- cgit v1.2.3 From 62eaec52e0b6aadfea629e7457d1d7d8647e840c Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Mon, 20 Jun 2022 15:31:27 +0100 Subject: Init eeconfig before reading handedness (#17256) --- quantum/split_common/split_util.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'quantum') diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index 48b9cce6d4..4892b7f8d8 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -135,6 +135,10 @@ void split_pre_init(void) { #if defined(SPLIT_HAND_PIN) setPinInput(SPLIT_HAND_PIN); wait_us(100); +#elif defined(EE_HANDS) + if (!eeconfig_is_enabled()) { + eeconfig_init(); + } #endif isLeftHand = is_keyboard_left(); -- cgit v1.2.3 From be42c5fb9885d3bcbf47f99ad6cef343ba2b0b97 Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Tue, 21 Jun 2022 18:53:34 +0100 Subject: Fix RGB heatmap to use XY positions and use correct led limits (#17184) * Fix RGB heatmap to use XY positions * lower effect area limit and make configurable * tidy up macro * Fix triggering in both directions. * add docs * fix bug when decreasing value * performance tweak --- docs/feature_rgb_matrix.md | 17 ++++- .../rgb_matrix/animations/typing_heatmap_anim.h | 84 +++++++++++----------- quantum/rgb_matrix/rgb_matrix.c | 11 ++- 3 files changed, 67 insertions(+), 45 deletions(-) (limited to 'quantum') diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md index 2e88ae4727..9eaf63d710 100644 --- a/docs/feature_rgb_matrix.md +++ b/docs/feature_rgb_matrix.md @@ -667,7 +667,22 @@ In order to change the delay of temperature decrease define `RGB_MATRIX_TYPING_H #define RGB_MATRIX_TYPING_HEATMAP_DECREASE_DELAY_MS 50 ``` -Heatmap effect may not light up the correct adjacent LEDs for certain key matrix layout such as split keyboards. The following define will limit the effect to pressed keys only: +As heatmap uses the physical position of the leds set in the g_led_config, you may need to tweak the following options to get the best effect for your keyboard. Note the size of this grid is `224x64`. + +Limit the distance the effect spreads to surrounding keys. + +```c +#define RGB_MATRIX_TYPING_HEATMAP_SPREAD 40 +``` + +Limit how hot surrounding keys get from each press. + +```c +#define RGB_MATRIX_TYPING_HEATMAP_AREA_LIMIT 16 +``` + +Remove the spread effect entirely. + ```c #define RGB_MATRIX_TYPING_HEATMAP_SLIM ``` diff --git a/quantum/rgb_matrix/animations/typing_heatmap_anim.h b/quantum/rgb_matrix/animations/typing_heatmap_anim.h index 4b17c4c3ed..cfc3fc015b 100644 --- a/quantum/rgb_matrix/animations/typing_heatmap_anim.h +++ b/quantum/rgb_matrix/animations/typing_heatmap_anim.h @@ -6,30 +6,35 @@ RGB_MATRIX_EFFECT(TYPING_HEATMAP) # define RGB_MATRIX_TYPING_HEATMAP_DECREASE_DELAY_MS 25 # endif +# ifndef RGB_MATRIX_TYPING_HEATMAP_SPREAD +# define RGB_MATRIX_TYPING_HEATMAP_SPREAD 40 +# endif + +# ifndef RGB_MATRIX_TYPING_HEATMAP_AREA_LIMIT +# define RGB_MATRIX_TYPING_HEATMAP_AREA_LIMIT 16 +# endif void process_rgb_matrix_typing_heatmap(uint8_t row, uint8_t col) { # ifdef RGB_MATRIX_TYPING_HEATMAP_SLIM // Limit effect to pressed keys g_rgb_frame_buffer[row][col] = qadd8(g_rgb_frame_buffer[row][col], 32); # else - uint8_t m_row = row - 1; - uint8_t p_row = row + 1; - uint8_t m_col = col - 1; - uint8_t p_col = col + 1; - - if (m_col < col) g_rgb_frame_buffer[row][m_col] = qadd8(g_rgb_frame_buffer[row][m_col], 16); - g_rgb_frame_buffer[row][col] = qadd8(g_rgb_frame_buffer[row][col], 32); - if (p_col < MATRIX_COLS) g_rgb_frame_buffer[row][p_col] = qadd8(g_rgb_frame_buffer[row][p_col], 16); - - if (p_row < MATRIX_ROWS) { - if (m_col < col) g_rgb_frame_buffer[p_row][m_col] = qadd8(g_rgb_frame_buffer[p_row][m_col], 13); - g_rgb_frame_buffer[p_row][col] = qadd8(g_rgb_frame_buffer[p_row][col], 16); - if (p_col < MATRIX_COLS) g_rgb_frame_buffer[p_row][p_col] = qadd8(g_rgb_frame_buffer[p_row][p_col], 13); - } - - if (m_row < row) { - if (m_col < col) g_rgb_frame_buffer[m_row][m_col] = qadd8(g_rgb_frame_buffer[m_row][m_col], 13); - g_rgb_frame_buffer[m_row][col] = qadd8(g_rgb_frame_buffer[m_row][col], 16); - if (p_col < MATRIX_COLS) g_rgb_frame_buffer[m_row][p_col] = qadd8(g_rgb_frame_buffer[m_row][p_col], 13); + for (uint8_t i_row = 0; i_row < MATRIX_ROWS; i_row++) { + for (uint8_t i_col = 0; i_col < MATRIX_COLS; i_col++) { + if (i_row == row && i_col == col) { + g_rgb_frame_buffer[row][col] = qadd8(g_rgb_frame_buffer[row][col], 32); + } else { +# define LED_DISTANCE(led_a, led_b) sqrt16(((int8_t)(led_a.x - led_b.x) * (int8_t)(led_a.x - led_b.x)) + ((int8_t)(led_a.y - led_b.y) * (int8_t)(led_a.y - led_b.y))) + uint8_t distance = LED_DISTANCE(g_led_config.point[g_led_config.matrix_co[row][col]], g_led_config.point[g_led_config.matrix_co[i_row][i_col]]); +# undef LED_DISTANCE + if (distance <= RGB_MATRIX_TYPING_HEATMAP_SPREAD) { + uint8_t amount = qsub8(RGB_MATRIX_TYPING_HEATMAP_SPREAD, distance); + if (amount > RGB_MATRIX_TYPING_HEATMAP_AREA_LIMIT) { + amount = RGB_MATRIX_TYPING_HEATMAP_AREA_LIMIT; + } + g_rgb_frame_buffer[i_row][i_col] = qadd8(g_rgb_frame_buffer[i_row][i_col], amount); + } + } + } } # endif } @@ -40,10 +45,7 @@ static uint16_t heatmap_decrease_timer; static bool decrease_heatmap_values; bool TYPING_HEATMAP(effect_params_t* params) { - // Modified version of RGB_MATRIX_USE_LIMITS to work off of matrix row / col size - uint8_t led_min = RGB_MATRIX_LED_PROCESS_LIMIT * params->iter; - uint8_t led_max = led_min + RGB_MATRIX_LED_PROCESS_LIMIT; - if (led_max > sizeof(g_rgb_frame_buffer)) led_max = sizeof(g_rgb_frame_buffer); + RGB_MATRIX_USE_LIMITS(led_min, led_max); if (params->init) { rgb_matrix_set_color_all(0, 0, 0); @@ -63,28 +65,26 @@ bool TYPING_HEATMAP(effect_params_t* params) { } // Render heatmap & decrease - for (int i = led_min; i < led_max; i++) { - uint8_t row = i % MATRIX_ROWS; - uint8_t col = i / MATRIX_ROWS; - uint8_t val = g_rgb_frame_buffer[row][col]; - - // set the pixel colour - uint8_t led[LED_HITS_TO_REMEMBER]; - uint8_t led_count = rgb_matrix_map_row_column_to_led(row, col, led); - for (uint8_t j = 0; j < led_count; ++j) { - if (!HAS_ANY_FLAGS(g_led_config.flags[led[j]], params->flags)) continue; - - HSV hsv = {170 - qsub8(val, 85), rgb_matrix_config.hsv.s, scale8((qadd8(170, val) - 170) * 3, rgb_matrix_config.hsv.v)}; - RGB rgb = rgb_matrix_hsv_to_rgb(hsv); - rgb_matrix_set_color(led[j], rgb.r, rgb.g, rgb.b); - } - - if (decrease_heatmap_values) { - g_rgb_frame_buffer[row][col] = qsub8(val, 1); + uint8_t count = 0; + for (uint8_t row = 0; row < MATRIX_ROWS && count < RGB_MATRIX_LED_PROCESS_LIMIT; row++) { + for (uint8_t col = 0; col < MATRIX_COLS && RGB_MATRIX_LED_PROCESS_LIMIT; col++) { + if (g_led_config.matrix_co[row][col] >= led_min && g_led_config.matrix_co[row][col] < led_max) { + count++; + uint8_t val = g_rgb_frame_buffer[row][col]; + if (!HAS_ANY_FLAGS(g_led_config.flags[g_led_config.matrix_co[row][col]], params->flags)) continue; + + HSV hsv = {170 - qsub8(val, 85), rgb_matrix_config.hsv.s, scale8((qadd8(170, val) - 170) * 3, rgb_matrix_config.hsv.v)}; + RGB rgb = rgb_matrix_hsv_to_rgb(hsv); + rgb_matrix_set_color(g_led_config.matrix_co[row][col], rgb.r, rgb.g, rgb.b); + + if (decrease_heatmap_values) { + g_rgb_frame_buffer[row][col] = qsub8(val, 1); + } + } } } - return led_max < sizeof(g_rgb_frame_buffer); + return rgb_matrix_check_finished_leds(led_max); } # endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c index f721dfc7f2..a51e379025 100644 --- a/quantum/rgb_matrix/rgb_matrix.c +++ b/quantum/rgb_matrix/rgb_matrix.c @@ -249,8 +249,15 @@ void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) { #endif // RGB_MATRIX_KEYREACTIVE_ENABLED #if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP) - if (rgb_matrix_config.mode == RGB_MATRIX_TYPING_HEATMAP) { - process_rgb_matrix_typing_heatmap(row, col); +# if defined(RGB_MATRIX_KEYRELEASES) + if (!pressed) +# else + if (pressed) +# endif // defined(RGB_MATRIX_KEYRELEASES) + { + if (rgb_matrix_config.mode == RGB_MATRIX_TYPING_HEATMAP) { + process_rgb_matrix_typing_heatmap(row, col); + } } #endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP) } -- cgit v1.2.3 From 2239527871deef1253ebe885df167726a100f971 Mon Sep 17 00:00:00 2001 From: SmugSam <88806297+SmugSam@users.noreply.github.com> Date: Wed, 22 Jun 2022 21:47:15 -0400 Subject: In honor of king terry (#17387) --- quantum/audio/song_list.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'quantum') diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h index 3e425abb47..ff22e6fe95 100644 --- a/quantum/audio/song_list.h +++ b/quantum/audio/song_list.h @@ -144,6 +144,12 @@ */ #define USSR_ANTHEM B__NOTE(_G6), B__NOTE(_C7), W__NOTE(_G6), H__NOTE(_A6), B__NOTE(_B6), W__NOTE(_E6), W__NOTE(_E6), B__NOTE(_A6), W__NOTE(_G6), H__NOTE(_F6), B__NOTE(_G6), W__NOTE(_C6), W__NOTE(_C6), B__NOTE(_D6), W__NOTE(_D6), W__NOTE(_E6), B__NOTE(_D6), W__NOTE(_D6), W__NOTE(_G6), B__NOTE(_F6), W__NOTE(_G6), W__NOTE(_A6), B__NOTE(_B6), +/* Title: Hymn Risen + * Author/Composer: Terrance Andrew Davis + * License: Public Domain + */ +#define TOS_HYMN_RISEN H__NOTE(_D5), H__NOTE(_E5), HD_NOTE(_F5), HD_NOTE(_F5), H__NOTE(_F5), HD_NOTE(_D5), E__NOTE(_E5), E__NOTE(_E5), H__NOTE(_C5), Q__NOTE(_D5), Q__NOTE(_D5), H__NOTE(_E5), H__NOTE(_C5), Q__NOTE(_G5), Q__NOTE(_F5), H__NOTE(_D5), H__NOTE(_E5), HD_NOTE(_F5), HD_NOTE(_F5), H__NOTE(_F5), HD_NOTE(_D5), E__NOTE(_E5), E__NOTE(_E5), H__NOTE(_C5), Q__NOTE(_D5), Q__NOTE(_D5), H__NOTE(_E5), H__NOTE(_C5), Q__NOTE(_G5), Q__NOTE(_F5), H__NOTE(_D5), H__NOTE(_C5), W__NOTE(_D5), W__NOTE(_E5), Q__NOTE(_A4), H__NOTE(_A4), Q__NOTE(_E5), Q__NOTE(_E5), Q__NOTE(_F5), Q__NOTE(_E5), Q__NOTE(_D5), Q__NOTE(_G5), Q__NOTE(_B4), Q__NOTE(_D5), Q__NOTE(_C5), M__NOTE(_F5, 80), H__NOTE(_D5), H__NOTE(_C5), W__NOTE(_D5), W__NOTE(_E5), Q__NOTE(_A4), H__NOTE(_A4), Q__NOTE(_E5), Q__NOTE(_E5), Q__NOTE(_F5), Q__NOTE(_E5), Q__NOTE(_D5), Q__NOTE(_G5), Q__NOTE(_B4), Q__NOTE(_D5), Q__NOTE(_C5), M__NOTE(_F5, 80) + /* Removed sounds + This list is here solely for compatibility, so that removed songs don't just break things * If you think that any of these songs were wrongfully removed, let us know and provide -- cgit v1.2.3 From 7060cb7b267e78ba693a77a3346c77c2d4209b01 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Thu, 23 Jun 2022 20:43:24 +0200 Subject: Refactor steno and add `STENO_PROTOCOL = [all|txbolt|geminipr]` (#17065) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor steno into STENO_ENABLE_[ALL|GEMINI|BOLT] * Update stenography documentation * STENO_ENABLE_TXBOLT → STENO_ENABLE_BOLT TXBOLT is a better name but BOLT is more consistent with the pre-existing TX Bolt related constants, which all drop the "TX " prefix * Comments * STENO_ENABLE_[GEMINI|BOLT|ALL] → STENO_PROTOCOL = [geminipr|txbolt|all] * Add note on lacking V-USB support * Clear chord at the end of the switch(mode){send_steno_chord} block * Return true if NOEVENT * update_chord_xxx → add_xxx_key_to_chord * Enable the defines for all the protocols if STENO_PROTOCOL = all * Mention how to use `steno_set_mode` * Set the default steno protocol to "all" This is done so that existing keymaps invoking `steno_set_mode` don't all suddenly break * Add data driver equivalents for stenography feature * Document format of serial steno packets (Thanks dnaq) * Add missing comma --- builddefs/common_features.mk | 25 ++- builddefs/show_options.mk | 1 + data/mappings/info_rules.json | 2 + data/schemas/keyboard.jsonschema | 11 ++ docs/feature_stenography.md | 123 ++++++++++--- quantum/keyboard.c | 2 +- quantum/keymap_extras/keymap_steno.h | 28 +++ quantum/process_keycode/process_steno.c | 312 +++++++++++++++++--------------- quantum/process_keycode/process_steno.h | 24 ++- 9 files changed, 349 insertions(+), 179 deletions(-) (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 83505596d2..b9ee0a30a7 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -92,10 +92,29 @@ ifeq ($(MUSIC_ENABLE), yes) SRC += $(QUANTUM_DIR)/process_keycode/process_music.c endif +VALID_STENO_PROTOCOL_TYPES := geminipr txbolt all +STENO_PROTOCOL ?= all ifeq ($(strip $(STENO_ENABLE)), yes) - OPT_DEFS += -DSTENO_ENABLE - VIRTSER_ENABLE ?= yes - SRC += $(QUANTUM_DIR)/process_keycode/process_steno.c + ifeq ($(filter $(STENO_PROTOCOL),$(VALID_STENO_PROTOCOL_TYPES)),) + $(call CATASTROPHIC_ERROR,Invalid STENO_PROTOCOL,STENO_PROTOCOL="$(STENO_PROTOCOL)" is not a valid stenography protocol) + else + OPT_DEFS += -DSTENO_ENABLE + VIRTSER_ENABLE ?= yes + + ifeq ($(strip $(STENO_PROTOCOL)), geminipr) + OPT_DEFS += -DSTENO_ENABLE_GEMINI + endif + ifeq ($(strip $(STENO_PROTOCOL)), txbolt) + OPT_DEFS += -DSTENO_ENABLE_BOLT + endif + ifeq ($(strip $(STENO_PROTOCOL)), all) + OPT_DEFS += -DSTENO_ENABLE_ALL + OPT_DEFS += -DSTENO_ENABLE_GEMINI + OPT_DEFS += -DSTENO_ENABLE_BOLT + endif + + SRC += $(QUANTUM_DIR)/process_keycode/process_steno.c + endif endif ifeq ($(strip $(VIRTSER_ENABLE)), yes) diff --git a/builddefs/show_options.mk b/builddefs/show_options.mk index 1c1c189f27..98537e6da2 100644 --- a/builddefs/show_options.mk +++ b/builddefs/show_options.mk @@ -45,6 +45,7 @@ OTHER_OPTION_NAMES = \ LEADER_ENABLE \ PRINTING_ENABLE \ STENO_ENABLE \ + STENO_PROTOCOL \ TAP_DANCE_ENABLE \ VIRTSER_ENABLE \ OLED_ENABLE \ diff --git a/data/mappings/info_rules.json b/data/mappings/info_rules.json index 5cdae962a5..279b5ac213 100644 --- a/data/mappings/info_rules.json +++ b/data/mappings/info_rules.json @@ -28,6 +28,8 @@ "SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"}, "SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "to_c": false}, "WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"}, + "STENO_ENABLE": {"info_key": "stenography.enabled", "value_type": "bool"}, + "STENO_PROTOCOL": {"info_key": "stenography.protocol"}, # Items we want flagged in lint "CTPC": {"info_key": "_deprecated.ctpc", "deprecated": true}, diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema index 8d9fc4754d..ec5377b3b3 100644 --- a/data/schemas/keyboard.jsonschema +++ b/data/schemas/keyboard.jsonschema @@ -361,6 +361,17 @@ } } }, + "stenography": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": {"type": "boolean"}, + "protocol": { + "type": "string", + "enum": ["all", "geminipr", "txbolt"] + } + } + }, "split": { "type": "object", "additionalProperties": false, diff --git a/docs/feature_stenography.md b/docs/feature_stenography.md index 2b52bb17a6..e13fe845c5 100644 --- a/docs/feature_stenography.md +++ b/docs/feature_stenography.md @@ -8,46 +8,107 @@ The [Open Steno Project](https://www.openstenoproject.org/) has built an open-so Plover can work with any standard QWERTY keyboard, although it is more efficient if the keyboard supports NKRO (n-key rollover) to allow Plover to see all the pressed keys at once. An example keymap for Plover can be found in `planck/keymaps/default`. Switching to the `PLOVER` layer adjusts the position of the keyboard to support the number bar. -To use Plover with QMK just enable NKRO and optionally adjust your layout if you have anything other than a standard layout. You may also want to purchase some steno-friendly keycaps to make it easier to hit multiple keys. +To enable NKRO, add `NKRO_ENABLE = yes` in your `rules.mk` and make sure to press `NK_ON` to turn it on because `NKRO_ENABLE = yes` merely adds the possibility of switching to NKRO mode but it doesn't automatically switch to it. If you want to automatically switch, add `#define FORCE_NKRO` in your `config.h`. + +You may also need to adjust your layout, either in QMK or in Plover, if you have anything other than a standard layout. You may also want to purchase some steno-friendly keycaps to make it easier to hit multiple keys. ## Plover with Steno Protocol :id=plover-with-steno-protocol -Plover also understands the language of several steno machines. QMK can speak a couple of these languages, TX Bolt and GeminiPR. An example layout can be found in `planck/keymaps/steno`. +Plover also understands the language of several steno machines. QMK can speak a couple of these languages: TX Bolt and GeminiPR. An example layout can be found in `planck/keymaps/steno`. + +When QMK speaks to Plover over a steno protocol, Plover will not use the keyboard as input. This means that you can switch back and forth between a standard keyboard and your steno keyboard, or even switch layers from Plover to standard and back without needing to activate/deactivate Plover. + +In this mode, Plover expects to speak with a steno machine over a serial port so QMK will present itself to the operating system as a virtual serial port in addition to a keyboard. -When QMK speaks to Plover over a steno protocol Plover will not use the keyboard as input. This means that you can switch back and forth between a standard keyboard and your steno keyboard, or even switch layers from Plover to standard and back without needing to activate/deactivate Plover. +> Note: Due to hardware limitations, you might not be able to run both a virtual serial port and mouse emulation at the same time. -In this mode Plover expects to speak with a steno machine over a serial port so QMK will present itself to the operating system as a virtual serial port in addition to a keyboard. By default QMK will speak the TX Bolt protocol but can be switched to GeminiPR; the last protocol used is stored in non-volatile memory so QMK will use the same protocol on restart. +!> Serial stenography protocols are not supported on [V-USB keyboards](compatible_microcontrollers#atmel-avr). -> Note: Due to hardware limitations you may not be able to run both a virtual serial port and mouse emulation at the same time. +To enable stenography protocols, add the following lines to your `rules.mk`: +```mk +STENO_ENABLE = yes +``` ### TX Bolt :id=tx-bolt -TX Bolt communicates the status of 24 keys over a very simple protocol in variable-sized (1-5 byte) packets. +TX Bolt communicates the status of 24 keys over a simple protocol in variable-sized (1–4 bytes) packets. -### GeminiPR :id=geminipr +To select TX Bolt, add the following lines to your `rules.mk`: +```mk +STENO_ENABLE = yes +STENO_PROTOCOL = txbolt +``` -GeminiPR encodes 42 keys into a 6-byte packet. While TX Bolt contains everything that is necessary for standard stenography, GeminiPR opens up many more options, including supporting non-English theories. +Each byte of the packet represents a different group of steno keys. Determining the group of a certain byte of the packet is done by checking the first two bits, the remaining bits are set if the corresponding steno key was pressed for the stroke. The last set of keys (as indicated by leading `11`) needs to keep track of less keys than there are bits so one of the bits is constantly 0. -## Configuring QMK for Steno :id=configuring-qmk-for-steno +The start of a new packet can be detected by comparing the group “ID” (the two MSBs) of the current byte to that of the previously received byte. If the group “ID” of the current byte is smaller or equal to that of the previous byte, it means that the current byte is the beginning of a new packet. -Firstly, enable steno in your keymap's Makefile. You may also need disable mousekeys, extra keys, or another USB endpoint to prevent conflicts. The builtin USB stack for some processors only supports a certain number of USB endpoints and the virtual serial port needed for steno fills 3 of them. +The format of TX Bolt packets is shown below. +``` +00HWPKTS 01UE*OAR 10GLBPRF 110#ZDST +``` + +Examples of steno strokes and the associated packet: +- `EUBG` = `01110000 10101000` +- `WAZ` = `00010000 01000010 11001000` +- `PHAPBGS` = `00101000 01000010 10101100 11000010` + +### GeminiPR :id=geminipr + +GeminiPR encodes 42 keys into a 6-byte packet. While TX Bolt contains everything that is necessary for standard stenography, GeminiPR opens up many more options, including differentiating between top and bottom `S-`, and supporting non-English theories. -```make +To select GeminiPR, add the following lines to your `rules.mk`: +```mk STENO_ENABLE = yes -MOUSEKEY_ENABLE = no +STENO_PROTOCOL = geminipr ``` -In your keymap create a new layer for Plover. You will need to include `keymap_steno.h`. See `planck/keymaps/steno/keymap.c` for an example. Remember to create a key to switch to the layer as well as a key for exiting the layer. If you would like to switch modes on the fly you can use the keycodes `QK_STENO_BOLT` and `QK_STENO_GEMINI`. If you only want to use one of the protocols you may set it up in your initialization function: +All packets in the GeminiPR protocol consist of exactly six bytes, used as bit-arrays for different groups of keys. The beginning of a packet is indicated by setting the most significant bit (MSB) to 1 while setting the MSB of the remaining five bytes to 0. -```c -void eeconfig_init_user() { - steno_set_mode(STENO_MODE_GEMINI); // or STENO_MODE_BOLT -} +The format of GeminiPR packets is shown below. +``` +1 Fn #1 #2 #3 #4 #5 #6 +0 S1- S2- T- K- P- W- H- +0 R- A- O- *1 *2 res1 res2 +0 pwr *3 *4 -E -U -F -R +0 -P -B -L -G -T -S -D +0 #7 #8 #9 #A #B #C -Z ``` -Once you have your keyboard flashed launch Plover. Click the 'Configure...' button. In the 'Machine' tab select the Stenotype Machine that corresponds to your desired protocol. Click the 'Configure...' button on this tab and enter the serial port or click 'Scan'. Baud rate is fine at 9600 (although you should be able to set as high as 115200 with no issues). Use the default settings for everything else (Data Bits: 8, Stop Bits: 1, Parity: N, no flow control). +Examples of steno strokes and the associated packet: +- `EUBG` = `10000000 00000000 00000000 00001100 00101000 00000000` +- `WAZ` = `10000000 00000010 00100000 00000000 00000000 00000001` +- `PHAPBGS` = `10000000 00000101 00100000 00000000 01101010 00000000` -On the display tab click 'Open stroke display'. With Plover disabled you should be able to hit keys on your keyboard and see them show up in the stroke display window. Use this to make sure you have set up your keymap correctly. You are now ready to steno! +### Switching protocols on the fly :id=switching-protocols-on-the-fly + +If you wish to switch the serial protocol used to transfer the steno chords without having to recompile your keyboard firmware every time, you can press the `QK_STENO_BOLT` and `QK_STENO_GEMINI` keycodes in order to switch protocols on the fly. + +To enable these special keycodes, add the following lines to your `rules.mk`: +```mk +STENO_ENABLE = yes +STENO_PROTOCOL = all +``` + +If you want to switch protocols programatically, as part of a custom macro for example, don't use `tap_code(QK_STENO_*)`, as `tap_code` only supports [basic keycodes](keycodes_basic). Instead, you should use `steno_set_mode(STENO_MODE_*)`, whose valid arguments are `STENO_MODE_BOLT` and `STENO_MODE_GEMINI`. + +The default protocol is Gemini PR but the last protocol used is stored in non-volatile memory so QMK will remember your choice between reboots of your keyboard — assuming that your keyboard features (emulated) EEPROM. + +Naturally, this option takes the most amount of firmware space as it needs to compile the code for all the available stenography protocols. In most cases, compiling a single stenography protocol is sufficient. + +The default value for `STENO_PROTOCOL` is `all`. + +## Configuring QMK for Steno :id=configuring-qmk-for-steno + +After enabling stenography and optionally selecting a protocol, you may also need disable mouse keys, extra keys, or another USB endpoint to prevent conflicts. The builtin USB stack for some processors only supports a certain number of USB endpoints and the virtual serial port needed for steno fills 3 of them. + +!> If you had *explicitly* set `VIRSTER_ENABLE = no`, none of the serial stenography protocols (GeminiPR, TX Bolt) will work properly. You are expected to either set it to `yes`, remove the line from your `rules.mk` or send the steno chords yourself in an alternative way using the [provided interceptable hooks](#interfacing-with-the-code). + +In your keymap, create a new layer for Plover, that you can fill in with the [steno keycodes](#keycode-reference) (you will need to include `keymap_steno.h`, see `planck/keymaps/steno/keymap.c` for an example). Remember to create a key to switch to the layer as well as a key for exiting the layer. + +Once you have your keyboard flashed, launch Plover. Click the 'Configure...' button. In the 'Machine' tab, select the Stenotype Machine that corresponds to your desired protocol. Click the 'Configure...' button on this tab and enter the serial port or click 'Scan'. Baud rate is fine at 9600 (although you should be able to set as high as 115200 with no issues). Use the default settings for everything else (Data Bits: 8, Stop Bits: 1, Parity: N, no flow control). + +To test your keymap, you can chord keys on your keyboard and either look at the output of the 'paper tape' (Tools > Paper Tape) or that of the 'layout display' (Tools > Layout Display). If your strokes correctly show up, you are now ready to steno! ## Learning Stenography :id=learning-stenography @@ -60,7 +121,7 @@ On the display tab click 'Open stroke display'. With Plover disabled you should The steno code has three interceptable hooks. If you define these functions, they will be called at certain points in processing; if they return true, processing continues, otherwise it's assumed you handled things. ```c -bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]); +bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE]); ``` This function is called when a chord is about to be sent. Mode will be one of `STENO_MODE_BOLT` or `STENO_MODE_GEMINI`. This represents the actual chord that would be sent via whichever protocol. You can modify the chord provided to alter what gets sent. Remember to return true if you want the regular sending process to happen. @@ -72,15 +133,23 @@ bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; } This function is called when a keypress has come in, before it is processed. The keycode should be one of `QK_STENO_BOLT`, `QK_STENO_GEMINI`, or one of the `STN_*` key values. ```c -bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed); +bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys); ``` -This function is called after a key has been processed, but before any decision about whether or not to send a chord. If `IS_PRESSED(record->event)` is false, and `pressed` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This is where to put hooks for things like, say, live displays of steno chords or keys. +This function is called after a key has been processed, but before any decision about whether or not to send a chord. This is where to put hooks for things like, say, live displays of steno chords or keys. + +If `IS_PRESSED(record->event)` is false, and `n_pressed_keys` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This relieves you of the need of keeping track of where a packet ends and another begins. + +The `chord` argument contains the packet of the current chord as specified by the protocol in use. This is *NOT* simply a list of chorded steno keys of the form `[STN_E, STN_U, STN_BR, STN_GR]`. Refer to the appropriate protocol section of this document to learn more about the format of the packets in your steno protocol/mode of choice. +The `n_pressed_keys` argument is the number of physical keys actually being held down. +This is not always equal to the number of bits set to 1 (aka the [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight)) in `chord` because it is possible to simultaneously press down four keys, then release three of those four keys and then press yet another key while the fourth finger is still holding down its key. +At the end of this scenario given as an example, `chord` would have five bits set to 1 but +`n_pressed_keys` would be set to 2 because there are only two keys currently being pressed down. ## Keycode Reference :id=keycode-reference -As defined in `keymap_steno.h`. +You must include `keymap_steno.h` to your `keymap.c` with `#include "keymap_steno.h"` before you can use these keycodes > Note: TX Bolt does not support the full set of keys. The TX Bolt implementation in QMK will map the GeminiPR keys to the nearest TX Bolt key so that one key map will work for both. @@ -124,10 +193,10 @@ As defined in `keymap_steno.h`. |`STN_SR`|`STN_SR`| `-S`| |`STN_DR`|`STN_DR`| `-D`| |`STN_ZR`|`STN_ZR`| `-Z`| -|`STN_FN`|| (GeminiPR only)| -|`STN_RES1`||(GeminiPR only)| -|`STN_RES2`||(GeminiPR only)| -|`STN_PWR`||(GeminiPR only)| +|`STN_FN`|| (Function)| +|`STN_RES1`||(Reset 1)| +|`STN_RES2`||(Reset 2)| +|`STN_PWR`||(Power)| If you do not want to hit two keys with one finger combined keycodes can be used. These are also defined in `keymap_steno.h`, and causes both keys to be reported as pressed or released. To use these keycodes define `STENO_COMBINEDMAP` in your `config.h` file. diff --git a/quantum/keyboard.c b/quantum/keyboard.c index a65f9d6d18..8273299a9a 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c @@ -381,7 +381,7 @@ void keyboard_init(void) { #ifdef ENCODER_ENABLE encoder_init(); #endif -#ifdef STENO_ENABLE +#ifdef STENO_ENABLE_ALL steno_init(); #endif #ifdef POINTING_DEVICE_ENABLE diff --git a/quantum/keymap_extras/keymap_steno.h b/quantum/keymap_extras/keymap_steno.h index e888ccd643..07d96b7465 100644 --- a/quantum/keymap_extras/keymap_steno.h +++ b/quantum/keymap_extras/keymap_steno.h @@ -89,3 +89,31 @@ enum steno_combined_keycodes { STN_COMB_MAX = STN_EU, }; #endif + +#ifdef STENO_ENABLE_BOLT +// TxBolt Codes +# define TXB_NUL 0 +# define TXB_S_L 0b00000001 +# define TXB_T_L 0b00000010 +# define TXB_K_L 0b00000100 +# define TXB_P_L 0b00001000 +# define TXB_W_L 0b00010000 +# define TXB_H_L 0b00100000 +# define TXB_R_L 0b01000001 +# define TXB_A_L 0b01000010 +# define TXB_O_L 0b01000100 +# define TXB_STR 0b01001000 +# define TXB_E_R 0b01010000 +# define TXB_U_R 0b01100000 +# define TXB_F_R 0b10000001 +# define TXB_R_R 0b10000010 +# define TXB_P_R 0b10000100 +# define TXB_B_R 0b10001000 +# define TXB_L_R 0b10010000 +# define TXB_G_R 0b10100000 +# define TXB_T_R 0b11000001 +# define TXB_S_R 0b11000010 +# define TXB_D_R 0b11000100 +# define TXB_Z_R 0b11001000 +# define TXB_NUM 0b11010000 +#endif // STENO_ENABLE_BOLT diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c index 12ee898212..20b8b9db4b 100644 --- a/quantum/process_keycode/process_steno.c +++ b/quantum/process_keycode/process_steno.c @@ -1,4 +1,4 @@ -/* Copyright 2017 Joseph Wasson +/* Copyright 2017, 2022 Joseph Wasson, Vladislav Kucheriavykh * * 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 @@ -15,77 +15,118 @@ */ #include "process_steno.h" #include "quantum_keycodes.h" -#include "eeprom.h" #include "keymap_steno.h" -#include "virtser.h" #include +#ifdef VIRTSER_ENABLE +# include "virtser.h" +#endif +#ifdef STENO_ENABLE_ALL +# include "eeprom.h" +#endif -// TxBolt Codes -#define TXB_NUL 0 -#define TXB_S_L 0b00000001 -#define TXB_T_L 0b00000010 -#define TXB_K_L 0b00000100 -#define TXB_P_L 0b00001000 -#define TXB_W_L 0b00010000 -#define TXB_H_L 0b00100000 -#define TXB_R_L 0b01000001 -#define TXB_A_L 0b01000010 -#define TXB_O_L 0b01000100 -#define TXB_STR 0b01001000 -#define TXB_E_R 0b01010000 -#define TXB_U_R 0b01100000 -#define TXB_F_R 0b10000001 -#define TXB_R_R 0b10000010 -#define TXB_P_R 0b10000100 -#define TXB_B_R 0b10001000 -#define TXB_L_R 0b10010000 -#define TXB_G_R 0b10100000 -#define TXB_T_R 0b11000001 -#define TXB_S_R 0b11000010 -#define TXB_D_R 0b11000100 -#define TXB_Z_R 0b11001000 -#define TXB_NUM 0b11010000 - -#define TXB_GRP0 0b00000000 -#define TXB_GRP1 0b01000000 -#define TXB_GRP2 0b10000000 -#define TXB_GRP3 0b11000000 -#define TXB_GRPMASK 0b11000000 - -#define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6) - -#define BOLT_STATE_SIZE 4 -#define GEMINI_STATE_SIZE 6 -#define MAX_STATE_SIZE GEMINI_STATE_SIZE - -static uint8_t state[MAX_STATE_SIZE] = {0}; -static uint8_t chord[MAX_STATE_SIZE] = {0}; -static int8_t pressed = 0; +// All steno keys that have been pressed to form this chord, +// stored in MAX_STROKE_SIZE groups of 8-bit arrays. +static uint8_t chord[MAX_STROKE_SIZE] = {0}; +// The number of physical keys actually being held down. +// This is not always equal to the number of 1 bits in `chord` because it is possible to +// simultaneously press down four keys, then release three of those four keys and then press yet +// another key while the fourth finger is still holding down its key. +// At the end of this scenario given as an example, `chord` would have five bits set to 1 but +// `n_pressed_keys` would be set to 2 because there are only two keys currently being pressed down. +static int8_t n_pressed_keys = 0; + +#ifdef STENO_ENABLE_ALL static steno_mode_t mode; - -static const uint8_t boltmap[64] PROGMEM = {TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L, TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL, TXB_NUL, TXB_STR, TXB_STR, TXB_E_R, TXB_U_R, TXB_F_R, TXB_R_R, TXB_P_R, TXB_B_R, TXB_L_R, TXB_G_R, TXB_T_R, TXB_S_R, TXB_D_R, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R}; - -#ifdef STENO_COMBINEDMAP -/* Used to look up when pressing the middle row key to combine two consonant or vowel keys */ -static const uint16_t combinedmap_first[] PROGMEM = {STN_S1, STN_TL, STN_PL, STN_HL, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, STN_A, STN_E}; -static const uint16_t combinedmap_second[] PROGMEM = {STN_S2, STN_KL, STN_WL, STN_RL, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR, STN_O, STN_U}; +#elif defined(STENO_ENABLE_GEMINI) +static const steno_mode_t mode = STENO_MODE_GEMINI; +#elif defined(STENO_ENABLE_BOLT) +static const steno_mode_t mode = STENO_MODE_BOLT; #endif -static void steno_clear_state(void) { - memset(state, 0, sizeof(state)); +static inline void steno_clear_chord(void) { memset(chord, 0, sizeof(chord)); } -static void send_steno_state(uint8_t size, bool send_empty) { - for (uint8_t i = 0; i < size; ++i) { - if (chord[i] || send_empty) { -#ifdef VIRTSER_ENABLE +#ifdef STENO_ENABLE_GEMINI + +# ifdef VIRTSER_ENABLE +void send_steno_chord_gemini(void) { + // Set MSB to 1 to indicate the start of packet + chord[0] |= 0x80; + for (uint8_t i = 0; i < GEMINI_STROKE_SIZE; ++i) { + virtser_send(chord[i]); + } +} +# else +# pragma message "VIRTSER_ENABLE = yes is required for Gemini PR to work properly out of the box!" +# endif // VIRTSER_ENABLE + +/** + * @precondition: `key` is pressed + */ +bool add_gemini_key_to_chord(uint8_t key) { + // Although each group of the packet is 8 bits long, the MSB is reserved + // to indicate whether that byte is the first byte of the packet (MSB=1) + // or one of the remaining five bytes of the packet (MSB=0). + // As a consequence, only 7 out of the 8 bits are left to be used as a bit array + // for the steno keys of that group. + const int group_idx = key / 7; + const int intra_group_idx = key - group_idx * 7; + // The 0th steno key of the group has bit=0b01000000, the 1st has bit=0b00100000, etc. + const uint8_t bit = 1 << (6 - intra_group_idx); + chord[group_idx] |= bit; + return false; +} +#endif // STENO_ENABLE_GEMINI + +#ifdef STENO_ENABLE_BOLT + +# define TXB_GRP0 0b00000000 +# define TXB_GRP1 0b01000000 +# define TXB_GRP2 0b10000000 +# define TXB_GRP3 0b11000000 +# define TXB_GRPMASK 0b11000000 + +# define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6) + +static const uint8_t boltmap[64] PROGMEM = {TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L, TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL, TXB_NUL, TXB_STR, TXB_STR, TXB_E_R, TXB_U_R, TXB_F_R, TXB_R_R, TXB_P_R, TXB_B_R, TXB_L_R, TXB_G_R, TXB_T_R, TXB_S_R, TXB_D_R, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R}; + +# ifdef VIRTSER_ENABLE +static void send_steno_chord_bolt(void) { + for (uint8_t i = 0; i < BOLT_STROKE_SIZE; ++i) { + // TX Bolt uses variable length packets where each byte corresponds to a bit array of certain keys. + // If a user chorded the keys of the first group with keys of the last group, for example, there + // would be bytes of 0x00 in `chord` for the middle groups which we mustn't send. + if (chord[i]) { virtser_send(chord[i]); -#endif } } + // Sending a null packet is not always necessary, but it is simpler and more reliable + // to unconditionally send it every time instead of keeping track of more states and + // creating more branches in the execution of the program. + virtser_send(0); } +# else +# pragma message "VIRTSER_ENABLE = yes is required for TX Bolt to work properly out of the box!" +# endif // VIRTSER_ENABLE + +/** + * @precondition: `key` is pressed + */ +static bool add_bolt_key_to_chord(uint8_t key) { + uint8_t boltcode = pgm_read_byte(boltmap + key); + chord[TXB_GET_GROUP(boltcode)] |= boltcode; + return false; +} +#endif // STENO_ENABLE_BOLT + +#ifdef STENO_COMBINEDMAP +/* Used to look up when pressing the middle row key to combine two consonant or vowel keys */ +static const uint16_t combinedmap_first[] PROGMEM = {STN_S1, STN_TL, STN_PL, STN_HL, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, STN_A, STN_E}; +static const uint16_t combinedmap_second[] PROGMEM = {STN_S2, STN_KL, STN_WL, STN_RL, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR, STN_O, STN_U}; +#endif +#ifdef STENO_ENABLE_ALL void steno_init() { if (!eeconfig_is_enabled()) { eeconfig_init(); @@ -94,19 +135,20 @@ void steno_init() { } void steno_set_mode(steno_mode_t new_mode) { - steno_clear_state(); + steno_clear_chord(); mode = new_mode; eeprom_update_byte(EECONFIG_STENOMODE, mode); } +#endif // STENO_ENABLE_ALL /* override to intercept chords right before they get sent. * return zero to suppress normal sending behavior. */ -__attribute__((weak)) bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { +__attribute__((weak)) bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE]) { return true; } -__attribute__((weak)) bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed) { +__attribute__((weak)) bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys) { return true; } @@ -114,108 +156,94 @@ __attribute__((weak)) bool process_steno_user(uint16_t keycode, keyrecord_t *rec return true; } -static void send_steno_chord(void) { - if (send_steno_chord_user(mode, chord)) { - switch (mode) { - case STENO_MODE_BOLT: - send_steno_state(BOLT_STATE_SIZE, false); -#ifdef VIRTSER_ENABLE - virtser_send(0); // terminating byte -#endif - break; - case STENO_MODE_GEMINI: - chord[0] |= 0x80; // Indicate start of packet - send_steno_state(GEMINI_STATE_SIZE, true); - break; - } +bool process_steno(uint16_t keycode, keyrecord_t *record) { + if (keycode < QK_STENO || keycode > QK_STENO_MAX) { + return true; // Not a steno key, pass it further along the chain + /* + * Clearing or sending the chord state is not necessary as we intentionally ignore whatever + * normal keyboard keys the user may have tapped while chording steno keys. + */ } - steno_clear_state(); -} - -uint8_t *steno_get_state(void) { - return &state[0]; -} - -uint8_t *steno_get_chord(void) { - return &chord[0]; -} - -static bool update_state_bolt(uint8_t key, bool press) { - uint8_t boltcode = pgm_read_byte(boltmap + key); - if (press) { - state[TXB_GET_GROUP(boltcode)] |= boltcode; - chord[TXB_GET_GROUP(boltcode)] |= boltcode; - } else { - state[TXB_GET_GROUP(boltcode)] &= ~boltcode; + if (IS_NOEVENT(record->event)) { + return true; } - return false; -} - -static bool update_state_gemini(uint8_t key, bool press) { - int idx = key / 7; - uint8_t bit = 1 << (6 - (key % 7)); - if (press) { - state[idx] |= bit; - chord[idx] |= bit; - } else { - state[idx] &= ~bit; + if (!process_steno_user(keycode, record)) { + return false; // User fully processed the steno key themselves } - return false; -} - -bool process_steno(uint16_t keycode, keyrecord_t *record) { switch (keycode) { +#ifdef STENO_ENABLE_ALL case QK_STENO_BOLT: - if (!process_steno_user(keycode, record)) { - return false; - } if (IS_PRESSED(record->event)) { steno_set_mode(STENO_MODE_BOLT); } return false; case QK_STENO_GEMINI: - if (!process_steno_user(keycode, record)) { - return false; - } if (IS_PRESSED(record->event)) { steno_set_mode(STENO_MODE_GEMINI); } return false; +#endif // STENO_ENABLE_ALL #ifdef STENO_COMBINEDMAP case QK_STENO_COMB ... QK_STENO_COMB_MAX: { - uint8_t result; - result = process_steno(combinedmap_first[keycode - QK_STENO_COMB], record); - result &= process_steno(combinedmap_second[keycode - QK_STENO_COMB], record); - return result; + bool first_result = process_steno(combinedmap_first[keycode - QK_STENO_COMB], record); + bool second_result = process_steno(combinedmap_second[keycode - QK_STENO_COMB], record); + return first_result && second_result; } -#endif +#endif // STENO_COMBINEDMAP case STN__MIN ... STN__MAX: - if (!process_steno_user(keycode, record)) { - return false; - } - switch (mode) { - case STENO_MODE_BOLT: - update_state_bolt(keycode - QK_STENO, IS_PRESSED(record->event)); - break; - case STENO_MODE_GEMINI: - update_state_gemini(keycode - QK_STENO, IS_PRESSED(record->event)); - break; - } - // allow postprocessing hooks - if (postprocess_steno_user(keycode, record, mode, chord, pressed)) { - if (IS_PRESSED(record->event)) { - ++pressed; - } else { - --pressed; - if (pressed <= 0) { - pressed = 0; - send_steno_chord(); - } + if (IS_PRESSED(record->event)) { + n_pressed_keys++; + switch (mode) { +#ifdef STENO_ENABLE_BOLT + case STENO_MODE_BOLT: + add_bolt_key_to_chord(keycode - QK_STENO); + break; +#endif // STENO_ENABLE_BOLT +#ifdef STENO_ENABLE_GEMINI + case STENO_MODE_GEMINI: + add_gemini_key_to_chord(keycode - QK_STENO); + break; +#endif // STENO_ENABLE_GEMINI + default: + return false; } + if (!postprocess_steno_user(keycode, record, mode, chord, n_pressed_keys)) { + return false; + } + } else { // is released + n_pressed_keys--; + if (!postprocess_steno_user(keycode, record, mode, chord, n_pressed_keys)) { + return false; + } + if (n_pressed_keys > 0) { + // User hasn't released all keys yet, + // so the chord cannot be sent + return false; + } + n_pressed_keys = 0; + if (!send_steno_chord_user(mode, chord)) { + steno_clear_chord(); + return false; + } + switch (mode) { +#if defined(STENO_ENABLE_BOLT) && defined(VIRTSER_ENABLE) + case STENO_MODE_BOLT: + send_steno_chord_bolt(); + break; +#endif // STENO_ENABLE_BOLT && VIRTSER_ENABLE +#if defined(STENO_ENABLE_GEMINI) && defined(VIRTSER_ENABLE) + case STENO_MODE_GEMINI: + send_steno_chord_gemini(); + break; +#endif // STENO_ENABLE_GEMINI && VIRTSER_ENABLE + default: + break; + } + steno_clear_chord(); } - return false; + break; } - return true; + return false; } diff --git a/quantum/process_keycode/process_steno.h b/quantum/process_keycode/process_steno.h index d11fd40af0..68d6097b9b 100644 --- a/quantum/process_keycode/process_steno.h +++ b/quantum/process_keycode/process_steno.h @@ -18,10 +18,22 @@ #include "quantum.h" -typedef enum { STENO_MODE_BOLT, STENO_MODE_GEMINI } steno_mode_t; +#define BOLT_STROKE_SIZE 4 +#define GEMINI_STROKE_SIZE 6 -bool process_steno(uint16_t keycode, keyrecord_t *record); -void steno_init(void); -void steno_set_mode(steno_mode_t mode); -uint8_t *steno_get_state(void); -uint8_t *steno_get_chord(void); +#ifdef STENO_ENABLE_GEMINI +# define MAX_STROKE_SIZE GEMINI_STROKE_SIZE +#else +# define MAX_STROKE_SIZE BOLT_STROKE_SIZE +#endif + +typedef enum { + STENO_MODE_GEMINI, + STENO_MODE_BOLT, +} steno_mode_t; + +bool process_steno(uint16_t keycode, keyrecord_t *record); +#ifdef STENO_ENABLE_ALL +void steno_init(void); +void steno_set_mode(steno_mode_t mode); +#endif // STENO_ENABLE_ALL -- cgit v1.2.3 From 3b9e186019f74d5046fbdd399b5cfa0baf513a75 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Fri, 24 Jun 2022 12:40:09 +0200 Subject: Do not enable PERMISSIVE_HOLD when TAPPING_TERM exceeds 500ms (#15674) --- docs/config_options.md | 2 +- docs/ja/config_options.md | 2 +- keyboards/1k/keymaps/tap_dance/config.h | 1 + .../1upkeyboards/sweet16/keymaps/ridingintraffic/config.h | 3 ++- keyboards/flehrad/bigswitch/keymaps/333fred/config.h | 1 + keyboards/handwired/ergocheap/config.h | 1 + keyboards/handwired/onekey/config.h | 1 + keyboards/handwired/uthol/rev3/config.h | 1 + keyboards/helix/pico/keymaps/mtei/config.h | 2 -- keyboards/helix/rev2/keymaps/five_rows/config.h | 2 -- keyboards/helix/rev3_5rows/keymaps/five_rows/config.h | 2 -- keyboards/idobao/id67/keymaps/thewerther/config.h | 1 + keyboards/thevankeyboards/minivan/keymaps/belak/config.h | 1 + keyboards/thevankeyboards/minivan/keymaps/halvves/config.h | 1 + .../woodkeys/bigseries/1key/keymaps/dudeofawesome/config.h | 1 + keyboards/xiudi/xd002/keymaps/tap_dance/config.h | 1 + keyboards/zfrontier/big_switch/config.h | 1 + layouts/community/66_ansi/xyverz/config.h | 1 + layouts/community/ergodox/adam/config.h | 2 +- quantum/action_tapping.c | 12 +++++------- users/hvp/config.h | 3 ++- 21 files changed, 24 insertions(+), 18 deletions(-) (limited to 'quantum') diff --git a/docs/config_options.md b/docs/config_options.md index 9aa360576a..c35227a407 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -141,7 +141,7 @@ If you define these options you will enable the associated feature, which may in ## Behaviors That Can Be Configured * `#define TAPPING_TERM 200` - * how long before a tap becomes a hold, if set above 500, a key tapped during the tapping term will turn it into a hold too + * how long before a key press becomes a hold * `#define TAPPING_TERM_PER_KEY` * enables handling for per key `TAPPING_TERM` settings * `#define RETRO_TAPPING` diff --git a/docs/ja/config_options.md b/docs/ja/config_options.md index fb43d015f2..42dd9d502a 100644 --- a/docs/ja/config_options.md +++ b/docs/ja/config_options.md @@ -144,7 +144,7 @@ QMK での全ての利用可能な設定にはデフォルトがあります。 ## 設定可能な挙動 :id=behaviors-that-can-be-configured * `#define TAPPING_TERM 200` - * タップがホールドになるまでの時間。500以上に設定された場合、タップ期間中にタップされたキーもホールドになります。(訳注: PERMISSIVE_HOLDも参照) + * タップがホールドになるまでの時間。 * `#define TAPPING_TERM_PER_KEY` * キーごとの `TAPPING_TERM` 設定の処理を有効にします * `#define RETRO_TAPPING` diff --git a/keyboards/1k/keymaps/tap_dance/config.h b/keyboards/1k/keymaps/tap_dance/config.h index 5df7869537..bd0163e447 100644 --- a/keyboards/1k/keymaps/tap_dance/config.h +++ b/keyboards/1k/keymaps/tap_dance/config.h @@ -4,3 +4,4 @@ #pragma once #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD diff --git a/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/config.h b/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/config.h index c835440076..161b46c814 100644 --- a/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/config.h +++ b/keyboards/1upkeyboards/sweet16/keymaps/ridingintraffic/config.h @@ -3,6 +3,7 @@ /* tap dance stuff*/ #undef TAPPING_TERM #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD #define TAPPING_TOGGLE 2 @@ -12,4 +13,4 @@ #define EXAMPLESTRING4 "tapdance_4" #undef RGBLED_NUM -#define RGBLED_NUM 16 \ No newline at end of file +#define RGBLED_NUM 16 diff --git a/keyboards/flehrad/bigswitch/keymaps/333fred/config.h b/keyboards/flehrad/bigswitch/keymaps/333fred/config.h index 3273cc8db4..6e9219115c 100644 --- a/keyboards/flehrad/bigswitch/keymaps/333fred/config.h +++ b/keyboards/flehrad/bigswitch/keymaps/333fred/config.h @@ -24,3 +24,4 @@ // Long tapping term on the big switch, because it takes so long to press #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD diff --git a/keyboards/handwired/ergocheap/config.h b/keyboards/handwired/ergocheap/config.h index 26905e8cb3..00b9616e3e 100644 --- a/keyboards/handwired/ergocheap/config.h +++ b/keyboards/handwired/ergocheap/config.h @@ -47,6 +47,7 @@ along with this program. If not, see . /* Set 0 if debouncing isn't needed */ #define DEBOUNCE 5 #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD /* * Feature disable options diff --git a/keyboards/handwired/onekey/config.h b/keyboards/handwired/onekey/config.h index f491d4d393..88c15806ce 100644 --- a/keyboards/handwired/onekey/config.h +++ b/keyboards/handwired/onekey/config.h @@ -42,6 +42,7 @@ along with this program. If not, see . #define LOCKING_RESYNC_ENABLE #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD /* * Feature disable options diff --git a/keyboards/handwired/uthol/rev3/config.h b/keyboards/handwired/uthol/rev3/config.h index 90880998b7..84ca3f0cc6 100644 --- a/keyboards/handwired/uthol/rev3/config.h +++ b/keyboards/handwired/uthol/rev3/config.h @@ -57,6 +57,7 @@ #define LOCKING_RESYNC_ENABLE #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD // RGB Stuff #define RGB_DI_PIN B0 diff --git a/keyboards/helix/pico/keymaps/mtei/config.h b/keyboards/helix/pico/keymaps/mtei/config.h index 1a4dc2c842..a633105ff9 100644 --- a/keyboards/helix/pico/keymaps/mtei/config.h +++ b/keyboards/helix/pico/keymaps/mtei/config.h @@ -13,8 +13,6 @@ #undef TAPPING_TERM #define TAPPING_TERM 300 #define PERMISSIVE_HOLD -/* when TAPPING_TERM >= 500 same effect PERMISSIVE_HOLD. - see tmk_core/common/action_tapping.c */ // If you need more program area, try select and reduce rgblight modes to use. diff --git a/keyboards/helix/rev2/keymaps/five_rows/config.h b/keyboards/helix/rev2/keymaps/five_rows/config.h index 4aae9b5cac..43f14aaf2c 100644 --- a/keyboards/helix/rev2/keymaps/five_rows/config.h +++ b/keyboards/helix/rev2/keymaps/five_rows/config.h @@ -6,8 +6,6 @@ #undef TAPPING_TERM #define TAPPING_TERM 300 #define PERMISSIVE_HOLD -/* when TAPPING_TERM >= 500 same effect PERMISSIVE_HOLD. - see tmk_core/common/action_tapping.c */ #undef OLED_UPDATE_INTERVAL #ifdef DEBUG_MATRIX_SCAN_RATE diff --git a/keyboards/helix/rev3_5rows/keymaps/five_rows/config.h b/keyboards/helix/rev3_5rows/keymaps/five_rows/config.h index ab679d14b9..a6fd32c613 100644 --- a/keyboards/helix/rev3_5rows/keymaps/five_rows/config.h +++ b/keyboards/helix/rev3_5rows/keymaps/five_rows/config.h @@ -6,8 +6,6 @@ #undef TAPPING_TERM #define TAPPING_TERM 300 #define PERMISSIVE_HOLD -/* when TAPPING_TERM >= 500 same effect PERMISSIVE_HOLD. - see tmk_core/common/action_tapping.c */ #undef OLED_UPDATE_INTERVAL #ifdef DEBUG_MATRIX_SCAN_RATE diff --git a/keyboards/idobao/id67/keymaps/thewerther/config.h b/keyboards/idobao/id67/keymaps/thewerther/config.h index a63a92b171..85498d91b8 100644 --- a/keyboards/idobao/id67/keymaps/thewerther/config.h +++ b/keyboards/idobao/id67/keymaps/thewerther/config.h @@ -18,6 +18,7 @@ #define DRIVER_LED_UNDERGLOW 10 #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD #if defined(RGB_MATRIX_ENABLE) #undef RGB_MATRIX_MAXIMUM_BRIGHTNESS diff --git a/keyboards/thevankeyboards/minivan/keymaps/belak/config.h b/keyboards/thevankeyboards/minivan/keymaps/belak/config.h index 47d96a29d8..488ffa5418 100644 --- a/keyboards/thevankeyboards/minivan/keymaps/belak/config.h +++ b/keyboards/thevankeyboards/minivan/keymaps/belak/config.h @@ -4,5 +4,6 @@ #include "../../config.h" #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD #endif diff --git a/keyboards/thevankeyboards/minivan/keymaps/halvves/config.h b/keyboards/thevankeyboards/minivan/keymaps/halvves/config.h index 6be8d217bd..c6404f8ce5 100644 --- a/keyboards/thevankeyboards/minivan/keymaps/halvves/config.h +++ b/keyboards/thevankeyboards/minivan/keymaps/halvves/config.h @@ -1,6 +1,7 @@ #pragma once #define TAPPING_TERM 505 +#define PERMISSIVE_HOLD #define RETRO_TAPPING // smooth mousekeys (copied from the ergo ez config) diff --git a/keyboards/woodkeys/bigseries/1key/keymaps/dudeofawesome/config.h b/keyboards/woodkeys/bigseries/1key/keymaps/dudeofawesome/config.h index 30b86224c6..131c755d4a 100644 --- a/keyboards/woodkeys/bigseries/1key/keymaps/dudeofawesome/config.h +++ b/keyboards/woodkeys/bigseries/1key/keymaps/dudeofawesome/config.h @@ -19,5 +19,6 @@ along with this program. If not, see . #define CONFIG_USER_H #define TAPPING_TERM 1000 +#define PERMISSIVE_HOLD #endif diff --git a/keyboards/xiudi/xd002/keymaps/tap_dance/config.h b/keyboards/xiudi/xd002/keymaps/tap_dance/config.h index b86e862d30..1fd93f875f 100644 --- a/keyboards/xiudi/xd002/keymaps/tap_dance/config.h +++ b/keyboards/xiudi/xd002/keymaps/tap_dance/config.h @@ -1,3 +1,4 @@ #pragma once #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD diff --git a/keyboards/zfrontier/big_switch/config.h b/keyboards/zfrontier/big_switch/config.h index ddec2b2796..99bd790cae 100644 --- a/keyboards/zfrontier/big_switch/config.h +++ b/keyboards/zfrontier/big_switch/config.h @@ -51,3 +51,4 @@ along with this program. If not, see . /* long tapping config */ #define TAPPING_TERM 500 +#define PERMISSIVE_HOLD diff --git a/layouts/community/66_ansi/xyverz/config.h b/layouts/community/66_ansi/xyverz/config.h index 06e5830af8..37a57dbffd 100644 --- a/layouts/community/66_ansi/xyverz/config.h +++ b/layouts/community/66_ansi/xyverz/config.h @@ -1,5 +1,6 @@ #pragma once #define TAPPING_TERM 600 // ms +#define PERMISSIVE_HOLD #undef RGBLIGHT_HUE_STEP #define RGBLIGHT_HUE_STEP 8 diff --git a/layouts/community/ergodox/adam/config.h b/layouts/community/ergodox/adam/config.h index 62e82d8b2b..1555ae11fd 100644 --- a/layouts/community/ergodox/adam/config.h +++ b/layouts/community/ergodox/adam/config.h @@ -1,5 +1,5 @@ #pragma once #undef TAPPING_TERM -#define TAPPING_TERM 300 //At 500 some bad logic takes hold +#define TAPPING_TERM 300 #define IGNORE_MOD_TAP_INTERRUPT diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c index 3c8b5678b7..df3317ac05 100644 --- a/quantum/action_tapping.c +++ b/quantum/action_tapping.c @@ -125,7 +125,7 @@ void action_tapping_process(keyrecord_t record) { /* return true when key event is processed or consumed. */ bool process_tapping(keyrecord_t *keyp) { keyevent_t event = keyp->event; -# if (defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)) || defined(TAPPING_TERM_PER_KEY) || defined(PERMISSIVE_HOLD_PER_KEY) || defined(TAPPING_FORCE_HOLD_PER_KEY) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY) +# if (defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)) || defined(PERMISSIVE_HOLD_PER_KEY) || defined(TAPPING_FORCE_HOLD_PER_KEY) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY) uint16_t tapping_keycode = get_record_keycode(&tapping_key, false); # endif @@ -164,17 +164,15 @@ bool process_tapping(keyrecord_t *keyp) { * useful for long TAPPING_TERM but may prevent fast typing. */ // clang-format off -# if defined(TAPPING_TERM_PER_KEY) || (TAPPING_TERM >= 500) || defined(PERMISSIVE_HOLD) || defined(PERMISSIVE_HOLD_PER_KEY) || (defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)) +# if defined(PERMISSIVE_HOLD) || defined(PERMISSIVE_HOLD_PER_KEY) || (defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)) else if ( ( - ( - GET_TAPPING_TERM(tapping_keycode, &tapping_key) >= 500 + IS_RELEASED(event) && waiting_buffer_typed(event) # ifdef PERMISSIVE_HOLD_PER_KEY - || get_permissive_hold(tapping_keycode, &tapping_key) + && get_permissive_hold(tapping_keycode, &tapping_key) # elif defined(PERMISSIVE_HOLD) - || true + && true # endif - ) && IS_RELEASED(event) && waiting_buffer_typed(event) ) // Causes nested taps to not wait past TAPPING_TERM/RETRO_SHIFT // unnecessarily and fixes them for Layer Taps. diff --git a/users/hvp/config.h b/users/hvp/config.h index 68dd8b4828..b7d0443bbc 100644 --- a/users/hvp/config.h +++ b/users/hvp/config.h @@ -15,4 +15,5 @@ */ #pragma once -#define LONG_TAPPING_TERM 1000 \ No newline at end of file +#define LONG_TAPPING_TERM 1000 +#define PERMISSIVE_HOLD -- cgit v1.2.3 From 01bc974365581da6563e2bbd2425233d97280fdd Mon Sep 17 00:00:00 2001 From: Thomas Kriechbaumer Date: Sat, 25 Jun 2022 22:22:28 +0200 Subject: improvements for Cirque Pinnacle trackpads (#17091) --- docs/feature_pointing_device.md | 21 ++++--- drivers/sensors/cirque_pinnacle.c | 100 ++++++++++++++++++++++++---------- drivers/sensors/cirque_pinnacle.h | 50 +++++++++++------ drivers/sensors/cirque_pinnacle_i2c.c | 4 +- drivers/sensors/cirque_pinnacle_spi.c | 4 +- quantum/pointing_device_drivers.c | 45 +++++++++++---- 6 files changed, 155 insertions(+), 69 deletions(-) (limited to 'quantum') diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md index 5dacc9f5ab..264362ea77 100644 --- a/docs/feature_pointing_device.md +++ b/docs/feature_pointing_device.md @@ -89,15 +89,15 @@ POINTING_DEVICE_DRIVER = cirque_pinnacle_spi This supports the Cirque Pinnacle 1CA027 Touch Controller, which is used in the TM040040, TM035035 and the TM023023 trackpads. These are I2C or SPI compatible, and both configurations are supported. -| Setting | Description | Default | -|---------------------------------|---------------------------------------------------------------------------------|-----------------------| -|`CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` | -|`CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` | -|`CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` | -|`CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` | -|`CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `ADC_ATTENUATE_4X` | -|`CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | -|`CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | +| Setting | Description | Default | +|-------------------------------- |-----------------------------------------------------------------------|--------------------- | +|`CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` | +|`CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` | +|`CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` | +|`CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` | +|`CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `ADC_ATTENUATE_4X` | +|`CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | +|`CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | **`CIRQUE_PINNACLE_ATTENUATION`** is a measure of how much data is suppressed in regards to sensitivity. The higher the attenuation, the less sensitive the touchpad will be. @@ -122,6 +122,9 @@ Default attenuation is set to 4X, although if you are using a thicker overlay (s Default Scaling/CPI is 1024. +Also see the `POINTING_DEVICE_TASK_THROTTLE_MS`, which defaults to 10ms when using Cirque Pinnacle, which matches the internal update rate of the position registers (in standard configuration). Advanced configuration for pen/stylus usage might require lower values. + + ### Pimoroni Trackball To use the Pimoroni Trackball module, add this to your `rules.mk`: diff --git a/drivers/sensors/cirque_pinnacle.c b/drivers/sensors/cirque_pinnacle.c index 670b96f2fb..1d1e4ccfc6 100644 --- a/drivers/sensors/cirque_pinnacle.c +++ b/drivers/sensors/cirque_pinnacle.c @@ -1,8 +1,13 @@ // Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license +// based on https://github.com/cirque-corp/Cirque_Pinnacle_1CA027/tree/master/Circular_Trackpad +// with modifications and changes for QMK +// refer to documentation: Gen2 and Gen3 (Pinnacle ASIC) at https://www.cirque.com/documentation + #include "cirque_pinnacle.h" #include "print.h" #include "debug.h" #include "wait.h" +#include "timer.h" // Registers for RAP // clang-format off @@ -41,12 +46,6 @@ #ifndef CIRQUE_PINNACLE_ATTENUATION # define CIRQUE_PINNACLE_ATTENUATION ADC_ATTENUATE_4X #endif - -// Register config values for this demo -#define SYSCONFIG_1_VALUE 0x00 -#define FEEDCONFIG_1_VALUE 0x03 // 0x03 for absolute mode 0x01 for relative mode -#define FEEDCONFIG_2_VALUE 0x1C // 0x1F for normal functionality 0x1E for intellimouse disabled -#define Z_IDLE_COUNT_VALUE 0x05 // clang-format on bool touchpad_init; @@ -114,16 +113,14 @@ void cirque_pinnacle_clear_flags() { // Enables/Disables the feed void cirque_pinnacle_enable_feed(bool feedEnable) { uint8_t temp; - RAP_ReadBytes(FEEDCONFIG_1, &temp, 1); // Store contents of FeedConfig1 register if (feedEnable) { temp |= 0x01; // Set Feed Enable bit - RAP_Write(0x04, temp); } else { temp &= ~0x01; // Clear Feed Enable bit - RAP_Write(0x04, temp); } + RAP_Write(FEEDCONFIG_1, temp); } /* ERA (Extended Register Access) Functions */ @@ -195,7 +192,7 @@ void cirque_pinnacle_tune_edge_sensitivity(void) { ERA_ReadBytes(0x0168, &temp, 1); } -/* Pinnacle-based TM040040 Functions */ +/* Pinnacle-based TM040040/TM035035/TM023023 Functions */ void cirque_pinnacle_init(void) { #if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) spi_init(); @@ -204,18 +201,44 @@ void cirque_pinnacle_init(void) { #endif touchpad_init = true; + // Host clears SW_CC flag cirque_pinnacle_clear_flags(); - // Host configures bits of registers 0x03 and 0x05 - RAP_Write(SYSCONFIG_1, SYSCONFIG_1_VALUE); - RAP_Write(FEEDCONFIG_2, FEEDCONFIG_2_VALUE); - - // Host enables preferred output mode (absolute) - RAP_Write(FEEDCONFIG_1, FEEDCONFIG_1_VALUE); + // SysConfig1 (Low Power Mode) + // Bit 0: Reset, 1=Reset + // Bit 1: Shutdown, 1=Shutdown, 0=Active + // Bit 2: Sleep Enable, 1=low power mode, 0=normal mode + // send a RESET command now, in case QMK had a soft-reset without a power cycle + RAP_Write(SYSCONFIG_1, 0x01); + wait_ms(30); // Pinnacle needs 10-15ms to boot, so wait long enough before configuring + RAP_Write(SYSCONFIG_1, 0x00); + wait_us(50); - // Host sets z-idle packet count to 5 (default is 30) - RAP_Write(Z_IDLE_COUNT, Z_IDLE_COUNT_VALUE); + // FeedConfig2 (Feature flags for Relative Mode Only) + // Bit 0: IntelliMouse Enable, 1=enable, 0=disable + // Bit 1: All Taps Disable, 1=disable, 0=enable + // Bit 2: Secondary Tap Disable, 1=disable, 0=enable + // Bit 3: Scroll Disable, 1=disable, 0=enable + // Bit 4: GlideExtend® Disable, 1=disable, 0=enable + // Bit 5: reserved + // Bit 6: reserved + // Bit 7: Swap X & Y, 1=90° rotation, 0=0° rotation + RAP_Write(FEEDCONFIG_2, 0x00); + + // FeedConfig1 (Data Output Flags) + // Bit 0: Feed enable, 1=feed, 0=no feed + // Bit 1: Data mode, 1=absolute, 0=relative + // Bit 2: Filter disable, 1=no filter, 0=filter + // Bit 3: X disable, 1=no X data, 0=X data + // Bit 4: Y disable, 1=no Y data, 0=Y data + // Bit 5: reserved + // Bit 6: X data Invert, 1=X max to 0, 0=0 to Y max + // Bit 7: Y data Invert, 1=Y max to 0, 0=0 to Y max + RAP_Write(FEEDCONFIG_1, CIRQUE_PINNACLE_POSITION_MODE << 1); + + // Host sets z-idle packet count to 5 (default is 0x1F/30) + RAP_Write(Z_IDLE_COUNT, 5); cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION); @@ -223,21 +246,42 @@ void cirque_pinnacle_init(void) { cirque_pinnacle_enable_feed(true); } -// Reads XYZ data from Pinnacle registers 0x14 through 0x17 -// Stores result in pinnacle_data_t struct with xValue, yValue, and zValue members pinnacle_data_t cirque_pinnacle_read_data(void) { - uint8_t data[6] = {0}; - pinnacle_data_t result = {0}; + uint8_t data_ready = 0; + uint8_t data[6] = {0}; + pinnacle_data_t result = {0}; + + // Check if there is valid data available + RAP_ReadBytes(STATUS_1, &data_ready, 1); // bit2 is Software Data Ready, bit3 is Command Complete, bit0 and bit1 are reserved/unused + if ((data_ready & 0x04) == 0) { + // no data available yet + result.valid = false; // be explicit + return result; + } + + // Read all data bytes RAP_ReadBytes(PACKET_BYTE_0, data, 6); + // Get ready for the next data sample cirque_pinnacle_clear_flags(); - result.buttonFlags = data[0] & 0x3F; - result.xValue = data[2] | ((data[4] & 0x0F) << 8); - result.yValue = data[3] | ((data[4] & 0xF0) << 4); - result.zValue = data[5] & 0x3F; - - result.touchDown = (result.xValue != 0 || result.yValue != 0); +#if CIRQUE_PINNACLE_POSITION_MODE + // Decode data for absolute mode + // Register 0x13 is unused in this mode (palm detection area) + result.buttonFlags = data[0] & 0x3F; // bit0 to bit5 are switch 0-5, only hardware button presses (from input pin on the Pinnacle chip) + result.xValue = data[2] | ((data[4] & 0x0F) << 8); // merge high and low bits for X + result.yValue = data[3] | ((data[4] & 0xF0) << 4); // merge high and low bits for Y + result.zValue = data[5] & 0x3F; // Z is only lower 6 bits, upper 2 bits are reserved/unused + result.touchDown = (result.xValue != 0 || result.yValue != 0); // (0,0) is a "magic coordinate" to indicate "finger touched down" +#else + // Decode data for relative mode + // Registers 0x16 and 0x17 are unused in this mode + result.buttons = data[0] & 0x07; // bit0 = primary button, bit1 = secondary button, bit2 = auxilary button, if Taps enabled then also software-recognized taps are reported + result.xDelta = data[1]; + result.yDelta = data[2]; + result.wheelCount = data[3]; +#endif + result.valid = true; return result; } diff --git a/drivers/sensors/cirque_pinnacle.h b/drivers/sensors/cirque_pinnacle.h index c8cb360e03..d65bdb41b6 100644 --- a/drivers/sensors/cirque_pinnacle.h +++ b/drivers/sensors/cirque_pinnacle.h @@ -5,23 +5,14 @@ #include #include -// Convenient way to store and access measurements -typedef struct { - uint16_t xValue; - uint16_t yValue; - uint16_t zValue; - uint8_t buttonFlags; - bool touchDown; -} pinnacle_data_t; - -void cirque_pinnacle_init(void); -pinnacle_data_t cirque_pinnacle_read_data(void); -void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution); -uint16_t cirque_pinnacle_get_scale(void); -void cirque_pinnacle_set_scale(uint16_t scale); - #ifndef CIRQUE_PINNACLE_TIMEOUT -# define CIRQUE_PINNACLE_TIMEOUT 20 +# define CIRQUE_PINNACLE_TIMEOUT 20 // I2C timeout in milliseconds +#endif + +#define CIRQUE_PINNACLE_ABSOLUTE_MODE 1 +#define CIRQUE_PINNACLE_RELATIVE_MODE 0 +#ifndef CIRQUE_PINNACLE_POSITION_MODE +# define CIRQUE_PINNACLE_POSITION_MODE CIRQUE_PINNACLE_ABSOLUTE_MODE #endif // Coordinate scaling values @@ -43,7 +34,9 @@ void cirque_pinnacle_set_scale(uint16_t scale); #ifndef CIRQUE_PINNACLE_Y_RANGE # define CIRQUE_PINNACLE_Y_RANGE (CIRQUE_PINNACLE_Y_UPPER - CIRQUE_PINNACLE_Y_LOWER) #endif - +#if !defined(POINTING_DEVICE_TASK_THROTTLE_MS) +# define POINTING_DEVICE_TASK_THROTTLE_MS 10 // Cirque Pinnacle in normal operation produces data every 10ms. Advanced configuration for pen/stylus usage might require lower values. +#endif #if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) # include "i2c_master.h" // Cirque's 7-bit I2C Slave Address @@ -72,3 +65,26 @@ void cirque_pinnacle_set_scale(uint16_t scale); # endif # endif #endif + +// Convenient way to store and access measurements +typedef struct { + bool valid; // true if valid data was read, false if no data was ready +#if CIRQUE_PINNACLE_POSITION_MODE + uint16_t xValue; + uint16_t yValue; + uint16_t zValue; + uint8_t buttonFlags; + bool touchDown; +#else + uint8_t xDelta; + uint8_t yDelta; + uint8_t wheelCount; + uint8_t buttons; +#endif +} pinnacle_data_t; + +void cirque_pinnacle_init(void); +pinnacle_data_t cirque_pinnacle_read_data(void); +void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution); +uint16_t cirque_pinnacle_get_scale(void); +void cirque_pinnacle_set_scale(uint16_t scale); diff --git a/drivers/sensors/cirque_pinnacle_i2c.c b/drivers/sensors/cirque_pinnacle_i2c.c index 8a38f1dcea..b328dd9a7a 100644 --- a/drivers/sensors/cirque_pinnacle_i2c.c +++ b/drivers/sensors/cirque_pinnacle_i2c.c @@ -19,7 +19,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) { i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, NULL, 0, CIRQUE_PINNACLE_TIMEOUT); if (i2c_readReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, data, count, CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) { #ifdef CONSOLE_ENABLE - dprintf("error right touchpad\n"); + dprintf("error cirque_pinnacle i2c_readReg\n"); #endif touchpad_init = false; } @@ -34,7 +34,7 @@ void RAP_Write(uint8_t address, uint8_t data) { if (touchpad_init) { if (i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, &data, sizeof(data), CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) { #ifdef CONSOLE_ENABLE - dprintf("error right touchpad\n"); + dprintf("error cirque_pinnacle i2c_writeReg\n"); #endif touchpad_init = false; } diff --git a/drivers/sensors/cirque_pinnacle_spi.c b/drivers/sensors/cirque_pinnacle_spi.c index 34c77df07b..bd980fc863 100644 --- a/drivers/sensors/cirque_pinnacle_spi.c +++ b/drivers/sensors/cirque_pinnacle_spi.c @@ -25,7 +25,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) { } } else { #ifdef CONSOLE_ENABLE - dprintf("error right touchpad\n"); + dprintf("error cirque_pinnacle spi_start read\n"); #endif touchpad_init = false; } @@ -43,7 +43,7 @@ void RAP_Write(uint8_t address, uint8_t data) { spi_write(data); } else { #ifdef CONSOLE_ENABLE - dprintf("error right touchpad\n"); + dprintf("error cirque_pinnacle spi_start write\n"); #endif touchpad_init = false; } diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c index 41d7018c86..435fcabf7c 100644 --- a/quantum/pointing_device_drivers.c +++ b/quantum/pointing_device_drivers.c @@ -50,6 +50,7 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = adns5050_get_cpi, }; // clang-format on + #elif defined(POINTING_DEVICE_DRIVER_adns9800) report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report) { @@ -69,6 +70,7 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = adns9800_get_cpi }; // clang-format on + #elif defined(POINTING_DEVICE_DRIVER_analog_joystick) report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report) { report_analog_joystick_t data = analog_joystick_read(); @@ -93,6 +95,7 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = NULL }; // clang-format on + #elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) # ifndef CIRQUE_PINNACLE_TAPPING_TERM # include "action.h" @@ -104,22 +107,40 @@ const pointing_device_driver_t pointing_device_driver = { # endif report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { - pinnacle_data_t touchData = cirque_pinnacle_read_data(); - static uint16_t x = 0, y = 0, mouse_timer = 0; - mouse_xy_report_t report_x = 0, report_y = 0; - static bool is_z_down = false; + pinnacle_data_t touchData = cirque_pinnacle_read_data(); + mouse_xy_report_t report_x = 0, report_y = 0; + static mouse_xy_report_t x = 0, y = 0; + static uint16_t mouse_timer = 0; + static bool is_z_down = false; + +# if !CIRQUE_PINNACLE_POSITION_MODE +# error Cirque Pinnacle with relative mode not implemented yet. +# endif + + if (!touchData.valid) { + return mouse_report; + } + +# if CONSOLE_ENABLE + if (debug_mouse && touchData.touchDown) { + dprintf("cirque_pinnacle touchData x=%4d y=%4d z=%2d\n", touchData.xValue, touchData.yValue, touchData.zValue); + } +# endif - cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); // Scale coordinates to arbitrary X, Y resolution + // Scale coordinates to arbitrary X, Y resolution + cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); if (x && y && touchData.xValue && touchData.yValue) { report_x = (mouse_xy_report_t)(touchData.xValue - x); report_y = (mouse_xy_report_t)(touchData.yValue - y); } - x = touchData.xValue; - y = touchData.yValue; + x = touchData.xValue; + y = touchData.yValue; + mouse_report.x = report_x; + mouse_report.y = report_y; - if ((bool)touchData.zValue != is_z_down) { - is_z_down = (bool)touchData.zValue; + if (touchData.touchDown != is_z_down) { + is_z_down = touchData.touchDown; if (!touchData.zValue) { if (timer_elapsed(mouse_timer) < CIRQUE_PINNACLE_TAPPING_TERM && mouse_timer != 0) { mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); @@ -138,8 +159,6 @@ report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { if (timer_elapsed(mouse_timer) > (CIRQUE_PINNACLE_TOUCH_DEBOUNCE)) { mouse_timer = 0; } - mouse_report.x = report_x; - mouse_report.y = report_y; return mouse_report; } @@ -210,6 +229,7 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = pimoroni_trackball_get_cpi }; // clang-format on + #elif defined(POINTING_DEVICE_DRIVER_pmw3360) static void pmw3360_device_init(void) { pmw3360_init(0); @@ -248,6 +268,7 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = pmw3360_get_cpi }; // clang-format on + #elif defined(POINTING_DEVICE_DRIVER_pmw3389) static void pmw3389_device_init(void) { pmw3389_init(); @@ -286,6 +307,7 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = pmw3389_get_cpi }; // clang-format on + #else __attribute__((weak)) void pointing_device_driver_init(void) {} __attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) { @@ -304,4 +326,5 @@ const pointing_device_driver_t pointing_device_driver = { .set_cpi = pointing_device_driver_set_cpi }; // clang-format on + #endif -- cgit v1.2.3 From 0d013a21e1347fc38e742b2bd876329e86c153a9 Mon Sep 17 00:00:00 2001 From: Thomas Kriechbaumer Date: Sun, 26 Jun 2022 18:15:25 +0200 Subject: [Split] Verify Split Pointing Device config (#17481) --- quantum/pointing_device.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'quantum') diff --git a/quantum/pointing_device.c b/quantum/pointing_device.c index 3c2e2bc09d..3aa4941687 100644 --- a/quantum/pointing_device.c +++ b/quantum/pointing_device.c @@ -25,6 +25,13 @@ #if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1 # error More than one rotation selected. This is not supported. #endif + +#if defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT) || defined(POINTING_DEVICE_COMBINED) +# ifndef SPLIT_POINTING_ENABLE +# error "Using POINTING_DEVICE_LEFT or POINTING_DEVICE_RIGHT or POINTING_DEVICE_COMBINED, then SPLIT_POINTING_ENABLE is required but has not been defined" +# endif +#endif + #if defined(SPLIT_POINTING_ENABLE) # include "transactions.h" # include "keyboard.h" -- cgit v1.2.3 From 01ecf332ff9f0c8f61e493cdca116f58d80bb5fb Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Mon, 27 Jun 2022 07:18:21 +1000 Subject: Generic wear-leveling algorithm (#16996) * Initial import of wear-leveling algorithm. * Alignment. * Docs tweaks. * Lock/unlock. * Update quantum/wear_leveling/wear_leveling_internal.h Co-authored-by: Stefan Kerkmann * More tests, fix issue with consolidation when unlocked. * More tests. * Review comments. * Add plumbing for FNV1a. * Another test checking that checksum mismatch clears the cache. * Check that the write log still gets played back. Co-authored-by: Stefan Kerkmann --- builddefs/build_test.mk | 1 + builddefs/common_features.mk | 6 + builddefs/testlist.mk | 1 + lib/fnv/Makefile | 304 +++ lib/fnv/README | 158 ++ lib/fnv/fnv.h | 249 +++ lib/fnv/fnv32.c | 467 ++++ lib/fnv/fnv64.c | 591 ++++++ lib/fnv/hash_32.c | 156 ++ lib/fnv/hash_32a.c | 144 ++ lib/fnv/hash_64.c | 312 +++ lib/fnv/hash_64a.c | 291 +++ lib/fnv/have_ulong64.c | 58 + lib/fnv/longlong.h | 18 + lib/fnv/qmk_fnv_type_validation.c | 14 + lib/fnv/test_fnv.c | 2237 ++++++++++++++++++++ quantum/wear_leveling/tests/backing_mocks.cpp | 154 ++ quantum/wear_leveling/tests/backing_mocks.hpp | 210 ++ quantum/wear_leveling/tests/rules.mk | 66 + quantum/wear_leveling/tests/testlist.mk | 6 + .../wear_leveling/tests/wear_leveling_2byte.cpp | 228 ++ .../tests/wear_leveling_2byte_optimized_writes.cpp | 295 +++ .../wear_leveling/tests/wear_leveling_4byte.cpp | 193 ++ .../wear_leveling/tests/wear_leveling_8byte.cpp | 178 ++ .../wear_leveling/tests/wear_leveling_general.cpp | 204 ++ quantum/wear_leveling/wear_leveling.c | 779 +++++++ quantum/wear_leveling/wear_leveling.h | 54 + quantum/wear_leveling/wear_leveling_internal.h | 145 ++ 28 files changed, 7519 insertions(+) create mode 100644 lib/fnv/Makefile create mode 100644 lib/fnv/README create mode 100644 lib/fnv/fnv.h create mode 100644 lib/fnv/fnv32.c create mode 100644 lib/fnv/fnv64.c create mode 100644 lib/fnv/hash_32.c create mode 100644 lib/fnv/hash_32a.c create mode 100644 lib/fnv/hash_64.c create mode 100644 lib/fnv/hash_64a.c create mode 100644 lib/fnv/have_ulong64.c create mode 100644 lib/fnv/longlong.h create mode 100644 lib/fnv/qmk_fnv_type_validation.c create mode 100644 lib/fnv/test_fnv.c create mode 100644 quantum/wear_leveling/tests/backing_mocks.cpp create mode 100644 quantum/wear_leveling/tests/backing_mocks.hpp create mode 100644 quantum/wear_leveling/tests/rules.mk create mode 100644 quantum/wear_leveling/tests/testlist.mk create mode 100644 quantum/wear_leveling/tests/wear_leveling_2byte.cpp create mode 100644 quantum/wear_leveling/tests/wear_leveling_2byte_optimized_writes.cpp create mode 100644 quantum/wear_leveling/tests/wear_leveling_4byte.cpp create mode 100644 quantum/wear_leveling/tests/wear_leveling_8byte.cpp create mode 100644 quantum/wear_leveling/tests/wear_leveling_general.cpp create mode 100644 quantum/wear_leveling/wear_leveling.c create mode 100644 quantum/wear_leveling/wear_leveling.h create mode 100644 quantum/wear_leveling/wear_leveling_internal.h (limited to 'quantum') diff --git a/builddefs/build_test.mk b/builddefs/build_test.mk index 834184f221..bd9b372c33 100644 --- a/builddefs/build_test.mk +++ b/builddefs/build_test.mk @@ -63,6 +63,7 @@ include $(TMK_PATH)/protocol.mk include $(QUANTUM_PATH)/debounce/tests/rules.mk include $(QUANTUM_PATH)/encoder/tests/rules.mk include $(QUANTUM_PATH)/sequencer/tests/rules.mk +include $(QUANTUM_PATH)/wear_leveling/tests/rules.mk include $(PLATFORM_PATH)/test/rules.mk ifneq ($(filter $(FULL_TESTS),$(TEST)),) include $(BUILDDEFS_PATH)/build_full_test.mk diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index b9ee0a30a7..552171fe68 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -650,6 +650,12 @@ ifeq ($(strip $(CRC_ENABLE)), yes) SRC += crc.c endif +ifeq ($(strip $(FNV_ENABLE)), yes) + OPT_DEFS += -DFNV_ENABLE + VPATH += $(LIB_PATH)/fnv + SRC += qmk_fnv_type_validation.c hash_32a.c hash_64a.c +endif + ifeq ($(strip $(HAPTIC_ENABLE)),yes) COMMON_VPATH += $(DRIVER_PATH)/haptic diff --git a/builddefs/testlist.mk b/builddefs/testlist.mk index b8d22bce80..8a30a44972 100644 --- a/builddefs/testlist.mk +++ b/builddefs/testlist.mk @@ -4,6 +4,7 @@ FULL_TESTS := $(notdir $(TEST_LIST)) include $(QUANTUM_PATH)/debounce/tests/testlist.mk include $(QUANTUM_PATH)/encoder/tests/testlist.mk include $(QUANTUM_PATH)/sequencer/tests/testlist.mk +include $(QUANTUM_PATH)/wear_leveling/tests/testlist.mk include $(PLATFORM_PATH)/test/testlist.mk define VALIDATE_TEST_LIST diff --git a/lib/fnv/Makefile b/lib/fnv/Makefile new file mode 100644 index 0000000000..c0673ded40 --- /dev/null +++ b/lib/fnv/Makefile @@ -0,0 +1,304 @@ +#!/bin/make +# +# hash - makefile for FNV hash tools +# +# @(#) $Revision: 5.2 $ +# @(#) $Id: Makefile,v 5.2 2012/03/21 01:42:15 chongo Exp $ +# @(#) $Source: /usr/local/src/cmd/fnv/RCS/Makefile,v $ +# +# See: +# http://www.isthe.com/chongo/tech/comp/fnv/index.html +# +# for the most up to date copy of this code and the FNV hash home page. +# +# Please do not copyright this code. This code is in the public domain. +# +# LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO +# EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. +# +# By: +# chongo /\oo/\ +# http://www.isthe.com/chongo/ +# +# Share and Enjoy! :-) + +# make tools +# +SHELL= /bin/sh +CFLAGS= -O3 -g3 +#CFLAGS= -O2 -g3 +#CC= cc +AR= ar +TAR= tar +EGREP= egrep +GZIP_BIN= gzip +INSTALL= install + +# If your system needs ranlib use: +# RANLIB= ranlib +# otherwise use: +# RANLIB= : +# +#RANLIB= ranlib +RANLIB= : + +# where to install things +# +DESTBIN= /usr/local/bin +DESTLIB= /usr/local/lib +DESTINC= /usr/local/include + +# what to build +# +SRC= hash_32.c hash_32a.c hash_64.c hash_64a.c \ + fnv32.c fnv64.c \ + have_ulong64.c test_fnv.c +NO64BIT_SRC= no64bit_fnv64.c no64bit_hash_64.c \ + no64bit_hash_64a.c no64bit_test_fnv.c +HSRC= fnv.h \ + longlong.h +ALL= ${SRC} ${HSRC} \ + README Makefile +PROGS= fnv032 fnv064 fnv132 fnv164 fnv1a32 fnv1a64 +OBSOLETE_PROGS= fnv0_32 fnv0_64 fnv1_32 fnv1_64 fnv1a_32 fnv1a_64 +NO64BIT_PROGS= no64bit_fnv064 no64bit_fnv164 no64bit_fnv1a64 +LIBS= libfnv.a +LIBOBJ= hash_32.o hash_64.o hash_32a.o hash_64a.o test_fnv.o +NO64BIT_OBJ= no64bit_fnv64.o no64bit_hash_64.o \ + no64bit_hash_64a.o no64bit_test_fnv.o +OTHEROBJ= fnv32.o fnv64.o +TARGETS= ${LIBOBJ} ${LIBS} ${PROGS} + +# default rule +# +all: ${TARGETS} + +# things to build +# +hash_32.o: hash_32.c longlong.h fnv.h + ${CC} ${CFLAGS} hash_32.c -c + +hash_64.o: hash_64.c longlong.h fnv.h + ${CC} ${CFLAGS} hash_64.c -c + +hash_32a.o: hash_32a.c longlong.h fnv.h + ${CC} ${CFLAGS} hash_32a.c -c + +hash_64a.o: hash_64a.c longlong.h fnv.h + ${CC} ${CFLAGS} hash_64a.c -c + +test_fnv.o: test_fnv.c longlong.h fnv.h + ${CC} ${CFLAGS} test_fnv.c -c + +fnv32.o: fnv32.c longlong.h fnv.h + ${CC} ${CFLAGS} fnv32.c -c + +fnv032: fnv32.o libfnv.a + ${CC} fnv32.o libfnv.a -o fnv032 + +fnv64.o: fnv64.c longlong.h fnv.h + ${CC} ${CFLAGS} fnv64.c -c + +fnv064: fnv64.o libfnv.a + ${CC} fnv64.o libfnv.a -o fnv064 + +libfnv.a: ${LIBOBJ} + rm -f $@ + ${AR} rv $@ ${LIBOBJ} + ${RANLIB} $@ + +fnv132: fnv032 + -rm -f $@ + -cp -f $? $@ + +fnv1a32: fnv032 + -rm -f $@ + -cp -f $? $@ + +fnv164: fnv064 + -rm -f $@ + -cp -f $? $@ + +fnv1a64: fnv064 + -rm -f $@ + -cp -f $? $@ + +longlong.h: have_ulong64.c Makefile + -@rm -f have_ulong64 have_ulong64.o ll_tmp longlong.h + @echo 'forming longlong.h' + @echo '/*' > longlong.h + @echo ' * DO NOT EDIT -- generated by the Makefile' >> longlong.h + @echo ' */' >> longlong.h + @echo '' >> longlong.h + @echo '#if !defined(__LONGLONG_H__)' >> longlong.h + @echo '#define __LONGLONG_H__' >> longlong.h + @echo '' >> longlong.h + @echo '/* do we have/want to use a long long type? */' >> longlong.h + -@rm -f have_ulong64.o have_ulong64 + -@${CC} ${CFLAGS} have_ulong64.c -c 2>/dev/null; true + -@${CC} ${CFLAGS} have_ulong64.o -o have_ulong64 2>/dev/null; true + -@${SHELL} -c "./have_ulong64 > ll_tmp 2>/dev/null" \ + >/dev/null 2>&1; true + -@if [ -s ll_tmp ]; then \ + cat ll_tmp >> longlong.h; \ + else \ + echo '#undef HAVE_64BIT_LONG_LONG /* no */' >> longlong.h; \ + fi + @echo '' >> longlong.h + @echo '/*' >> longlong.h + @echo ' * NO64BIT_LONG_LONG undef HAVE_64BIT_LONG_LONG' >> longlong.h + @echo ' */' >> longlong.h + @echo '#if defined(NO64BIT_LONG_LONG)' >> longlong.h + @echo '#undef HAVE_64BIT_LONG_LONG' >> longlong.h + @echo '#endif /* NO64BIT_LONG_LONG */' >> longlong.h + @echo '' >> longlong.h + @echo '#endif /* !__LONGLONG_H__ */' >> longlong.h + -@rm -f have_ulong64 have_ulong64.o ll_tmp + @echo 'longlong.h formed' + +# utilities +# +install: all + -@if [ -d "${DESTBIN}" ]; then \ + echo " mkdir -p ${DESTBIN}"; \ + mkdir -p ${DESTBIN}; \ + fi + -@if [ -d "${DESTLIB}" ]; then \ + echo " mkdir -p ${DESTLIB}"; \ + mkdir -p ${DESTLIB}; \ + fi + -@if [ -d "${DESTINC}" ]; then \ + echo " mkdir -p ${DESTINC}"; \ + mkdir -p ${DESTINC}; \ + fi + ${INSTALL} -m 0755 ${PROGS} ${DESTBIN} + ${INSTALL} -m 0644 ${LIBS} ${DESTLIB} + ${RANLIB} ${DESTLIB}/libfnv.a + ${INSTALL} -m 0644 ${HSRC} ${DESTINC} + @# remove osolete programs + for i in ${OBSOLETE_PROGS}; do \ + if [ -f "${DESTBIN}/$$i" ]; then \ + echo "rm -f ${DESTBIN}/$$i"; \ + rm -f "${DESTBIN}/$$i"; \ + fi; \ + done + +clean: + -rm -f have_ulong64 have_ulong64.o ll_tmp ll_tmp2 longlong.h + -rm -f ${LIBOBJ} + -rm -f ${OTHEROBJ} + +clobber: clean + -rm -f ${TARGETS} + -rm -f ${OBSOLETE_PROGS} lltmp lltmp2 ll_tmp + -rm -f ${NO64BIT_SRC} + -rm -f ${NO64BIT_OBJ} + -rm -f ${NO64BIT_PROGS} + -rm -f vector.c + +check: ${PROGS} + @echo -n "FNV-0 32 bit tests: " + @./fnv032 -t 1 -v + @echo -n "FNV-1 32 bit tests: " + @./fnv132 -t 1 -v + @echo -n "FNV-1a 32 bit tests: " + @./fnv1a32 -t 1 -v + @echo -n "FNV-0 64 bit tests: " + @./fnv064 -t 1 -v + @echo -n "FNV-1 64 bit tests: " + @./fnv164 -t 1 -v + @echo -n "FNV-1a 64 bit tests: " + @./fnv1a64 -t 1 -v + +############################### +# generate test vector source # +############################### + +no64bit_fnv64.c: fnv64.c + -rm -f $@ + -cp -f $? $@ + +no64bit_hash_64.c: hash_64.c + -rm -f $@ + -cp -f $? $@ + +no64bit_hash_64a.c: hash_64a.c + -rm -f $@ + -cp -f $? $@ + +no64bit_test_fnv.c: test_fnv.c + -rm -f $@ + -cp -f $? $@ + +no64bit_fnv64.o: no64bit_fnv64.c longlong.h fnv.h + ${CC} ${CFLAGS} -DNO64BIT_LONG_LONG no64bit_fnv64.c -c + +no64bit_hash_64.o: no64bit_hash_64.c longlong.h fnv.h + ${CC} ${CFLAGS} -DNO64BIT_LONG_LONG no64bit_hash_64.c -c + +no64bit_hash_64a.o: no64bit_hash_64a.c longlong.h fnv.h + ${CC} ${CFLAGS} -DNO64BIT_LONG_LONG no64bit_hash_64a.c -c + +no64bit_test_fnv.o: no64bit_test_fnv.c longlong.h fnv.h + ${CC} ${CFLAGS} -DNO64BIT_LONG_LONG no64bit_test_fnv.c -c + +no64bit_fnv064: no64bit_fnv64.o no64bit_hash_64.o \ + no64bit_hash_64a.o no64bit_test_fnv.o + ${CC} ${CFLAGS} no64bit_fnv64.o no64bit_hash_64.o \ + no64bit_hash_64a.o no64bit_test_fnv.o -o $@ + +no64bit_fnv164: no64bit_fnv064 + -rm -f $@ + -cp -f $? $@ + +no64bit_fnv1a64: no64bit_fnv064 + -rm -f $@ + -cp -f $? $@ + +vector.c: ${PROGS} ${NO64BIT_PROGS} + -rm -f $@ + echo '/* start of output generated by make $@ */' >> $@ + echo '' >> $@ + #@ + echo '/* FNV-0 32 bit test vectors */' >> $@ + ./fnv032 -t 0 >> $@ + echo '' >> $@ + #@ + echo '/* FNV-1 32 bit test vectors */' >> $@ + ./fnv132 -t 0 >> $@ + echo '' >> $@ + #@ + echo '/* FNV-1a 32 bit test vectors */' >> $@ + ./fnv1a32 -t 0 >> $@ + echo '' >> $@ + #@ + echo '/* FNV-0 64 bit test vectors */' >> $@ + echo '#if defined(HAVE_64BIT_LONG_LONG)' >> $@ + ./fnv064 -t 0 >> $@ + echo '#else /* HAVE_64BIT_LONG_LONG */' >> $@ + ./no64bit_fnv064 -t 0 >> $@ + echo '#endif /* HAVE_64BIT_LONG_LONG */' >> $@ + echo '' >> $@ + #@ + echo '/* FNV-1 64 bit test vectors */' >> $@ + echo '#if defined(HAVE_64BIT_LONG_LONG)' >> $@ + ./fnv164 -t 0 >> $@ + echo '#else /* HAVE_64BIT_LONG_LONG */' >> $@ + ./no64bit_fnv164 -t 0 >> $@ + echo '#endif /* HAVE_64BIT_LONG_LONG */' >> $@ + echo '' >> $@ + #@ + echo '/* FNV-1a 64 bit test vectors */' >> $@ + echo '#if defined(HAVE_64BIT_LONG_LONG)' >> $@ + ./fnv1a64 -t 0 >> $@ + echo '#else /* HAVE_64BIT_LONG_LONG */' >> $@ + ./no64bit_fnv1a64 -t 0 >> $@ + echo '#endif /* HAVE_64BIT_LONG_LONG */' >> $@ + echo '' >> $@ + #@ + echo '/* end of output generated by make $@ */' >> $@ diff --git a/lib/fnv/README b/lib/fnv/README new file mode 100644 index 0000000000..60aa9aaf61 --- /dev/null +++ b/lib/fnv/README @@ -0,0 +1,158 @@ +#=====================# +# Fowler/Noll/Vo hash # +#=====================# + +The basis of this hash algorithm was taken from an idea sent +as reviewer comments to the IEEE POSIX P1003.2 committee by: + + Phong Vo (http://www.research.att.com/info/kpv) + Glenn Fowler (http://www.research.att.com/~gsf/) + +In a subsequent ballot round: + + Landon Curt Noll (http://www.isthe.com/chongo) + +improved on their algorithm. Some people tried this hash +and found that it worked rather well. In an EMail message +to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + +FNV hashes are designed to be fast while maintaining a low +collision rate. The FNV speed allows one to quickly hash lots +of data while maintaining a reasonable collision rate. See: + + http://www.isthe.com/chongo/tech/comp/fnv/index.html + +for more details as well as other forms of the FNV hash. +Comments, questions, bug fixes and suggestions welcome at +the address given in the above URL. + + +#==================# +# FNV hash utility # +#==================# + +Two hash utilities (32 bit and 64 bit) are provided: + + fnv032 [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...] + fnv132 [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...] + fnv1a32 [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...] + + fnv064 [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...] + fnv164 [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...] + fnv1a64 [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...] + + -b bcnt mask off all but the lower bcnt bits (default: 32) + -m multiple hashes, one per line for each arg + -s hash arg as a string (ignoring terminating NUL bytes) + -t code 0 ==> generate test vectors, 1 ==> test FNV hash + -v verbose mode, print arg after hash (implies -m) + arg string (if -s was given) or filename (default stdin) + +The fnv032, fnv064 implement the historic FNV-0 hash. +The fnv132, fnv164 implement the recommended FNV-1 hash. +The fnv1a32, fnv1a64 implement the recommended FNV-1a hash. + +This is the original historic FNV algorithm with a 0 offset basis. +It is recommended that FNV-1, with a non-0 offset basis be used instead. + +To test FNV hashes, try: + + fnv032 -t 1 -v + fnv132 -t 1 -v + fnv1a32 -t 1 -v + + fnv064 -t 1 -v + fnv164 -t 1 -v + fnv1a64 -t 1 -v + +If you are compiling, try: + + make check + + +#==================# +# FNV hash library # +#==================# + +The libfnv.a library implements both a 32 bit and a 64 bit FNV hash +on collections of bytes, a NUL terminated strings or on an open file +descriptor. + +Here is the 32 bit FNV 1 hash: + + Fnv32_t fnv_32_buf(void *buf, int len, Fnv32_t hval); /* byte buf */ + Fnv32_t fnv_32_str(char *string, Fnv32_t hval); /* string */ + +Here is the 32 bit FNV 1a hash: + + Fnv32_t fnv_32a_buf(void *buf, int len, Fnv32_t hval); /* byte buf */ + Fnv32_t fnv_32a_str(char *string, Fnv32_t hval); /* string */ + +Here is the 64 bit FNV 1 hash: + + Fnv64_t fnv_64_buf(void *buf, int len, Fnv64_t hval); /* byte buf */ + Fnv64_t fnv_64_str(char *string, Fnv64_t hval); /* string */ + +Here is the 64 bit FNV 1a hash: + + Fnv64_t fnv_64a_buf(void *buf, int len, Fnv64_t hval); /* byte buf */ + Fnv64_t fnv_64a_str(char *string, Fnv64_t hval); /* string */ + +On the first call to a hash function, one must supply the initial basis +that is appropriate for the hash in question: + + FNV-0: (not recommended) + + FNV0_32_INIT /* 32 bit FNV-0 initial basis */ + FNV0_64_INIT /* 64 bit FNV-0 initial basis */ + + FNV-1: + + FNV1_32_INIT /* 32 bit FNV-1 initial basis */ + FNV1_64_INIT /* 64 bit FNV-1 initial basis */ + + FNV-1a: + + FNV1A_32_INIT /* 32 bit FNV-1a initial basis */ + FNV1A_64_INIT /* 64 bit FNV-1a initial basis */ + +For example to perform a 64 bit FNV-1 hash: + + #include "fnv.h" + + Fnv64_t hash_val; + + hash_val = fnv_64_str("a string", FNV1_64_INIT); + hash_val = fnv_64_str("more string", hash_val); + +produces the same final hash value as: + + hash_val = fnv_64_str("a stringmore string", FNV1_64_INIT); + +NOTE: If one used 'FNV0_64_INIT' instead of 'FNV1_64_INIT' one would get the + historic FNV-0 hash instead recommended FNV-1 hash. + +To perform a 32 bit FNV-1 hash: + + #include "fnv.h" + + Fnv32_t hash_val; + + hash_val = fnv_32_buf(buf, length_of_buf, FNV1_32_INIT); + hash_val = fnv_32_str("more data", hash_val); + +To perform a 64 bit FNV-1a hash: + + #include "fnv.h" + + Fnv64_t hash_val; + + hash_val = fnv_64a_buf(buf, length_of_buf, FNV1_64_INIT); + hash_val = fnv_64a_str("more data", hash_val); + +=-= + +chongo /\oo/\ +http://www.isthe.com/chongo + +Share and Enjoy! diff --git a/lib/fnv/fnv.h b/lib/fnv/fnv.h new file mode 100644 index 0000000000..2083a4aa23 --- /dev/null +++ b/lib/fnv/fnv.h @@ -0,0 +1,249 @@ +/* + * fnv - Fowler/Noll/Vo- hash code + * + * @(#) $Revision: 5.4 $ + * @(#) $Id: fnv.h,v 5.4 2009/07/30 22:49:13 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/fnv.h,v $ + * + *** + * + * Fowler/Noll/Vo- hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * NOTE: The FNV-0 historic hash is not recommended. One should use + * the FNV-1 hash instead. + * + * To use the 32 bit FNV-0 historic hash, pass FNV0_32_INIT as the + * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str(). + * + * To use the 64 bit FNV-0 historic hash, pass FNV0_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + * To use the recommended 32 bit FNV-1 hash, pass FNV1_32_INIT as the + * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str(). + * + * To use the recommended 64 bit FNV-1 hash, pass FNV1_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + * To use the recommended 32 bit FNV-1a hash, pass FNV1_32A_INIT as the + * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_str(). + * + * To use the recommended 64 bit FNV-1a hash, pass FNV1A_64_INIT as the + * Fnv64_t hashval argument to fnv_64a_buf() or fnv_64a_str(). + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#if !defined(__FNV_H__) +#define __FNV_H__ + +#include + +#define FNV_VERSION "5.0.2" /* @(#) FNV Version */ + + +/* + * 32 bit FNV-0 hash type + */ +typedef u_int32_t Fnv32_t; + + +/* + * 32 bit FNV-0 zero initial basis + * + * This historic hash is not recommended. One should use + * the FNV-1 hash and initial basis instead. + */ +#define FNV0_32_INIT ((Fnv32_t)0) + + +/* + * 32 bit FNV-1 and FNV-1a non-zero initial basis + * + * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets: + * + * chongo /\../\ + * + * NOTE: The \'s above are not back-slashing escape characters. + * They are literal ASCII backslash 0x5c characters. + * + * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition. + */ +#define FNV1_32_INIT ((Fnv32_t)0x811c9dc5) +#define FNV1_32A_INIT FNV1_32_INIT + + +/* + * determine how 64 bit unsigned values are represented + */ +#include "longlong.h" + + +/* + * 64 bit FNV-0 hash + */ +#if defined(HAVE_64BIT_LONG_LONG) +typedef u_int64_t Fnv64_t; +#else /* HAVE_64BIT_LONG_LONG */ +typedef struct { + u_int32_t w32[2]; /* w32[0] is low order, w32[1] is high order word */ +} Fnv64_t; +#endif /* HAVE_64BIT_LONG_LONG */ + + +/* + * 64 bit FNV-0 zero initial basis + * + * This historic hash is not recommended. One should use + * the FNV-1 hash and initial basis instead. + */ +#if defined(HAVE_64BIT_LONG_LONG) +#define FNV0_64_INIT ((Fnv64_t)0) +#else /* HAVE_64BIT_LONG_LONG */ +extern const Fnv64_t fnv0_64_init; +#define FNV0_64_INIT (fnv0_64_init) +#endif /* HAVE_64BIT_LONG_LONG */ + + +/* + * 64 bit FNV-1 non-zero initial basis + * + * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets: + * + * chongo /\../\ + * + * NOTE: The \'s above are not back-slashing escape characters. + * They are literal ASCII backslash 0x5c characters. + * + * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition. + */ +#if defined(HAVE_64BIT_LONG_LONG) +#define FNV1_64_INIT ((Fnv64_t)0xcbf29ce484222325ULL) +#define FNV1A_64_INIT FNV1_64_INIT +#else /* HAVE_64BIT_LONG_LONG */ +extern const fnv1_64_init; +extern const Fnv64_t fnv1a_64_init; +#define FNV1_64_INIT (fnv1_64_init) +#define FNV1A_64_INIT (fnv1a_64_init) +#endif /* HAVE_64BIT_LONG_LONG */ + + +/* + * hash types + */ +enum fnv_type { + FNV_NONE = 0, /* invalid FNV hash type */ + FNV0_32 = 1, /* FNV-0 32 bit hash */ + FNV1_32 = 2, /* FNV-1 32 bit hash */ + FNV1a_32 = 3, /* FNV-1a 32 bit hash */ + FNV0_64 = 4, /* FNV-0 64 bit hash */ + FNV1_64 = 5, /* FNV-1 64 bit hash */ + FNV1a_64 = 6, /* FNV-1a 64 bit hash */ +}; + + +/* + * these test vectors are used as part o the FNV test suite + */ +struct test_vector { + void *buf; /* start of test vector buffer */ + int len; /* length of test vector */ +}; +struct fnv0_32_test_vector { + struct test_vector *test; /* test vector buffer to hash */ + Fnv32_t fnv0_32; /* expected FNV-0 32 bit hash value */ +}; +struct fnv1_32_test_vector { + struct test_vector *test; /* test vector buffer to hash */ + Fnv32_t fnv1_32; /* expected FNV-1 32 bit hash value */ +}; +struct fnv1a_32_test_vector { + struct test_vector *test; /* test vector buffer to hash */ + Fnv32_t fnv1a_32; /* expected FNV-1a 32 bit hash value */ +}; +struct fnv0_64_test_vector { + struct test_vector *test; /* test vector buffer to hash */ + Fnv64_t fnv0_64; /* expected FNV-0 64 bit hash value */ +}; +struct fnv1_64_test_vector { + struct test_vector *test; /* test vector buffer to hash */ + Fnv64_t fnv1_64; /* expected FNV-1 64 bit hash value */ +}; +struct fnv1a_64_test_vector { + struct test_vector *test; /* test vector buffer to hash */ + Fnv64_t fnv1a_64; /* expected FNV-1a 64 bit hash value */ +}; + + +/* + * external functions + */ +/* hash_32.c */ +extern Fnv32_t fnv_32_buf(void *buf, size_t len, Fnv32_t hashval); +extern Fnv32_t fnv_32_str(char *buf, Fnv32_t hashval); + +/* hash_32a.c */ +extern Fnv32_t fnv_32a_buf(void *buf, size_t len, Fnv32_t hashval); +extern Fnv32_t fnv_32a_str(char *buf, Fnv32_t hashval); + +/* hash_64.c */ +extern Fnv64_t fnv_64_buf(void *buf, size_t len, Fnv64_t hashval); +extern Fnv64_t fnv_64_str(char *buf, Fnv64_t hashval); + +/* hash_64a.c */ +extern Fnv64_t fnv_64a_buf(void *buf, size_t len, Fnv64_t hashval); +extern Fnv64_t fnv_64a_str(char *buf, Fnv64_t hashval); + +/* test_fnv.c */ +extern struct test_vector fnv_test_str[]; +extern struct fnv0_32_test_vector fnv0_32_vector[]; +extern struct fnv1_32_test_vector fnv1_32_vector[]; +extern struct fnv1a_32_test_vector fnv1a_32_vector[]; +extern struct fnv0_64_test_vector fnv0_64_vector[]; +extern struct fnv1_64_test_vector fnv1_64_vector[]; +extern struct fnv1a_64_test_vector fnv1a_64_vector[]; +extern void unknown_hash_type(char *prog, enum fnv_type type, int code); +extern void print_fnv32(Fnv32_t hval, Fnv32_t mask, int verbose, char *arg); +extern void print_fnv64(Fnv64_t hval, Fnv64_t mask, int verbose, char *arg); + + +#endif /* __FNV_H__ */ diff --git a/lib/fnv/fnv32.c b/lib/fnv/fnv32.c new file mode 100644 index 0000000000..58c61f03fc --- /dev/null +++ b/lib/fnv/fnv32.c @@ -0,0 +1,467 @@ +/* + * fnv32 - 32 bit Fowler/Noll/Vo hash of a buffer or string + * + * @(#) $Revision: 5.5 $ + * @(#) $Id: fnv32.c,v 5.5 2012/03/21 01:38:12 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/fnv32.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include +#include +#include +#include +#include +#include +#include "longlong.h" +#include "fnv.h" + +#define WIDTH 32 /* bit width of hash */ + +#define BUF_SIZE (32*1024) /* number of bytes to hash at a time */ + +static char *usage = +"usage: %s [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...]\n" +"\n" +"\t-b bcnt\tmask off all but the lower bcnt bits (default 32)\n" +"\t-m\tmultiple hashes, one per line for each arg\n" +"\t-s\thash arg as a string (ignoring terminating NUL bytes)\n" +"\t-t code\t test hash code: (0 ==> generate test vectors\n" +"\t\t\t\t 1 ==> validate against FNV test vectors)\n" +"\t-v\tverbose mode, print arg after hash (implies -m)\n" +"\targ\tstring (if -s was given) or filename (default stdin)\n" +"\n" +"\tNOTE: Programs that begin with fnv0 implement the FNV-0 hash.\n" +"\t The FNV-0 hash is historic FNV algorithm that is now deprecated.\n" +"\n" +"\tSee http://www.isthe.com/chongo/tech/comp/fnv/index.html for more info.\n" +"\n" +"\t@(#) FNV Version: %s\n"; +static char *program; /* our name */ + + +/* + * test_fnv32 - test the FNV32 hash + * + * given: + * hash_type type of FNV hash to test + * init_hval initial hash value + * mask lower bit mask + * v_flag 1 => print test failure info on stderr + * code 0 ==> generate FNV test vectors + * 1 ==> validate against FNV test vectors + * + * returns: 0 ==> OK, else test vector failure number + */ +static int +test_fnv32(enum fnv_type hash_type, Fnv32_t init_hval, + Fnv32_t mask, int v_flag, int code) +{ + struct test_vector *t; /* FNV test vestor */ + Fnv32_t hval; /* current hash value */ + int tstnum; /* test vector that failed, starting at 1 */ + + /* + * print preamble if generating test vectors + */ + if (code == 0) { + switch (hash_type) { + case FNV0_32: + printf("struct fnv0_32_test_vector fnv0_32_vector[] = {\n"); + break; + case FNV1_32: + printf("struct fnv1_32_test_vector fnv1_32_vector[] = {\n"); + break; + case FNV1a_32: + printf("struct fnv1a_32_test_vector fnv1a_32_vector[] = {\n"); + break; + default: + unknown_hash_type(program, hash_type, 12); /* exit(12) */ + /*NOTREACHED*/ + } + } + + /* + * loop thru all test vectors + */ + for (t = fnv_test_str, tstnum = 1; t->buf != NULL; ++t, ++tstnum) { + + /* + * compute the FNV hash + */ + hval = init_hval; + switch (hash_type) { + case FNV0_32: + case FNV1_32: + hval = fnv_32_buf(t->buf, t->len, hval); + break; + case FNV1a_32: + hval = fnv_32a_buf(t->buf, t->len, hval); + break; + default: + unknown_hash_type(program, hash_type, 13); /* exit(13) */ + /*NOTREACHED*/ + } + + /* + * print the vector + */ + switch (code) { + case 0: /* generate the test vector */ + printf(" { &fnv_test_str[%d], (Fnv32_t) 0x%08lxUL },\n", + tstnum-1, hval & mask); + break; + case 1: /* validate against test vector */ + switch (hash_type) { + case FNV0_32: + if ((hval&mask) != (fnv0_32_vector[tstnum-1].fnv0_32 & mask)) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv0_32 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%08lx != generated: 0x%08lx\n", + program, (hval&mask), + (fnv0_32_vector[tstnum-1].fnv0_32 & mask)); + } + return tstnum; + } + break; + case FNV1_32: + if ((hval&mask) != (fnv1_32_vector[tstnum-1].fnv1_32 & mask)) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv1_32 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%08lx != generated: 0x%08lx\n", + program, (hval&mask), + (fnv1_32_vector[tstnum-1].fnv1_32 & mask)); + } + return tstnum; + } + break; + case FNV1a_32: + if ((hval&mask) != (fnv1a_32_vector[tstnum-1].fnv1a_32 &mask)) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv1a_32 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%08lx != generated: 0x%08lx\n", + program, (hval&mask), + (fnv1a_32_vector[tstnum-1].fnv1a_32 & mask)); + } + return tstnum; + } + break; + } + break; + default: + fprintf(stderr, "%s: -m %d not implemented yet\n", program, code); + exit(14); + } + } + + /* + * print completion if generating test vectors + */ + if (code == 0) { + printf(" { NULL, 0 }\n"); + printf("};\n"); + } + + /* + * no failures, return code 0 ==> all OK + */ + return 0; +} + + +/* + * main - the main function + * + * See the above usage for details. + */ +int +main(int argc, char *argv[]) +{ + char buf[BUF_SIZE+1]; /* read buffer */ + int readcnt; /* number of characters written */ + Fnv32_t hval; /* current hash value */ + int s_flag = 0; /* 1 => -s was given, hash args as strings */ + int m_flag = 0; /* 1 => print multiple hashes, one per arg */ + int v_flag = 0; /* 1 => verbose hash print */ + int b_flag = WIDTH; /* -b flag value */ + int t_flag = -1; /* FNV test vector code (0=>print, 1=>test) */ + enum fnv_type hash_type = FNV_NONE; /* type of FNV hash to perform */ + Fnv32_t bmask; /* mask to apply to output */ + extern char *optarg; /* option argument */ + extern int optind; /* argv index of the next arg */ + int fd; /* open file to process */ + char *p; + int i; + + /* + * parse args + */ + program = argv[0]; + while ((i = getopt(argc, argv, "b:mst:v")) != -1) { + switch (i) { + case 'b': /* bcnt bit mask count */ + b_flag = atoi(optarg); + break; + case 'm': /* print multiple hashes, one per arg */ + m_flag = 1; + break; + case 's': /* hash args as strings */ + s_flag = 1; + break; + case 't': /* FNV test vector code */ + t_flag = atoi(optarg); + if (t_flag < 0 || t_flag > 1) { + fprintf(stderr, "%s: -t code must be 0 or 1\n", program); + fprintf(stderr, usage, program, FNV_VERSION); + exit(1); + } + m_flag = 1; + break; + case 'v': /* verbose hash print */ + m_flag = 1; + v_flag = 1; + break; + default: + fprintf(stderr, usage, program, FNV_VERSION); + exit(1); + } + } + /* -t code incompatible with -b, -m and args */ + if (t_flag >= 0) { + if (b_flag != WIDTH) { + fprintf(stderr, "%s: -t code incompatible with -b\n", program); + exit(2); + } + if (s_flag != 0) { + fprintf(stderr, "%s: -t code incompatible with -s\n", program); + exit(3); + } + if (optind < argc) { + fprintf(stderr, "%s: -t code incompatible args\n", program); + exit(4); + } + } + /* -s requires at least 1 arg */ + if (s_flag && optind >= argc) { + fprintf(stderr, usage, program, FNV_VERSION); + exit(5); + } + /* limit -b values */ + if (b_flag < 0 || b_flag > WIDTH) { + fprintf(stderr, "%s: -b bcnt: %d must be >= 0 and < %d\n", + program, b_flag, WIDTH); + exit(6); + } + if (b_flag == WIDTH) { + bmask = (Fnv32_t)0xffffffff; + } else { + bmask = (Fnv32_t)((1 << b_flag) - 1); + } + + /* + * start with the initial basis depending on the hash type + */ + p = strrchr(program, '/'); + if (p == NULL) { + p = program; + } else { + ++p; + } + if (strcmp(p, "fnv032") == 0) { + /* using non-recommended FNV-0 and zero initial basis */ + hval = FNV0_32_INIT; + hash_type = FNV0_32; + } else if (strcmp(p, "fnv132") == 0) { + /* using FNV-1 and non-zero initial basis */ + hval = FNV1_32_INIT; + hash_type = FNV1_32; + } else if (strcmp(p, "fnv1a32") == 0) { + /* start with the FNV-1a initial basis */ + hval = FNV1_32A_INIT; + hash_type = FNV1a_32; + } else { + fprintf(stderr, "%s: unknown program name, unknown hash type\n", + program); + exit(7); + } + + /* + * FNV test vector processing, if needed + */ + if (t_flag >= 0) { + int code; /* test vector that failed, starting at 1 */ + + /* + * perform all tests + */ + code = test_fnv32(hash_type, hval, bmask, v_flag, t_flag); + + /* + * evaluate the tests + */ + if (code == 0) { + if (v_flag) { + printf("passed\n"); + } + exit(0); + } else { + printf("failed vector (1 is 1st test): %d\n", code); + exit(8); + } + } + + /* + * string hashing + */ + if (s_flag) { + + /* hash any other strings */ + for (i=optind; i < argc; ++i) { + switch (hash_type) { + case FNV0_32: + case FNV1_32: + hval = fnv_32_str(argv[i], hval); + break; + case FNV1a_32: + hval = fnv_32a_str(argv[i], hval); + break; + default: + unknown_hash_type(program, hash_type, 9); /* exit(9) */ + /*NOTREACHED*/ + } + if (m_flag) { + print_fnv32(hval, bmask, v_flag, argv[i]); + } + } + + + /* + * file hashing + */ + } else { + + /* + * case: process only stdin + */ + if (optind >= argc) { + + /* case: process only stdin */ + while ((readcnt = read(0, buf, BUF_SIZE)) > 0) { + switch (hash_type) { + case FNV0_32: + case FNV1_32: + hval = fnv_32_buf(buf, readcnt, hval); + break; + case FNV1a_32: + hval = fnv_32a_buf(buf, readcnt, hval); + break; + default: + unknown_hash_type(program, hash_type, 10); /* exit(10) */ + /*NOTREACHED*/ + } + } + if (m_flag) { + print_fnv32(hval, bmask, v_flag, "(stdin)"); + } + + } else { + + /* + * process any other files + */ + for (i=optind; i < argc; ++i) { + + /* open the file */ + fd = open(argv[i], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: unable to open file: %s\n", + program, argv[i]); + exit(4); + } + + /* hash the file */ + while ((readcnt = read(fd, buf, BUF_SIZE)) > 0) { + switch (hash_type) { + case FNV0_32: + case FNV1_32: + hval = fnv_32_buf(buf, readcnt, hval); + break; + case FNV1a_32: + hval = fnv_32a_buf(buf, readcnt, hval); + break; + default: + unknown_hash_type(program, hash_type, 11);/* exit(11) */ + /*NOTREACHED*/ + } + } + + /* finish processing the file */ + if (m_flag) { + print_fnv32(hval, bmask, v_flag, argv[i]); + } + close(fd); + } + } + } + + /* + * report hash and exit + */ + if (!m_flag) { + print_fnv32(hval, bmask, v_flag, ""); + } + return 0; /* exit(0); */ +} diff --git a/lib/fnv/fnv64.c b/lib/fnv/fnv64.c new file mode 100644 index 0000000000..0662d4d657 --- /dev/null +++ b/lib/fnv/fnv64.c @@ -0,0 +1,591 @@ +/* + * fnv_64 - 64 bit Fowler/Noll/Vo hash of a buffer or string + * + * @(#) $Revision: 5.5 $ + * @(#) $Id: fnv64.c,v 5.5 2012/03/21 01:38:12 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/fnv64.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include +#include +#include +#include +#include +#include +#include "longlong.h" +#include "fnv.h" + +#define WIDTH 64 /* bit width of hash */ + +#define BUF_SIZE (32*1024) /* number of bytes to hash at a time */ + +static char *usage = +"usage: %s [-b bcnt] [-m] [-s arg] [-t code] [-v] [arg ...]\n" +"\n" +"\t-b bcnt\tmask off all but the lower bcnt bits (default 64)\n" +"\t-m\tmultiple hashes, one per line for each arg\n" +"\t-s\thash arg as a string (ignoring terminating NUL bytes)\n" +"\t-t code\t test hash code: (0 ==> generate test vectors\n" +"\t\t\t\t 1 ==> validate against FNV test vectors)\n" +"\t-v\tverbose mode, print arg after hash (implies -m)\n" +"\targ\tstring (if -s was given) or filename (default stdin)\n" +"\n" +"\tNOTE: Programs that begin with fnv0 implement the FNV-0 hash.\n" +"\t The FNV-0 hash is historic FNV algorithm that is now deprecated.\n" +"\n" +"\tSee http://www.isthe.com/chongo/tech/comp/fnv/index.html for more info.\n" +"\n" +"\t@(#) FNV Version: %s\n"; +static char *program; /* our name */ + + +/* + * test_fnv64 - test the FNV64 hash + * + * given: + * hash_type type of FNV hash to test + * init_hval initial hash value + * mask lower bit mask + * v_flag 1 => print test failure info on stderr + * code 0 ==> generate FNV test vectors + * 1 ==> validate against FNV test vectors + * + * returns: 0 ==> OK, else test vector failure number + */ +static int +test_fnv64(enum fnv_type hash_type, Fnv64_t init_hval, + Fnv64_t mask, int v_flag, int code) +{ + struct test_vector *t; /* FNV test vestor */ + Fnv64_t hval; /* current hash value */ + int tstnum; /* test vector that failed, starting at 1 */ + + /* + * print preamble if generating test vectors + */ + if (code == 0) { + switch (hash_type) { + case FNV0_64: + printf("struct fnv0_64_test_vector fnv0_64_vector[] = {\n"); + break; + case FNV1_64: + printf("struct fnv1_64_test_vector fnv1_64_vector[] = {\n"); + break; + case FNV1a_64: + printf("struct fnv1a_64_test_vector fnv1a_64_vector[] = {\n"); + break; + default: + unknown_hash_type(program, hash_type, 12); /* exit(12) */ + /*NOTREACHED*/ + } + } + + /* + * loop thru all test vectors + */ + for (t = fnv_test_str, tstnum = 1; t->buf != NULL; ++t, ++tstnum) { + + /* + * compute the FNV hash + */ + hval = init_hval; + switch (hash_type) { + case FNV0_64: + case FNV1_64: + hval = fnv_64_buf(t->buf, t->len, hval); + break; + case FNV1a_64: + hval = fnv_64a_buf(t->buf, t->len, hval); + break; + default: + unknown_hash_type(program, hash_type, 13); /* exit(13) */ + /*NOTREACHED*/ + } + + /* + * print the vector + */ +#if defined(HAVE_64BIT_LONG_LONG) + /* + * HAVE_64BIT_LONG_LONG testing + */ + switch (code) { + case 0: /* generate the test vector */ + printf(" { &fnv_test_str[%d], (Fnv64_t) 0x%016llxULL },\n", + tstnum-1, hval & mask); + break; + + case 1: /* validate against test vector */ + switch (hash_type) { + case FNV0_64: + if ((hval&mask) != (fnv0_64_vector[tstnum-1].fnv0_64 & mask)) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv0_64 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%016llx != generated: 0x%016llx\n", + program, + (hval&mask), + (fnv0_64_vector[tstnum-1].fnv0_64 & mask)); + } + return tstnum; + } + break; + case FNV1_64: + if ((hval&mask) != (fnv1_64_vector[tstnum-1].fnv1_64 & mask)) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv1_64 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%016llx != generated: 0x%016llx\n", + program, + (hval&mask), + (fnv1_64_vector[tstnum-1].fnv1_64 & mask)); + } + return tstnum; + } + break; + case FNV1a_64: + if ((hval&mask) != (fnv1a_64_vector[tstnum-1].fnv1a_64 &mask)) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv1a_64 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%016llx != generated: 0x%016llx\n", + program, + (hval&mask), + (fnv1a_64_vector[tstnum-1].fnv1a_64 & mask)); + } + return tstnum; + } + break; + } + break; + + default: + fprintf(stderr, "%s: -m %d not implemented yet\n", program, code); + exit(14); + } +#else /* HAVE_64BIT_LONG_LONG */ + /* + * non HAVE_64BIT_LONG_LONG testing + */ + switch (code) { + case 0: /* generate the test vector */ + printf(" { &fnv_test_str[%d], " + "(Fnv64_t) {0x%08lxUL, 0x%08lxUL} },\n", + tstnum-1, + (hval.w32[0] & mask.w32[0]), + (hval.w32[1] & mask.w32[1])); + break; + + case 1: /* validate against test vector */ + switch (hash_type) { + case FNV0_64: + if (((hval.w32[0] & mask.w32[0]) != + (fnv0_64_vector[tstnum-1].fnv0_64.w32[0] & + mask.w32[0])) && + ((hval.w32[1] & mask.w32[1]) != + (fnv0_64_vector[tstnum-1].fnv0_64.w32[1] & + mask.w32[1]))) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv0_64 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%08llx%08llx != " + "generated: 0x%08llx%08llx\n", + program, + (hval.w32[0] & mask.w32[0]), + (hval.w32[1] & mask.w32[1]), + ((fnv0_64_vector[tstnum-1].fnv0_64.w32[0] & + mask.w32[0])), + ((fnv0_64_vector[tstnum-1].fnv0_64.w32[1] & + mask.w32[1]))); + } + return tstnum; + } + break; + case FNV1_64: + if (((hval.w32[0] & mask.w32[0]) != + (fnv1_64_vector[tstnum-1].fnv1_64.w32[0] & + mask.w32[0])) && + ((hval.w32[1] & mask.w32[1]) != + (fnv1_64_vector[tstnum-1].fnv1_64.w32[1] & + mask.w32[1]))) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv1_64 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%08llx%08llx != " + "generated: 0x%08llx%08llx\n", + program, + (hval.w32[0] & mask.w32[0]), + (hval.w32[1] & mask.w32[1]), + ((fnv1_64_vector[tstnum-1].fnv1_64.w32[0] & + mask.w32[0])), + ((fnv1_64_vector[tstnum-1].fnv1_64.w32[1] & + mask.w32[1]))); + } + return tstnum; + } + break; + case FNV1a_64: + if (((hval.w32[0] & mask.w32[0]) != + (fnv1a_64_vector[tstnum-1].fnv1a_64.w32[0] & + mask.w32[0])) && + ((hval.w32[1] & mask.w32[1]) != + (fnv1a_64_vector[tstnum-1].fnv1a_64.w32[1] & + mask.w32[1]))) { + if (v_flag) { + fprintf(stderr, "%s: failed fnv1a_64 test # %d\n", + program, tstnum); + fprintf(stderr, "%s: test # 1 is 1st test\n", program); + fprintf(stderr, + "%s: expected 0x%08llx%08llx != " + "generated: 0x%08llx%08llx\n", + program, + (hval.w32[0] & mask.w32[0]), + (hval.w32[1] & mask.w32[1]), + ((fnv1a_64_vector[tstnum-1].fnv1a_64.w32[0] & + mask.w32[0])), + ((fnv1a_64_vector[tstnum-1].fnv1a_64.w32[1] & + mask.w32[1]))); + } + return tstnum; + } + break; + } + break; + + default: + fprintf(stderr, "%s: -m %d not implemented yet\n", program, code); + exit(15); + } +#endif /* HAVE_64BIT_LONG_LONG */ + } + + /* + * print completion if generating test vectors + */ + if (code == 0) { +#if defined(HAVE_64BIT_LONG_LONG) + printf(" { NULL, (Fnv64_t) 0 }\n"); +#else /* HAVE_64BIT_LONG_LONG */ + printf(" { NULL, (Fnv64_t) {0,0} }\n"); +#endif /* HAVE_64BIT_LONG_LONG */ + printf("};\n"); + } + + /* + * no failures, return code 0 ==> all OK + */ + return 0; +} + + +/* + * main - the main function + * + * See the above usage for details. + */ +int +main(int argc, char *argv[]) +{ + char buf[BUF_SIZE+1]; /* read buffer */ + int readcnt; /* number of characters written */ + Fnv64_t hval; /* current hash value */ + int s_flag = 0; /* 1 => -s was given, hash args as strings */ + int m_flag = 0; /* 1 => print multiple hashes, one per arg */ + int v_flag = 0; /* 1 => verbose hash print */ + int b_flag = WIDTH; /* -b flag value */ + int t_flag = -1; /* FNV test vector code (0=>print, 1=>test) */ + enum fnv_type hash_type = FNV_NONE; /* type of FNV hash to perform */ + Fnv64_t bmask; /* mask to apply to output */ + extern char *optarg; /* option argument */ + extern int optind; /* argv index of the next arg */ + int fd; /* open file to process */ + char *p; + int i; + + /* + * parse args + */ + program = argv[0]; + while ((i = getopt(argc, argv, "b:mst:v")) != -1) { + switch (i) { + case 'b': /* bcnt bit mask count */ + b_flag = atoi(optarg); + break; + case 'm': /* print multiple hashes, one per arg */ + m_flag = 1; + break; + case 's': /* hash args as strings */ + s_flag = 1; + break; + case 't': /* FNV test vector code */ + t_flag = atoi(optarg); + if (t_flag < 0 || t_flag > 1) { + fprintf(stderr, "%s: -t code must be 0 or 1\n", program); + fprintf(stderr, usage, program, FNV_VERSION); + exit(1); + } + m_flag = 1; + break; + case 'v': /* verbose hash print */ + m_flag = 1; + v_flag = 1; + break; + default: + fprintf(stderr, usage, program, FNV_VERSION); + exit(1); + } + } + /* -t code incompatible with -b, -m and args */ + if (t_flag >= 0) { + if (b_flag != WIDTH) { + fprintf(stderr, "%s: -t code incompatible with -b\n", program); + exit(2); + } + if (s_flag != 0) { + fprintf(stderr, "%s: -t code incompatible with -s\n", program); + exit(3); + } + if (optind < argc) { + fprintf(stderr, "%s: -t code incompatible args\n", program); + exit(4); + } + } + /* -s requires at least 1 arg */ + if (s_flag && optind >= argc) { + fprintf(stderr, usage, program, FNV_VERSION); + exit(5); + } + /* limit -b values */ + if (b_flag < 0 || b_flag > WIDTH) { + fprintf(stderr, "%s: -b bcnt: %d must be >= 0 and < %d\n", + program, b_flag, WIDTH); + exit(6); + } +#if defined(HAVE_64BIT_LONG_LONG) + if (b_flag == WIDTH) { + bmask = (Fnv64_t)0xffffffffffffffffULL; + } else { + bmask = (Fnv64_t)((1ULL << b_flag) - 1ULL); + } +#else /* HAVE_64BIT_LONG_LONG */ + if (b_flag == WIDTH) { + bmask.w32[0] = 0xffffffffUL; + bmask.w32[1] = 0xffffffffUL; + } else if (b_flag >= WIDTH/2) { + bmask.w32[0] = 0xffffffffUL; + bmask.w32[1] = ((1UL << (b_flag-(WIDTH/2))) - 1UL); + } else { + bmask.w32[0] = ((1UL << b_flag) - 1UL); + bmask.w32[1] = 0UL; + } +#endif /* HAVE_64BIT_LONG_LONG */ + + /* + * start with the initial basis depending on the hash type + */ + p = strrchr(program, '/'); + if (p == NULL) { + p = program; + } else { + ++p; + } + if (strcmp(p, "fnv064") == 0 || strcmp(p, "no64bit_fnv064") == 0) { + /* using non-recommended FNV-0 and zero initial basis */ + hval = FNV0_64_INIT; + hash_type = FNV0_64; + } else if (strcmp(p, "fnv164") == 0 || strcmp(p, "no64bit_fnv164") == 0) { + /* using FNV-1 and non-zero initial basis */ + hval = FNV1_64_INIT; + hash_type = FNV1_64; + } else if (strcmp(p, "fnv1a64") == 0 || strcmp(p, "no64bit_fnv1a64") == 0) { + /* start with the FNV-1a initial basis */ + hval = FNV1A_64_INIT; + hash_type = FNV1a_64; + } else { + fprintf(stderr, "%s: unknown program name, unknown hash type\n", + program); + exit(7); + } + + /* + * FNV test vector processing, if needed + */ + if (t_flag >= 0) { + int code; /* test vector that failed, starting at 1 */ + + /* + * perform all tests + */ + code = test_fnv64(hash_type, hval, bmask, v_flag, t_flag); + + /* + * evaluate the tests + */ + if (code == 0) { + if (v_flag) { + printf("passed\n"); + } + exit(0); + } else { + printf("failed vector (1 is 1st test): %d\n", code); + exit(8); + } + } + + /* + * string hashing + */ + if (s_flag) { + + /* hash any other strings */ + for (i=optind; i < argc; ++i) { + switch (hash_type) { + case FNV0_64: + case FNV1_64: + hval = fnv_64_str(argv[i], hval); + break; + case FNV1a_64: + hval = fnv_64a_str(argv[i], hval); + break; + default: + unknown_hash_type(program, hash_type, 9); /* exit(9) */ + /*NOTREACHED*/ + } + if (m_flag) { + print_fnv64(hval, bmask, v_flag, argv[i]); + } + } + + + /* + * file hashing + */ + } else { + + /* + * case: process only stdin + */ + if (optind >= argc) { + + /* case: process only stdin */ + while ((readcnt = read(0, buf, BUF_SIZE)) > 0) { + switch (hash_type) { + case FNV0_64: + case FNV1_64: + hval = fnv_64_buf(buf, readcnt, hval); + break; + case FNV1a_64: + hval = fnv_64a_buf(buf, readcnt, hval); + break; + default: + unknown_hash_type(program, hash_type, 10); /* exit(10) */ + /*NOTREACHED*/ + } + } + if (m_flag) { + print_fnv64(hval, bmask, v_flag, "(stdin)"); + } + + } else { + + /* + * process any other files + */ + for (i=optind; i < argc; ++i) { + + /* open the file */ + fd = open(argv[i], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: unable to open file: %s\n", + program, argv[i]); + exit(4); + } + + /* hash the file */ + while ((readcnt = read(fd, buf, BUF_SIZE)) > 0) { + switch (hash_type) { + case FNV0_64: + case FNV1_64: + hval = fnv_64_buf(buf, readcnt, hval); + break; + case FNV1a_64: + hval = fnv_64a_buf(buf, readcnt, hval); + break; + default: + unknown_hash_type(program, hash_type, 11);/* exit(11) */ + /*NOTREACHED*/ + } + } + + /* finish processing the file */ + if (m_flag) { + print_fnv64(hval, bmask, v_flag, argv[i]); + } + close(fd); + } + } + } + + /* + * report hash and exit + */ + if (!m_flag) { + print_fnv64(hval, bmask, v_flag, ""); + } + return 0; /* exit(0); */ +} diff --git a/lib/fnv/hash_32.c b/lib/fnv/hash_32.c new file mode 100644 index 0000000000..077170ff6d --- /dev/null +++ b/lib/fnv/hash_32.c @@ -0,0 +1,156 @@ +/* + * hash_32 - 32 bit Fowler/Noll/Vo hash code + * + * @(#) $Revision: 5.1 $ + * @(#) $Id: hash_32.c,v 5.1 2009/06/30 09:13:32 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_32.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + *** + * + * NOTE: The FNV-0 historic hash is not recommended. One should use + * the FNV-1 hash instead. + * + * To use the 32 bit FNV-0 historic hash, pass FNV0_32_INIT as the + * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str(). + * + * To use the recommended 32 bit FNV-1 hash, pass FNV1_32_INIT as the + * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str(). + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include "fnv.h" + + +/* + * 32 bit magic FNV-0 and FNV-1 prime + */ +#define FNV_32_PRIME ((Fnv32_t)0x01000193) + + +/* + * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer + * + * input: + * buf - start of buffer to hash + * len - length of buffer in octets + * hval - previous hash value or 0 if first call + * + * returns: + * 32 bit hash as a static hash type + * + * NOTE: To use the 32 bit FNV-0 historic hash, use FNV0_32_INIT as the hval + * argument on the first call to either fnv_32_buf() or fnv_32_str(). + * + * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hval + * argument on the first call to either fnv_32_buf() or fnv_32_str(). + */ +Fnv32_t +fnv_32_buf(void *buf, size_t len, Fnv32_t hval) +{ + unsigned char *bp = (unsigned char *)buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ + + /* + * FNV-1 hash each octet in the buffer + */ + while (bp < be) { + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); +#endif + + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t)*bp++; + } + + /* return our new hash value */ + return hval; +} + + +/* + * fnv_32_str - perform a 32 bit Fowler/Noll/Vo hash on a string + * + * input: + * str - string to hash + * hval - previous hash value or 0 if first call + * + * returns: + * 32 bit hash as a static hash type + * + * NOTE: To use the 32 bit FNV-0 historic hash, use FNV0_32_INIT as the hval + * argument on the first call to either fnv_32_buf() or fnv_32_str(). + * + * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hval + * argument on the first call to either fnv_32_buf() or fnv_32_str(). + */ +Fnv32_t +fnv_32_str(char *str, Fnv32_t hval) +{ + unsigned char *s = (unsigned char *)str; /* unsigned string */ + + /* + * FNV-1 hash each octet in the buffer + */ + while (*s) { + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); +#endif + + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t)*s++; + } + + /* return our new hash value */ + return hval; +} diff --git a/lib/fnv/hash_32a.c b/lib/fnv/hash_32a.c new file mode 100644 index 0000000000..8b10acf3e2 --- /dev/null +++ b/lib/fnv/hash_32a.c @@ -0,0 +1,144 @@ +/* + * hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code + * + * @(#) $Revision: 5.1 $ + * @(#) $Id: hash_32a.c,v 5.1 2009/06/30 09:13:32 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_32a.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + *** + * + * To use the recommended 32 bit FNV-1a hash, pass FNV1_32A_INIT as the + * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_str(). + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include "fnv.h" + + +/* + * 32 bit magic FNV-1a prime + */ +#define FNV_32_PRIME ((Fnv32_t)0x01000193) + + +/* + * fnv_32a_buf - perform a 32 bit Fowler/Noll/Vo FNV-1a hash on a buffer + * + * input: + * buf - start of buffer to hash + * len - length of buffer in octets + * hval - previous hash value or 0 if first call + * + * returns: + * 32 bit hash as a static hash type + * + * NOTE: To use the recommended 32 bit FNV-1a hash, use FNV1_32A_INIT as the + * hval arg on the first call to either fnv_32a_buf() or fnv_32a_str(). + */ +Fnv32_t +fnv_32a_buf(void *buf, size_t len, Fnv32_t hval) +{ + unsigned char *bp = (unsigned char *)buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ + + /* + * FNV-1a hash each octet in the buffer + */ + while (bp < be) { + + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t)*bp++; + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); +#endif + } + + /* return our new hash value */ + return hval; +} + + +/* + * fnv_32a_str - perform a 32 bit Fowler/Noll/Vo FNV-1a hash on a string + * + * input: + * str - string to hash + * hval - previous hash value or 0 if first call + * + * returns: + * 32 bit hash as a static hash type + * + * NOTE: To use the recommended 32 bit FNV-1a hash, use FNV1_32A_INIT as the + * hval arg on the first call to either fnv_32a_buf() or fnv_32a_str(). + */ +Fnv32_t +fnv_32a_str(char *str, Fnv32_t hval) +{ + unsigned char *s = (unsigned char *)str; /* unsigned string */ + + /* + * FNV-1a hash each octet in the buffer + */ + while (*s) { + + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t)*s++; + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); +#endif + } + + /* return our new hash value */ + return hval; +} diff --git a/lib/fnv/hash_64.c b/lib/fnv/hash_64.c new file mode 100644 index 0000000000..4338605dca --- /dev/null +++ b/lib/fnv/hash_64.c @@ -0,0 +1,312 @@ +/* + * hash_64 - 64 bit Fowler/Noll/Vo-0 hash code + * + * @(#) $Revision: 5.1 $ + * @(#) $Id: hash_64.c,v 5.1 2009/06/30 09:01:38 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * NOTE: The FNV-0 historic hash is not recommended. One should use + * the FNV-1 hash instead. + * + * To use the 64 bit FNV-0 historic hash, pass FNV0_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + * To use the recommended 64 bit FNV-1 hash, pass FNV1_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include "fnv.h" + + +/* + * FNV-0 defines the initial basis to be zero + */ +#if !defined(HAVE_64BIT_LONG_LONG) +const Fnv64_t fnv0_64_init = { 0UL, 0UL }; +#endif /* ! HAVE_64BIT_LONG_LONG */ + + +/* + * FNV-1 defines the initial basis to be non-zero + */ +#if !defined(HAVE_64BIT_LONG_LONG) +const Fnv64_t fnv1_64_init = { 0x84222325UL, 0xcbf29ce4UL }; +#endif /* ! HAVE_64BIT_LONG_LONG */ + + +/* + * 64 bit magic FNV-0 and FNV-1 prime + */ +#if defined(HAVE_64BIT_LONG_LONG) +#define FNV_64_PRIME ((Fnv64_t)0x100000001b3ULL) +#else /* HAVE_64BIT_LONG_LONG */ +#define FNV_64_PRIME_LOW ((unsigned long)0x1b3) /* lower bits of FNV prime */ +#define FNV_64_PRIME_SHIFT (8) /* top FNV prime shift above 2^32 */ +#endif /* HAVE_64BIT_LONG_LONG */ + + +/* + * fnv_64_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer + * + * input: + * buf - start of buffer to hash + * len - length of buffer in octets + * hval - previous hash value or 0 if first call + * + * returns: + * 64 bit hash as a static hash type + * + * NOTE: To use the 64 bit FNV-0 historic hash, use FNV0_64_INIT as the hval + * argument on the first call to either fnv_64_buf() or fnv_64_str(). + * + * NOTE: To use the recommended 64 bit FNV-1 hash, use FNV1_64_INIT as the hval + * argument on the first call to either fnv_64_buf() or fnv_64_str(). + */ +Fnv64_t +fnv_64_buf(void *buf, size_t len, Fnv64_t hval) +{ + unsigned char *bp = (unsigned char *)buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ + +#if defined(HAVE_64BIT_LONG_LONG) + + /* + * FNV-1 hash each octet of the buffer + */ + while (bp < be) { + + /* multiply by the 64 bit FNV magic prime mod 2^64 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_64_PRIME; +#else /* NO_FNV_GCC_OPTIMIZATION */ + hval += (hval << 1) + (hval << 4) + (hval << 5) + + (hval << 7) + (hval << 8) + (hval << 40); +#endif /* NO_FNV_GCC_OPTIMIZATION */ + + /* xor the bottom with the current octet */ + hval ^= (Fnv64_t)*bp++; + } + +#else /* HAVE_64BIT_LONG_LONG */ + + unsigned long val[4]; /* hash value in base 2^16 */ + unsigned long tmp[4]; /* tmp 64 bit value */ + + /* + * Convert Fnv64_t hval into a base 2^16 array + */ + val[0] = hval.w32[0]; + val[1] = (val[0] >> 16); + val[0] &= 0xffff; + val[2] = hval.w32[1]; + val[3] = (val[2] >> 16); + val[2] &= 0xffff; + + /* + * FNV-1 hash each octet of the buffer + */ + while (bp < be) { + + /* + * multiply by the 64 bit FNV magic prime mod 2^64 + * + * Using 0x100000001b3 we have the following digits base 2^16: + * + * 0x0 0x100 0x0 0x1b3 + * + * which is the same as: + * + * 0x0 1<> 16); + val[0] = tmp[0] & 0xffff; + tmp[2] += (tmp[1] >> 16); + val[1] = tmp[1] & 0xffff; + val[3] = tmp[3] + (tmp[2] >> 16); + val[2] = tmp[2] & 0xffff; + /* + * Doing a val[3] &= 0xffff; is not really needed since it simply + * removes multiples of 2^64. We can discard these excess bits + * outside of the loop when we convert to Fnv64_t. + */ + + /* xor the bottom with the current octet */ + val[0] ^= (unsigned long)*bp++; + } + + /* + * Convert base 2^16 array back into an Fnv64_t + */ + hval.w32[1] = ((val[3]<<16) | val[2]); + hval.w32[0] = ((val[1]<<16) | val[0]); + +#endif /* HAVE_64BIT_LONG_LONG */ + + /* return our new hash value */ + return hval; +} + + +/* + * fnv_64_str - perform a 64 bit Fowler/Noll/Vo hash on a buffer + * + * input: + * buf - start of buffer to hash + * hval - previous hash value or 0 if first call + * + * returns: + * 64 bit hash as a static hash type + * + * NOTE: To use the 64 bit FNV-0 historic hash, use FNV0_64_INIT as the hval + * argument on the first call to either fnv_64_buf() or fnv_64_str(). + * + * NOTE: To use the recommended 64 bit FNV-1 hash, use FNV1_64_INIT as the hval + * argument on the first call to either fnv_64_buf() or fnv_64_str(). + */ +Fnv64_t +fnv_64_str(char *str, Fnv64_t hval) +{ + unsigned char *s = (unsigned char *)str; /* unsigned string */ + +#if defined(HAVE_64BIT_LONG_LONG) + + /* + * FNV-1 hash each octet of the string + */ + while (*s) { + + /* multiply by the 64 bit FNV magic prime mod 2^64 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_64_PRIME; +#else /* NO_FNV_GCC_OPTIMIZATION */ + hval += (hval << 1) + (hval << 4) + (hval << 5) + + (hval << 7) + (hval << 8) + (hval << 40); +#endif /* NO_FNV_GCC_OPTIMIZATION */ + + /* xor the bottom with the current octet */ + hval ^= (Fnv64_t)*s++; + } + +#else /* !HAVE_64BIT_LONG_LONG */ + + unsigned long val[4]; /* hash value in base 2^16 */ + unsigned long tmp[4]; /* tmp 64 bit value */ + + /* + * Convert Fnv64_t hval into a base 2^16 array + */ + val[0] = hval.w32[0]; + val[1] = (val[0] >> 16); + val[0] &= 0xffff; + val[2] = hval.w32[1]; + val[3] = (val[2] >> 16); + val[2] &= 0xffff; + + /* + * FNV-1 hash each octet of the string + */ + while (*s) { + + /* + * multiply by the 64 bit FNV magic prime mod 2^64 + * + * Using 1099511628211, we have the following digits base 2^16: + * + * 0x0 0x100 0x0 0x1b3 + * + * which is the same as: + * + * 0x0 1<> 16); + val[0] = tmp[0] & 0xffff; + tmp[2] += (tmp[1] >> 16); + val[1] = tmp[1] & 0xffff; + val[3] = tmp[3] + (tmp[2] >> 16); + val[2] = tmp[2] & 0xffff; + /* + * Doing a val[3] &= 0xffff; is not really needed since it simply + * removes multiples of 2^64. We can discard these excess bits + * outside of the loop when we convert to Fnv64_t. + */ + + /* xor the bottom with the current octet */ + val[0] ^= (unsigned long)(*s++); + } + + /* + * Convert base 2^16 array back into an Fnv64_t + */ + hval.w32[1] = ((val[3]<<16) | val[2]); + hval.w32[0] = ((val[1]<<16) | val[0]); + +#endif /* !HAVE_64BIT_LONG_LONG */ + + /* return our new hash value */ + return hval; +} diff --git a/lib/fnv/hash_64a.c b/lib/fnv/hash_64a.c new file mode 100644 index 0000000000..6660f92ddf --- /dev/null +++ b/lib/fnv/hash_64a.c @@ -0,0 +1,291 @@ +/* + * hash_64 - 64 bit Fowler/Noll/Vo-0 FNV-1a hash code + * + * @(#) $Revision: 5.1 $ + * @(#) $Id: hash_64a.c,v 5.1 2009/06/30 09:01:38 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64a.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * To use the recommended 64 bit FNV-1a hash, pass FNV1A_64_INIT as the + * Fnv64_t hashval argument to fnv_64a_buf() or fnv_64a_str(). + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include "fnv.h" + + +/* + * FNV-1a defines the initial basis to be non-zero + */ +#if !defined(HAVE_64BIT_LONG_LONG) +const Fnv64_t fnv1a_64_init = { 0x84222325, 0xcbf29ce4 }; +#endif /* ! HAVE_64BIT_LONG_LONG */ + + +/* + * 64 bit magic FNV-1a prime + */ +#if defined(HAVE_64BIT_LONG_LONG) +#define FNV_64_PRIME ((Fnv64_t)0x100000001b3ULL) +#else /* HAVE_64BIT_LONG_LONG */ +#define FNV_64_PRIME_LOW ((unsigned long)0x1b3) /* lower bits of FNV prime */ +#define FNV_64_PRIME_SHIFT (8) /* top FNV prime shift above 2^32 */ +#endif /* HAVE_64BIT_LONG_LONG */ + + +/* + * fnv_64a_buf - perform a 64 bit Fowler/Noll/Vo FNV-1a hash on a buffer + * + * input: + * buf - start of buffer to hash + * len - length of buffer in octets + * hval - previous hash value or 0 if first call + * + * returns: + * 64 bit hash as a static hash type + * + * NOTE: To use the recommended 64 bit FNV-1a hash, use FNV1A_64_INIT as the + * hval arg on the first call to either fnv_64a_buf() or fnv_64a_str(). + */ +Fnv64_t +fnv_64a_buf(void *buf, size_t len, Fnv64_t hval) +{ + unsigned char *bp = (unsigned char *)buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ + +#if defined(HAVE_64BIT_LONG_LONG) + /* + * FNV-1a hash each octet of the buffer + */ + while (bp < be) { + + /* xor the bottom with the current octet */ + hval ^= (Fnv64_t)*bp++; + + /* multiply by the 64 bit FNV magic prime mod 2^64 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_64_PRIME; +#else /* NO_FNV_GCC_OPTIMIZATION */ + hval += (hval << 1) + (hval << 4) + (hval << 5) + + (hval << 7) + (hval << 8) + (hval << 40); +#endif /* NO_FNV_GCC_OPTIMIZATION */ + } + +#else /* HAVE_64BIT_LONG_LONG */ + + unsigned long val[4]; /* hash value in base 2^16 */ + unsigned long tmp[4]; /* tmp 64 bit value */ + + /* + * Convert Fnv64_t hval into a base 2^16 array + */ + val[0] = hval.w32[0]; + val[1] = (val[0] >> 16); + val[0] &= 0xffff; + val[2] = hval.w32[1]; + val[3] = (val[2] >> 16); + val[2] &= 0xffff; + + /* + * FNV-1a hash each octet of the buffer + */ + while (bp < be) { + + /* xor the bottom with the current octet */ + val[0] ^= (unsigned long)*bp++; + + /* + * multiply by the 64 bit FNV magic prime mod 2^64 + * + * Using 0x100000001b3 we have the following digits base 2^16: + * + * 0x0 0x100 0x0 0x1b3 + * + * which is the same as: + * + * 0x0 1<> 16); + val[0] = tmp[0] & 0xffff; + tmp[2] += (tmp[1] >> 16); + val[1] = tmp[1] & 0xffff; + val[3] = tmp[3] + (tmp[2] >> 16); + val[2] = tmp[2] & 0xffff; + /* + * Doing a val[3] &= 0xffff; is not really needed since it simply + * removes multiples of 2^64. We can discard these excess bits + * outside of the loop when we convert to Fnv64_t. + */ + } + + /* + * Convert base 2^16 array back into an Fnv64_t + */ + hval.w32[1] = ((val[3]<<16) | val[2]); + hval.w32[0] = ((val[1]<<16) | val[0]); + +#endif /* HAVE_64BIT_LONG_LONG */ + + /* return our new hash value */ + return hval; +} + + +/* + * fnv_64a_str - perform a 64 bit Fowler/Noll/Vo FNV-1a hash on a buffer + * + * input: + * buf - start of buffer to hash + * hval - previous hash value or 0 if first call + * + * returns: + * 64 bit hash as a static hash type + * + * NOTE: To use the recommended 64 bit FNV-1a hash, use FNV1A_64_INIT as the + * hval arg on the first call to either fnv_64a_buf() or fnv_64a_str(). + */ +Fnv64_t +fnv_64a_str(char *str, Fnv64_t hval) +{ + unsigned char *s = (unsigned char *)str; /* unsigned string */ + +#if defined(HAVE_64BIT_LONG_LONG) + + /* + * FNV-1a hash each octet of the string + */ + while (*s) { + + /* xor the bottom with the current octet */ + hval ^= (Fnv64_t)*s++; + + /* multiply by the 64 bit FNV magic prime mod 2^64 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_64_PRIME; +#else /* NO_FNV_GCC_OPTIMIZATION */ + hval += (hval << 1) + (hval << 4) + (hval << 5) + + (hval << 7) + (hval << 8) + (hval << 40); +#endif /* NO_FNV_GCC_OPTIMIZATION */ + } + +#else /* !HAVE_64BIT_LONG_LONG */ + + unsigned long val[4]; /* hash value in base 2^16 */ + unsigned long tmp[4]; /* tmp 64 bit value */ + + /* + * Convert Fnv64_t hval into a base 2^16 array + */ + val[0] = hval.w32[0]; + val[1] = (val[0] >> 16); + val[0] &= 0xffff; + val[2] = hval.w32[1]; + val[3] = (val[2] >> 16); + val[2] &= 0xffff; + + /* + * FNV-1a hash each octet of the string + */ + while (*s) { + + /* xor the bottom with the current octet */ + + /* + * multiply by the 64 bit FNV magic prime mod 2^64 + * + * Using 1099511628211, we have the following digits base 2^16: + * + * 0x0 0x100 0x0 0x1b3 + * + * which is the same as: + * + * 0x0 1<> 16); + val[0] = tmp[0] & 0xffff; + tmp[2] += (tmp[1] >> 16); + val[1] = tmp[1] & 0xffff; + val[3] = tmp[3] + (tmp[2] >> 16); + val[2] = tmp[2] & 0xffff; + /* + * Doing a val[3] &= 0xffff; is not really needed since it simply + * removes multiples of 2^64. We can discard these excess bits + * outside of the loop when we convert to Fnv64_t. + */ + val[0] ^= (unsigned long)(*s++); + } + + /* + * Convert base 2^16 array back into an Fnv64_t + */ + hval.w32[1] = ((val[3]<<16) | val[2]); + hval.w32[0] = ((val[1]<<16) | val[0]); + +#endif /* !HAVE_64BIT_LONG_LONG */ + + /* return our new hash value */ + return hval; +} diff --git a/lib/fnv/have_ulong64.c b/lib/fnv/have_ulong64.c new file mode 100644 index 0000000000..5c06262388 --- /dev/null +++ b/lib/fnv/have_ulong64.c @@ -0,0 +1,58 @@ +/* + * have_ulong64 - Determine if we have a 64 bit unsigned long long + * + * usage: + * have_ulong64 > longlong.h + * + * Not all systems have a 'long long type' so this may not compile on + * your system. + * + * This prog outputs the define: + * + * HAVE_64BIT_LONG_LONG + * defined ==> we have a 64 bit unsigned long long + * undefined ==> we must simulate a 64 bit unsigned long long + */ +/* + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +/* + * have the compiler try its hand with unsigned and signed long longs + */ +#if ! defined(NO64BIT_LONG_LONG) +unsigned long long val = 1099511628211ULL; +#endif /* NO64BIT_LONG_LONG */ + +int +main(void) +{ + /* + * ensure that the length of long long val is what we expect + */ +#if defined(NO64BIT_LONG_LONG) + printf("#undef HAVE_64BIT_LONG_LONG\t/* no */\n"); +#else /* NO64BIT_LONG_LONG */ + if (val == 1099511628211ULL && sizeof(val) == 8) { + printf("#define HAVE_64BIT_LONG_LONG\t/* yes */\n"); + } +#endif /* NO64BIT_LONG_LONG */ + + /* exit(0); */ + return 0; +} diff --git a/lib/fnv/longlong.h b/lib/fnv/longlong.h new file mode 100644 index 0000000000..c8cfe48f29 --- /dev/null +++ b/lib/fnv/longlong.h @@ -0,0 +1,18 @@ +/* + * DO NOT EDIT -- generated by the Makefile + */ + +#if !defined(__LONGLONG_H__) +#define __LONGLONG_H__ + +/* do we have/want to use a long long type? */ +#define HAVE_64BIT_LONG_LONG /* yes */ + +/* + * NO64BIT_LONG_LONG undef HAVE_64BIT_LONG_LONG + */ +#if defined(NO64BIT_LONG_LONG) +#undef HAVE_64BIT_LONG_LONG +#endif /* NO64BIT_LONG_LONG */ + +#endif /* !__LONGLONG_H__ */ diff --git a/lib/fnv/qmk_fnv_type_validation.c b/lib/fnv/qmk_fnv_type_validation.c new file mode 100644 index 0000000000..e8576617ba --- /dev/null +++ b/lib/fnv/qmk_fnv_type_validation.c @@ -0,0 +1,14 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include "fnv.h" + +// This library was originally sourced from: +// http://www.isthe.com/chongo/tech/comp/fnv/index.html +// +// Version at the time of retrieval on 2022-06-26: v5.0.3 + +_Static_assert(sizeof(long long) == 8, "long long should be 64 bits"); +_Static_assert(sizeof(unsigned long long) == 8, "unsigned long long should be 64 bits"); + +_Static_assert(sizeof(Fnv32_t) == 4, "Fnv32_t should be 32 bits"); +_Static_assert(sizeof(Fnv64_t) == 8, "Fnv64_t should be 64 bits"); diff --git a/lib/fnv/test_fnv.c b/lib/fnv/test_fnv.c new file mode 100644 index 0000000000..efec3dec1d --- /dev/null +++ b/lib/fnv/test_fnv.c @@ -0,0 +1,2237 @@ +/* + * test_fnv - FNV test suite + * + * @(#) $Revision: 5.3 $ + * @(#) $Id: test_fnv.c,v 5.3 2009/06/30 11:50:41 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/test_fnv.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include "longlong.h" +#include "fnv.h" + +#define LEN(x) (sizeof(x)-1) +/* TEST macro does not include trailing NUL byte in the test vector */ +#define TEST(x) {x, LEN(x)} +/* TEST0 macro includes the trailing NUL byte in the test vector */ +#define TEST0(x) {x, sizeof(x)} +/* REPEAT500 - repeat a string 500 times */ +#define R500(x) R100(x)R100(x)R100(x)R100(x)R100(x) +#define R100(x) R10(x)R10(x)R10(x)R10(x)R10(x)R10(x)R10(x)R10(x)R10(x)R10(x) +#define R10(x) x x x x x x x x x x + +/* + * FNV test vectors + * + * NOTE: A NULL pointer marks beyond the end of the test vectors. + * + * NOTE: The order of the fnv_test_str[] test vectors is 1-to-1 with: + * + * struct fnv0_32_test_vector fnv0_32_vector[]; + * struct fnv1_32_test_vector fnv1_32_vector[]; + * struct fnv1a_32_test_vector fnv1a_32_vector[]; + * struct fnv0_64_test_vector fnv0_64_vector[]; + * struct fnv1_64_test_vector fnv1_64_vector[]; + * struct fnv1a_64_test_vector fnv1a_64_vector[]; + * + * IMPORTANT NOTE: + * + * If you change the fnv_test_str[] array, you need + * to also change ALL of the above fnv*_vector arrays!!! + * + * To rebuild, try: + * + * make vector.c + * + * and then fold the results into the source file. + * Of course, you better make sure that the vaules + * produced by the above command are valid, otherwise + * you will be testing against invalid vectors! + */ +struct test_vector fnv_test_str[] = { + TEST(""), + TEST("a"), + TEST("b"), + TEST("c"), + TEST("d"), + TEST("e"), + TEST("f"), + TEST("fo"), + TEST("foo"), + TEST("foob"), + TEST("fooba"), + TEST("foobar"), + TEST0(""), + TEST0("a"), + TEST0("b"), + TEST0("c"), + TEST0("d"), + TEST0("e"), + TEST0("f"), + TEST0("fo"), + TEST0("foo"), + TEST0("foob"), + TEST0("fooba"), + TEST0("foobar"), + TEST("ch"), + TEST("cho"), + TEST("chon"), + TEST("chong"), + TEST("chongo"), + TEST("chongo "), + TEST("chongo w"), + TEST("chongo wa"), + TEST("chongo was"), + TEST("chongo was "), + TEST("chongo was h"), + TEST("chongo was he"), + TEST("chongo was her"), + TEST("chongo was here"), + TEST("chongo was here!"), + TEST("chongo was here!\n"), + TEST0("ch"), + TEST0("cho"), + TEST0("chon"), + TEST0("chong"), + TEST0("chongo"), + TEST0("chongo "), + TEST0("chongo w"), + TEST0("chongo wa"), + TEST0("chongo was"), + TEST0("chongo was "), + TEST0("chongo was h"), + TEST0("chongo was he"), + TEST0("chongo was her"), + TEST0("chongo was here"), + TEST0("chongo was here!"), + TEST0("chongo was here!\n"), + TEST("cu"), + TEST("cur"), + TEST("curd"), + TEST("curds"), + TEST("curds "), + TEST("curds a"), + TEST("curds an"), + TEST("curds and"), + TEST("curds and "), + TEST("curds and w"), + TEST("curds and wh"), + TEST("curds and whe"), + TEST("curds and whey"), + TEST("curds and whey\n"), + TEST0("cu"), + TEST0("cur"), + TEST0("curd"), + TEST0("curds"), + TEST0("curds "), + TEST0("curds a"), + TEST0("curds an"), + TEST0("curds and"), + TEST0("curds and "), + TEST0("curds and w"), + TEST0("curds and wh"), + TEST0("curds and whe"), + TEST0("curds and whey"), + TEST0("curds and whey\n"), + TEST("hi"), TEST0("hi"), + TEST("hello"), TEST0("hello"), + TEST("\xff\x00\x00\x01"), TEST("\x01\x00\x00\xff"), + TEST("\xff\x00\x00\x02"), TEST("\x02\x00\x00\xff"), + TEST("\xff\x00\x00\x03"), TEST("\x03\x00\x00\xff"), + TEST("\xff\x00\x00\x04"), TEST("\x04\x00\x00\xff"), + TEST("\x40\x51\x4e\x44"), TEST("\x44\x4e\x51\x40"), + TEST("\x40\x51\x4e\x4a"), TEST("\x4a\x4e\x51\x40"), + TEST("\x40\x51\x4e\x54"), TEST("\x54\x4e\x51\x40"), + TEST("127.0.0.1"), TEST0("127.0.0.1"), + TEST("127.0.0.2"), TEST0("127.0.0.2"), + TEST("127.0.0.3"), TEST0("127.0.0.3"), + TEST("64.81.78.68"), TEST0("64.81.78.68"), + TEST("64.81.78.74"), TEST0("64.81.78.74"), + TEST("64.81.78.84"), TEST0("64.81.78.84"), + TEST("feedface"), TEST0("feedface"), + TEST("feedfacedaffdeed"), TEST0("feedfacedaffdeed"), + TEST("feedfacedeadbeef"), TEST0("feedfacedeadbeef"), + TEST("line 1\nline 2\nline 3"), + TEST("chongo /\\../\\"), + TEST0("chongo /\\../\\"), + TEST("chongo (Landon Curt Noll) /\\../\\"), + TEST0("chongo (Landon Curt Noll) /\\../\\"), + TEST("http://antwrp.gsfc.nasa.gov/apod/astropix.html"), + TEST("http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash"), + TEST("http://epod.usra.edu/"), + TEST("http://exoplanet.eu/"), + TEST("http://hvo.wr.usgs.gov/cam3/"), + TEST("http://hvo.wr.usgs.gov/cams/HMcam/"), + TEST("http://hvo.wr.usgs.gov/kilauea/update/deformation.html"), + TEST("http://hvo.wr.usgs.gov/kilauea/update/images.html"), + TEST("http://hvo.wr.usgs.gov/kilauea/update/maps.html"), + TEST("http://hvo.wr.usgs.gov/volcanowatch/current_issue.html"), + TEST("http://neo.jpl.nasa.gov/risk/"), + TEST("http://norvig.com/21-days.html"), + TEST("http://primes.utm.edu/curios/home.php"), + TEST("http://slashdot.org/"), + TEST("http://tux.wr.usgs.gov/Maps/155.25-19.5.html"), + TEST("http://volcano.wr.usgs.gov/kilaueastatus.php"), + TEST("http://www.avo.alaska.edu/activity/Redoubt.php"), + TEST("http://www.dilbert.com/fast/"), + TEST("http://www.fourmilab.ch/gravitation/orbits/"), + TEST("http://www.fpoa.net/"), + TEST("http://www.ioccc.org/index.html"), + TEST("http://www.isthe.com/cgi-bin/number.cgi"), + TEST("http://www.isthe.com/chongo/bio.html"), + TEST("http://www.isthe.com/chongo/index.html"), + TEST("http://www.isthe.com/chongo/src/calc/lucas-calc"), + TEST("http://www.isthe.com/chongo/tech/astro/venus2004.html"), + TEST("http://www.isthe.com/chongo/tech/astro/vita.html"), + TEST("http://www.isthe.com/chongo/tech/comp/c/expert.html"), + TEST("http://www.isthe.com/chongo/tech/comp/calc/index.html"), + TEST("http://www.isthe.com/chongo/tech/comp/fnv/index.html"), + TEST("http://www.isthe.com/chongo/tech/math/number/howhigh.html"), + TEST("http://www.isthe.com/chongo/tech/math/number/number.html"), + TEST("http://www.isthe.com/chongo/tech/math/prime/mersenne.html"), + TEST("http://www.isthe.com/chongo/tech/math/prime/mersenne.html#largest"), + TEST("http://www.lavarnd.org/cgi-bin/corpspeak.cgi"), + TEST("http://www.lavarnd.org/cgi-bin/haiku.cgi"), + TEST("http://www.lavarnd.org/cgi-bin/rand-none.cgi"), + TEST("http://www.lavarnd.org/cgi-bin/randdist.cgi"), + TEST("http://www.lavarnd.org/index.html"), + TEST("http://www.lavarnd.org/what/nist-test.html"), + TEST("http://www.macosxhints.com/"), + TEST("http://www.mellis.com/"), + TEST("http://www.nature.nps.gov/air/webcams/parks/havoso2alert/havoalert.cfm"), + TEST("http://www.nature.nps.gov/air/webcams/parks/havoso2alert/timelines_24.cfm"), + TEST("http://www.paulnoll.com/"), + TEST("http://www.pepysdiary.com/"), + TEST("http://www.sciencenews.org/index/home/activity/view"), + TEST("http://www.skyandtelescope.com/"), + TEST("http://www.sput.nl/~rob/sirius.html"), + TEST("http://www.systemexperts.com/"), + TEST("http://www.tq-international.com/phpBB3/index.php"), + TEST("http://www.travelquesttours.com/index.htm"), + TEST("http://www.wunderground.com/global/stations/89606.html"), + TEST(R10("21701")), + TEST(R10("M21701")), + TEST(R10("2^21701-1")), + TEST(R10("\x54\xc5")), + TEST(R10("\xc5\x54")), + TEST(R10("23209")), + TEST(R10("M23209")), + TEST(R10("2^23209-1")), + TEST(R10("\x5a\xa9")), + TEST(R10("\xa9\x5a")), + TEST(R10("391581216093")), + TEST(R10("391581*2^216093-1")), + TEST(R10("\x05\xf9\x9d\x03\x4c\x81")), + TEST(R10("FEDCBA9876543210")), + TEST(R10("\xfe\xdc\xba\x98\x76\x54\x32\x10")), + TEST(R10("EFCDAB8967452301")), + TEST(R10("\xef\xcd\xab\x89\x67\x45\x23\x01")), + TEST(R10("0123456789ABCDEF")), + TEST(R10("\x01\x23\x45\x67\x89\xab\xcd\xef")), + TEST(R10("1032547698BADCFE")), + TEST(R10("\x10\x32\x54\x76\x98\xba\xdc\xfe")), + TEST(R500("\x00")), + TEST(R500("\x07")), + TEST(R500("~")), + TEST(R500("\x7f")), + {NULL, 0} /* MUST BE LAST */ +}; + + +/* + * insert the contents of vector.c below + * + * make vector.c + * :r vector.c + */ +/* start of output generated by make vector.c */ + +/* FNV-0 32 bit test vectors */ +struct fnv0_32_test_vector fnv0_32_vector[] = { + { &fnv_test_str[0], (Fnv32_t) 0x00000000UL }, + { &fnv_test_str[1], (Fnv32_t) 0x00000061UL }, + { &fnv_test_str[2], (Fnv32_t) 0x00000062UL }, + { &fnv_test_str[3], (Fnv32_t) 0x00000063UL }, + { &fnv_test_str[4], (Fnv32_t) 0x00000064UL }, + { &fnv_test_str[5], (Fnv32_t) 0x00000065UL }, + { &fnv_test_str[6], (Fnv32_t) 0x00000066UL }, + { &fnv_test_str[7], (Fnv32_t) 0x6600a0fdUL }, + { &fnv_test_str[8], (Fnv32_t) 0x8ffd6e28UL }, + { &fnv_test_str[9], (Fnv32_t) 0xd3f4689aUL }, + { &fnv_test_str[10], (Fnv32_t) 0x43c0aa0fUL }, + { &fnv_test_str[11], (Fnv32_t) 0xb74bb5efUL }, + { &fnv_test_str[12], (Fnv32_t) 0x00000000UL }, + { &fnv_test_str[13], (Fnv32_t) 0x610098b3UL }, + { &fnv_test_str[14], (Fnv32_t) 0x62009a46UL }, + { &fnv_test_str[15], (Fnv32_t) 0x63009bd9UL }, + { &fnv_test_str[16], (Fnv32_t) 0x64009d6cUL }, + { &fnv_test_str[17], (Fnv32_t) 0x65009effUL }, + { &fnv_test_str[18], (Fnv32_t) 0x6600a092UL }, + { &fnv_test_str[19], (Fnv32_t) 0x8ffd6e47UL }, + { &fnv_test_str[20], (Fnv32_t) 0xd3f468f8UL }, + { &fnv_test_str[21], (Fnv32_t) 0x43c0aa6eUL }, + { &fnv_test_str[22], (Fnv32_t) 0xb74bb59dUL }, + { &fnv_test_str[23], (Fnv32_t) 0x7b2f673dUL }, + { &fnv_test_str[24], (Fnv32_t) 0x63009bb1UL }, + { &fnv_test_str[25], (Fnv32_t) 0x8af517ccUL }, + { &fnv_test_str[26], (Fnv32_t) 0x8bd4764aUL }, + { &fnv_test_str[27], (Fnv32_t) 0x69763619UL }, + { &fnv_test_str[28], (Fnv32_t) 0x1e172934UL }, + { &fnv_test_str[29], (Fnv32_t) 0x9275dcfcUL }, + { &fnv_test_str[30], (Fnv32_t) 0x8b8ae0c3UL }, + { &fnv_test_str[31], (Fnv32_t) 0x6e9fd298UL }, + { &fnv_test_str[32], (Fnv32_t) 0xbd98853bUL }, + { &fnv_test_str[33], (Fnv32_t) 0xb219bbc1UL }, + { &fnv_test_str[34], (Fnv32_t) 0x1f8290bbUL }, + { &fnv_test_str[35], (Fnv32_t) 0x5589d604UL }, + { &fnv_test_str[36], (Fnv32_t) 0xabfbe83eUL }, + { &fnv_test_str[37], (Fnv32_t) 0xfb8e99ffUL }, + { &fnv_test_str[38], (Fnv32_t) 0x007c6c4cUL }, + { &fnv_test_str[39], (Fnv32_t) 0x0fde7baeUL }, + { &fnv_test_str[40], (Fnv32_t) 0x8af517a3UL }, + { &fnv_test_str[41], (Fnv32_t) 0x8bd47624UL }, + { &fnv_test_str[42], (Fnv32_t) 0x6976367eUL }, + { &fnv_test_str[43], (Fnv32_t) 0x1e17295bUL }, + { &fnv_test_str[44], (Fnv32_t) 0x9275dcdcUL }, + { &fnv_test_str[45], (Fnv32_t) 0x8b8ae0b4UL }, + { &fnv_test_str[46], (Fnv32_t) 0x6e9fd2f9UL }, + { &fnv_test_str[47], (Fnv32_t) 0xbd988548UL }, + { &fnv_test_str[48], (Fnv32_t) 0xb219bbe1UL }, + { &fnv_test_str[49], (Fnv32_t) 0x1f8290d3UL }, + { &fnv_test_str[50], (Fnv32_t) 0x5589d661UL }, + { &fnv_test_str[51], (Fnv32_t) 0xabfbe84cUL }, + { &fnv_test_str[52], (Fnv32_t) 0xfb8e999aUL }, + { &fnv_test_str[53], (Fnv32_t) 0x007c6c6dUL }, + { &fnv_test_str[54], (Fnv32_t) 0x0fde7ba4UL }, + { &fnv_test_str[55], (Fnv32_t) 0xa93cb2eaUL }, + { &fnv_test_str[56], (Fnv32_t) 0x63009bacUL }, + { &fnv_test_str[57], (Fnv32_t) 0x85f50fb6UL }, + { &fnv_test_str[58], (Fnv32_t) 0x96c7bbe6UL }, + { &fnv_test_str[59], (Fnv32_t) 0x426ccb61UL }, + { &fnv_test_str[60], (Fnv32_t) 0xf2442993UL }, + { &fnv_test_str[61], (Fnv32_t) 0xf44d7208UL }, + { &fnv_test_str[62], (Fnv32_t) 0x9dea82f6UL }, + { &fnv_test_str[63], (Fnv32_t) 0x8e2c2926UL }, + { &fnv_test_str[64], (Fnv32_t) 0xf584c6f2UL }, + { &fnv_test_str[65], (Fnv32_t) 0x72052e81UL }, + { &fnv_test_str[66], (Fnv32_t) 0xff28357bUL }, + { &fnv_test_str[67], (Fnv32_t) 0x274c30c4UL }, + { &fnv_test_str[68], (Fnv32_t) 0xa0f0c4f5UL }, + { &fnv_test_str[69], (Fnv32_t) 0x50060da5UL }, + { &fnv_test_str[70], (Fnv32_t) 0x85f50fc4UL }, + { &fnv_test_str[71], (Fnv32_t) 0x96c7bb82UL }, + { &fnv_test_str[72], (Fnv32_t) 0x426ccb12UL }, + { &fnv_test_str[73], (Fnv32_t) 0xf24429b3UL }, + { &fnv_test_str[74], (Fnv32_t) 0xf44d7269UL }, + { &fnv_test_str[75], (Fnv32_t) 0x9dea8298UL }, + { &fnv_test_str[76], (Fnv32_t) 0x8e2c2942UL }, + { &fnv_test_str[77], (Fnv32_t) 0xf584c6d2UL }, + { &fnv_test_str[78], (Fnv32_t) 0x72052ef6UL }, + { &fnv_test_str[79], (Fnv32_t) 0xff283513UL }, + { &fnv_test_str[80], (Fnv32_t) 0x274c30a1UL }, + { &fnv_test_str[81], (Fnv32_t) 0xa0f0c48cUL }, + { &fnv_test_str[82], (Fnv32_t) 0x50060dafUL }, + { &fnv_test_str[83], (Fnv32_t) 0x9e877abfUL }, + { &fnv_test_str[84], (Fnv32_t) 0x6800a3d1UL }, + { &fnv_test_str[85], (Fnv32_t) 0x8a01e203UL }, + { &fnv_test_str[86], (Fnv32_t) 0xec6d6be8UL }, + { &fnv_test_str[87], (Fnv32_t) 0x1840de38UL }, + { &fnv_test_str[88], (Fnv32_t) 0xa7cc97b4UL }, + { &fnv_test_str[89], (Fnv32_t) 0x3ee6b3b4UL }, + { &fnv_test_str[90], (Fnv32_t) 0xa7cc97b7UL }, + { &fnv_test_str[91], (Fnv32_t) 0x7dcd6669UL }, + { &fnv_test_str[92], (Fnv32_t) 0xa7cc97b6UL }, + { &fnv_test_str[93], (Fnv32_t) 0xbcb4191eUL }, + { &fnv_test_str[94], (Fnv32_t) 0xa7cc97b1UL }, + { &fnv_test_str[95], (Fnv32_t) 0xfb9acdd3UL }, + { &fnv_test_str[96], (Fnv32_t) 0x89380433UL }, + { &fnv_test_str[97], (Fnv32_t) 0x8acd2855UL }, + { &fnv_test_str[98], (Fnv32_t) 0x8938043dUL }, + { &fnv_test_str[99], (Fnv32_t) 0xcaeed493UL }, + { &fnv_test_str[100], (Fnv32_t) 0x89380423UL }, + { &fnv_test_str[101], (Fnv32_t) 0x59382a25UL }, + { &fnv_test_str[102], (Fnv32_t) 0x567f75d7UL }, + { &fnv_test_str[103], (Fnv32_t) 0x01a68175UL }, + { &fnv_test_str[104], (Fnv32_t) 0x567f75d4UL }, + { &fnv_test_str[105], (Fnv32_t) 0xfea67cbcUL }, + { &fnv_test_str[106], (Fnv32_t) 0x567f75d5UL }, + { &fnv_test_str[107], (Fnv32_t) 0xffa67e4fUL }, + { &fnv_test_str[108], (Fnv32_t) 0xd131b668UL }, + { &fnv_test_str[109], (Fnv32_t) 0xb94225b8UL }, + { &fnv_test_str[110], (Fnv32_t) 0xd231b7d7UL }, + { &fnv_test_str[111], (Fnv32_t) 0xbb446775UL }, + { &fnv_test_str[112], (Fnv32_t) 0xdf31cc6eUL }, + { &fnv_test_str[113], (Fnv32_t) 0xc964d12aUL }, + { &fnv_test_str[114], (Fnv32_t) 0x23af8f9fUL }, + { &fnv_test_str[115], (Fnv32_t) 0xcc5f174dUL }, + { &fnv_test_str[116], (Fnv32_t) 0x96b29b8cUL }, + { &fnv_test_str[117], (Fnv32_t) 0xc72add64UL }, + { &fnv_test_str[118], (Fnv32_t) 0x528fb7efUL }, + { &fnv_test_str[119], (Fnv32_t) 0xe73e8d3dUL }, + { &fnv_test_str[120], (Fnv32_t) 0x876386feUL }, + { &fnv_test_str[121], (Fnv32_t) 0x811c9dc5UL }, + { &fnv_test_str[122], (Fnv32_t) 0x050c5d1fUL }, + { &fnv_test_str[123], (Fnv32_t) 0x14bf7238UL }, + { &fnv_test_str[124], (Fnv32_t) 0xe160ce28UL }, + { &fnv_test_str[125], (Fnv32_t) 0x89dc5a75UL }, + { &fnv_test_str[126], (Fnv32_t) 0xd89b69a0UL }, + { &fnv_test_str[127], (Fnv32_t) 0x94471a88UL }, + { &fnv_test_str[128], (Fnv32_t) 0xe78db65fUL }, + { &fnv_test_str[129], (Fnv32_t) 0x0c3009a2UL }, + { &fnv_test_str[130], (Fnv32_t) 0x122dff03UL }, + { &fnv_test_str[131], (Fnv32_t) 0xb4cd8875UL }, + { &fnv_test_str[132], (Fnv32_t) 0xf4dba725UL }, + { &fnv_test_str[133], (Fnv32_t) 0x41a16560UL }, + { &fnv_test_str[134], (Fnv32_t) 0x9c0f941fUL }, + { &fnv_test_str[135], (Fnv32_t) 0x451a5348UL }, + { &fnv_test_str[136], (Fnv32_t) 0x3f1d1d89UL }, + { &fnv_test_str[137], (Fnv32_t) 0x1b91b57aUL }, + { &fnv_test_str[138], (Fnv32_t) 0x3e99b577UL }, + { &fnv_test_str[139], (Fnv32_t) 0x4c9de07aUL }, + { &fnv_test_str[140], (Fnv32_t) 0x1ddf7572UL }, + { &fnv_test_str[141], (Fnv32_t) 0x64e81976UL }, + { &fnv_test_str[142], (Fnv32_t) 0x1106a888UL }, + { &fnv_test_str[143], (Fnv32_t) 0xa498d8e5UL }, + { &fnv_test_str[144], (Fnv32_t) 0x3c03d2e3UL }, + { &fnv_test_str[145], (Fnv32_t) 0x26568b28UL }, + { &fnv_test_str[146], (Fnv32_t) 0x70d7fb42UL }, + { &fnv_test_str[147], (Fnv32_t) 0xd3ae1d22UL }, + { &fnv_test_str[148], (Fnv32_t) 0xac8ea5f4UL }, + { &fnv_test_str[149], (Fnv32_t) 0x4d0abd60UL }, + { &fnv_test_str[150], (Fnv32_t) 0x48f5e086UL }, + { &fnv_test_str[151], (Fnv32_t) 0xa8f6241bUL }, + { &fnv_test_str[152], (Fnv32_t) 0x572f864fUL }, + { &fnv_test_str[153], (Fnv32_t) 0xa5340803UL }, + { &fnv_test_str[154], (Fnv32_t) 0x22881aa8UL }, + { &fnv_test_str[155], (Fnv32_t) 0xc2e2f5a2UL }, + { &fnv_test_str[156], (Fnv32_t) 0xebf5aec7UL }, + { &fnv_test_str[157], (Fnv32_t) 0x3cdbfb85UL }, + { &fnv_test_str[158], (Fnv32_t) 0xbb859704UL }, + { &fnv_test_str[159], (Fnv32_t) 0xc956fe11UL }, + { &fnv_test_str[160], (Fnv32_t) 0x8f11a7c9UL }, + { &fnv_test_str[161], (Fnv32_t) 0x36c48ecfUL }, + { &fnv_test_str[162], (Fnv32_t) 0x24bfa27eUL }, + { &fnv_test_str[163], (Fnv32_t) 0xf2596ad1UL }, + { &fnv_test_str[164], (Fnv32_t) 0xf14a9b45UL }, + { &fnv_test_str[165], (Fnv32_t) 0x7d45835aUL }, + { &fnv_test_str[166], (Fnv32_t) 0x6e49334dUL }, + { &fnv_test_str[167], (Fnv32_t) 0x71767337UL }, + { &fnv_test_str[168], (Fnv32_t) 0x858a1a8aUL }, + { &fnv_test_str[169], (Fnv32_t) 0x16e75ac2UL }, + { &fnv_test_str[170], (Fnv32_t) 0x409f99dfUL }, + { &fnv_test_str[171], (Fnv32_t) 0x6d6652ddUL }, + { &fnv_test_str[172], (Fnv32_t) 0x2761a9ffUL }, + { &fnv_test_str[173], (Fnv32_t) 0x41f0d616UL }, + { &fnv_test_str[174], (Fnv32_t) 0x0e2d0d0fUL }, + { &fnv_test_str[175], (Fnv32_t) 0x06adc8fdUL }, + { &fnv_test_str[176], (Fnv32_t) 0x60e0d4b9UL }, + { &fnv_test_str[177], (Fnv32_t) 0x5ddc79d3UL }, + { &fnv_test_str[178], (Fnv32_t) 0x1e6d0b46UL }, + { &fnv_test_str[179], (Fnv32_t) 0x1d1514d8UL }, + { &fnv_test_str[180], (Fnv32_t) 0xb1903a4eUL }, + { &fnv_test_str[181], (Fnv32_t) 0x8200c318UL }, + { &fnv_test_str[182], (Fnv32_t) 0x15e22888UL }, + { &fnv_test_str[183], (Fnv32_t) 0x57591760UL }, + { &fnv_test_str[184], (Fnv32_t) 0x02462efcUL }, + { &fnv_test_str[185], (Fnv32_t) 0x7651ec44UL }, + { &fnv_test_str[186], (Fnv32_t) 0x7c24e9d4UL }, + { &fnv_test_str[187], (Fnv32_t) 0x1952a034UL }, + { &fnv_test_str[188], (Fnv32_t) 0xd4c46864UL }, + { &fnv_test_str[189], (Fnv32_t) 0xcb57cde0UL }, + { &fnv_test_str[190], (Fnv32_t) 0x71136a70UL }, + { &fnv_test_str[191], (Fnv32_t) 0x0618fb40UL }, + { &fnv_test_str[192], (Fnv32_t) 0x69a24fc0UL }, + { &fnv_test_str[193], (Fnv32_t) 0x6a9be510UL }, + { &fnv_test_str[194], (Fnv32_t) 0xe0477040UL }, + { &fnv_test_str[195], (Fnv32_t) 0x85aa94b0UL }, + { &fnv_test_str[196], (Fnv32_t) 0xc6d76240UL }, + { &fnv_test_str[197], (Fnv32_t) 0xa9f09e40UL }, + { &fnv_test_str[198], (Fnv32_t) 0xa0291540UL }, + { &fnv_test_str[199], (Fnv32_t) 0x00000000UL }, + { &fnv_test_str[200], (Fnv32_t) 0x2e672aa4UL }, + { &fnv_test_str[201], (Fnv32_t) 0x84b1aa48UL }, + { &fnv_test_str[202], (Fnv32_t) 0xfc24ba24UL }, + { NULL, 0 } +}; + +/* FNV-1 32 bit test vectors */ +struct fnv1_32_test_vector fnv1_32_vector[] = { + { &fnv_test_str[0], (Fnv32_t) 0x811c9dc5UL }, + { &fnv_test_str[1], (Fnv32_t) 0x050c5d7eUL }, + { &fnv_test_str[2], (Fnv32_t) 0x050c5d7dUL }, + { &fnv_test_str[3], (Fnv32_t) 0x050c5d7cUL }, + { &fnv_test_str[4], (Fnv32_t) 0x050c5d7bUL }, + { &fnv_test_str[5], (Fnv32_t) 0x050c5d7aUL }, + { &fnv_test_str[6], (Fnv32_t) 0x050c5d79UL }, + { &fnv_test_str[7], (Fnv32_t) 0x6b772514UL }, + { &fnv_test_str[8], (Fnv32_t) 0x408f5e13UL }, + { &fnv_test_str[9], (Fnv32_t) 0xb4b1178bUL }, + { &fnv_test_str[10], (Fnv32_t) 0xfdc80fb0UL }, + { &fnv_test_str[11], (Fnv32_t) 0x31f0b262UL }, + { &fnv_test_str[12], (Fnv32_t) 0x050c5d1fUL }, + { &fnv_test_str[13], (Fnv32_t) 0x70772d5aUL }, + { &fnv_test_str[14], (Fnv32_t) 0x6f772bc7UL }, + { &fnv_test_str[15], (Fnv32_t) 0x6e772a34UL }, + { &fnv_test_str[16], (Fnv32_t) 0x6d7728a1UL }, + { &fnv_test_str[17], (Fnv32_t) 0x6c77270eUL }, + { &fnv_test_str[18], (Fnv32_t) 0x6b77257bUL }, + { &fnv_test_str[19], (Fnv32_t) 0x408f5e7cUL }, + { &fnv_test_str[20], (Fnv32_t) 0xb4b117e9UL }, + { &fnv_test_str[21], (Fnv32_t) 0xfdc80fd1UL }, + { &fnv_test_str[22], (Fnv32_t) 0x31f0b210UL }, + { &fnv_test_str[23], (Fnv32_t) 0xffe8d046UL }, + { &fnv_test_str[24], (Fnv32_t) 0x6e772a5cUL }, + { &fnv_test_str[25], (Fnv32_t) 0x4197aebbUL }, + { &fnv_test_str[26], (Fnv32_t) 0xfcc8100fUL }, + { &fnv_test_str[27], (Fnv32_t) 0xfdf147faUL }, + { &fnv_test_str[28], (Fnv32_t) 0xbcd44ee1UL }, + { &fnv_test_str[29], (Fnv32_t) 0x23382c13UL }, + { &fnv_test_str[30], (Fnv32_t) 0x846d619eUL }, + { &fnv_test_str[31], (Fnv32_t) 0x1630abdbUL }, + { &fnv_test_str[32], (Fnv32_t) 0xc99e89b2UL }, + { &fnv_test_str[33], (Fnv32_t) 0x1692c316UL }, + { &fnv_test_str[34], (Fnv32_t) 0x9f091bcaUL }, + { &fnv_test_str[35], (Fnv32_t) 0x2556be9bUL }, + { &fnv_test_str[36], (Fnv32_t) 0x628e0e73UL }, + { &fnv_test_str[37], (Fnv32_t) 0x98a0bf6cUL }, + { &fnv_test_str[38], (Fnv32_t) 0xb10d5725UL }, + { &fnv_test_str[39], (Fnv32_t) 0xdd002f35UL }, + { &fnv_test_str[40], (Fnv32_t) 0x4197aed4UL }, + { &fnv_test_str[41], (Fnv32_t) 0xfcc81061UL }, + { &fnv_test_str[42], (Fnv32_t) 0xfdf1479dUL }, + { &fnv_test_str[43], (Fnv32_t) 0xbcd44e8eUL }, + { &fnv_test_str[44], (Fnv32_t) 0x23382c33UL }, + { &fnv_test_str[45], (Fnv32_t) 0x846d61e9UL }, + { &fnv_test_str[46], (Fnv32_t) 0x1630abbaUL }, + { &fnv_test_str[47], (Fnv32_t) 0xc99e89c1UL }, + { &fnv_test_str[48], (Fnv32_t) 0x1692c336UL }, + { &fnv_test_str[49], (Fnv32_t) 0x9f091ba2UL }, + { &fnv_test_str[50], (Fnv32_t) 0x2556befeUL }, + { &fnv_test_str[51], (Fnv32_t) 0x628e0e01UL }, + { &fnv_test_str[52], (Fnv32_t) 0x98a0bf09UL }, + { &fnv_test_str[53], (Fnv32_t) 0xb10d5704UL }, + { &fnv_test_str[54], (Fnv32_t) 0xdd002f3fUL }, + { &fnv_test_str[55], (Fnv32_t) 0x1c4a506fUL }, + { &fnv_test_str[56], (Fnv32_t) 0x6e772a41UL }, + { &fnv_test_str[57], (Fnv32_t) 0x26978421UL }, + { &fnv_test_str[58], (Fnv32_t) 0xe184ff97UL }, + { &fnv_test_str[59], (Fnv32_t) 0x9b5e5ac6UL }, + { &fnv_test_str[60], (Fnv32_t) 0x5b88e592UL }, + { &fnv_test_str[61], (Fnv32_t) 0xaa8164b7UL }, + { &fnv_test_str[62], (Fnv32_t) 0x20b18c7bUL }, + { &fnv_test_str[63], (Fnv32_t) 0xf28025c5UL }, + { &fnv_test_str[64], (Fnv32_t) 0x84bb753fUL }, + { &fnv_test_str[65], (Fnv32_t) 0x3219925aUL }, + { &fnv_test_str[66], (Fnv32_t) 0x384163c6UL }, + { &fnv_test_str[67], (Fnv32_t) 0x54f010d7UL }, + { &fnv_test_str[68], (Fnv32_t) 0x8cea820cUL }, + { &fnv_test_str[69], (Fnv32_t) 0xe12ab8eeUL }, + { &fnv_test_str[70], (Fnv32_t) 0x26978453UL }, + { &fnv_test_str[71], (Fnv32_t) 0xe184fff3UL }, + { &fnv_test_str[72], (Fnv32_t) 0x9b5e5ab5UL }, + { &fnv_test_str[73], (Fnv32_t) 0x5b88e5b2UL }, + { &fnv_test_str[74], (Fnv32_t) 0xaa8164d6UL }, + { &fnv_test_str[75], (Fnv32_t) 0x20b18c15UL }, + { &fnv_test_str[76], (Fnv32_t) 0xf28025a1UL }, + { &fnv_test_str[77], (Fnv32_t) 0x84bb751fUL }, + { &fnv_test_str[78], (Fnv32_t) 0x3219922dUL }, + { &fnv_test_str[79], (Fnv32_t) 0x384163aeUL }, + { &fnv_test_str[80], (Fnv32_t) 0x54f010b2UL }, + { &fnv_test_str[81], (Fnv32_t) 0x8cea8275UL }, + { &fnv_test_str[82], (Fnv32_t) 0xe12ab8e4UL }, + { &fnv_test_str[83], (Fnv32_t) 0x64411eaaUL }, + { &fnv_test_str[84], (Fnv32_t) 0x6977223cUL }, + { &fnv_test_str[85], (Fnv32_t) 0x428ae474UL }, + { &fnv_test_str[86], (Fnv32_t) 0xb6fa7167UL }, + { &fnv_test_str[87], (Fnv32_t) 0x73408525UL }, + { &fnv_test_str[88], (Fnv32_t) 0xb78320a1UL }, + { &fnv_test_str[89], (Fnv32_t) 0x0caf4135UL }, + { &fnv_test_str[90], (Fnv32_t) 0xb78320a2UL }, + { &fnv_test_str[91], (Fnv32_t) 0xcdc88e80UL }, + { &fnv_test_str[92], (Fnv32_t) 0xb78320a3UL }, + { &fnv_test_str[93], (Fnv32_t) 0x8ee1dbcbUL }, + { &fnv_test_str[94], (Fnv32_t) 0xb78320a4UL }, + { &fnv_test_str[95], (Fnv32_t) 0x4ffb2716UL }, + { &fnv_test_str[96], (Fnv32_t) 0x860632aaUL }, + { &fnv_test_str[97], (Fnv32_t) 0xcc2c5c64UL }, + { &fnv_test_str[98], (Fnv32_t) 0x860632a4UL }, + { &fnv_test_str[99], (Fnv32_t) 0x2a7ec4a6UL }, + { &fnv_test_str[100], (Fnv32_t) 0x860632baUL }, + { &fnv_test_str[101], (Fnv32_t) 0xfefe8e14UL }, + { &fnv_test_str[102], (Fnv32_t) 0x0a3cffd8UL }, + { &fnv_test_str[103], (Fnv32_t) 0xf606c108UL }, + { &fnv_test_str[104], (Fnv32_t) 0x0a3cffdbUL }, + { &fnv_test_str[105], (Fnv32_t) 0xf906c5c1UL }, + { &fnv_test_str[106], (Fnv32_t) 0x0a3cffdaUL }, + { &fnv_test_str[107], (Fnv32_t) 0xf806c42eUL }, + { &fnv_test_str[108], (Fnv32_t) 0xc07167d7UL }, + { &fnv_test_str[109], (Fnv32_t) 0xc9867775UL }, + { &fnv_test_str[110], (Fnv32_t) 0xbf716668UL }, + { &fnv_test_str[111], (Fnv32_t) 0xc78435b8UL }, + { &fnv_test_str[112], (Fnv32_t) 0xc6717155UL }, + { &fnv_test_str[113], (Fnv32_t) 0xb99568cfUL }, + { &fnv_test_str[114], (Fnv32_t) 0x7662e0d6UL }, + { &fnv_test_str[115], (Fnv32_t) 0x33a7f0e2UL }, + { &fnv_test_str[116], (Fnv32_t) 0xc2732f95UL }, + { &fnv_test_str[117], (Fnv32_t) 0xb053e78fUL }, + { &fnv_test_str[118], (Fnv32_t) 0x3a19c02aUL }, + { &fnv_test_str[119], (Fnv32_t) 0xa089821eUL }, + { &fnv_test_str[120], (Fnv32_t) 0x31ae8f83UL }, + { &fnv_test_str[121], (Fnv32_t) 0x995fa9c4UL }, + { &fnv_test_str[122], (Fnv32_t) 0x35983f8cUL }, + { &fnv_test_str[123], (Fnv32_t) 0x5036a251UL }, + { &fnv_test_str[124], (Fnv32_t) 0x97018583UL }, + { &fnv_test_str[125], (Fnv32_t) 0xb4448d60UL }, + { &fnv_test_str[126], (Fnv32_t) 0x025dfe59UL }, + { &fnv_test_str[127], (Fnv32_t) 0xc5eab3afUL }, + { &fnv_test_str[128], (Fnv32_t) 0x7d21ba1eUL }, + { &fnv_test_str[129], (Fnv32_t) 0x7704cddbUL }, + { &fnv_test_str[130], (Fnv32_t) 0xd0071bfeUL }, + { &fnv_test_str[131], (Fnv32_t) 0x0ff3774cUL }, + { &fnv_test_str[132], (Fnv32_t) 0xb0fea0eaUL }, + { &fnv_test_str[133], (Fnv32_t) 0x58177303UL }, + { &fnv_test_str[134], (Fnv32_t) 0x4f599cdaUL }, + { &fnv_test_str[135], (Fnv32_t) 0x3e590a47UL }, + { &fnv_test_str[136], (Fnv32_t) 0x965595f8UL }, + { &fnv_test_str[137], (Fnv32_t) 0xc37f178dUL }, + { &fnv_test_str[138], (Fnv32_t) 0x9711dd26UL }, + { &fnv_test_str[139], (Fnv32_t) 0x23c99b7fUL }, + { &fnv_test_str[140], (Fnv32_t) 0x6e568b17UL }, + { &fnv_test_str[141], (Fnv32_t) 0x43f0245bUL }, + { &fnv_test_str[142], (Fnv32_t) 0xbcb7a001UL }, + { &fnv_test_str[143], (Fnv32_t) 0x12e6dffeUL }, + { &fnv_test_str[144], (Fnv32_t) 0x0792f2d6UL }, + { &fnv_test_str[145], (Fnv32_t) 0xb966936bUL }, + { &fnv_test_str[146], (Fnv32_t) 0x46439ac5UL }, + { &fnv_test_str[147], (Fnv32_t) 0x728d49afUL }, + { &fnv_test_str[148], (Fnv32_t) 0xd33745c9UL }, + { &fnv_test_str[149], (Fnv32_t) 0xbc382a57UL }, + { &fnv_test_str[150], (Fnv32_t) 0x4bda1d31UL }, + { &fnv_test_str[151], (Fnv32_t) 0xce35ccaeUL }, + { &fnv_test_str[152], (Fnv32_t) 0x3b6eed94UL }, + { &fnv_test_str[153], (Fnv32_t) 0x445c9c58UL }, + { &fnv_test_str[154], (Fnv32_t) 0x3db8bf9dUL }, + { &fnv_test_str[155], (Fnv32_t) 0x2dee116dUL }, + { &fnv_test_str[156], (Fnv32_t) 0xc18738daUL }, + { &fnv_test_str[157], (Fnv32_t) 0x5b156176UL }, + { &fnv_test_str[158], (Fnv32_t) 0x2aa7d593UL }, + { &fnv_test_str[159], (Fnv32_t) 0xb2409658UL }, + { &fnv_test_str[160], (Fnv32_t) 0xe1489528UL }, + { &fnv_test_str[161], (Fnv32_t) 0xfe1ee07eUL }, + { &fnv_test_str[162], (Fnv32_t) 0xe8842315UL }, + { &fnv_test_str[163], (Fnv32_t) 0x3a6a63a2UL }, + { &fnv_test_str[164], (Fnv32_t) 0x06d2c18cUL }, + { &fnv_test_str[165], (Fnv32_t) 0xf8ef7225UL }, + { &fnv_test_str[166], (Fnv32_t) 0x843d3300UL }, + { &fnv_test_str[167], (Fnv32_t) 0xbb24f7aeUL }, + { &fnv_test_str[168], (Fnv32_t) 0x878c0ec9UL }, + { &fnv_test_str[169], (Fnv32_t) 0xb557810fUL }, + { &fnv_test_str[170], (Fnv32_t) 0x57423246UL }, + { &fnv_test_str[171], (Fnv32_t) 0x87f7505eUL }, + { &fnv_test_str[172], (Fnv32_t) 0xbb809f20UL }, + { &fnv_test_str[173], (Fnv32_t) 0x8932abb5UL }, + { &fnv_test_str[174], (Fnv32_t) 0x0a9b3aa0UL }, + { &fnv_test_str[175], (Fnv32_t) 0xb8682a24UL }, + { &fnv_test_str[176], (Fnv32_t) 0xa7ac1c56UL }, + { &fnv_test_str[177], (Fnv32_t) 0x11409252UL }, + { &fnv_test_str[178], (Fnv32_t) 0xa987f517UL }, + { &fnv_test_str[179], (Fnv32_t) 0xf309e7edUL }, + { &fnv_test_str[180], (Fnv32_t) 0xc9e8f417UL }, + { &fnv_test_str[181], (Fnv32_t) 0x7f447bddUL }, + { &fnv_test_str[182], (Fnv32_t) 0xb929adc5UL }, + { &fnv_test_str[183], (Fnv32_t) 0x57022879UL }, + { &fnv_test_str[184], (Fnv32_t) 0xdcfd2c49UL }, + { &fnv_test_str[185], (Fnv32_t) 0x6edafff5UL }, + { &fnv_test_str[186], (Fnv32_t) 0xf04fb1f1UL }, + { &fnv_test_str[187], (Fnv32_t) 0xfb7de8b9UL }, + { &fnv_test_str[188], (Fnv32_t) 0xc5f1d7e9UL }, + { &fnv_test_str[189], (Fnv32_t) 0x32c1f439UL }, + { &fnv_test_str[190], (Fnv32_t) 0x7fd3eb7dUL }, + { &fnv_test_str[191], (Fnv32_t) 0x81597da5UL }, + { &fnv_test_str[192], (Fnv32_t) 0x05eb7a25UL }, + { &fnv_test_str[193], (Fnv32_t) 0x9c0fa1b5UL }, + { &fnv_test_str[194], (Fnv32_t) 0x53ccb1c5UL }, + { &fnv_test_str[195], (Fnv32_t) 0xfabece15UL }, + { &fnv_test_str[196], (Fnv32_t) 0x4ad745a5UL }, + { &fnv_test_str[197], (Fnv32_t) 0xe5bdc495UL }, + { &fnv_test_str[198], (Fnv32_t) 0x23b3c0a5UL }, + { &fnv_test_str[199], (Fnv32_t) 0xfa823dd5UL }, + { &fnv_test_str[200], (Fnv32_t) 0x0c6c58b9UL }, + { &fnv_test_str[201], (Fnv32_t) 0xe2dbccd5UL }, + { &fnv_test_str[202], (Fnv32_t) 0xdb7f50f9UL }, + { NULL, 0 } +}; + +/* FNV-1a 32 bit test vectors */ +struct fnv1a_32_test_vector fnv1a_32_vector[] = { + { &fnv_test_str[0], (Fnv32_t) 0x811c9dc5UL }, + { &fnv_test_str[1], (Fnv32_t) 0xe40c292cUL }, + { &fnv_test_str[2], (Fnv32_t) 0xe70c2de5UL }, + { &fnv_test_str[3], (Fnv32_t) 0xe60c2c52UL }, + { &fnv_test_str[4], (Fnv32_t) 0xe10c2473UL }, + { &fnv_test_str[5], (Fnv32_t) 0xe00c22e0UL }, + { &fnv_test_str[6], (Fnv32_t) 0xe30c2799UL }, + { &fnv_test_str[7], (Fnv32_t) 0x6222e842UL }, + { &fnv_test_str[8], (Fnv32_t) 0xa9f37ed7UL }, + { &fnv_test_str[9], (Fnv32_t) 0x3f5076efUL }, + { &fnv_test_str[10], (Fnv32_t) 0x39aaa18aUL }, + { &fnv_test_str[11], (Fnv32_t) 0xbf9cf968UL }, + { &fnv_test_str[12], (Fnv32_t) 0x050c5d1fUL }, + { &fnv_test_str[13], (Fnv32_t) 0x2b24d044UL }, + { &fnv_test_str[14], (Fnv32_t) 0x9d2c3f7fUL }, + { &fnv_test_str[15], (Fnv32_t) 0x7729c516UL }, + { &fnv_test_str[16], (Fnv32_t) 0xb91d6109UL }, + { &fnv_test_str[17], (Fnv32_t) 0x931ae6a0UL }, + { &fnv_test_str[18], (Fnv32_t) 0x052255dbUL }, + { &fnv_test_str[19], (Fnv32_t) 0xbef39fe6UL }, + { &fnv_test_str[20], (Fnv32_t) 0x6150ac75UL }, + { &fnv_test_str[21], (Fnv32_t) 0x9aab3a3dUL }, + { &fnv_test_str[22], (Fnv32_t) 0x519c4c3eUL }, + { &fnv_test_str[23], (Fnv32_t) 0x0c1c9eb8UL }, + { &fnv_test_str[24], (Fnv32_t) 0x5f299f4eUL }, + { &fnv_test_str[25], (Fnv32_t) 0xef8580f3UL }, + { &fnv_test_str[26], (Fnv32_t) 0xac297727UL }, + { &fnv_test_str[27], (Fnv32_t) 0x4546b9c0UL }, + { &fnv_test_str[28], (Fnv32_t) 0xbd564e7dUL }, + { &fnv_test_str[29], (Fnv32_t) 0x6bdd5c67UL }, + { &fnv_test_str[30], (Fnv32_t) 0xdd77ed30UL }, + { &fnv_test_str[31], (Fnv32_t) 0xf4ca9683UL }, + { &fnv_test_str[32], (Fnv32_t) 0x4aeb9bd0UL }, + { &fnv_test_str[33], (Fnv32_t) 0xe0e67ad0UL }, + { &fnv_test_str[34], (Fnv32_t) 0xc2d32fa8UL }, + { &fnv_test_str[35], (Fnv32_t) 0x7f743fb7UL }, + { &fnv_test_str[36], (Fnv32_t) 0x6900631fUL }, + { &fnv_test_str[37], (Fnv32_t) 0xc59c990eUL }, + { &fnv_test_str[38], (Fnv32_t) 0x448524fdUL }, + { &fnv_test_str[39], (Fnv32_t) 0xd49930d5UL }, + { &fnv_test_str[40], (Fnv32_t) 0x1c85c7caUL }, + { &fnv_test_str[41], (Fnv32_t) 0x0229fe89UL }, + { &fnv_test_str[42], (Fnv32_t) 0x2c469265UL }, + { &fnv_test_str[43], (Fnv32_t) 0xce566940UL }, + { &fnv_test_str[44], (Fnv32_t) 0x8bdd8ec7UL }, + { &fnv_test_str[45], (Fnv32_t) 0x34787625UL }, + { &fnv_test_str[46], (Fnv32_t) 0xd3ca6290UL }, + { &fnv_test_str[47], (Fnv32_t) 0xddeaf039UL }, + { &fnv_test_str[48], (Fnv32_t) 0xc0e64870UL }, + { &fnv_test_str[49], (Fnv32_t) 0xdad35570UL }, + { &fnv_test_str[50], (Fnv32_t) 0x5a740578UL }, + { &fnv_test_str[51], (Fnv32_t) 0x5b004d15UL }, + { &fnv_test_str[52], (Fnv32_t) 0x6a9c09cdUL }, + { &fnv_test_str[53], (Fnv32_t) 0x2384f10aUL }, + { &fnv_test_str[54], (Fnv32_t) 0xda993a47UL }, + { &fnv_test_str[55], (Fnv32_t) 0x8227df4fUL }, + { &fnv_test_str[56], (Fnv32_t) 0x4c298165UL }, + { &fnv_test_str[57], (Fnv32_t) 0xfc563735UL }, + { &fnv_test_str[58], (Fnv32_t) 0x8cb91483UL }, + { &fnv_test_str[59], (Fnv32_t) 0x775bf5d0UL }, + { &fnv_test_str[60], (Fnv32_t) 0xd5c428d0UL }, + { &fnv_test_str[61], (Fnv32_t) 0x34cc0ea3UL }, + { &fnv_test_str[62], (Fnv32_t) 0xea3b4cb7UL }, + { &fnv_test_str[63], (Fnv32_t) 0x8e59f029UL }, + { &fnv_test_str[64], (Fnv32_t) 0x2094de2bUL }, + { &fnv_test_str[65], (Fnv32_t) 0xa65a0ad4UL }, + { &fnv_test_str[66], (Fnv32_t) 0x9bbee5f4UL }, + { &fnv_test_str[67], (Fnv32_t) 0xbe836343UL }, + { &fnv_test_str[68], (Fnv32_t) 0x22d5344eUL }, + { &fnv_test_str[69], (Fnv32_t) 0x19a1470cUL }, + { &fnv_test_str[70], (Fnv32_t) 0x4a56b1ffUL }, + { &fnv_test_str[71], (Fnv32_t) 0x70b8e86fUL }, + { &fnv_test_str[72], (Fnv32_t) 0x0a5b4a39UL }, + { &fnv_test_str[73], (Fnv32_t) 0xb5c3f670UL }, + { &fnv_test_str[74], (Fnv32_t) 0x53cc3f70UL }, + { &fnv_test_str[75], (Fnv32_t) 0xc03b0a99UL }, + { &fnv_test_str[76], (Fnv32_t) 0x7259c415UL }, + { &fnv_test_str[77], (Fnv32_t) 0x4095108bUL }, + { &fnv_test_str[78], (Fnv32_t) 0x7559bdb1UL }, + { &fnv_test_str[79], (Fnv32_t) 0xb3bf0bbcUL }, + { &fnv_test_str[80], (Fnv32_t) 0x2183ff1cUL }, + { &fnv_test_str[81], (Fnv32_t) 0x2bd54279UL }, + { &fnv_test_str[82], (Fnv32_t) 0x23a156caUL }, + { &fnv_test_str[83], (Fnv32_t) 0x64e2d7e4UL }, + { &fnv_test_str[84], (Fnv32_t) 0x683af69aUL }, + { &fnv_test_str[85], (Fnv32_t) 0xaed2346eUL }, + { &fnv_test_str[86], (Fnv32_t) 0x4f9f2cabUL }, + { &fnv_test_str[87], (Fnv32_t) 0x02935131UL }, + { &fnv_test_str[88], (Fnv32_t) 0xc48fb86dUL }, + { &fnv_test_str[89], (Fnv32_t) 0x2269f369UL }, + { &fnv_test_str[90], (Fnv32_t) 0xc18fb3b4UL }, + { &fnv_test_str[91], (Fnv32_t) 0x50ef1236UL }, + { &fnv_test_str[92], (Fnv32_t) 0xc28fb547UL }, + { &fnv_test_str[93], (Fnv32_t) 0x96c3bf47UL }, + { &fnv_test_str[94], (Fnv32_t) 0xbf8fb08eUL }, + { &fnv_test_str[95], (Fnv32_t) 0xf3e4d49cUL }, + { &fnv_test_str[96], (Fnv32_t) 0x32179058UL }, + { &fnv_test_str[97], (Fnv32_t) 0x280bfee6UL }, + { &fnv_test_str[98], (Fnv32_t) 0x30178d32UL }, + { &fnv_test_str[99], (Fnv32_t) 0x21addaf8UL }, + { &fnv_test_str[100], (Fnv32_t) 0x4217a988UL }, + { &fnv_test_str[101], (Fnv32_t) 0x772633d6UL }, + { &fnv_test_str[102], (Fnv32_t) 0x08a3d11eUL }, + { &fnv_test_str[103], (Fnv32_t) 0xb7e2323aUL }, + { &fnv_test_str[104], (Fnv32_t) 0x07a3cf8bUL }, + { &fnv_test_str[105], (Fnv32_t) 0x91dfb7d1UL }, + { &fnv_test_str[106], (Fnv32_t) 0x06a3cdf8UL }, + { &fnv_test_str[107], (Fnv32_t) 0x6bdd3d68UL }, + { &fnv_test_str[108], (Fnv32_t) 0x1d5636a7UL }, + { &fnv_test_str[109], (Fnv32_t) 0xd5b808e5UL }, + { &fnv_test_str[110], (Fnv32_t) 0x1353e852UL }, + { &fnv_test_str[111], (Fnv32_t) 0xbf16b916UL }, + { &fnv_test_str[112], (Fnv32_t) 0xa55b89edUL }, + { &fnv_test_str[113], (Fnv32_t) 0x3c1a2017UL }, + { &fnv_test_str[114], (Fnv32_t) 0x0588b13cUL }, + { &fnv_test_str[115], (Fnv32_t) 0xf22f0174UL }, + { &fnv_test_str[116], (Fnv32_t) 0xe83641e1UL }, + { &fnv_test_str[117], (Fnv32_t) 0x6e69b533UL }, + { &fnv_test_str[118], (Fnv32_t) 0xf1760448UL }, + { &fnv_test_str[119], (Fnv32_t) 0x64c8bd58UL }, + { &fnv_test_str[120], (Fnv32_t) 0x97b4ea23UL }, + { &fnv_test_str[121], (Fnv32_t) 0x9a4e92e6UL }, + { &fnv_test_str[122], (Fnv32_t) 0xcfb14012UL }, + { &fnv_test_str[123], (Fnv32_t) 0xf01b2511UL }, + { &fnv_test_str[124], (Fnv32_t) 0x0bbb59c3UL }, + { &fnv_test_str[125], (Fnv32_t) 0xce524afaUL }, + { &fnv_test_str[126], (Fnv32_t) 0xdd16ef45UL }, + { &fnv_test_str[127], (Fnv32_t) 0x60648bb3UL }, + { &fnv_test_str[128], (Fnv32_t) 0x7fa4bcfcUL }, + { &fnv_test_str[129], (Fnv32_t) 0x5053ae17UL }, + { &fnv_test_str[130], (Fnv32_t) 0xc9302890UL }, + { &fnv_test_str[131], (Fnv32_t) 0x956ded32UL }, + { &fnv_test_str[132], (Fnv32_t) 0x9136db84UL }, + { &fnv_test_str[133], (Fnv32_t) 0xdf9d3323UL }, + { &fnv_test_str[134], (Fnv32_t) 0x32bb6cd0UL }, + { &fnv_test_str[135], (Fnv32_t) 0xc8f8385bUL }, + { &fnv_test_str[136], (Fnv32_t) 0xeb08bfbaUL }, + { &fnv_test_str[137], (Fnv32_t) 0x62cc8e3dUL }, + { &fnv_test_str[138], (Fnv32_t) 0xc3e20f5cUL }, + { &fnv_test_str[139], (Fnv32_t) 0x39e97f17UL }, + { &fnv_test_str[140], (Fnv32_t) 0x7837b203UL }, + { &fnv_test_str[141], (Fnv32_t) 0x319e877bUL }, + { &fnv_test_str[142], (Fnv32_t) 0xd3e63f89UL }, + { &fnv_test_str[143], (Fnv32_t) 0x29b50b38UL }, + { &fnv_test_str[144], (Fnv32_t) 0x5ed678b8UL }, + { &fnv_test_str[145], (Fnv32_t) 0xb0d5b793UL }, + { &fnv_test_str[146], (Fnv32_t) 0x52450be5UL }, + { &fnv_test_str[147], (Fnv32_t) 0xfa72d767UL }, + { &fnv_test_str[148], (Fnv32_t) 0x95066709UL }, + { &fnv_test_str[149], (Fnv32_t) 0x7f52e123UL }, + { &fnv_test_str[150], (Fnv32_t) 0x76966481UL }, + { &fnv_test_str[151], (Fnv32_t) 0x063258b0UL }, + { &fnv_test_str[152], (Fnv32_t) 0x2ded6e8aUL }, + { &fnv_test_str[153], (Fnv32_t) 0xb07d7c52UL }, + { &fnv_test_str[154], (Fnv32_t) 0xd0c71b71UL }, + { &fnv_test_str[155], (Fnv32_t) 0xf684f1bdUL }, + { &fnv_test_str[156], (Fnv32_t) 0x868ecfa8UL }, + { &fnv_test_str[157], (Fnv32_t) 0xf794f684UL }, + { &fnv_test_str[158], (Fnv32_t) 0xd19701c3UL }, + { &fnv_test_str[159], (Fnv32_t) 0x346e171eUL }, + { &fnv_test_str[160], (Fnv32_t) 0x91f8f676UL }, + { &fnv_test_str[161], (Fnv32_t) 0x0bf58848UL }, + { &fnv_test_str[162], (Fnv32_t) 0x6317b6d1UL }, + { &fnv_test_str[163], (Fnv32_t) 0xafad4c54UL }, + { &fnv_test_str[164], (Fnv32_t) 0x0f25681eUL }, + { &fnv_test_str[165], (Fnv32_t) 0x91b18d49UL }, + { &fnv_test_str[166], (Fnv32_t) 0x7d61c12eUL }, + { &fnv_test_str[167], (Fnv32_t) 0x5147d25cUL }, + { &fnv_test_str[168], (Fnv32_t) 0x9a8b6805UL }, + { &fnv_test_str[169], (Fnv32_t) 0x4cd2a447UL }, + { &fnv_test_str[170], (Fnv32_t) 0x1e549b14UL }, + { &fnv_test_str[171], (Fnv32_t) 0x2fe1b574UL }, + { &fnv_test_str[172], (Fnv32_t) 0xcf0cd31eUL }, + { &fnv_test_str[173], (Fnv32_t) 0x6c471669UL }, + { &fnv_test_str[174], (Fnv32_t) 0x0e5eef1eUL }, + { &fnv_test_str[175], (Fnv32_t) 0x2bed3602UL }, + { &fnv_test_str[176], (Fnv32_t) 0xb26249e0UL }, + { &fnv_test_str[177], (Fnv32_t) 0x2c9b86a4UL }, + { &fnv_test_str[178], (Fnv32_t) 0xe415e2bbUL }, + { &fnv_test_str[179], (Fnv32_t) 0x18a98d1dUL }, + { &fnv_test_str[180], (Fnv32_t) 0xb7df8b7bUL }, + { &fnv_test_str[181], (Fnv32_t) 0x241e9075UL }, + { &fnv_test_str[182], (Fnv32_t) 0x063f70ddUL }, + { &fnv_test_str[183], (Fnv32_t) 0x0295aed9UL }, + { &fnv_test_str[184], (Fnv32_t) 0x56a7f781UL }, + { &fnv_test_str[185], (Fnv32_t) 0x253bc645UL }, + { &fnv_test_str[186], (Fnv32_t) 0x46610921UL }, + { &fnv_test_str[187], (Fnv32_t) 0x7c1577f9UL }, + { &fnv_test_str[188], (Fnv32_t) 0x512b2851UL }, + { &fnv_test_str[189], (Fnv32_t) 0x76823999UL }, + { &fnv_test_str[190], (Fnv32_t) 0xc0586935UL }, + { &fnv_test_str[191], (Fnv32_t) 0xf3415c85UL }, + { &fnv_test_str[192], (Fnv32_t) 0x0ae4ff65UL }, + { &fnv_test_str[193], (Fnv32_t) 0x58b79725UL }, + { &fnv_test_str[194], (Fnv32_t) 0xdea43aa5UL }, + { &fnv_test_str[195], (Fnv32_t) 0x2bb3be35UL }, + { &fnv_test_str[196], (Fnv32_t) 0xea777a45UL }, + { &fnv_test_str[197], (Fnv32_t) 0x8f21c305UL }, + { &fnv_test_str[198], (Fnv32_t) 0x5c9d0865UL }, + { &fnv_test_str[199], (Fnv32_t) 0xfa823dd5UL }, + { &fnv_test_str[200], (Fnv32_t) 0x21a27271UL }, + { &fnv_test_str[201], (Fnv32_t) 0x83c5c6d5UL }, + { &fnv_test_str[202], (Fnv32_t) 0x813b0881UL }, + { NULL, 0 } +}; + +/* FNV-0 64 bit test vectors */ +#if defined(HAVE_64BIT_LONG_LONG) +struct fnv0_64_test_vector fnv0_64_vector[] = { + { &fnv_test_str[0], (Fnv64_t) 0x0000000000000000ULL }, + { &fnv_test_str[1], (Fnv64_t) 0x0000000000000061ULL }, + { &fnv_test_str[2], (Fnv64_t) 0x0000000000000062ULL }, + { &fnv_test_str[3], (Fnv64_t) 0x0000000000000063ULL }, + { &fnv_test_str[4], (Fnv64_t) 0x0000000000000064ULL }, + { &fnv_test_str[5], (Fnv64_t) 0x0000000000000065ULL }, + { &fnv_test_str[6], (Fnv64_t) 0x0000000000000066ULL }, + { &fnv_test_str[7], (Fnv64_t) 0x000066000000ad3dULL }, + { &fnv_test_str[8], (Fnv64_t) 0x015a8f0001265ec8ULL }, + { &fnv_test_str[9], (Fnv64_t) 0x733fc501f4330dbaULL }, + { &fnv_test_str[10], (Fnv64_t) 0x08697c51f2c0536fULL }, + { &fnv_test_str[11], (Fnv64_t) 0x0b91ae3f7ccdc5efULL }, + { &fnv_test_str[12], (Fnv64_t) 0x0000000000000000ULL }, + { &fnv_test_str[13], (Fnv64_t) 0x000061000000a4d3ULL }, + { &fnv_test_str[14], (Fnv64_t) 0x000062000000a686ULL }, + { &fnv_test_str[15], (Fnv64_t) 0x000063000000a839ULL }, + { &fnv_test_str[16], (Fnv64_t) 0x000064000000a9ecULL }, + { &fnv_test_str[17], (Fnv64_t) 0x000065000000ab9fULL }, + { &fnv_test_str[18], (Fnv64_t) 0x000066000000ad52ULL }, + { &fnv_test_str[19], (Fnv64_t) 0x015a8f0001265ea7ULL }, + { &fnv_test_str[20], (Fnv64_t) 0x733fc501f4330dd8ULL }, + { &fnv_test_str[21], (Fnv64_t) 0x08697c51f2c0530eULL }, + { &fnv_test_str[22], (Fnv64_t) 0x0b91ae3f7ccdc59dULL }, + { &fnv_test_str[23], (Fnv64_t) 0x765104e111a7551dULL }, + { &fnv_test_str[24], (Fnv64_t) 0x000063000000a851ULL }, + { &fnv_test_str[25], (Fnv64_t) 0x01508a00011e01ccULL }, + { &fnv_test_str[26], (Fnv64_t) 0x59dc4a01e5fd0dcaULL }, + { &fnv_test_str[27], (Fnv64_t) 0xae5f8b39ccfe6e59ULL }, + { &fnv_test_str[28], (Fnv64_t) 0x4ac7ec3754558154ULL }, + { &fnv_test_str[29], (Fnv64_t) 0x6737b6044d4ac19cULL }, + { &fnv_test_str[30], (Fnv64_t) 0xae6be54f5606fc63ULL }, + { &fnv_test_str[31], (Fnv64_t) 0x685308cf2ddedc58ULL }, + { &fnv_test_str[32], (Fnv64_t) 0x23f4500af1b069fbULL }, + { &fnv_test_str[33], (Fnv64_t) 0xc88dfd98aec415a1ULL }, + { &fnv_test_str[34], (Fnv64_t) 0x8d5b8b70f730c0fbULL }, + { &fnv_test_str[35], (Fnv64_t) 0x634eebf407d7eae4ULL }, + { &fnv_test_str[36], (Fnv64_t) 0x9705d3a953e4211eULL }, + { &fnv_test_str[37], (Fnv64_t) 0x8307c6b98ca4459fULL }, + { &fnv_test_str[38], (Fnv64_t) 0x4a7c4c49fb224d0cULL }, + { &fnv_test_str[39], (Fnv64_t) 0xb382adb5bb48eb6eULL }, + { &fnv_test_str[40], (Fnv64_t) 0x01508a00011e01a3ULL }, + { &fnv_test_str[41], (Fnv64_t) 0x59dc4a01e5fd0da4ULL }, + { &fnv_test_str[42], (Fnv64_t) 0xae5f8b39ccfe6e3eULL }, + { &fnv_test_str[43], (Fnv64_t) 0x4ac7ec375455813bULL }, + { &fnv_test_str[44], (Fnv64_t) 0x6737b6044d4ac1bcULL }, + { &fnv_test_str[45], (Fnv64_t) 0xae6be54f5606fc14ULL }, + { &fnv_test_str[46], (Fnv64_t) 0x685308cf2ddedc39ULL }, + { &fnv_test_str[47], (Fnv64_t) 0x23f4500af1b06988ULL }, + { &fnv_test_str[48], (Fnv64_t) 0xc88dfd98aec41581ULL }, + { &fnv_test_str[49], (Fnv64_t) 0x8d5b8b70f730c093ULL }, + { &fnv_test_str[50], (Fnv64_t) 0x634eebf407d7ea81ULL }, + { &fnv_test_str[51], (Fnv64_t) 0x9705d3a953e4216cULL }, + { &fnv_test_str[52], (Fnv64_t) 0x8307c6b98ca445faULL }, + { &fnv_test_str[53], (Fnv64_t) 0x4a7c4c49fb224d2dULL }, + { &fnv_test_str[54], (Fnv64_t) 0xb382adb5bb48eb64ULL }, + { &fnv_test_str[55], (Fnv64_t) 0x4ff899cd3ce80beaULL }, + { &fnv_test_str[56], (Fnv64_t) 0x000063000000a84cULL }, + { &fnv_test_str[57], (Fnv64_t) 0x01508500011df956ULL }, + { &fnv_test_str[58], (Fnv64_t) 0x59cb5501e5eead46ULL }, + { &fnv_test_str[59], (Fnv64_t) 0x832eb839b4906d81ULL }, + { &fnv_test_str[60], (Fnv64_t) 0x78d08b0dd16a1213ULL }, + { &fnv_test_str[61], (Fnv64_t) 0xb46e5b7ad73cb628ULL }, + { &fnv_test_str[62], (Fnv64_t) 0xd43b99bbbc298596ULL }, + { &fnv_test_str[63], (Fnv64_t) 0xcacbd000ba8dfd86ULL }, + { &fnv_test_str[64], (Fnv64_t) 0x264ff73cff45ca92ULL }, + { &fnv_test_str[65], (Fnv64_t) 0x5fabaea5c3973661ULL }, + { &fnv_test_str[66], (Fnv64_t) 0x27f024ab59f166bbULL }, + { &fnv_test_str[67], (Fnv64_t) 0xce750a29d5318fa4ULL }, + { &fnv_test_str[68], (Fnv64_t) 0x026fe915433713d5ULL }, + { &fnv_test_str[69], (Fnv64_t) 0x5b3ce4213696b2e5ULL }, + { &fnv_test_str[70], (Fnv64_t) 0x01508500011df924ULL }, + { &fnv_test_str[71], (Fnv64_t) 0x59cb5501e5eead22ULL }, + { &fnv_test_str[72], (Fnv64_t) 0x832eb839b4906df2ULL }, + { &fnv_test_str[73], (Fnv64_t) 0x78d08b0dd16a1233ULL }, + { &fnv_test_str[74], (Fnv64_t) 0xb46e5b7ad73cb649ULL }, + { &fnv_test_str[75], (Fnv64_t) 0xd43b99bbbc2985f8ULL }, + { &fnv_test_str[76], (Fnv64_t) 0xcacbd000ba8dfde2ULL }, + { &fnv_test_str[77], (Fnv64_t) 0x264ff73cff45cab2ULL }, + { &fnv_test_str[78], (Fnv64_t) 0x5fabaea5c3973616ULL }, + { &fnv_test_str[79], (Fnv64_t) 0x27f024ab59f166d3ULL }, + { &fnv_test_str[80], (Fnv64_t) 0xce750a29d5318fc1ULL }, + { &fnv_test_str[81], (Fnv64_t) 0x026fe915433713acULL }, + { &fnv_test_str[82], (Fnv64_t) 0x5b3ce4213696b2efULL }, + { &fnv_test_str[83], (Fnv64_t) 0x9f2a896fc211fb1fULL }, + { &fnv_test_str[84], (Fnv64_t) 0x000068000000b0d1ULL }, + { &fnv_test_str[85], (Fnv64_t) 0x01618900012c7323ULL }, + { &fnv_test_str[86], (Fnv64_t) 0x3fa86e63bc7d03c8ULL }, + { &fnv_test_str[87], (Fnv64_t) 0xa8375b79486d6cd8ULL }, + { &fnv_test_str[88], (Fnv64_t) 0xa0d18504e316ac54ULL }, + { &fnv_test_str[89], (Fnv64_t) 0x08a97b0004e7fe54ULL }, + { &fnv_test_str[90], (Fnv64_t) 0xa0d18504e316ac57ULL }, + { &fnv_test_str[91], (Fnv64_t) 0x1152f60009cffda9ULL }, + { &fnv_test_str[92], (Fnv64_t) 0xa0d18504e316ac56ULL }, + { &fnv_test_str[93], (Fnv64_t) 0x19fc71000eb7fcfeULL }, + { &fnv_test_str[94], (Fnv64_t) 0xa0d18504e316ac51ULL }, + { &fnv_test_str[95], (Fnv64_t) 0x22a5ec00139ffa53ULL }, + { &fnv_test_str[96], (Fnv64_t) 0x29bed00139779a33ULL }, + { &fnv_test_str[97], (Fnv64_t) 0x4dbc81014e3c19f5ULL }, + { &fnv_test_str[98], (Fnv64_t) 0x29bed00139779a3dULL }, + { &fnv_test_str[99], (Fnv64_t) 0x81a72b016b9f7573ULL }, + { &fnv_test_str[100], (Fnv64_t) 0x29bed00139779a23ULL }, + { &fnv_test_str[101], (Fnv64_t) 0xd85411019cbbce45ULL }, + { &fnv_test_str[102], (Fnv64_t) 0xf548616b8621d657ULL }, + { &fnv_test_str[103], (Fnv64_t) 0xebd3e0b4eb7f35d5ULL }, + { &fnv_test_str[104], (Fnv64_t) 0xf548616b8621d654ULL }, + { &fnv_test_str[105], (Fnv64_t) 0xebd3ddb4eb7f30bcULL }, + { &fnv_test_str[106], (Fnv64_t) 0xf548616b8621d655ULL }, + { &fnv_test_str[107], (Fnv64_t) 0xebd3deb4eb7f326fULL }, + { &fnv_test_str[108], (Fnv64_t) 0x581cb60340ab0968ULL }, + { &fnv_test_str[109], (Fnv64_t) 0x63d2af86e2a0fbb8ULL }, + { &fnv_test_str[110], (Fnv64_t) 0x581cb70340ab0b37ULL }, + { &fnv_test_str[111], (Fnv64_t) 0x63d63186e2a40e75ULL }, + { &fnv_test_str[112], (Fnv64_t) 0x581cc40340ab212eULL }, + { &fnv_test_str[113], (Fnv64_t) 0x64023f86e2c9612aULL }, + { &fnv_test_str[114], (Fnv64_t) 0xdbda6a26c33c909fULL }, + { &fnv_test_str[115], (Fnv64_t) 0xd0b2feddbfe9be2dULL }, + { &fnv_test_str[116], (Fnv64_t) 0x9c9eae3f5d037decULL }, + { &fnv_test_str[117], (Fnv64_t) 0x252001ab0ceef804ULL }, + { &fnv_test_str[118], (Fnv64_t) 0x4456a56f9e05cfefULL }, + { &fnv_test_str[119], (Fnv64_t) 0x250b0ba983e0531dULL }, + { &fnv_test_str[120], (Fnv64_t) 0x52b007213b27b33eULL }, + { &fnv_test_str[121], (Fnv64_t) 0xcbf29ce484222325ULL }, + { &fnv_test_str[122], (Fnv64_t) 0xaf63bd4c8601b7dfULL }, + { &fnv_test_str[123], (Fnv64_t) 0x128599ccddae09f8ULL }, + { &fnv_test_str[124], (Fnv64_t) 0x270e4f1caebaf068ULL }, + { &fnv_test_str[125], (Fnv64_t) 0x01517d497446a395ULL }, + { &fnv_test_str[126], (Fnv64_t) 0x9af5a29a89450b40ULL }, + { &fnv_test_str[127], (Fnv64_t) 0xb502f6c063ba72e8ULL }, + { &fnv_test_str[128], (Fnv64_t) 0xacf41561498ca7dfULL }, + { &fnv_test_str[129], (Fnv64_t) 0x6be8c2423a351542ULL }, + { &fnv_test_str[130], (Fnv64_t) 0xd04f1f6da96ce4a3ULL }, + { &fnv_test_str[131], (Fnv64_t) 0x69eb9a8f282c7235ULL }, + { &fnv_test_str[132], (Fnv64_t) 0x6a7e5a418f77cfc5ULL }, + { &fnv_test_str[133], (Fnv64_t) 0xbcaf568ddc2ecba0ULL }, + { &fnv_test_str[134], (Fnv64_t) 0xb03b5cc4c38f8b1fULL }, + { &fnv_test_str[135], (Fnv64_t) 0xf89a9f51432db828ULL }, + { &fnv_test_str[136], (Fnv64_t) 0x549e856be6103429ULL }, + { &fnv_test_str[137], (Fnv64_t) 0x3cf50d224d29377aULL }, + { &fnv_test_str[138], (Fnv64_t) 0xdb762df418c10c37ULL }, + { &fnv_test_str[139], (Fnv64_t) 0xfeeb4226b0e9a6baULL }, + { &fnv_test_str[140], (Fnv64_t) 0x7004a4cd9310c052ULL }, + { &fnv_test_str[141], (Fnv64_t) 0xd1c727d7f5329276ULL }, + { &fnv_test_str[142], (Fnv64_t) 0xbe313796596ce908ULL }, + { &fnv_test_str[143], (Fnv64_t) 0x768f67ede090fcc5ULL }, + { &fnv_test_str[144], (Fnv64_t) 0xa81563cc9db9bfc3ULL }, + { &fnv_test_str[145], (Fnv64_t) 0x47194043c55197a8ULL }, + { &fnv_test_str[146], (Fnv64_t) 0xc99d81864aebab02ULL }, + { &fnv_test_str[147], (Fnv64_t) 0xcc1f161b235ea4a2ULL }, + { &fnv_test_str[148], (Fnv64_t) 0xaadab0c420ecd434ULL }, + { &fnv_test_str[149], (Fnv64_t) 0x6b3c034d6f44d740ULL }, + { &fnv_test_str[150], (Fnv64_t) 0x73a45e850602cbc6ULL }, + { &fnv_test_str[151], (Fnv64_t) 0x72360f04f0cd227bULL }, + { &fnv_test_str[152], (Fnv64_t) 0xa9ca80be384a778fULL }, + { &fnv_test_str[153], (Fnv64_t) 0xd4085e66906889e3ULL }, + { &fnv_test_str[154], (Fnv64_t) 0x93aa8b2748efdbc8ULL }, + { &fnv_test_str[155], (Fnv64_t) 0x6f8cd678407436a2ULL }, + { &fnv_test_str[156], (Fnv64_t) 0xf39a43d4dc8be4c7ULL }, + { &fnv_test_str[157], (Fnv64_t) 0xd7f5cec91125d245ULL }, + { &fnv_test_str[158], (Fnv64_t) 0x691d7b73be18adc4ULL }, + { &fnv_test_str[159], (Fnv64_t) 0xf4361e01caf6b691ULL }, + { &fnv_test_str[160], (Fnv64_t) 0xde7d8264f64be089ULL }, + { &fnv_test_str[161], (Fnv64_t) 0xa34ff43e5545c06fULL }, + { &fnv_test_str[162], (Fnv64_t) 0x181f0b8e908a2bdeULL }, + { &fnv_test_str[163], (Fnv64_t) 0x28a965b78ddbc071ULL }, + { &fnv_test_str[164], (Fnv64_t) 0xead9cea0e3cc6ae5ULL }, + { &fnv_test_str[165], (Fnv64_t) 0x0b6743153b43ebbaULL }, + { &fnv_test_str[166], (Fnv64_t) 0xa7aa3f012c74528dULL }, + { &fnv_test_str[167], (Fnv64_t) 0x2d5d8ad7f9dffeb7ULL }, + { &fnv_test_str[168], (Fnv64_t) 0x00750fb6e19624eaULL }, + { &fnv_test_str[169], (Fnv64_t) 0x01c125a4e6c76c82ULL }, + { &fnv_test_str[170], (Fnv64_t) 0x3fde3afac0722f1fULL }, + { &fnv_test_str[171], (Fnv64_t) 0xd7c3eaf4abaa379dULL }, + { &fnv_test_str[172], (Fnv64_t) 0xd2217e1c923c9f3fULL }, + { &fnv_test_str[173], (Fnv64_t) 0x82d0a2e3b725caf6ULL }, + { &fnv_test_str[174], (Fnv64_t) 0x0a10bee8eeb72e4fULL }, + { &fnv_test_str[175], (Fnv64_t) 0xc530e8723e72c6fdULL }, + { &fnv_test_str[176], (Fnv64_t) 0xd8d34dcd2e7bad99ULL }, + { &fnv_test_str[177], (Fnv64_t) 0xecf77466e9a2baf3ULL }, + { &fnv_test_str[178], (Fnv64_t) 0xde3d2ddb043b9666ULL }, + { &fnv_test_str[179], (Fnv64_t) 0xd1cc824e1a8157d8ULL }, + { &fnv_test_str[180], (Fnv64_t) 0x7d5c68ecbc90512eULL }, + { &fnv_test_str[181], (Fnv64_t) 0x2f7c691b1d7c76d8ULL }, + { &fnv_test_str[182], (Fnv64_t) 0x5d88c2bad3a46bc8ULL }, + { &fnv_test_str[183], (Fnv64_t) 0xdf107320276647a0ULL }, + { &fnv_test_str[184], (Fnv64_t) 0x0f78f22e7e70e9bcULL }, + { &fnv_test_str[185], (Fnv64_t) 0x8c67be5c80f67d04ULL }, + { &fnv_test_str[186], (Fnv64_t) 0x07c1adfa4d019194ULL }, + { &fnv_test_str[187], (Fnv64_t) 0xce1312420c5b1af4ULL }, + { &fnv_test_str[188], (Fnv64_t) 0x043a41b2dc53ab24ULL }, + { &fnv_test_str[189], (Fnv64_t) 0x0b038eebf7340860ULL }, + { &fnv_test_str[190], (Fnv64_t) 0x1bcd837353fb69b0ULL }, + { &fnv_test_str[191], (Fnv64_t) 0x46f992fc59eff180ULL }, + { &fnv_test_str[192], (Fnv64_t) 0x497678ee29ae79c0ULL }, + { &fnv_test_str[193], (Fnv64_t) 0xb10a62280ddd4450ULL }, + { &fnv_test_str[194], (Fnv64_t) 0x35eb228db4d68140ULL }, + { &fnv_test_str[195], (Fnv64_t) 0x8b350e86d9470870ULL }, + { &fnv_test_str[196], (Fnv64_t) 0x4e1fbdb2812e9540ULL }, + { &fnv_test_str[197], (Fnv64_t) 0x051e080df69a0600ULL }, + { &fnv_test_str[198], (Fnv64_t) 0x45e1e8ae54dadb40ULL }, + { &fnv_test_str[199], (Fnv64_t) 0x0000000000000000ULL }, + { &fnv_test_str[200], (Fnv64_t) 0xcd73806290557064ULL }, + { &fnv_test_str[201], (Fnv64_t) 0x2613a37bbe0317c8ULL }, + { &fnv_test_str[202], (Fnv64_t) 0x1480e21fcf2ae5e4ULL }, + { NULL, (Fnv64_t) 0 } +}; +#else /* HAVE_64BIT_LONG_LONG */ +struct fnv0_64_test_vector fnv0_64_vector[] = { + { &fnv_test_str[0], (Fnv64_t) {0x00000000UL, 0x00000000UL} }, + { &fnv_test_str[1], (Fnv64_t) {0x00000061UL, 0x00000000UL} }, + { &fnv_test_str[2], (Fnv64_t) {0x00000062UL, 0x00000000UL} }, + { &fnv_test_str[3], (Fnv64_t) {0x00000063UL, 0x00000000UL} }, + { &fnv_test_str[4], (Fnv64_t) {0x00000064UL, 0x00000000UL} }, + { &fnv_test_str[5], (Fnv64_t) {0x00000065UL, 0x00000000UL} }, + { &fnv_test_str[6], (Fnv64_t) {0x00000066UL, 0x00000000UL} }, + { &fnv_test_str[7], (Fnv64_t) {0x0000ad3dUL, 0x00006600UL} }, + { &fnv_test_str[8], (Fnv64_t) {0x01265ec8UL, 0x015a8f00UL} }, + { &fnv_test_str[9], (Fnv64_t) {0xf4330dbaUL, 0x733fc501UL} }, + { &fnv_test_str[10], (Fnv64_t) {0xf2c0536fUL, 0x08697c51UL} }, + { &fnv_test_str[11], (Fnv64_t) {0x7ccdc5efUL, 0x0b91ae3fUL} }, + { &fnv_test_str[12], (Fnv64_t) {0x00000000UL, 0x00000000UL} }, + { &fnv_test_str[13], (Fnv64_t) {0x0000a4d3UL, 0x00006100UL} }, + { &fnv_test_str[14], (Fnv64_t) {0x0000a686UL, 0x00006200UL} }, + { &fnv_test_str[15], (Fnv64_t) {0x0000a839UL, 0x00006300UL} }, + { &fnv_test_str[16], (Fnv64_t) {0x0000a9ecUL, 0x00006400UL} }, + { &fnv_test_str[17], (Fnv64_t) {0x0000ab9fUL, 0x00006500UL} }, + { &fnv_test_str[18], (Fnv64_t) {0x0000ad52UL, 0x00006600UL} }, + { &fnv_test_str[19], (Fnv64_t) {0x01265ea7UL, 0x015a8f00UL} }, + { &fnv_test_str[20], (Fnv64_t) {0xf4330dd8UL, 0x733fc501UL} }, + { &fnv_test_str[21], (Fnv64_t) {0xf2c0530eUL, 0x08697c51UL} }, + { &fnv_test_str[22], (Fnv64_t) {0x7ccdc59dUL, 0x0b91ae3fUL} }, + { &fnv_test_str[23], (Fnv64_t) {0x11a7551dUL, 0x765104e1UL} }, + { &fnv_test_str[24], (Fnv64_t) {0x0000a851UL, 0x00006300UL} }, + { &fnv_test_str[25], (Fnv64_t) {0x011e01ccUL, 0x01508a00UL} }, + { &fnv_test_str[26], (Fnv64_t) {0xe5fd0dcaUL, 0x59dc4a01UL} }, + { &fnv_test_str[27], (Fnv64_t) {0xccfe6e59UL, 0xae5f8b39UL} }, + { &fnv_test_str[28], (Fnv64_t) {0x54558154UL, 0x4ac7ec37UL} }, + { &fnv_test_str[29], (Fnv64_t) {0x4d4ac19cUL, 0x6737b604UL} }, + { &fnv_test_str[30], (Fnv64_t) {0x5606fc63UL, 0xae6be54fUL} }, + { &fnv_test_str[31], (Fnv64_t) {0x2ddedc58UL, 0x685308cfUL} }, + { &fnv_test_str[32], (Fnv64_t) {0xf1b069fbUL, 0x23f4500aUL} }, + { &fnv_test_str[33], (Fnv64_t) {0xaec415a1UL, 0xc88dfd98UL} }, + { &fnv_test_str[34], (Fnv64_t) {0xf730c0fbUL, 0x8d5b8b70UL} }, + { &fnv_test_str[35], (Fnv64_t) {0x07d7eae4UL, 0x634eebf4UL} }, + { &fnv_test_str[36], (Fnv64_t) {0x53e4211eUL, 0x9705d3a9UL} }, + { &fnv_test_str[37], (Fnv64_t) {0x8ca4459fUL, 0x8307c6b9UL} }, + { &fnv_test_str[38], (Fnv64_t) {0xfb224d0cUL, 0x4a7c4c49UL} }, + { &fnv_test_str[39], (Fnv64_t) {0xbb48eb6eUL, 0xb382adb5UL} }, + { &fnv_test_str[40], (Fnv64_t) {0x011e01a3UL, 0x01508a00UL} }, + { &fnv_test_str[41], (Fnv64_t) {0xe5fd0da4UL, 0x59dc4a01UL} }, + { &fnv_test_str[42], (Fnv64_t) {0xccfe6e3eUL, 0xae5f8b39UL} }, + { &fnv_test_str[43], (Fnv64_t) {0x5455813bUL, 0x4ac7ec37UL} }, + { &fnv_test_str[44], (Fnv64_t) {0x4d4ac1bcUL, 0x6737b604UL} }, + { &fnv_test_str[45], (Fnv64_t) {0x5606fc14UL, 0xae6be54fUL} }, + { &fnv_test_str[46], (Fnv64_t) {0x2ddedc39UL, 0x685308cfUL} }, + { &fnv_test_str[47], (Fnv64_t) {0xf1b06988UL, 0x23f4500aUL} }, + { &fnv_test_str[48], (Fnv64_t) {0xaec41581UL, 0xc88dfd98UL} }, + { &fnv_test_str[49], (Fnv64_t) {0xf730c093UL, 0x8d5b8b70UL} }, + { &fnv_test_str[50], (Fnv64_t) {0x07d7ea81UL, 0x634eebf4UL} }, + { &fnv_test_str[51], (Fnv64_t) {0x53e4216cUL, 0x9705d3a9UL} }, + { &fnv_test_str[52], (Fnv64_t) {0x8ca445faUL, 0x8307c6b9UL} }, + { &fnv_test_str[53], (Fnv64_t) {0xfb224d2dUL, 0x4a7c4c49UL} }, + { &fnv_test_str[54], (Fnv64_t) {0xbb48eb64UL, 0xb382adb5UL} }, + { &fnv_test_str[55], (Fnv64_t) {0x3ce80beaUL, 0x4ff899cdUL} }, + { &fnv_test_str[56], (Fnv64_t) {0x0000a84cUL, 0x00006300UL} }, + { &fnv_test_str[57], (Fnv64_t) {0x011df956UL, 0x01508500UL} }, + { &fnv_test_str[58], (Fnv64_t) {0xe5eead46UL, 0x59cb5501UL} }, + { &fnv_test_str[59], (Fnv64_t) {0xb4906d81UL, 0x832eb839UL} }, + { &fnv_test_str[60], (Fnv64_t) {0xd16a1213UL, 0x78d08b0dUL} }, + { &fnv_test_str[61], (Fnv64_t) {0xd73cb628UL, 0xb46e5b7aUL} }, + { &fnv_test_str[62], (Fnv64_t) {0xbc298596UL, 0xd43b99bbUL} }, + { &fnv_test_str[63], (Fnv64_t) {0xba8dfd86UL, 0xcacbd000UL} }, + { &fnv_test_str[64], (Fnv64_t) {0xff45ca92UL, 0x264ff73cUL} }, + { &fnv_test_str[65], (Fnv64_t) {0xc3973661UL, 0x5fabaea5UL} }, + { &fnv_test_str[66], (Fnv64_t) {0x59f166bbUL, 0x27f024abUL} }, + { &fnv_test_str[67], (Fnv64_t) {0xd5318fa4UL, 0xce750a29UL} }, + { &fnv_test_str[68], (Fnv64_t) {0x433713d5UL, 0x026fe915UL} }, + { &fnv_test_str[69], (Fnv64_t) {0x3696b2e5UL, 0x5b3ce421UL} }, + { &fnv_test_str[70], (Fnv64_t) {0x011df924UL, 0x01508500UL} }, + { &fnv_test_str[71], (Fnv64_t) {0xe5eead22UL, 0x59cb5501UL} }, + { &fnv_test_str[72], (Fnv64_t) {0xb4906df2UL, 0x832eb839UL} }, + { &fnv_test_str[73], (Fnv64_t) {0xd16a1233UL, 0x78d08b0dUL} }, + { &fnv_test_str[74], (Fnv64_t) {0xd73cb649UL, 0xb46e5b7aUL} }, + { &fnv_test_str[75], (Fnv64_t) {0xbc2985f8UL, 0xd43b99bbUL} }, + { &fnv_test_str[76], (Fnv64_t) {0xba8dfde2UL, 0xcacbd000UL} }, + { &fnv_test_str[77], (Fnv64_t) {0xff45cab2UL, 0x264ff73cUL} }, + { &fnv_test_str[78], (Fnv64_t) {0xc3973616UL, 0x5fabaea5UL} }, + { &fnv_test_str[79], (Fnv64_t) {0x59f166d3UL, 0x27f024abUL} }, + { &fnv_test_str[80], (Fnv64_t) {0xd5318fc1UL, 0xce750a29UL} }, + { &fnv_test_str[81], (Fnv64_t) {0x433713acUL, 0x026fe915UL} }, + { &fnv_test_str[82], (Fnv64_t) {0x3696b2efUL, 0x5b3ce421UL} }, + { &fnv_test_str[83], (Fnv64_t) {0xc211fb1fUL, 0x9f2a896fUL} }, + { &fnv_test_str[84], (Fnv64_t) {0x0000b0d1UL, 0x00006800UL} }, + { &fnv_test_str[85], (Fnv64_t) {0x012c7323UL, 0x01618900UL} }, + { &fnv_test_str[86], (Fnv64_t) {0xbc7d03c8UL, 0x3fa86e63UL} }, + { &fnv_test_str[87], (Fnv64_t) {0x486d6cd8UL, 0xa8375b79UL} }, + { &fnv_test_str[88], (Fnv64_t) {0xe316ac54UL, 0xa0d18504UL} }, + { &fnv_test_str[89], (Fnv64_t) {0x04e7fe54UL, 0x08a97b00UL} }, + { &fnv_test_str[90], (Fnv64_t) {0xe316ac57UL, 0xa0d18504UL} }, + { &fnv_test_str[91], (Fnv64_t) {0x09cffda9UL, 0x1152f600UL} }, + { &fnv_test_str[92], (Fnv64_t) {0xe316ac56UL, 0xa0d18504UL} }, + { &fnv_test_str[93], (Fnv64_t) {0x0eb7fcfeUL, 0x19fc7100UL} }, + { &fnv_test_str[94], (Fnv64_t) {0xe316ac51UL, 0xa0d18504UL} }, + { &fnv_test_str[95], (Fnv64_t) {0x139ffa53UL, 0x22a5ec00UL} }, + { &fnv_test_str[96], (Fnv64_t) {0x39779a33UL, 0x29bed001UL} }, + { &fnv_test_str[97], (Fnv64_t) {0x4e3c19f5UL, 0x4dbc8101UL} }, + { &fnv_test_str[98], (Fnv64_t) {0x39779a3dUL, 0x29bed001UL} }, + { &fnv_test_str[99], (Fnv64_t) {0x6b9f7573UL, 0x81a72b01UL} }, + { &fnv_test_str[100], (Fnv64_t) {0x39779a23UL, 0x29bed001UL} }, + { &fnv_test_str[101], (Fnv64_t) {0x9cbbce45UL, 0xd8541101UL} }, + { &fnv_test_str[102], (Fnv64_t) {0x8621d657UL, 0xf548616bUL} }, + { &fnv_test_str[103], (Fnv64_t) {0xeb7f35d5UL, 0xebd3e0b4UL} }, + { &fnv_test_str[104], (Fnv64_t) {0x8621d654UL, 0xf548616bUL} }, + { &fnv_test_str[105], (Fnv64_t) {0xeb7f30bcUL, 0xebd3ddb4UL} }, + { &fnv_test_str[106], (Fnv64_t) {0x8621d655UL, 0xf548616bUL} }, + { &fnv_test_str[107], (Fnv64_t) {0xeb7f326fUL, 0xebd3deb4UL} }, + { &fnv_test_str[108], (Fnv64_t) {0x40ab0968UL, 0x581cb603UL} }, + { &fnv_test_str[109], (Fnv64_t) {0xe2a0fbb8UL, 0x63d2af86UL} }, + { &fnv_test_str[110], (Fnv64_t) {0x40ab0b37UL, 0x581cb703UL} }, + { &fnv_test_str[111], (Fnv64_t) {0xe2a40e75UL, 0x63d63186UL} }, + { &fnv_test_str[112], (Fnv64_t) {0x40ab212eUL, 0x581cc403UL} }, + { &fnv_test_str[113], (Fnv64_t) {0xe2c9612aUL, 0x64023f86UL} }, + { &fnv_test_str[114], (Fnv64_t) {0xc33c909fUL, 0xdbda6a26UL} }, + { &fnv_test_str[115], (Fnv64_t) {0xbfe9be2dUL, 0xd0b2feddUL} }, + { &fnv_test_str[116], (Fnv64_t) {0x5d037decUL, 0x9c9eae3fUL} }, + { &fnv_test_str[117], (Fnv64_t) {0x0ceef804UL, 0x252001abUL} }, + { &fnv_test_str[118], (Fnv64_t) {0x9e05cfefUL, 0x4456a56fUL} }, + { &fnv_test_str[119], (Fnv64_t) {0x83e0531dUL, 0x250b0ba9UL} }, + { &fnv_test_str[120], (Fnv64_t) {0x3b27b33eUL, 0x52b00721UL} }, + { &fnv_test_str[121], (Fnv64_t) {0x84222325UL, 0xcbf29ce4UL} }, + { &fnv_test_str[122], (Fnv64_t) {0x8601b7dfUL, 0xaf63bd4cUL} }, + { &fnv_test_str[123], (Fnv64_t) {0xddae09f8UL, 0x128599ccUL} }, + { &fnv_test_str[124], (Fnv64_t) {0xaebaf068UL, 0x270e4f1cUL} }, + { &fnv_test_str[125], (Fnv64_t) {0x7446a395UL, 0x01517d49UL} }, + { &fnv_test_str[126], (Fnv64_t) {0x89450b40UL, 0x9af5a29aUL} }, + { &fnv_test_str[127], (Fnv64_t) {0x63ba72e8UL, 0xb502f6c0UL} }, + { &fnv_test_str[128], (Fnv64_t) {0x498ca7dfUL, 0xacf41561UL} }, + { &fnv_test_str[129], (Fnv64_t) {0x3a351542UL, 0x6be8c242UL} }, + { &fnv_test_str[130], (Fnv64_t) {0xa96ce4a3UL, 0xd04f1f6dUL} }, + { &fnv_test_str[131], (Fnv64_t) {0x282c7235UL, 0x69eb9a8fUL} }, + { &fnv_test_str[132], (Fnv64_t) {0x8f77cfc5UL, 0x6a7e5a41UL} }, + { &fnv_test_str[133], (Fnv64_t) {0xdc2ecba0UL, 0xbcaf568dUL} }, + { &fnv_test_str[134], (Fnv64_t) {0xc38f8b1fUL, 0xb03b5cc4UL} }, + { &fnv_test_str[135], (Fnv64_t) {0x432db828UL, 0xf89a9f51UL} }, + { &fnv_test_str[136], (Fnv64_t) {0xe6103429UL, 0x549e856bUL} }, + { &fnv_test_str[137], (Fnv64_t) {0x4d29377aUL, 0x3cf50d22UL} }, + { &fnv_test_str[138], (Fnv64_t) {0x18c10c37UL, 0xdb762df4UL} }, + { &fnv_test_str[139], (Fnv64_t) {0xb0e9a6baUL, 0xfeeb4226UL} }, + { &fnv_test_str[140], (Fnv64_t) {0x9310c052UL, 0x7004a4cdUL} }, + { &fnv_test_str[141], (Fnv64_t) {0xf5329276UL, 0xd1c727d7UL} }, + { &fnv_test_str[142], (Fnv64_t) {0x596ce908UL, 0xbe313796UL} }, + { &fnv_test_str[143], (Fnv64_t) {0xe090fcc5UL, 0x768f67edUL} }, + { &fnv_test_str[144], (Fnv64_t) {0x9db9bfc3UL, 0xa81563ccUL} }, + { &fnv_test_str[145], (Fnv64_t) {0xc55197a8UL, 0x47194043UL} }, + { &fnv_test_str[146], (Fnv64_t) {0x4aebab02UL, 0xc99d8186UL} }, + { &fnv_test_str[147], (Fnv64_t) {0x235ea4a2UL, 0xcc1f161bUL} }, + { &fnv_test_str[148], (Fnv64_t) {0x20ecd434UL, 0xaadab0c4UL} }, + { &fnv_test_str[149], (Fnv64_t) {0x6f44d740UL, 0x6b3c034dUL} }, + { &fnv_test_str[150], (Fnv64_t) {0x0602cbc6UL, 0x73a45e85UL} }, + { &fnv_test_str[151], (Fnv64_t) {0xf0cd227bUL, 0x72360f04UL} }, + { &fnv_test_str[152], (Fnv64_t) {0x384a778fUL, 0xa9ca80beUL} }, + { &fnv_test_str[153], (Fnv64_t) {0x906889e3UL, 0xd4085e66UL} }, + { &fnv_test_str[154], (Fnv64_t) {0x48efdbc8UL, 0x93aa8b27UL} }, + { &fnv_test_str[155], (Fnv64_t) {0x407436a2UL, 0x6f8cd678UL} }, + { &fnv_test_str[156], (Fnv64_t) {0xdc8be4c7UL, 0xf39a43d4UL} }, + { &fnv_test_str[157], (Fnv64_t) {0x1125d245UL, 0xd7f5cec9UL} }, + { &fnv_test_str[158], (Fnv64_t) {0xbe18adc4UL, 0x691d7b73UL} }, + { &fnv_test_str[159], (Fnv64_t) {0xcaf6b691UL, 0xf4361e01UL} }, + { &fnv_test_str[160], (Fnv64_t) {0xf64be089UL, 0xde7d8264UL} }, + { &fnv_test_str[161], (Fnv64_t) {0x5545c06fUL, 0xa34ff43eUL} }, + { &fnv_test_str[162], (Fnv64_t) {0x908a2bdeUL, 0x181f0b8eUL} }, + { &fnv_test_str[163], (Fnv64_t) {0x8ddbc071UL, 0x28a965b7UL} }, + { &fnv_test_str[164], (Fnv64_t) {0xe3cc6ae5UL, 0xead9cea0UL} }, + { &fnv_test_str[165], (Fnv64_t) {0x3b43ebbaUL, 0x0b674315UL} }, + { &fnv_test_str[166], (Fnv64_t) {0x2c74528dUL, 0xa7aa3f01UL} }, + { &fnv_test_str[167], (Fnv64_t) {0xf9dffeb7UL, 0x2d5d8ad7UL} }, + { &fnv_test_str[168], (Fnv64_t) {0xe19624eaUL, 0x00750fb6UL} }, + { &fnv_test_str[169], (Fnv64_t) {0xe6c76c82UL, 0x01c125a4UL} }, + { &fnv_test_str[170], (Fnv64_t) {0xc0722f1fUL, 0x3fde3afaUL} }, + { &fnv_test_str[171], (Fnv64_t) {0xabaa379dUL, 0xd7c3eaf4UL} }, + { &fnv_test_str[172], (Fnv64_t) {0x923c9f3fUL, 0xd2217e1cUL} }, + { &fnv_test_str[173], (Fnv64_t) {0xb725caf6UL, 0x82d0a2e3UL} }, + { &fnv_test_str[174], (Fnv64_t) {0xeeb72e4fUL, 0x0a10bee8UL} }, + { &fnv_test_str[175], (Fnv64_t) {0x3e72c6fdUL, 0xc530e872UL} }, + { &fnv_test_str[176], (Fnv64_t) {0x2e7bad99UL, 0xd8d34dcdUL} }, + { &fnv_test_str[177], (Fnv64_t) {0xe9a2baf3UL, 0xecf77466UL} }, + { &fnv_test_str[178], (Fnv64_t) {0x043b9666UL, 0xde3d2ddbUL} }, + { &fnv_test_str[179], (Fnv64_t) {0x1a8157d8UL, 0xd1cc824eUL} }, + { &fnv_test_str[180], (Fnv64_t) {0xbc90512eUL, 0x7d5c68ecUL} }, + { &fnv_test_str[181], (Fnv64_t) {0x1d7c76d8UL, 0x2f7c691bUL} }, + { &fnv_test_str[182], (Fnv64_t) {0xd3a46bc8UL, 0x5d88c2baUL} }, + { &fnv_test_str[183], (Fnv64_t) {0x276647a0UL, 0xdf107320UL} }, + { &fnv_test_str[184], (Fnv64_t) {0x7e70e9bcUL, 0x0f78f22eUL} }, + { &fnv_test_str[185], (Fnv64_t) {0x80f67d04UL, 0x8c67be5cUL} }, + { &fnv_test_str[186], (Fnv64_t) {0x4d019194UL, 0x07c1adfaUL} }, + { &fnv_test_str[187], (Fnv64_t) {0x0c5b1af4UL, 0xce131242UL} }, + { &fnv_test_str[188], (Fnv64_t) {0xdc53ab24UL, 0x043a41b2UL} }, + { &fnv_test_str[189], (Fnv64_t) {0xf7340860UL, 0x0b038eebUL} }, + { &fnv_test_str[190], (Fnv64_t) {0x53fb69b0UL, 0x1bcd8373UL} }, + { &fnv_test_str[191], (Fnv64_t) {0x59eff180UL, 0x46f992fcUL} }, + { &fnv_test_str[192], (Fnv64_t) {0x29ae79c0UL, 0x497678eeUL} }, + { &fnv_test_str[193], (Fnv64_t) {0x0ddd4450UL, 0xb10a6228UL} }, + { &fnv_test_str[194], (Fnv64_t) {0xb4d68140UL, 0x35eb228dUL} }, + { &fnv_test_str[195], (Fnv64_t) {0xd9470870UL, 0x8b350e86UL} }, + { &fnv_test_str[196], (Fnv64_t) {0x812e9540UL, 0x4e1fbdb2UL} }, + { &fnv_test_str[197], (Fnv64_t) {0xf69a0600UL, 0x051e080dUL} }, + { &fnv_test_str[198], (Fnv64_t) {0x54dadb40UL, 0x45e1e8aeUL} }, + { &fnv_test_str[199], (Fnv64_t) {0x00000000UL, 0x00000000UL} }, + { &fnv_test_str[200], (Fnv64_t) {0x90557064UL, 0xcd738062UL} }, + { &fnv_test_str[201], (Fnv64_t) {0xbe0317c8UL, 0x2613a37bUL} }, + { &fnv_test_str[202], (Fnv64_t) {0xcf2ae5e4UL, 0x1480e21fUL} }, + { NULL, (Fnv64_t) {0,0} } +}; +#endif /* HAVE_64BIT_LONG_LONG */ + +/* FNV-1 64 bit test vectors */ +#if defined(HAVE_64BIT_LONG_LONG) +struct fnv1_64_test_vector fnv1_64_vector[] = { + { &fnv_test_str[0], (Fnv64_t) 0xcbf29ce484222325ULL }, + { &fnv_test_str[1], (Fnv64_t) 0xaf63bd4c8601b7beULL }, + { &fnv_test_str[2], (Fnv64_t) 0xaf63bd4c8601b7bdULL }, + { &fnv_test_str[3], (Fnv64_t) 0xaf63bd4c8601b7bcULL }, + { &fnv_test_str[4], (Fnv64_t) 0xaf63bd4c8601b7bbULL }, + { &fnv_test_str[5], (Fnv64_t) 0xaf63bd4c8601b7baULL }, + { &fnv_test_str[6], (Fnv64_t) 0xaf63bd4c8601b7b9ULL }, + { &fnv_test_str[7], (Fnv64_t) 0x08326207b4eb2f34ULL }, + { &fnv_test_str[8], (Fnv64_t) 0xd8cbc7186ba13533ULL }, + { &fnv_test_str[9], (Fnv64_t) 0x0378817ee2ed65cbULL }, + { &fnv_test_str[10], (Fnv64_t) 0xd329d59b9963f790ULL }, + { &fnv_test_str[11], (Fnv64_t) 0x340d8765a4dda9c2ULL }, + { &fnv_test_str[12], (Fnv64_t) 0xaf63bd4c8601b7dfULL }, + { &fnv_test_str[13], (Fnv64_t) 0x08326707b4eb37daULL }, + { &fnv_test_str[14], (Fnv64_t) 0x08326607b4eb3627ULL }, + { &fnv_test_str[15], (Fnv64_t) 0x08326507b4eb3474ULL }, + { &fnv_test_str[16], (Fnv64_t) 0x08326407b4eb32c1ULL }, + { &fnv_test_str[17], (Fnv64_t) 0x08326307b4eb310eULL }, + { &fnv_test_str[18], (Fnv64_t) 0x08326207b4eb2f5bULL }, + { &fnv_test_str[19], (Fnv64_t) 0xd8cbc7186ba1355cULL }, + { &fnv_test_str[20], (Fnv64_t) 0x0378817ee2ed65a9ULL }, + { &fnv_test_str[21], (Fnv64_t) 0xd329d59b9963f7f1ULL }, + { &fnv_test_str[22], (Fnv64_t) 0x340d8765a4dda9b0ULL }, + { &fnv_test_str[23], (Fnv64_t) 0x50a6d3b724a774a6ULL }, + { &fnv_test_str[24], (Fnv64_t) 0x08326507b4eb341cULL }, + { &fnv_test_str[25], (Fnv64_t) 0xd8d5c8186ba98bfbULL }, + { &fnv_test_str[26], (Fnv64_t) 0x1ccefc7ef118dbefULL }, + { &fnv_test_str[27], (Fnv64_t) 0x0c92fab3ad3db77aULL }, + { &fnv_test_str[28], (Fnv64_t) 0x9b77794f5fdec421ULL }, + { &fnv_test_str[29], (Fnv64_t) 0x0ac742dfe7874433ULL }, + { &fnv_test_str[30], (Fnv64_t) 0xd7dad5766ad8e2deULL }, + { &fnv_test_str[31], (Fnv64_t) 0xa1bb96378e897f5bULL }, + { &fnv_test_str[32], (Fnv64_t) 0x5b3f9b6733a367d2ULL }, + { &fnv_test_str[33], (Fnv64_t) 0xb07ce25cbea969f6ULL }, + { &fnv_test_str[34], (Fnv64_t) 0x8d9e9997f9df0d6aULL }, + { &fnv_test_str[35], (Fnv64_t) 0x838c673d9603cb7bULL }, + { &fnv_test_str[36], (Fnv64_t) 0x8b5ee8a5e872c273ULL }, + { &fnv_test_str[37], (Fnv64_t) 0x4507c4e9fb00690cULL }, + { &fnv_test_str[38], (Fnv64_t) 0x4c9ca59581b27f45ULL }, + { &fnv_test_str[39], (Fnv64_t) 0xe0aca20b624e4235ULL }, + { &fnv_test_str[40], (Fnv64_t) 0xd8d5c8186ba98b94ULL }, + { &fnv_test_str[41], (Fnv64_t) 0x1ccefc7ef118db81ULL }, + { &fnv_test_str[42], (Fnv64_t) 0x0c92fab3ad3db71dULL }, + { &fnv_test_str[43], (Fnv64_t) 0x9b77794f5fdec44eULL }, + { &fnv_test_str[44], (Fnv64_t) 0x0ac742dfe7874413ULL }, + { &fnv_test_str[45], (Fnv64_t) 0xd7dad5766ad8e2a9ULL }, + { &fnv_test_str[46], (Fnv64_t) 0xa1bb96378e897f3aULL }, + { &fnv_test_str[47], (Fnv64_t) 0x5b3f9b6733a367a1ULL }, + { &fnv_test_str[48], (Fnv64_t) 0xb07ce25cbea969d6ULL }, + { &fnv_test_str[49], (Fnv64_t) 0x8d9e9997f9df0d02ULL }, + { &fnv_test_str[50], (Fnv64_t) 0x838c673d9603cb1eULL }, + { &fnv_test_str[51], (Fnv64_t) 0x8b5ee8a5e872c201ULL }, + { &fnv_test_str[52], (Fnv64_t) 0x4507c4e9fb006969ULL }, + { &fnv_test_str[53], (Fnv64_t) 0x4c9ca59581b27f64ULL }, + { &fnv_test_str[54], (Fnv64_t) 0xe0aca20b624e423fULL }, + { &fnv_test_str[55], (Fnv64_t) 0x13998e580afa800fULL }, + { &fnv_test_str[56], (Fnv64_t) 0x08326507b4eb3401ULL }, + { &fnv_test_str[57], (Fnv64_t) 0xd8d5ad186ba95dc1ULL }, + { &fnv_test_str[58], (Fnv64_t) 0x1c72e17ef0ca4e97ULL }, + { &fnv_test_str[59], (Fnv64_t) 0x2183c1b327c38ae6ULL }, + { &fnv_test_str[60], (Fnv64_t) 0xb66d096c914504f2ULL }, + { &fnv_test_str[61], (Fnv64_t) 0x404bf57ad8476757ULL }, + { &fnv_test_str[62], (Fnv64_t) 0x887976bd815498bbULL }, + { &fnv_test_str[63], (Fnv64_t) 0x3afd7f02c2bf85a5ULL }, + { &fnv_test_str[64], (Fnv64_t) 0xfc4476b0eb70177fULL }, + { &fnv_test_str[65], (Fnv64_t) 0x186d2da00f77ecbaULL }, + { &fnv_test_str[66], (Fnv64_t) 0xf97140fa48c74066ULL }, + { &fnv_test_str[67], (Fnv64_t) 0xa2b1cf49aa926d37ULL }, + { &fnv_test_str[68], (Fnv64_t) 0x0690712cd6cf940cULL }, + { &fnv_test_str[69], (Fnv64_t) 0xf7045b3102b8906eULL }, + { &fnv_test_str[70], (Fnv64_t) 0xd8d5ad186ba95db3ULL }, + { &fnv_test_str[71], (Fnv64_t) 0x1c72e17ef0ca4ef3ULL }, + { &fnv_test_str[72], (Fnv64_t) 0x2183c1b327c38a95ULL }, + { &fnv_test_str[73], (Fnv64_t) 0xb66d096c914504d2ULL }, + { &fnv_test_str[74], (Fnv64_t) 0x404bf57ad8476736ULL }, + { &fnv_test_str[75], (Fnv64_t) 0x887976bd815498d5ULL }, + { &fnv_test_str[76], (Fnv64_t) 0x3afd7f02c2bf85c1ULL }, + { &fnv_test_str[77], (Fnv64_t) 0xfc4476b0eb70175fULL }, + { &fnv_test_str[78], (Fnv64_t) 0x186d2da00f77eccdULL }, + { &fnv_test_str[79], (Fnv64_t) 0xf97140fa48c7400eULL }, + { &fnv_test_str[80], (Fnv64_t) 0xa2b1cf49aa926d52ULL }, + { &fnv_test_str[81], (Fnv64_t) 0x0690712cd6cf9475ULL }, + { &fnv_test_str[82], (Fnv64_t) 0xf7045b3102b89064ULL }, + { &fnv_test_str[83], (Fnv64_t) 0x74f762479f9d6aeaULL }, + { &fnv_test_str[84], (Fnv64_t) 0x08326007b4eb2b9cULL }, + { &fnv_test_str[85], (Fnv64_t) 0xd8c4c9186b9b1a14ULL }, + { &fnv_test_str[86], (Fnv64_t) 0x7b495389bdbdd4c7ULL }, + { &fnv_test_str[87], (Fnv64_t) 0x3b6dba0d69908e25ULL }, + { &fnv_test_str[88], (Fnv64_t) 0xd6b2b17bf4b71261ULL }, + { &fnv_test_str[89], (Fnv64_t) 0x447bfb7f98e615b5ULL }, + { &fnv_test_str[90], (Fnv64_t) 0xd6b2b17bf4b71262ULL }, + { &fnv_test_str[91], (Fnv64_t) 0x3bd2807f93fe1660ULL }, + { &fnv_test_str[92], (Fnv64_t) 0xd6b2b17bf4b71263ULL }, + { &fnv_test_str[93], (Fnv64_t) 0x3329057f8f16170bULL }, + { &fnv_test_str[94], (Fnv64_t) 0xd6b2b17bf4b71264ULL }, + { &fnv_test_str[95], (Fnv64_t) 0x2a7f8a7f8a2e19b6ULL }, + { &fnv_test_str[96], (Fnv64_t) 0x23d3767e64b2f98aULL }, + { &fnv_test_str[97], (Fnv64_t) 0xff768d7e4f9d86a4ULL }, + { &fnv_test_str[98], (Fnv64_t) 0x23d3767e64b2f984ULL }, + { &fnv_test_str[99], (Fnv64_t) 0xccd1837e334e4aa6ULL }, + { &fnv_test_str[100], (Fnv64_t) 0x23d3767e64b2f99aULL }, + { &fnv_test_str[101], (Fnv64_t) 0x7691fd7e028f6754ULL }, + { &fnv_test_str[102], (Fnv64_t) 0x34ad3b1041204318ULL }, + { &fnv_test_str[103], (Fnv64_t) 0xa29e749ea9d201c8ULL }, + { &fnv_test_str[104], (Fnv64_t) 0x34ad3b104120431bULL }, + { &fnv_test_str[105], (Fnv64_t) 0xa29e779ea9d206e1ULL }, + { &fnv_test_str[106], (Fnv64_t) 0x34ad3b104120431aULL }, + { &fnv_test_str[107], (Fnv64_t) 0xa29e769ea9d2052eULL }, + { &fnv_test_str[108], (Fnv64_t) 0x02a17ebca4aa3497ULL }, + { &fnv_test_str[109], (Fnv64_t) 0x229ef18bcd375c95ULL }, + { &fnv_test_str[110], (Fnv64_t) 0x02a17dbca4aa32c8ULL }, + { &fnv_test_str[111], (Fnv64_t) 0x229b6f8bcd3449d8ULL }, + { &fnv_test_str[112], (Fnv64_t) 0x02a184bca4aa3ed5ULL }, + { &fnv_test_str[113], (Fnv64_t) 0x22b3618bcd48c3efULL }, + { &fnv_test_str[114], (Fnv64_t) 0x5c2c346706186f36ULL }, + { &fnv_test_str[115], (Fnv64_t) 0xb78c410f5b84f8c2ULL }, + { &fnv_test_str[116], (Fnv64_t) 0xed9478212b267395ULL }, + { &fnv_test_str[117], (Fnv64_t) 0xd9bbb55c5256662fULL }, + { &fnv_test_str[118], (Fnv64_t) 0x8c54f0203249438aULL }, + { &fnv_test_str[119], (Fnv64_t) 0xbd9790b5727dc37eULL }, + { &fnv_test_str[120], (Fnv64_t) 0xa64e5f36c9e2b0e3ULL }, + { &fnv_test_str[121], (Fnv64_t) 0x8fd0680da3088a04ULL }, + { &fnv_test_str[122], (Fnv64_t) 0x67aad32c078284ccULL }, + { &fnv_test_str[123], (Fnv64_t) 0xb37d55d81c57b331ULL }, + { &fnv_test_str[124], (Fnv64_t) 0x55ac0f3829057c43ULL }, + { &fnv_test_str[125], (Fnv64_t) 0xcb27f4b8e1b6cc20ULL }, + { &fnv_test_str[126], (Fnv64_t) 0x26caf88bcbef2d19ULL }, + { &fnv_test_str[127], (Fnv64_t) 0x8e6e063b97e61b8fULL }, + { &fnv_test_str[128], (Fnv64_t) 0xb42750f7f3b7c37eULL }, + { &fnv_test_str[129], (Fnv64_t) 0xf3c6ba64cf7ca99bULL }, + { &fnv_test_str[130], (Fnv64_t) 0xebfb69b427ea80feULL }, + { &fnv_test_str[131], (Fnv64_t) 0x39b50c3ed970f46cULL }, + { &fnv_test_str[132], (Fnv64_t) 0x5b9b177aa3eb3e8aULL }, + { &fnv_test_str[133], (Fnv64_t) 0x6510063ecf4ec903ULL }, + { &fnv_test_str[134], (Fnv64_t) 0x2b3bbd2c00797c7aULL }, + { &fnv_test_str[135], (Fnv64_t) 0xf1d6204ff5cb4aa7ULL }, + { &fnv_test_str[136], (Fnv64_t) 0x4836e27ccf099f38ULL }, + { &fnv_test_str[137], (Fnv64_t) 0x82efbb0dd073b44dULL }, + { &fnv_test_str[138], (Fnv64_t) 0x4a80c282ffd7d4c6ULL }, + { &fnv_test_str[139], (Fnv64_t) 0x305d1a9c9ee43bdfULL }, + { &fnv_test_str[140], (Fnv64_t) 0x15c366948ffc6997ULL }, + { &fnv_test_str[141], (Fnv64_t) 0x80153ae218916e7bULL }, + { &fnv_test_str[142], (Fnv64_t) 0xfa23e2bdf9e2a9e1ULL }, + { &fnv_test_str[143], (Fnv64_t) 0xd47e8d8a2333c6deULL }, + { &fnv_test_str[144], (Fnv64_t) 0x7e128095f688b056ULL }, + { &fnv_test_str[145], (Fnv64_t) 0x2f5356890efcedabULL }, + { &fnv_test_str[146], (Fnv64_t) 0x95c2b383014f55c5ULL }, + { &fnv_test_str[147], (Fnv64_t) 0x4727a5339ce6070fULL }, + { &fnv_test_str[148], (Fnv64_t) 0xb0555ecd575108e9ULL }, + { &fnv_test_str[149], (Fnv64_t) 0x48d785770bb4af37ULL }, + { &fnv_test_str[150], (Fnv64_t) 0x09d4701c12af02b1ULL }, + { &fnv_test_str[151], (Fnv64_t) 0x79f031e78f3cf62eULL }, + { &fnv_test_str[152], (Fnv64_t) 0x52a1ee85db1b5a94ULL }, + { &fnv_test_str[153], (Fnv64_t) 0x6bd95b2eb37fa6b8ULL }, + { &fnv_test_str[154], (Fnv64_t) 0x74971b7077aef85dULL }, + { &fnv_test_str[155], (Fnv64_t) 0xb4e4fae2ffcc1aadULL }, + { &fnv_test_str[156], (Fnv64_t) 0x2bd48bd898b8f63aULL }, + { &fnv_test_str[157], (Fnv64_t) 0xe9966ac1556257f6ULL }, + { &fnv_test_str[158], (Fnv64_t) 0x92a3d1cd078ba293ULL }, + { &fnv_test_str[159], (Fnv64_t) 0xf81175a482e20ab8ULL }, + { &fnv_test_str[160], (Fnv64_t) 0x5bbb3de722e73048ULL }, + { &fnv_test_str[161], (Fnv64_t) 0x6b4f363492b9f2beULL }, + { &fnv_test_str[162], (Fnv64_t) 0xc2d559df73d59875ULL }, + { &fnv_test_str[163], (Fnv64_t) 0xf75f62284bc7a8c2ULL }, + { &fnv_test_str[164], (Fnv64_t) 0xda8dd8e116a9f1ccULL }, + { &fnv_test_str[165], (Fnv64_t) 0xbdc1e6ab76057885ULL }, + { &fnv_test_str[166], (Fnv64_t) 0xfec6a4238a1224a0ULL }, + { &fnv_test_str[167], (Fnv64_t) 0xc03f40f3223e290eULL }, + { &fnv_test_str[168], (Fnv64_t) 0x1ed21673466ffda9ULL }, + { &fnv_test_str[169], (Fnv64_t) 0xdf70f906bb0dd2afULL }, + { &fnv_test_str[170], (Fnv64_t) 0xf3dcda369f2af666ULL }, + { &fnv_test_str[171], (Fnv64_t) 0x9ebb11573cdcebdeULL }, + { &fnv_test_str[172], (Fnv64_t) 0x81c72d9077fedca0ULL }, + { &fnv_test_str[173], (Fnv64_t) 0x0ec074a31be5fb15ULL }, + { &fnv_test_str[174], (Fnv64_t) 0x2a8b3280b6c48f20ULL }, + { &fnv_test_str[175], (Fnv64_t) 0xfd31777513309344ULL }, + { &fnv_test_str[176], (Fnv64_t) 0x194534a86ad006b6ULL }, + { &fnv_test_str[177], (Fnv64_t) 0x3be6fdf46e0cfe12ULL }, + { &fnv_test_str[178], (Fnv64_t) 0x017cc137a07eb057ULL }, + { &fnv_test_str[179], (Fnv64_t) 0x9428fc6e7d26b54dULL }, + { &fnv_test_str[180], (Fnv64_t) 0x9aaa2e3603ef8ad7ULL }, + { &fnv_test_str[181], (Fnv64_t) 0x82c6d3f3a0ccdf7dULL }, + { &fnv_test_str[182], (Fnv64_t) 0xc86eeea00cf09b65ULL }, + { &fnv_test_str[183], (Fnv64_t) 0x705f8189dbb58299ULL }, + { &fnv_test_str[184], (Fnv64_t) 0x415a7f554391ca69ULL }, + { &fnv_test_str[185], (Fnv64_t) 0xcfe3d49fa2bdc555ULL }, + { &fnv_test_str[186], (Fnv64_t) 0xf0f9c56039b25191ULL }, + { &fnv_test_str[187], (Fnv64_t) 0x7075cb6abd1d32d9ULL }, + { &fnv_test_str[188], (Fnv64_t) 0x43c94e2c8b277509ULL }, + { &fnv_test_str[189], (Fnv64_t) 0x3cbfd4e4ea670359ULL }, + { &fnv_test_str[190], (Fnv64_t) 0xc05887810f4d019dULL }, + { &fnv_test_str[191], (Fnv64_t) 0x14468ff93ac22dc5ULL }, + { &fnv_test_str[192], (Fnv64_t) 0xebed699589d99c05ULL }, + { &fnv_test_str[193], (Fnv64_t) 0x6d99f6df321ca5d5ULL }, + { &fnv_test_str[194], (Fnv64_t) 0x0cd410d08c36d625ULL }, + { &fnv_test_str[195], (Fnv64_t) 0xef1b2a2c86831d35ULL }, + { &fnv_test_str[196], (Fnv64_t) 0x3b349c4d69ee5f05ULL }, + { &fnv_test_str[197], (Fnv64_t) 0x55248ce88f45f035ULL }, + { &fnv_test_str[198], (Fnv64_t) 0xaa69ca6a18a4c885ULL }, + { &fnv_test_str[199], (Fnv64_t) 0x1fe3fce62bd816b5ULL }, + { &fnv_test_str[200], (Fnv64_t) 0x0289a488a8df69d9ULL }, + { &fnv_test_str[201], (Fnv64_t) 0x15e96e1613df98b5ULL }, + { &fnv_test_str[202], (Fnv64_t) 0xe6be57375ad89b99ULL }, + { NULL, (Fnv64_t) 0 } +}; +#else /* HAVE_64BIT_LONG_LONG */ +struct fnv1_64_test_vector fnv1_64_vector[] = { + { &fnv_test_str[0], (Fnv64_t) {0x84222325UL, 0xcbf29ce4UL} }, + { &fnv_test_str[1], (Fnv64_t) {0x8601b7beUL, 0xaf63bd4cUL} }, + { &fnv_test_str[2], (Fnv64_t) {0x8601b7bdUL, 0xaf63bd4cUL} }, + { &fnv_test_str[3], (Fnv64_t) {0x8601b7bcUL, 0xaf63bd4cUL} }, + { &fnv_test_str[4], (Fnv64_t) {0x8601b7bbUL, 0xaf63bd4cUL} }, + { &fnv_test_str[5], (Fnv64_t) {0x8601b7baUL, 0xaf63bd4cUL} }, + { &fnv_test_str[6], (Fnv64_t) {0x8601b7b9UL, 0xaf63bd4cUL} }, + { &fnv_test_str[7], (Fnv64_t) {0xb4eb2f34UL, 0x08326207UL} }, + { &fnv_test_str[8], (Fnv64_t) {0x6ba13533UL, 0xd8cbc718UL} }, + { &fnv_test_str[9], (Fnv64_t) {0xe2ed65cbUL, 0x0378817eUL} }, + { &fnv_test_str[10], (Fnv64_t) {0x9963f790UL, 0xd329d59bUL} }, + { &fnv_test_str[11], (Fnv64_t) {0xa4dda9c2UL, 0x340d8765UL} }, + { &fnv_test_str[12], (Fnv64_t) {0x8601b7dfUL, 0xaf63bd4cUL} }, + { &fnv_test_str[13], (Fnv64_t) {0xb4eb37daUL, 0x08326707UL} }, + { &fnv_test_str[14], (Fnv64_t) {0xb4eb3627UL, 0x08326607UL} }, + { &fnv_test_str[15], (Fnv64_t) {0xb4eb3474UL, 0x08326507UL} }, + { &fnv_test_str[16], (Fnv64_t) {0xb4eb32c1UL, 0x08326407UL} }, + { &fnv_test_str[17], (Fnv64_t) {0xb4eb310eUL, 0x08326307UL} }, + { &fnv_test_str[18], (Fnv64_t) {0xb4eb2f5bUL, 0x08326207UL} }, + { &fnv_test_str[19], (Fnv64_t) {0x6ba1355cUL, 0xd8cbc718UL} }, + { &fnv_test_str[20], (Fnv64_t) {0xe2ed65a9UL, 0x0378817eUL} }, + { &fnv_test_str[21], (Fnv64_t) {0x9963f7f1UL, 0xd329d59bUL} }, + { &fnv_test_str[22], (Fnv64_t) {0xa4dda9b0UL, 0x340d8765UL} }, + { &fnv_test_str[23], (Fnv64_t) {0x24a774a6UL, 0x50a6d3b7UL} }, + { &fnv_test_str[24], (Fnv64_t) {0xb4eb341cUL, 0x08326507UL} }, + { &fnv_test_str[25], (Fnv64_t) {0x6ba98bfbUL, 0xd8d5c818UL} }, + { &fnv_test_str[26], (Fnv64_t) {0xf118dbefUL, 0x1ccefc7eUL} }, + { &fnv_test_str[27], (Fnv64_t) {0xad3db77aUL, 0x0c92fab3UL} }, + { &fnv_test_str[28], (Fnv64_t) {0x5fdec421UL, 0x9b77794fUL} }, + { &fnv_test_str[29], (Fnv64_t) {0xe7874433UL, 0x0ac742dfUL} }, + { &fnv_test_str[30], (Fnv64_t) {0x6ad8e2deUL, 0xd7dad576UL} }, + { &fnv_test_str[31], (Fnv64_t) {0x8e897f5bUL, 0xa1bb9637UL} }, + { &fnv_test_str[32], (Fnv64_t) {0x33a367d2UL, 0x5b3f9b67UL} }, + { &fnv_test_str[33], (Fnv64_t) {0xbea969f6UL, 0xb07ce25cUL} }, + { &fnv_test_str[34], (Fnv64_t) {0xf9df0d6aUL, 0x8d9e9997UL} }, + { &fnv_test_str[35], (Fnv64_t) {0x9603cb7bUL, 0x838c673dUL} }, + { &fnv_test_str[36], (Fnv64_t) {0xe872c273UL, 0x8b5ee8a5UL} }, + { &fnv_test_str[37], (Fnv64_t) {0xfb00690cUL, 0x4507c4e9UL} }, + { &fnv_test_str[38], (Fnv64_t) {0x81b27f45UL, 0x4c9ca595UL} }, + { &fnv_test_str[39], (Fnv64_t) {0x624e4235UL, 0xe0aca20bUL} }, + { &fnv_test_str[40], (Fnv64_t) {0x6ba98b94UL, 0xd8d5c818UL} }, + { &fnv_test_str[41], (Fnv64_t) {0xf118db81UL, 0x1ccefc7eUL} }, + { &fnv_test_str[42], (Fnv64_t) {0xad3db71dUL, 0x0c92fab3UL} }, + { &fnv_test_str[43], (Fnv64_t) {0x5fdec44eUL, 0x9b77794fUL} }, + { &fnv_test_str[44], (Fnv64_t) {0xe7874413UL, 0x0ac742dfUL} }, + { &fnv_test_str[45], (Fnv64_t) {0x6ad8e2a9UL, 0xd7dad576UL} }, + { &fnv_test_str[46], (Fnv64_t) {0x8e897f3aUL, 0xa1bb9637UL} }, + { &fnv_test_str[47], (Fnv64_t) {0x33a367a1UL, 0x5b3f9b67UL} }, + { &fnv_test_str[48], (Fnv64_t) {0xbea969d6UL, 0xb07ce25cUL} }, + { &fnv_test_str[49], (Fnv64_t) {0xf9df0d02UL, 0x8d9e9997UL} }, + { &fnv_test_str[50], (Fnv64_t) {0x9603cb1eUL, 0x838c673dUL} }, + { &fnv_test_str[51], (Fnv64_t) {0xe872c201UL, 0x8b5ee8a5UL} }, + { &fnv_test_str[52], (Fnv64_t) {0xfb006969UL, 0x4507c4e9UL} }, + { &fnv_test_str[53], (Fnv64_t) {0x81b27f64UL, 0x4c9ca595UL} }, + { &fnv_test_str[54], (Fnv64_t) {0x624e423fUL, 0xe0aca20bUL} }, + { &fnv_test_str[55], (Fnv64_t) {0x0afa800fUL, 0x13998e58UL} }, + { &fnv_test_str[56], (Fnv64_t) {0xb4eb3401UL, 0x08326507UL} }, + { &fnv_test_str[57], (Fnv64_t) {0x6ba95dc1UL, 0xd8d5ad18UL} }, + { &fnv_test_str[58], (Fnv64_t) {0xf0ca4e97UL, 0x1c72e17eUL} }, + { &fnv_test_str[59], (Fnv64_t) {0x27c38ae6UL, 0x2183c1b3UL} }, + { &fnv_test_str[60], (Fnv64_t) {0x914504f2UL, 0xb66d096cUL} }, + { &fnv_test_str[61], (Fnv64_t) {0xd8476757UL, 0x404bf57aUL} }, + { &fnv_test_str[62], (Fnv64_t) {0x815498bbUL, 0x887976bdUL} }, + { &fnv_test_str[63], (Fnv64_t) {0xc2bf85a5UL, 0x3afd7f02UL} }, + { &fnv_test_str[64], (Fnv64_t) {0xeb70177fUL, 0xfc4476b0UL} }, + { &fnv_test_str[65], (Fnv64_t) {0x0f77ecbaUL, 0x186d2da0UL} }, + { &fnv_test_str[66], (Fnv64_t) {0x48c74066UL, 0xf97140faUL} }, + { &fnv_test_str[67], (Fnv64_t) {0xaa926d37UL, 0xa2b1cf49UL} }, + { &fnv_test_str[68], (Fnv64_t) {0xd6cf940cUL, 0x0690712cUL} }, + { &fnv_test_str[69], (Fnv64_t) {0x02b8906eUL, 0xf7045b31UL} }, + { &fnv_test_str[70], (Fnv64_t) {0x6ba95db3UL, 0xd8d5ad18UL} }, + { &fnv_test_str[71], (Fnv64_t) {0xf0ca4ef3UL, 0x1c72e17eUL} }, + { &fnv_test_str[72], (Fnv64_t) {0x27c38a95UL, 0x2183c1b3UL} }, + { &fnv_test_str[73], (Fnv64_t) {0x914504d2UL, 0xb66d096cUL} }, + { &fnv_test_str[74], (Fnv64_t) {0xd8476736UL, 0x404bf57aUL} }, + { &fnv_test_str[75], (Fnv64_t) {0x815498d5UL, 0x887976bdUL} }, + { &fnv_test_str[76], (Fnv64_t) {0xc2bf85c1UL, 0x3afd7f02UL} }, + { &fnv_test_str[77], (Fnv64_t) {0xeb70175fUL, 0xfc4476b0UL} }, + { &fnv_test_str[78], (Fnv64_t) {0x0f77eccdUL, 0x186d2da0UL} }, + { &fnv_test_str[79], (Fnv64_t) {0x48c7400eUL, 0xf97140faUL} }, + { &fnv_test_str[80], (Fnv64_t) {0xaa926d52UL, 0xa2b1cf49UL} }, + { &fnv_test_str[81], (Fnv64_t) {0xd6cf9475UL, 0x0690712cUL} }, + { &fnv_test_str[82], (Fnv64_t) {0x02b89064UL, 0xf7045b31UL} }, + { &fnv_test_str[83], (Fnv64_t) {0x9f9d6aeaUL, 0x74f76247UL} }, + { &fnv_test_str[84], (Fnv64_t) {0xb4eb2b9cUL, 0x08326007UL} }, + { &fnv_test_str[85], (Fnv64_t) {0x6b9b1a14UL, 0xd8c4c918UL} }, + { &fnv_test_str[86], (Fnv64_t) {0xbdbdd4c7UL, 0x7b495389UL} }, + { &fnv_test_str[87], (Fnv64_t) {0x69908e25UL, 0x3b6dba0dUL} }, + { &fnv_test_str[88], (Fnv64_t) {0xf4b71261UL, 0xd6b2b17bUL} }, + { &fnv_test_str[89], (Fnv64_t) {0x98e615b5UL, 0x447bfb7fUL} }, + { &fnv_test_str[90], (Fnv64_t) {0xf4b71262UL, 0xd6b2b17bUL} }, + { &fnv_test_str[91], (Fnv64_t) {0x93fe1660UL, 0x3bd2807fUL} }, + { &fnv_test_str[92], (Fnv64_t) {0xf4b71263UL, 0xd6b2b17bUL} }, + { &fnv_test_str[93], (Fnv64_t) {0x8f16170bUL, 0x3329057fUL} }, + { &fnv_test_str[94], (Fnv64_t) {0xf4b71264UL, 0xd6b2b17bUL} }, + { &fnv_test_str[95], (Fnv64_t) {0x8a2e19b6UL, 0x2a7f8a7fUL} }, + { &fnv_test_str[96], (Fnv64_t) {0x64b2f98aUL, 0x23d3767eUL} }, + { &fnv_test_str[97], (Fnv64_t) {0x4f9d86a4UL, 0xff768d7eUL} }, + { &fnv_test_str[98], (Fnv64_t) {0x64b2f984UL, 0x23d3767eUL} }, + { &fnv_test_str[99], (Fnv64_t) {0x334e4aa6UL, 0xccd1837eUL} }, + { &fnv_test_str[100], (Fnv64_t) {0x64b2f99aUL, 0x23d3767eUL} }, + { &fnv_test_str[101], (Fnv64_t) {0x028f6754UL, 0x7691fd7eUL} }, + { &fnv_test_str[102], (Fnv64_t) {0x41204318UL, 0x34ad3b10UL} }, + { &fnv_test_str[103], (Fnv64_t) {0xa9d201c8UL, 0xa29e749eUL} }, + { &fnv_test_str[104], (Fnv64_t) {0x4120431bUL, 0x34ad3b10UL} }, + { &fnv_test_str[105], (Fnv64_t) {0xa9d206e1UL, 0xa29e779eUL} }, + { &fnv_test_str[106], (Fnv64_t) {0x4120431aUL, 0x34ad3b10UL} }, + { &fnv_test_str[107], (Fnv64_t) {0xa9d2052eUL, 0xa29e769eUL} }, + { &fnv_test_str[108], (Fnv64_t) {0xa4aa3497UL, 0x02a17ebcUL} }, + { &fnv_test_str[109], (Fnv64_t) {0xcd375c95UL, 0x229ef18bUL} }, + { &fnv_test_str[110], (Fnv64_t) {0xa4aa32c8UL, 0x02a17dbcUL} }, + { &fnv_test_str[111], (Fnv64_t) {0xcd3449d8UL, 0x229b6f8bUL} }, + { &fnv_test_str[112], (Fnv64_t) {0xa4aa3ed5UL, 0x02a184bcUL} }, + { &fnv_test_str[113], (Fnv64_t) {0xcd48c3efUL, 0x22b3618bUL} }, + { &fnv_test_str[114], (Fnv64_t) {0x06186f36UL, 0x5c2c3467UL} }, + { &fnv_test_str[115], (Fnv64_t) {0x5b84f8c2UL, 0xb78c410fUL} }, + { &fnv_test_str[116], (Fnv64_t) {0x2b267395UL, 0xed947821UL} }, + { &fnv_test_str[117], (Fnv64_t) {0x5256662fUL, 0xd9bbb55cUL} }, + { &fnv_test_str[118], (Fnv64_t) {0x3249438aUL, 0x8c54f020UL} }, + { &fnv_test_str[119], (Fnv64_t) {0x727dc37eUL, 0xbd9790b5UL} }, + { &fnv_test_str[120], (Fnv64_t) {0xc9e2b0e3UL, 0xa64e5f36UL} }, + { &fnv_test_str[121], (Fnv64_t) {0xa3088a04UL, 0x8fd0680dUL} }, + { &fnv_test_str[122], (Fnv64_t) {0x078284ccUL, 0x67aad32cUL} }, + { &fnv_test_str[123], (Fnv64_t) {0x1c57b331UL, 0xb37d55d8UL} }, + { &fnv_test_str[124], (Fnv64_t) {0x29057c43UL, 0x55ac0f38UL} }, + { &fnv_test_str[125], (Fnv64_t) {0xe1b6cc20UL, 0xcb27f4b8UL} }, + { &fnv_test_str[126], (Fnv64_t) {0xcbef2d19UL, 0x26caf88bUL} }, + { &fnv_test_str[127], (Fnv64_t) {0x97e61b8fUL, 0x8e6e063bUL} }, + { &fnv_test_str[128], (Fnv64_t) {0xf3b7c37eUL, 0xb42750f7UL} }, + { &fnv_test_str[129], (Fnv64_t) {0xcf7ca99bUL, 0xf3c6ba64UL} }, + { &fnv_test_str[130], (Fnv64_t) {0x27ea80feUL, 0xebfb69b4UL} }, + { &fnv_test_str[131], (Fnv64_t) {0xd970f46cUL, 0x39b50c3eUL} }, + { &fnv_test_str[132], (Fnv64_t) {0xa3eb3e8aUL, 0x5b9b177aUL} }, + { &fnv_test_str[133], (Fnv64_t) {0xcf4ec903UL, 0x6510063eUL} }, + { &fnv_test_str[134], (Fnv64_t) {0x00797c7aUL, 0x2b3bbd2cUL} }, + { &fnv_test_str[135], (Fnv64_t) {0xf5cb4aa7UL, 0xf1d6204fUL} }, + { &fnv_test_str[136], (Fnv64_t) {0xcf099f38UL, 0x4836e27cUL} }, + { &fnv_test_str[137], (Fnv64_t) {0xd073b44dUL, 0x82efbb0dUL} }, + { &fnv_test_str[138], (Fnv64_t) {0xffd7d4c6UL, 0x4a80c282UL} }, + { &fnv_test_str[139], (Fnv64_t) {0x9ee43bdfUL, 0x305d1a9cUL} }, + { &fnv_test_str[140], (Fnv64_t) {0x8ffc6997UL, 0x15c36694UL} }, + { &fnv_test_str[141], (Fnv64_t) {0x18916e7bUL, 0x80153ae2UL} }, + { &fnv_test_str[142], (Fnv64_t) {0xf9e2a9e1UL, 0xfa23e2bdUL} }, + { &fnv_test_str[143], (Fnv64_t) {0x2333c6deUL, 0xd47e8d8aUL} }, + { &fnv_test_str[144], (Fnv64_t) {0xf688b056UL, 0x7e128095UL} }, + { &fnv_test_str[145], (Fnv64_t) {0x0efcedabUL, 0x2f535689UL} }, + { &fnv_test_str[146], (Fnv64_t) {0x014f55c5UL, 0x95c2b383UL} }, + { &fnv_test_str[147], (Fnv64_t) {0x9ce6070fUL, 0x4727a533UL} }, + { &fnv_test_str[148], (Fnv64_t) {0x575108e9UL, 0xb0555ecdUL} }, + { &fnv_test_str[149], (Fnv64_t) {0x0bb4af37UL, 0x48d78577UL} }, + { &fnv_test_str[150], (Fnv64_t) {0x12af02b1UL, 0x09d4701cUL} }, + { &fnv_test_str[151], (Fnv64_t) {0x8f3cf62eUL, 0x79f031e7UL} }, + { &fnv_test_str[152], (Fnv64_t) {0xdb1b5a94UL, 0x52a1ee85UL} }, + { &fnv_test_str[153], (Fnv64_t) {0xb37fa6b8UL, 0x6bd95b2eUL} }, + { &fnv_test_str[154], (Fnv64_t) {0x77aef85dUL, 0x74971b70UL} }, + { &fnv_test_str[155], (Fnv64_t) {0xffcc1aadUL, 0xb4e4fae2UL} }, + { &fnv_test_str[156], (Fnv64_t) {0x98b8f63aUL, 0x2bd48bd8UL} }, + { &fnv_test_str[157], (Fnv64_t) {0x556257f6UL, 0xe9966ac1UL} }, + { &fnv_test_str[158], (Fnv64_t) {0x078ba293UL, 0x92a3d1cdUL} }, + { &fnv_test_str[159], (Fnv64_t) {0x82e20ab8UL, 0xf81175a4UL} }, + { &fnv_test_str[160], (Fnv64_t) {0x22e73048UL, 0x5bbb3de7UL} }, + { &fnv_test_str[161], (Fnv64_t) {0x92b9f2beUL, 0x6b4f3634UL} }, + { &fnv_test_str[162], (Fnv64_t) {0x73d59875UL, 0xc2d559dfUL} }, + { &fnv_test_str[163], (Fnv64_t) {0x4bc7a8c2UL, 0xf75f6228UL} }, + { &fnv_test_str[164], (Fnv64_t) {0x16a9f1ccUL, 0xda8dd8e1UL} }, + { &fnv_test_str[165], (Fnv64_t) {0x76057885UL, 0xbdc1e6abUL} }, + { &fnv_test_str[166], (Fnv64_t) {0x8a1224a0UL, 0xfec6a423UL} }, + { &fnv_test_str[167], (Fnv64_t) {0x223e290eUL, 0xc03f40f3UL} }, + { &fnv_test_str[168], (Fnv64_t) {0x466ffda9UL, 0x1ed21673UL} }, + { &fnv_test_str[169], (Fnv64_t) {0xbb0dd2afUL, 0xdf70f906UL} }, + { &fnv_test_str[170], (Fnv64_t) {0x9f2af666UL, 0xf3dcda36UL} }, + { &fnv_test_str[171], (Fnv64_t) {0x3cdcebdeUL, 0x9ebb1157UL} }, + { &fnv_test_str[172], (Fnv64_t) {0x77fedca0UL, 0x81c72d90UL} }, + { &fnv_test_str[173], (Fnv64_t) {0x1be5fb15UL, 0x0ec074a3UL} }, + { &fnv_test_str[174], (Fnv64_t) {0xb6c48f20UL, 0x2a8b3280UL} }, + { &fnv_test_str[175], (Fnv64_t) {0x13309344UL, 0xfd317775UL} }, + { &fnv_test_str[176], (Fnv64_t) {0x6ad006b6UL, 0x194534a8UL} }, + { &fnv_test_str[177], (Fnv64_t) {0x6e0cfe12UL, 0x3be6fdf4UL} }, + { &fnv_test_str[178], (Fnv64_t) {0xa07eb057UL, 0x017cc137UL} }, + { &fnv_test_str[179], (Fnv64_t) {0x7d26b54dUL, 0x9428fc6eUL} }, + { &fnv_test_str[180], (Fnv64_t) {0x03ef8ad7UL, 0x9aaa2e36UL} }, + { &fnv_test_str[181], (Fnv64_t) {0xa0ccdf7dUL, 0x82c6d3f3UL} }, + { &fnv_test_str[182], (Fnv64_t) {0x0cf09b65UL, 0xc86eeea0UL} }, + { &fnv_test_str[183], (Fnv64_t) {0xdbb58299UL, 0x705f8189UL} }, + { &fnv_test_str[184], (Fnv64_t) {0x4391ca69UL, 0x415a7f55UL} }, + { &fnv_test_str[185], (Fnv64_t) {0xa2bdc555UL, 0xcfe3d49fUL} }, + { &fnv_test_str[186], (Fnv64_t) {0x39b25191UL, 0xf0f9c560UL} }, + { &fnv_test_str[187], (Fnv64_t) {0xbd1d32d9UL, 0x7075cb6aUL} }, + { &fnv_test_str[188], (Fnv64_t) {0x8b277509UL, 0x43c94e2cUL} }, + { &fnv_test_str[189], (Fnv64_t) {0xea670359UL, 0x3cbfd4e4UL} }, + { &fnv_test_str[190], (Fnv64_t) {0x0f4d019dUL, 0xc0588781UL} }, + { &fnv_test_str[191], (Fnv64_t) {0x3ac22dc5UL, 0x14468ff9UL} }, + { &fnv_test_str[192], (Fnv64_t) {0x89d99c05UL, 0xebed6995UL} }, + { &fnv_test_str[193], (Fnv64_t) {0x321ca5d5UL, 0x6d99f6dfUL} }, + { &fnv_test_str[194], (Fnv64_t) {0x8c36d625UL, 0x0cd410d0UL} }, + { &fnv_test_str[195], (Fnv64_t) {0x86831d35UL, 0xef1b2a2cUL} }, + { &fnv_test_str[196], (Fnv64_t) {0x69ee5f05UL, 0x3b349c4dUL} }, + { &fnv_test_str[197], (Fnv64_t) {0x8f45f035UL, 0x55248ce8UL} }, + { &fnv_test_str[198], (Fnv64_t) {0x18a4c885UL, 0xaa69ca6aUL} }, + { &fnv_test_str[199], (Fnv64_t) {0x2bd816b5UL, 0x1fe3fce6UL} }, + { &fnv_test_str[200], (Fnv64_t) {0xa8df69d9UL, 0x0289a488UL} }, + { &fnv_test_str[201], (Fnv64_t) {0x13df98b5UL, 0x15e96e16UL} }, + { &fnv_test_str[202], (Fnv64_t) {0x5ad89b99UL, 0xe6be5737UL} }, + { NULL, (Fnv64_t) {0,0} } +}; +#endif /* HAVE_64BIT_LONG_LONG */ + +/* FNV-1a 64 bit test vectors */ +#if defined(HAVE_64BIT_LONG_LONG) +struct fnv1a_64_test_vector fnv1a_64_vector[] = { + { &fnv_test_str[0], (Fnv64_t) 0xcbf29ce484222325ULL }, + { &fnv_test_str[1], (Fnv64_t) 0xaf63dc4c8601ec8cULL }, + { &fnv_test_str[2], (Fnv64_t) 0xaf63df4c8601f1a5ULL }, + { &fnv_test_str[3], (Fnv64_t) 0xaf63de4c8601eff2ULL }, + { &fnv_test_str[4], (Fnv64_t) 0xaf63d94c8601e773ULL }, + { &fnv_test_str[5], (Fnv64_t) 0xaf63d84c8601e5c0ULL }, + { &fnv_test_str[6], (Fnv64_t) 0xaf63db4c8601ead9ULL }, + { &fnv_test_str[7], (Fnv64_t) 0x08985907b541d342ULL }, + { &fnv_test_str[8], (Fnv64_t) 0xdcb27518fed9d577ULL }, + { &fnv_test_str[9], (Fnv64_t) 0xdd120e790c2512afULL }, + { &fnv_test_str[10], (Fnv64_t) 0xcac165afa2fef40aULL }, + { &fnv_test_str[11], (Fnv64_t) 0x85944171f73967e8ULL }, + { &fnv_test_str[12], (Fnv64_t) 0xaf63bd4c8601b7dfULL }, + { &fnv_test_str[13], (Fnv64_t) 0x089be207b544f1e4ULL }, + { &fnv_test_str[14], (Fnv64_t) 0x08a61407b54d9b5fULL }, + { &fnv_test_str[15], (Fnv64_t) 0x08a2ae07b54ab836ULL }, + { &fnv_test_str[16], (Fnv64_t) 0x0891b007b53c4869ULL }, + { &fnv_test_str[17], (Fnv64_t) 0x088e4a07b5396540ULL }, + { &fnv_test_str[18], (Fnv64_t) 0x08987c07b5420ebbULL }, + { &fnv_test_str[19], (Fnv64_t) 0xdcb28a18fed9f926ULL }, + { &fnv_test_str[20], (Fnv64_t) 0xdd1270790c25b935ULL }, + { &fnv_test_str[21], (Fnv64_t) 0xcac146afa2febf5dULL }, + { &fnv_test_str[22], (Fnv64_t) 0x8593d371f738acfeULL }, + { &fnv_test_str[23], (Fnv64_t) 0x34531ca7168b8f38ULL }, + { &fnv_test_str[24], (Fnv64_t) 0x08a25607b54a22aeULL }, + { &fnv_test_str[25], (Fnv64_t) 0xf5faf0190cf90df3ULL }, + { &fnv_test_str[26], (Fnv64_t) 0xf27397910b3221c7ULL }, + { &fnv_test_str[27], (Fnv64_t) 0x2c8c2b76062f22e0ULL }, + { &fnv_test_str[28], (Fnv64_t) 0xe150688c8217b8fdULL }, + { &fnv_test_str[29], (Fnv64_t) 0xf35a83c10e4f1f87ULL }, + { &fnv_test_str[30], (Fnv64_t) 0xd1edd10b507344d0ULL }, + { &fnv_test_str[31], (Fnv64_t) 0x2a5ee739b3ddb8c3ULL }, + { &fnv_test_str[32], (Fnv64_t) 0xdcfb970ca1c0d310ULL }, + { &fnv_test_str[33], (Fnv64_t) 0x4054da76daa6da90ULL }, + { &fnv_test_str[34], (Fnv64_t) 0xf70a2ff589861368ULL }, + { &fnv_test_str[35], (Fnv64_t) 0x4c628b38aed25f17ULL }, + { &fnv_test_str[36], (Fnv64_t) 0x9dd1f6510f78189fULL }, + { &fnv_test_str[37], (Fnv64_t) 0xa3de85bd491270ceULL }, + { &fnv_test_str[38], (Fnv64_t) 0x858e2fa32a55e61dULL }, + { &fnv_test_str[39], (Fnv64_t) 0x46810940eff5f915ULL }, + { &fnv_test_str[40], (Fnv64_t) 0xf5fadd190cf8edaaULL }, + { &fnv_test_str[41], (Fnv64_t) 0xf273ed910b32b3e9ULL }, + { &fnv_test_str[42], (Fnv64_t) 0x2c8c5276062f6525ULL }, + { &fnv_test_str[43], (Fnv64_t) 0xe150b98c821842a0ULL }, + { &fnv_test_str[44], (Fnv64_t) 0xf35aa3c10e4f55e7ULL }, + { &fnv_test_str[45], (Fnv64_t) 0xd1ed680b50729265ULL }, + { &fnv_test_str[46], (Fnv64_t) 0x2a5f0639b3dded70ULL }, + { &fnv_test_str[47], (Fnv64_t) 0xdcfbaa0ca1c0f359ULL }, + { &fnv_test_str[48], (Fnv64_t) 0x4054ba76daa6a430ULL }, + { &fnv_test_str[49], (Fnv64_t) 0xf709c7f5898562b0ULL }, + { &fnv_test_str[50], (Fnv64_t) 0x4c62e638aed2f9b8ULL }, + { &fnv_test_str[51], (Fnv64_t) 0x9dd1a8510f779415ULL }, + { &fnv_test_str[52], (Fnv64_t) 0xa3de2abd4911d62dULL }, + { &fnv_test_str[53], (Fnv64_t) 0x858e0ea32a55ae0aULL }, + { &fnv_test_str[54], (Fnv64_t) 0x46810f40eff60347ULL }, + { &fnv_test_str[55], (Fnv64_t) 0xc33bce57bef63eafULL }, + { &fnv_test_str[56], (Fnv64_t) 0x08a24307b54a0265ULL }, + { &fnv_test_str[57], (Fnv64_t) 0xf5b9fd190cc18d15ULL }, + { &fnv_test_str[58], (Fnv64_t) 0x4c968290ace35703ULL }, + { &fnv_test_str[59], (Fnv64_t) 0x07174bd5c64d9350ULL }, + { &fnv_test_str[60], (Fnv64_t) 0x5a294c3ff5d18750ULL }, + { &fnv_test_str[61], (Fnv64_t) 0x05b3c1aeb308b843ULL }, + { &fnv_test_str[62], (Fnv64_t) 0xb92a48da37d0f477ULL }, + { &fnv_test_str[63], (Fnv64_t) 0x73cdddccd80ebc49ULL }, + { &fnv_test_str[64], (Fnv64_t) 0xd58c4c13210a266bULL }, + { &fnv_test_str[65], (Fnv64_t) 0xe78b6081243ec194ULL }, + { &fnv_test_str[66], (Fnv64_t) 0xb096f77096a39f34ULL }, + { &fnv_test_str[67], (Fnv64_t) 0xb425c54ff807b6a3ULL }, + { &fnv_test_str[68], (Fnv64_t) 0x23e520e2751bb46eULL }, + { &fnv_test_str[69], (Fnv64_t) 0x1a0b44ccfe1385ecULL }, + { &fnv_test_str[70], (Fnv64_t) 0xf5ba4b190cc2119fULL }, + { &fnv_test_str[71], (Fnv64_t) 0x4c962690ace2baafULL }, + { &fnv_test_str[72], (Fnv64_t) 0x0716ded5c64cda19ULL }, + { &fnv_test_str[73], (Fnv64_t) 0x5a292c3ff5d150f0ULL }, + { &fnv_test_str[74], (Fnv64_t) 0x05b3e0aeb308ecf0ULL }, + { &fnv_test_str[75], (Fnv64_t) 0xb92a5eda37d119d9ULL }, + { &fnv_test_str[76], (Fnv64_t) 0x73ce41ccd80f6635ULL }, + { &fnv_test_str[77], (Fnv64_t) 0xd58c2c132109f00bULL }, + { &fnv_test_str[78], (Fnv64_t) 0xe78baf81243f47d1ULL }, + { &fnv_test_str[79], (Fnv64_t) 0xb0968f7096a2ee7cULL }, + { &fnv_test_str[80], (Fnv64_t) 0xb425a84ff807855cULL }, + { &fnv_test_str[81], (Fnv64_t) 0x23e4e9e2751b56f9ULL }, + { &fnv_test_str[82], (Fnv64_t) 0x1a0b4eccfe1396eaULL }, + { &fnv_test_str[83], (Fnv64_t) 0x54abd453bb2c9004ULL }, + { &fnv_test_str[84], (Fnv64_t) 0x08ba5f07b55ec3daULL }, + { &fnv_test_str[85], (Fnv64_t) 0x337354193006cb6eULL }, + { &fnv_test_str[86], (Fnv64_t) 0xa430d84680aabd0bULL }, + { &fnv_test_str[87], (Fnv64_t) 0xa9bc8acca21f39b1ULL }, + { &fnv_test_str[88], (Fnv64_t) 0x6961196491cc682dULL }, + { &fnv_test_str[89], (Fnv64_t) 0xad2bb1774799dfe9ULL }, + { &fnv_test_str[90], (Fnv64_t) 0x6961166491cc6314ULL }, + { &fnv_test_str[91], (Fnv64_t) 0x8d1bb3904a3b1236ULL }, + { &fnv_test_str[92], (Fnv64_t) 0x6961176491cc64c7ULL }, + { &fnv_test_str[93], (Fnv64_t) 0xed205d87f40434c7ULL }, + { &fnv_test_str[94], (Fnv64_t) 0x6961146491cc5faeULL }, + { &fnv_test_str[95], (Fnv64_t) 0xcd3baf5e44f8ad9cULL }, + { &fnv_test_str[96], (Fnv64_t) 0xe3b36596127cd6d8ULL }, + { &fnv_test_str[97], (Fnv64_t) 0xf77f1072c8e8a646ULL }, + { &fnv_test_str[98], (Fnv64_t) 0xe3b36396127cd372ULL }, + { &fnv_test_str[99], (Fnv64_t) 0x6067dce9932ad458ULL }, + { &fnv_test_str[100], (Fnv64_t) 0xe3b37596127cf208ULL }, + { &fnv_test_str[101], (Fnv64_t) 0x4b7b10fa9fe83936ULL }, + { &fnv_test_str[102], (Fnv64_t) 0xaabafe7104d914beULL }, + { &fnv_test_str[103], (Fnv64_t) 0xf4d3180b3cde3edaULL }, + { &fnv_test_str[104], (Fnv64_t) 0xaabafd7104d9130bULL }, + { &fnv_test_str[105], (Fnv64_t) 0xf4cfb20b3cdb5bb1ULL }, + { &fnv_test_str[106], (Fnv64_t) 0xaabafc7104d91158ULL }, + { &fnv_test_str[107], (Fnv64_t) 0xf4cc4c0b3cd87888ULL }, + { &fnv_test_str[108], (Fnv64_t) 0xe729bac5d2a8d3a7ULL }, + { &fnv_test_str[109], (Fnv64_t) 0x74bc0524f4dfa4c5ULL }, + { &fnv_test_str[110], (Fnv64_t) 0xe72630c5d2a5b352ULL }, + { &fnv_test_str[111], (Fnv64_t) 0x6b983224ef8fb456ULL }, + { &fnv_test_str[112], (Fnv64_t) 0xe73042c5d2ae266dULL }, + { &fnv_test_str[113], (Fnv64_t) 0x8527e324fdeb4b37ULL }, + { &fnv_test_str[114], (Fnv64_t) 0x0a83c86fee952abcULL }, + { &fnv_test_str[115], (Fnv64_t) 0x7318523267779d74ULL }, + { &fnv_test_str[116], (Fnv64_t) 0x3e66d3d56b8caca1ULL }, + { &fnv_test_str[117], (Fnv64_t) 0x956694a5c0095593ULL }, + { &fnv_test_str[118], (Fnv64_t) 0xcac54572bb1a6fc8ULL }, + { &fnv_test_str[119], (Fnv64_t) 0xa7a4c9f3edebf0d8ULL }, + { &fnv_test_str[120], (Fnv64_t) 0x7829851fac17b143ULL }, + { &fnv_test_str[121], (Fnv64_t) 0x2c8f4c9af81bcf06ULL }, + { &fnv_test_str[122], (Fnv64_t) 0xd34e31539740c732ULL }, + { &fnv_test_str[123], (Fnv64_t) 0x3605a2ac253d2db1ULL }, + { &fnv_test_str[124], (Fnv64_t) 0x08c11b8346f4a3c3ULL }, + { &fnv_test_str[125], (Fnv64_t) 0x6be396289ce8a6daULL }, + { &fnv_test_str[126], (Fnv64_t) 0xd9b957fb7fe794c5ULL }, + { &fnv_test_str[127], (Fnv64_t) 0x05be33da04560a93ULL }, + { &fnv_test_str[128], (Fnv64_t) 0x0957f1577ba9747cULL }, + { &fnv_test_str[129], (Fnv64_t) 0xda2cc3acc24fba57ULL }, + { &fnv_test_str[130], (Fnv64_t) 0x74136f185b29e7f0ULL }, + { &fnv_test_str[131], (Fnv64_t) 0xb2f2b4590edb93b2ULL }, + { &fnv_test_str[132], (Fnv64_t) 0xb3608fce8b86ae04ULL }, + { &fnv_test_str[133], (Fnv64_t) 0x4a3a865079359063ULL }, + { &fnv_test_str[134], (Fnv64_t) 0x5b3a7ef496880a50ULL }, + { &fnv_test_str[135], (Fnv64_t) 0x48fae3163854c23bULL }, + { &fnv_test_str[136], (Fnv64_t) 0x07aaa640476e0b9aULL }, + { &fnv_test_str[137], (Fnv64_t) 0x2f653656383a687dULL }, + { &fnv_test_str[138], (Fnv64_t) 0xa1031f8e7599d79cULL }, + { &fnv_test_str[139], (Fnv64_t) 0xa31908178ff92477ULL }, + { &fnv_test_str[140], (Fnv64_t) 0x097edf3c14c3fb83ULL }, + { &fnv_test_str[141], (Fnv64_t) 0xb51ca83feaa0971bULL }, + { &fnv_test_str[142], (Fnv64_t) 0xdd3c0d96d784f2e9ULL }, + { &fnv_test_str[143], (Fnv64_t) 0x86cd26a9ea767d78ULL }, + { &fnv_test_str[144], (Fnv64_t) 0xe6b215ff54a30c18ULL }, + { &fnv_test_str[145], (Fnv64_t) 0xec5b06a1c5531093ULL }, + { &fnv_test_str[146], (Fnv64_t) 0x45665a929f9ec5e5ULL }, + { &fnv_test_str[147], (Fnv64_t) 0x8c7609b4a9f10907ULL }, + { &fnv_test_str[148], (Fnv64_t) 0x89aac3a491f0d729ULL }, + { &fnv_test_str[149], (Fnv64_t) 0x32ce6b26e0f4a403ULL }, + { &fnv_test_str[150], (Fnv64_t) 0x614ab44e02b53e01ULL }, + { &fnv_test_str[151], (Fnv64_t) 0xfa6472eb6eef3290ULL }, + { &fnv_test_str[152], (Fnv64_t) 0x9e5d75eb1948eb6aULL }, + { &fnv_test_str[153], (Fnv64_t) 0xb6d12ad4a8671852ULL }, + { &fnv_test_str[154], (Fnv64_t) 0x88826f56eba07af1ULL }, + { &fnv_test_str[155], (Fnv64_t) 0x44535bf2645bc0fdULL }, + { &fnv_test_str[156], (Fnv64_t) 0x169388ffc21e3728ULL }, + { &fnv_test_str[157], (Fnv64_t) 0xf68aac9e396d8224ULL }, + { &fnv_test_str[158], (Fnv64_t) 0x8e87d7e7472b3883ULL }, + { &fnv_test_str[159], (Fnv64_t) 0x295c26caa8b423deULL }, + { &fnv_test_str[160], (Fnv64_t) 0x322c814292e72176ULL }, + { &fnv_test_str[161], (Fnv64_t) 0x8a06550eb8af7268ULL }, + { &fnv_test_str[162], (Fnv64_t) 0xef86d60e661bcf71ULL }, + { &fnv_test_str[163], (Fnv64_t) 0x9e5426c87f30ee54ULL }, + { &fnv_test_str[164], (Fnv64_t) 0xf1ea8aa826fd047eULL }, + { &fnv_test_str[165], (Fnv64_t) 0x0babaf9a642cb769ULL }, + { &fnv_test_str[166], (Fnv64_t) 0x4b3341d4068d012eULL }, + { &fnv_test_str[167], (Fnv64_t) 0xd15605cbc30a335cULL }, + { &fnv_test_str[168], (Fnv64_t) 0x5b21060aed8412e5ULL }, + { &fnv_test_str[169], (Fnv64_t) 0x45e2cda1ce6f4227ULL }, + { &fnv_test_str[170], (Fnv64_t) 0x50ae3745033ad7d4ULL }, + { &fnv_test_str[171], (Fnv64_t) 0xaa4588ced46bf414ULL }, + { &fnv_test_str[172], (Fnv64_t) 0xc1b0056c4a95467eULL }, + { &fnv_test_str[173], (Fnv64_t) 0x56576a71de8b4089ULL }, + { &fnv_test_str[174], (Fnv64_t) 0xbf20965fa6dc927eULL }, + { &fnv_test_str[175], (Fnv64_t) 0x569f8383c2040882ULL }, + { &fnv_test_str[176], (Fnv64_t) 0xe1e772fba08feca0ULL }, + { &fnv_test_str[177], (Fnv64_t) 0x4ced94af97138ac4ULL }, + { &fnv_test_str[178], (Fnv64_t) 0xc4112ffb337a82fbULL }, + { &fnv_test_str[179], (Fnv64_t) 0xd64a4fd41de38b7dULL }, + { &fnv_test_str[180], (Fnv64_t) 0x4cfc32329edebcbbULL }, + { &fnv_test_str[181], (Fnv64_t) 0x0803564445050395ULL }, + { &fnv_test_str[182], (Fnv64_t) 0xaa1574ecf4642ffdULL }, + { &fnv_test_str[183], (Fnv64_t) 0x694bc4e54cc315f9ULL }, + { &fnv_test_str[184], (Fnv64_t) 0xa3d7cb273b011721ULL }, + { &fnv_test_str[185], (Fnv64_t) 0x577c2f8b6115bfa5ULL }, + { &fnv_test_str[186], (Fnv64_t) 0xb7ec8c1a769fb4c1ULL }, + { &fnv_test_str[187], (Fnv64_t) 0x5d5cfce63359ab19ULL }, + { &fnv_test_str[188], (Fnv64_t) 0x33b96c3cd65b5f71ULL }, + { &fnv_test_str[189], (Fnv64_t) 0xd845097780602bb9ULL }, + { &fnv_test_str[190], (Fnv64_t) 0x84d47645d02da3d5ULL }, + { &fnv_test_str[191], (Fnv64_t) 0x83544f33b58773a5ULL }, + { &fnv_test_str[192], (Fnv64_t) 0x9175cbb2160836c5ULL }, + { &fnv_test_str[193], (Fnv64_t) 0xc71b3bc175e72bc5ULL }, + { &fnv_test_str[194], (Fnv64_t) 0x636806ac222ec985ULL }, + { &fnv_test_str[195], (Fnv64_t) 0xb6ef0e6950f52ed5ULL }, + { &fnv_test_str[196], (Fnv64_t) 0xead3d8a0f3dfdaa5ULL }, + { &fnv_test_str[197], (Fnv64_t) 0x922908fe9a861ba5ULL }, + { &fnv_test_str[198], (Fnv64_t) 0x6d4821de275fd5c5ULL }, + { &fnv_test_str[199], (Fnv64_t) 0x1fe3fce62bd816b5ULL }, + { &fnv_test_str[200], (Fnv64_t) 0xc23e9fccd6f70591ULL }, + { &fnv_test_str[201], (Fnv64_t) 0xc1af12bdfe16b5b5ULL }, + { &fnv_test_str[202], (Fnv64_t) 0x39e9f18f2f85e221ULL }, + { NULL, (Fnv64_t) 0 } +}; +#else /* HAVE_64BIT_LONG_LONG */ +struct fnv1a_64_test_vector fnv1a_64_vector[] = { + { &fnv_test_str[0], (Fnv64_t) {0x84222325UL, 0xcbf29ce4UL} }, + { &fnv_test_str[1], (Fnv64_t) {0x8601ec8cUL, 0xaf63dc4cUL} }, + { &fnv_test_str[2], (Fnv64_t) {0x8601f1a5UL, 0xaf63df4cUL} }, + { &fnv_test_str[3], (Fnv64_t) {0x8601eff2UL, 0xaf63de4cUL} }, + { &fnv_test_str[4], (Fnv64_t) {0x8601e773UL, 0xaf63d94cUL} }, + { &fnv_test_str[5], (Fnv64_t) {0x8601e5c0UL, 0xaf63d84cUL} }, + { &fnv_test_str[6], (Fnv64_t) {0x8601ead9UL, 0xaf63db4cUL} }, + { &fnv_test_str[7], (Fnv64_t) {0xb541d342UL, 0x08985907UL} }, + { &fnv_test_str[8], (Fnv64_t) {0xfed9d577UL, 0xdcb27518UL} }, + { &fnv_test_str[9], (Fnv64_t) {0x0c2512afUL, 0xdd120e79UL} }, + { &fnv_test_str[10], (Fnv64_t) {0xa2fef40aUL, 0xcac165afUL} }, + { &fnv_test_str[11], (Fnv64_t) {0xf73967e8UL, 0x85944171UL} }, + { &fnv_test_str[12], (Fnv64_t) {0x8601b7dfUL, 0xaf63bd4cUL} }, + { &fnv_test_str[13], (Fnv64_t) {0xb544f1e4UL, 0x089be207UL} }, + { &fnv_test_str[14], (Fnv64_t) {0xb54d9b5fUL, 0x08a61407UL} }, + { &fnv_test_str[15], (Fnv64_t) {0xb54ab836UL, 0x08a2ae07UL} }, + { &fnv_test_str[16], (Fnv64_t) {0xb53c4869UL, 0x0891b007UL} }, + { &fnv_test_str[17], (Fnv64_t) {0xb5396540UL, 0x088e4a07UL} }, + { &fnv_test_str[18], (Fnv64_t) {0xb5420ebbUL, 0x08987c07UL} }, + { &fnv_test_str[19], (Fnv64_t) {0xfed9f926UL, 0xdcb28a18UL} }, + { &fnv_test_str[20], (Fnv64_t) {0x0c25b935UL, 0xdd127079UL} }, + { &fnv_test_str[21], (Fnv64_t) {0xa2febf5dUL, 0xcac146afUL} }, + { &fnv_test_str[22], (Fnv64_t) {0xf738acfeUL, 0x8593d371UL} }, + { &fnv_test_str[23], (Fnv64_t) {0x168b8f38UL, 0x34531ca7UL} }, + { &fnv_test_str[24], (Fnv64_t) {0xb54a22aeUL, 0x08a25607UL} }, + { &fnv_test_str[25], (Fnv64_t) {0x0cf90df3UL, 0xf5faf019UL} }, + { &fnv_test_str[26], (Fnv64_t) {0x0b3221c7UL, 0xf2739791UL} }, + { &fnv_test_str[27], (Fnv64_t) {0x062f22e0UL, 0x2c8c2b76UL} }, + { &fnv_test_str[28], (Fnv64_t) {0x8217b8fdUL, 0xe150688cUL} }, + { &fnv_test_str[29], (Fnv64_t) {0x0e4f1f87UL, 0xf35a83c1UL} }, + { &fnv_test_str[30], (Fnv64_t) {0x507344d0UL, 0xd1edd10bUL} }, + { &fnv_test_str[31], (Fnv64_t) {0xb3ddb8c3UL, 0x2a5ee739UL} }, + { &fnv_test_str[32], (Fnv64_t) {0xa1c0d310UL, 0xdcfb970cUL} }, + { &fnv_test_str[33], (Fnv64_t) {0xdaa6da90UL, 0x4054da76UL} }, + { &fnv_test_str[34], (Fnv64_t) {0x89861368UL, 0xf70a2ff5UL} }, + { &fnv_test_str[35], (Fnv64_t) {0xaed25f17UL, 0x4c628b38UL} }, + { &fnv_test_str[36], (Fnv64_t) {0x0f78189fUL, 0x9dd1f651UL} }, + { &fnv_test_str[37], (Fnv64_t) {0x491270ceUL, 0xa3de85bdUL} }, + { &fnv_test_str[38], (Fnv64_t) {0x2a55e61dUL, 0x858e2fa3UL} }, + { &fnv_test_str[39], (Fnv64_t) {0xeff5f915UL, 0x46810940UL} }, + { &fnv_test_str[40], (Fnv64_t) {0x0cf8edaaUL, 0xf5fadd19UL} }, + { &fnv_test_str[41], (Fnv64_t) {0x0b32b3e9UL, 0xf273ed91UL} }, + { &fnv_test_str[42], (Fnv64_t) {0x062f6525UL, 0x2c8c5276UL} }, + { &fnv_test_str[43], (Fnv64_t) {0x821842a0UL, 0xe150b98cUL} }, + { &fnv_test_str[44], (Fnv64_t) {0x0e4f55e7UL, 0xf35aa3c1UL} }, + { &fnv_test_str[45], (Fnv64_t) {0x50729265UL, 0xd1ed680bUL} }, + { &fnv_test_str[46], (Fnv64_t) {0xb3dded70UL, 0x2a5f0639UL} }, + { &fnv_test_str[47], (Fnv64_t) {0xa1c0f359UL, 0xdcfbaa0cUL} }, + { &fnv_test_str[48], (Fnv64_t) {0xdaa6a430UL, 0x4054ba76UL} }, + { &fnv_test_str[49], (Fnv64_t) {0x898562b0UL, 0xf709c7f5UL} }, + { &fnv_test_str[50], (Fnv64_t) {0xaed2f9b8UL, 0x4c62e638UL} }, + { &fnv_test_str[51], (Fnv64_t) {0x0f779415UL, 0x9dd1a851UL} }, + { &fnv_test_str[52], (Fnv64_t) {0x4911d62dUL, 0xa3de2abdUL} }, + { &fnv_test_str[53], (Fnv64_t) {0x2a55ae0aUL, 0x858e0ea3UL} }, + { &fnv_test_str[54], (Fnv64_t) {0xeff60347UL, 0x46810f40UL} }, + { &fnv_test_str[55], (Fnv64_t) {0xbef63eafUL, 0xc33bce57UL} }, + { &fnv_test_str[56], (Fnv64_t) {0xb54a0265UL, 0x08a24307UL} }, + { &fnv_test_str[57], (Fnv64_t) {0x0cc18d15UL, 0xf5b9fd19UL} }, + { &fnv_test_str[58], (Fnv64_t) {0xace35703UL, 0x4c968290UL} }, + { &fnv_test_str[59], (Fnv64_t) {0xc64d9350UL, 0x07174bd5UL} }, + { &fnv_test_str[60], (Fnv64_t) {0xf5d18750UL, 0x5a294c3fUL} }, + { &fnv_test_str[61], (Fnv64_t) {0xb308b843UL, 0x05b3c1aeUL} }, + { &fnv_test_str[62], (Fnv64_t) {0x37d0f477UL, 0xb92a48daUL} }, + { &fnv_test_str[63], (Fnv64_t) {0xd80ebc49UL, 0x73cdddccUL} }, + { &fnv_test_str[64], (Fnv64_t) {0x210a266bUL, 0xd58c4c13UL} }, + { &fnv_test_str[65], (Fnv64_t) {0x243ec194UL, 0xe78b6081UL} }, + { &fnv_test_str[66], (Fnv64_t) {0x96a39f34UL, 0xb096f770UL} }, + { &fnv_test_str[67], (Fnv64_t) {0xf807b6a3UL, 0xb425c54fUL} }, + { &fnv_test_str[68], (Fnv64_t) {0x751bb46eUL, 0x23e520e2UL} }, + { &fnv_test_str[69], (Fnv64_t) {0xfe1385ecUL, 0x1a0b44ccUL} }, + { &fnv_test_str[70], (Fnv64_t) {0x0cc2119fUL, 0xf5ba4b19UL} }, + { &fnv_test_str[71], (Fnv64_t) {0xace2baafUL, 0x4c962690UL} }, + { &fnv_test_str[72], (Fnv64_t) {0xc64cda19UL, 0x0716ded5UL} }, + { &fnv_test_str[73], (Fnv64_t) {0xf5d150f0UL, 0x5a292c3fUL} }, + { &fnv_test_str[74], (Fnv64_t) {0xb308ecf0UL, 0x05b3e0aeUL} }, + { &fnv_test_str[75], (Fnv64_t) {0x37d119d9UL, 0xb92a5edaUL} }, + { &fnv_test_str[76], (Fnv64_t) {0xd80f6635UL, 0x73ce41ccUL} }, + { &fnv_test_str[77], (Fnv64_t) {0x2109f00bUL, 0xd58c2c13UL} }, + { &fnv_test_str[78], (Fnv64_t) {0x243f47d1UL, 0xe78baf81UL} }, + { &fnv_test_str[79], (Fnv64_t) {0x96a2ee7cUL, 0xb0968f70UL} }, + { &fnv_test_str[80], (Fnv64_t) {0xf807855cUL, 0xb425a84fUL} }, + { &fnv_test_str[81], (Fnv64_t) {0x751b56f9UL, 0x23e4e9e2UL} }, + { &fnv_test_str[82], (Fnv64_t) {0xfe1396eaUL, 0x1a0b4eccUL} }, + { &fnv_test_str[83], (Fnv64_t) {0xbb2c9004UL, 0x54abd453UL} }, + { &fnv_test_str[84], (Fnv64_t) {0xb55ec3daUL, 0x08ba5f07UL} }, + { &fnv_test_str[85], (Fnv64_t) {0x3006cb6eUL, 0x33735419UL} }, + { &fnv_test_str[86], (Fnv64_t) {0x80aabd0bUL, 0xa430d846UL} }, + { &fnv_test_str[87], (Fnv64_t) {0xa21f39b1UL, 0xa9bc8accUL} }, + { &fnv_test_str[88], (Fnv64_t) {0x91cc682dUL, 0x69611964UL} }, + { &fnv_test_str[89], (Fnv64_t) {0x4799dfe9UL, 0xad2bb177UL} }, + { &fnv_test_str[90], (Fnv64_t) {0x91cc6314UL, 0x69611664UL} }, + { &fnv_test_str[91], (Fnv64_t) {0x4a3b1236UL, 0x8d1bb390UL} }, + { &fnv_test_str[92], (Fnv64_t) {0x91cc64c7UL, 0x69611764UL} }, + { &fnv_test_str[93], (Fnv64_t) {0xf40434c7UL, 0xed205d87UL} }, + { &fnv_test_str[94], (Fnv64_t) {0x91cc5faeUL, 0x69611464UL} }, + { &fnv_test_str[95], (Fnv64_t) {0x44f8ad9cUL, 0xcd3baf5eUL} }, + { &fnv_test_str[96], (Fnv64_t) {0x127cd6d8UL, 0xe3b36596UL} }, + { &fnv_test_str[97], (Fnv64_t) {0xc8e8a646UL, 0xf77f1072UL} }, + { &fnv_test_str[98], (Fnv64_t) {0x127cd372UL, 0xe3b36396UL} }, + { &fnv_test_str[99], (Fnv64_t) {0x932ad458UL, 0x6067dce9UL} }, + { &fnv_test_str[100], (Fnv64_t) {0x127cf208UL, 0xe3b37596UL} }, + { &fnv_test_str[101], (Fnv64_t) {0x9fe83936UL, 0x4b7b10faUL} }, + { &fnv_test_str[102], (Fnv64_t) {0x04d914beUL, 0xaabafe71UL} }, + { &fnv_test_str[103], (Fnv64_t) {0x3cde3edaUL, 0xf4d3180bUL} }, + { &fnv_test_str[104], (Fnv64_t) {0x04d9130bUL, 0xaabafd71UL} }, + { &fnv_test_str[105], (Fnv64_t) {0x3cdb5bb1UL, 0xf4cfb20bUL} }, + { &fnv_test_str[106], (Fnv64_t) {0x04d91158UL, 0xaabafc71UL} }, + { &fnv_test_str[107], (Fnv64_t) {0x3cd87888UL, 0xf4cc4c0bUL} }, + { &fnv_test_str[108], (Fnv64_t) {0xd2a8d3a7UL, 0xe729bac5UL} }, + { &fnv_test_str[109], (Fnv64_t) {0xf4dfa4c5UL, 0x74bc0524UL} }, + { &fnv_test_str[110], (Fnv64_t) {0xd2a5b352UL, 0xe72630c5UL} }, + { &fnv_test_str[111], (Fnv64_t) {0xef8fb456UL, 0x6b983224UL} }, + { &fnv_test_str[112], (Fnv64_t) {0xd2ae266dUL, 0xe73042c5UL} }, + { &fnv_test_str[113], (Fnv64_t) {0xfdeb4b37UL, 0x8527e324UL} }, + { &fnv_test_str[114], (Fnv64_t) {0xee952abcUL, 0x0a83c86fUL} }, + { &fnv_test_str[115], (Fnv64_t) {0x67779d74UL, 0x73185232UL} }, + { &fnv_test_str[116], (Fnv64_t) {0x6b8caca1UL, 0x3e66d3d5UL} }, + { &fnv_test_str[117], (Fnv64_t) {0xc0095593UL, 0x956694a5UL} }, + { &fnv_test_str[118], (Fnv64_t) {0xbb1a6fc8UL, 0xcac54572UL} }, + { &fnv_test_str[119], (Fnv64_t) {0xedebf0d8UL, 0xa7a4c9f3UL} }, + { &fnv_test_str[120], (Fnv64_t) {0xac17b143UL, 0x7829851fUL} }, + { &fnv_test_str[121], (Fnv64_t) {0xf81bcf06UL, 0x2c8f4c9aUL} }, + { &fnv_test_str[122], (Fnv64_t) {0x9740c732UL, 0xd34e3153UL} }, + { &fnv_test_str[123], (Fnv64_t) {0x253d2db1UL, 0x3605a2acUL} }, + { &fnv_test_str[124], (Fnv64_t) {0x46f4a3c3UL, 0x08c11b83UL} }, + { &fnv_test_str[125], (Fnv64_t) {0x9ce8a6daUL, 0x6be39628UL} }, + { &fnv_test_str[126], (Fnv64_t) {0x7fe794c5UL, 0xd9b957fbUL} }, + { &fnv_test_str[127], (Fnv64_t) {0x04560a93UL, 0x05be33daUL} }, + { &fnv_test_str[128], (Fnv64_t) {0x7ba9747cUL, 0x0957f157UL} }, + { &fnv_test_str[129], (Fnv64_t) {0xc24fba57UL, 0xda2cc3acUL} }, + { &fnv_test_str[130], (Fnv64_t) {0x5b29e7f0UL, 0x74136f18UL} }, + { &fnv_test_str[131], (Fnv64_t) {0x0edb93b2UL, 0xb2f2b459UL} }, + { &fnv_test_str[132], (Fnv64_t) {0x8b86ae04UL, 0xb3608fceUL} }, + { &fnv_test_str[133], (Fnv64_t) {0x79359063UL, 0x4a3a8650UL} }, + { &fnv_test_str[134], (Fnv64_t) {0x96880a50UL, 0x5b3a7ef4UL} }, + { &fnv_test_str[135], (Fnv64_t) {0x3854c23bUL, 0x48fae316UL} }, + { &fnv_test_str[136], (Fnv64_t) {0x476e0b9aUL, 0x07aaa640UL} }, + { &fnv_test_str[137], (Fnv64_t) {0x383a687dUL, 0x2f653656UL} }, + { &fnv_test_str[138], (Fnv64_t) {0x7599d79cUL, 0xa1031f8eUL} }, + { &fnv_test_str[139], (Fnv64_t) {0x8ff92477UL, 0xa3190817UL} }, + { &fnv_test_str[140], (Fnv64_t) {0x14c3fb83UL, 0x097edf3cUL} }, + { &fnv_test_str[141], (Fnv64_t) {0xeaa0971bUL, 0xb51ca83fUL} }, + { &fnv_test_str[142], (Fnv64_t) {0xd784f2e9UL, 0xdd3c0d96UL} }, + { &fnv_test_str[143], (Fnv64_t) {0xea767d78UL, 0x86cd26a9UL} }, + { &fnv_test_str[144], (Fnv64_t) {0x54a30c18UL, 0xe6b215ffUL} }, + { &fnv_test_str[145], (Fnv64_t) {0xc5531093UL, 0xec5b06a1UL} }, + { &fnv_test_str[146], (Fnv64_t) {0x9f9ec5e5UL, 0x45665a92UL} }, + { &fnv_test_str[147], (Fnv64_t) {0xa9f10907UL, 0x8c7609b4UL} }, + { &fnv_test_str[148], (Fnv64_t) {0x91f0d729UL, 0x89aac3a4UL} }, + { &fnv_test_str[149], (Fnv64_t) {0xe0f4a403UL, 0x32ce6b26UL} }, + { &fnv_test_str[150], (Fnv64_t) {0x02b53e01UL, 0x614ab44eUL} }, + { &fnv_test_str[151], (Fnv64_t) {0x6eef3290UL, 0xfa6472ebUL} }, + { &fnv_test_str[152], (Fnv64_t) {0x1948eb6aUL, 0x9e5d75ebUL} }, + { &fnv_test_str[153], (Fnv64_t) {0xa8671852UL, 0xb6d12ad4UL} }, + { &fnv_test_str[154], (Fnv64_t) {0xeba07af1UL, 0x88826f56UL} }, + { &fnv_test_str[155], (Fnv64_t) {0x645bc0fdUL, 0x44535bf2UL} }, + { &fnv_test_str[156], (Fnv64_t) {0xc21e3728UL, 0x169388ffUL} }, + { &fnv_test_str[157], (Fnv64_t) {0x396d8224UL, 0xf68aac9eUL} }, + { &fnv_test_str[158], (Fnv64_t) {0x472b3883UL, 0x8e87d7e7UL} }, + { &fnv_test_str[159], (Fnv64_t) {0xa8b423deUL, 0x295c26caUL} }, + { &fnv_test_str[160], (Fnv64_t) {0x92e72176UL, 0x322c8142UL} }, + { &fnv_test_str[161], (Fnv64_t) {0xb8af7268UL, 0x8a06550eUL} }, + { &fnv_test_str[162], (Fnv64_t) {0x661bcf71UL, 0xef86d60eUL} }, + { &fnv_test_str[163], (Fnv64_t) {0x7f30ee54UL, 0x9e5426c8UL} }, + { &fnv_test_str[164], (Fnv64_t) {0x26fd047eUL, 0xf1ea8aa8UL} }, + { &fnv_test_str[165], (Fnv64_t) {0x642cb769UL, 0x0babaf9aUL} }, + { &fnv_test_str[166], (Fnv64_t) {0x068d012eUL, 0x4b3341d4UL} }, + { &fnv_test_str[167], (Fnv64_t) {0xc30a335cUL, 0xd15605cbUL} }, + { &fnv_test_str[168], (Fnv64_t) {0xed8412e5UL, 0x5b21060aUL} }, + { &fnv_test_str[169], (Fnv64_t) {0xce6f4227UL, 0x45e2cda1UL} }, + { &fnv_test_str[170], (Fnv64_t) {0x033ad7d4UL, 0x50ae3745UL} }, + { &fnv_test_str[171], (Fnv64_t) {0xd46bf414UL, 0xaa4588ceUL} }, + { &fnv_test_str[172], (Fnv64_t) {0x4a95467eUL, 0xc1b0056cUL} }, + { &fnv_test_str[173], (Fnv64_t) {0xde8b4089UL, 0x56576a71UL} }, + { &fnv_test_str[174], (Fnv64_t) {0xa6dc927eUL, 0xbf20965fUL} }, + { &fnv_test_str[175], (Fnv64_t) {0xc2040882UL, 0x569f8383UL} }, + { &fnv_test_str[176], (Fnv64_t) {0xa08feca0UL, 0xe1e772fbUL} }, + { &fnv_test_str[177], (Fnv64_t) {0x97138ac4UL, 0x4ced94afUL} }, + { &fnv_test_str[178], (Fnv64_t) {0x337a82fbUL, 0xc4112ffbUL} }, + { &fnv_test_str[179], (Fnv64_t) {0x1de38b7dUL, 0xd64a4fd4UL} }, + { &fnv_test_str[180], (Fnv64_t) {0x9edebcbbUL, 0x4cfc3232UL} }, + { &fnv_test_str[181], (Fnv64_t) {0x45050395UL, 0x08035644UL} }, + { &fnv_test_str[182], (Fnv64_t) {0xf4642ffdUL, 0xaa1574ecUL} }, + { &fnv_test_str[183], (Fnv64_t) {0x4cc315f9UL, 0x694bc4e5UL} }, + { &fnv_test_str[184], (Fnv64_t) {0x3b011721UL, 0xa3d7cb27UL} }, + { &fnv_test_str[185], (Fnv64_t) {0x6115bfa5UL, 0x577c2f8bUL} }, + { &fnv_test_str[186], (Fnv64_t) {0x769fb4c1UL, 0xb7ec8c1aUL} }, + { &fnv_test_str[187], (Fnv64_t) {0x3359ab19UL, 0x5d5cfce6UL} }, + { &fnv_test_str[188], (Fnv64_t) {0xd65b5f71UL, 0x33b96c3cUL} }, + { &fnv_test_str[189], (Fnv64_t) {0x80602bb9UL, 0xd8450977UL} }, + { &fnv_test_str[190], (Fnv64_t) {0xd02da3d5UL, 0x84d47645UL} }, + { &fnv_test_str[191], (Fnv64_t) {0xb58773a5UL, 0x83544f33UL} }, + { &fnv_test_str[192], (Fnv64_t) {0x160836c5UL, 0x9175cbb2UL} }, + { &fnv_test_str[193], (Fnv64_t) {0x75e72bc5UL, 0xc71b3bc1UL} }, + { &fnv_test_str[194], (Fnv64_t) {0x222ec985UL, 0x636806acUL} }, + { &fnv_test_str[195], (Fnv64_t) {0x50f52ed5UL, 0xb6ef0e69UL} }, + { &fnv_test_str[196], (Fnv64_t) {0xf3dfdaa5UL, 0xead3d8a0UL} }, + { &fnv_test_str[197], (Fnv64_t) {0x9a861ba5UL, 0x922908feUL} }, + { &fnv_test_str[198], (Fnv64_t) {0x275fd5c5UL, 0x6d4821deUL} }, + { &fnv_test_str[199], (Fnv64_t) {0x2bd816b5UL, 0x1fe3fce6UL} }, + { &fnv_test_str[200], (Fnv64_t) {0xd6f70591UL, 0xc23e9fccUL} }, + { &fnv_test_str[201], (Fnv64_t) {0xfe16b5b5UL, 0xc1af12bdUL} }, + { &fnv_test_str[202], (Fnv64_t) {0x2f85e221UL, 0x39e9f18fUL} }, + { NULL, (Fnv64_t) {0,0} } +}; +#endif /* HAVE_64BIT_LONG_LONG */ + +/* end of output generated by make vector.c */ +/* + * insert the contents of vector.c above + */ + + +/* + * unknown_hash_type - report an unknown hash type error + * + * NOTE: Does not return. + */ +void +unknown_hash_type(char *prog, enum fnv_type type, int code) +{ + fprintf(stderr, "%s: unknown or unexpexted hash type: %d\n", prog, type); + exit(code); +} + + +/* + * print_fnv32 - print an FNV hash + * + * given: + * hval the hash value to print + * mask lower bit mask + * verbose 1 => print arg with hash + * arg string or filename arg + */ +void +print_fnv32(Fnv32_t hval, Fnv32_t mask, int verbose, char *arg) +{ + if (verbose) { + printf("0x%08lx %s\n", hval & mask, arg); + } else { + printf("0x%08lx\n", hval & mask); + } +} + + +/* + * print_fnv64 - print an FNV hash + * + * given: + * hval the hash value to print + * mask lower bit mask + * verbose 1 => print arg with hash + * arg string or filename arg + */ +void +print_fnv64(Fnv64_t hval, Fnv64_t mask, int verbose, char *arg) +{ +#if defined(HAVE_64BIT_LONG_LONG) + if (verbose) { + printf("0x%016llx %s\n", hval & mask, arg); + } else { + printf("0x%016llx\n", hval & mask); + } +#else + if (verbose) { + printf("0x%08lx%08lx %s\n", + hval.w32[1] & mask.w32[1], + hval.w32[0] & mask.w32[0], + arg); + } else { + printf("0x%08lx%08lx\n", + hval.w32[1] & mask.w32[1], + hval.w32[0] & mask.w32[0]); + } +#endif +} diff --git a/quantum/wear_leveling/tests/backing_mocks.cpp b/quantum/wear_leveling/tests/backing_mocks.cpp new file mode 100644 index 0000000000..1dbb26f8e7 --- /dev/null +++ b/quantum/wear_leveling/tests/backing_mocks.cpp @@ -0,0 +1,154 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "backing_mocks.hpp" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Backing Store Mock implementation +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MockBackingStore::reset_instance() { + for (auto&& e : backing_storage) + e.reset(); + + locked = true; + + backing_erasure_count = 0; + backing_max_write_count = 0; + backing_total_write_count = 0; + + backing_init_invoke_count = 0; + backing_unlock_invoke_count = 0; + backing_erase_invoke_count = 0; + backing_write_invoke_count = 0; + backing_lock_invoke_count = 0; + + init_success_callback = [](std::uint64_t) { return true; }; + erase_success_callback = [](std::uint64_t) { return true; }; + unlock_success_callback = [](std::uint64_t) { return true; }; + write_success_callback = [](std::uint64_t, std::uint32_t) { return true; }; + lock_success_callback = [](std::uint64_t) { return true; }; + + write_log.clear(); +} + +bool MockBackingStore::init(void) { + ++backing_init_invoke_count; + + if (init_success_callback) { + return init_success_callback(backing_init_invoke_count); + } + return true; +} + +bool MockBackingStore::unlock(void) { + ++backing_unlock_invoke_count; + + EXPECT_TRUE(is_locked()) << "Attempted to unlock but was not locked"; + locked = false; + + if (unlock_success_callback) { + return unlock_success_callback(backing_unlock_invoke_count); + } + return true; +} + +bool MockBackingStore::erase(void) { + ++backing_erase_invoke_count; + + // Erase each slot + for (std::size_t i = 0; i < backing_storage.size(); ++i) { + // Drop out of erase early with failure if we need to + if (erase_success_callback && !erase_success_callback(backing_erase_invoke_count)) { + append_log(true); + return false; + } + + backing_storage[i].erase(); + } + + // Keep track of the erase in the write log so that we can verify during tests + append_log(true); + + ++backing_erasure_count; + return true; +} + +bool MockBackingStore::write(uint32_t address, backing_store_int_t value) { + ++backing_write_invoke_count; + + // precondition: value's buffer size already matches BACKING_STORE_WRITE_SIZE + EXPECT_TRUE(address % BACKING_STORE_WRITE_SIZE == 0) << "Supplied address was not aligned with the backing store integral size"; + EXPECT_TRUE(address + BACKING_STORE_WRITE_SIZE <= WEAR_LEVELING_BACKING_SIZE) << "Address would result of out-of-bounds access"; + EXPECT_FALSE(is_locked()) << "Write was attempted without being unlocked first"; + + // Drop out of write early with failure if we need to + if (write_success_callback && !write_success_callback(backing_write_invoke_count, address)) { + return false; + } + + // Write the complement as we're simulating flash memory -- 0xFF means 0x00 + std::size_t index = address / BACKING_STORE_WRITE_SIZE; + backing_storage[index].set(~value); + + // Keep track of the write log so that we can verify during tests + append_log(address, value); + + // Keep track of the total number of writes into the backing store + ++backing_total_write_count; + + return true; +} + +bool MockBackingStore::lock(void) { + ++backing_lock_invoke_count; + + EXPECT_FALSE(is_locked()) << "Attempted to lock but was not unlocked"; + locked = true; + + if (lock_success_callback) { + return lock_success_callback(backing_lock_invoke_count); + } + return true; +} + +bool MockBackingStore::read(uint32_t address, backing_store_int_t& value) const { + // precondition: value's buffer size already matches BACKING_STORE_WRITE_SIZE + EXPECT_TRUE(address % BACKING_STORE_WRITE_SIZE == 0) << "Supplied address was not aligned with the backing store integral size"; + EXPECT_TRUE(address + BACKING_STORE_WRITE_SIZE <= WEAR_LEVELING_BACKING_SIZE) << "Address would result of out-of-bounds access"; + + // Read and take the complement as we're simulating flash memory -- 0xFF means 0x00 + std::size_t index = address / BACKING_STORE_WRITE_SIZE; + value = ~backing_storage[index].get(); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Backing Implementation +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern "C" bool backing_store_init(void) { + return MockBackingStore::Instance().init(); +} + +extern "C" bool backing_store_unlock(void) { + return MockBackingStore::Instance().unlock(); +} + +extern "C" bool backing_store_erase(void) { + return MockBackingStore::Instance().erase(); +} + +extern "C" bool backing_store_write(uint32_t address, backing_store_int_t value) { + return MockBackingStore::Instance().write(address, value); +} + +extern "C" bool backing_store_lock(void) { + return MockBackingStore::Instance().lock(); +} + +extern "C" bool backing_store_read(uint32_t address, backing_store_int_t* value) { + return MockBackingStore::Instance().read(address, *value); +} diff --git a/quantum/wear_leveling/tests/backing_mocks.hpp b/quantum/wear_leveling/tests/backing_mocks.hpp new file mode 100644 index 0000000000..e7af7895f3 --- /dev/null +++ b/quantum/wear_leveling/tests/backing_mocks.hpp @@ -0,0 +1,210 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include "fnv.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" +}; + +// Maximum number of mock write log entries to keep +using MOCK_WRITE_LOG_MAX_ENTRIES = std::integral_constant; +// Complement to the backing store integral, for emulating flash erases of all bytes=0xFF +using BACKING_STORE_INTEGRAL_COMPLEMENT = std::integral_constant; +// Total number of elements stored in the backing arrays +using BACKING_STORE_ELEMENT_COUNT = std::integral_constant; + +class MockBackingStoreElement { + private: + backing_store_int_t value; + std::size_t writes; + std::size_t erases; + + public: + MockBackingStoreElement() : value(BACKING_STORE_INTEGRAL_COMPLEMENT::value), writes(0), erases(0) {} + void reset() { + erase(); + writes = 0; + erases = 0; + } + void erase() { + if (!is_erased()) { + ++erases; + } + value = BACKING_STORE_INTEGRAL_COMPLEMENT::value; + } + backing_store_int_t get() const { + return value; + } + void set(const backing_store_int_t& v) { + EXPECT_TRUE(is_erased()) << "Attempted write at index which isn't empty."; + value = v; + ++writes; + } + std::size_t num_writes() const { + return writes; + } + std::size_t num_erases() const { + return erases; + } + bool is_erased() const { + return value == BACKING_STORE_INTEGRAL_COMPLEMENT::value; + } +}; + +struct MockBackingStoreLogEntry { + MockBackingStoreLogEntry(uint32_t address, backing_store_int_t value) : address(address), value(value), erased(false) {} + MockBackingStoreLogEntry(bool erased) : address(0), value(0), erased(erased) {} + uint32_t address = 0; // The address of the operation + backing_store_int_t value = 0; // The value of the operation + bool erased = false; // Whether the entire backing store was erased +}; + +class MockBackingStore { + private: + MockBackingStore() { + reset_instance(); + } + + // Type containing each of the entries and the write counts + using storage_t = std::array; + + // Whether the backing store is locked + bool locked; + // The actual data stored in the emulated flash + storage_t backing_storage; + // The number of erase cycles that have occurred + std::uint64_t backing_erasure_count; + // The max number of writes to an element of the backing store + std::uint64_t backing_max_write_count; + // The total number of writes to all elements of the backing store + std::uint64_t backing_total_write_count; + // The write log for the backing store + std::vector write_log; + + // The number of times each API was invoked + std::uint64_t backing_init_invoke_count; + std::uint64_t backing_unlock_invoke_count; + std::uint64_t backing_erase_invoke_count; + std::uint64_t backing_write_invoke_count; + std::uint64_t backing_lock_invoke_count; + + // Whether init should succeed + std::function init_success_callback; + // Whether erase should succeed + std::function erase_success_callback; + // Whether unlocks should succeed + std::function unlock_success_callback; + // Whether writes should succeed + std::function write_success_callback; + // Whether locks should succeed + std::function lock_success_callback; + + template + void append_log(Args&&... args) { + if (write_log.size() < MOCK_WRITE_LOG_MAX_ENTRIES::value) { + write_log.emplace_back(std::forward(args)...); + } + } + + public: + static MockBackingStore& Instance() { + static MockBackingStore instance; + return instance; + } + + std::uint64_t erasure_count() const { + return backing_erasure_count; + } + std::uint64_t max_write_count() const { + return backing_max_write_count; + } + std::uint64_t total_write_count() const { + return backing_total_write_count; + } + + // The number of times each API was invoked + std::uint64_t init_invoke_count() const { + return backing_init_invoke_count; + } + std::uint64_t unlock_invoke_count() const { + return backing_unlock_invoke_count; + } + std::uint64_t erase_invoke_count() const { + return backing_erase_invoke_count; + } + std::uint64_t write_invoke_count() const { + return backing_write_invoke_count; + } + std::uint64_t lock_invoke_count() const { + return backing_lock_invoke_count; + } + + // Clear out the internal data for the next run + void reset_instance(); + + bool is_locked() const { + return locked; + } + + // APIs for the backing store + bool init(); + bool unlock(); + bool erase(); + bool write(std::uint32_t address, backing_store_int_t value); + bool lock(); + bool read(std::uint32_t address, backing_store_int_t& value) const; + + // Control over when init/writes/erases should succeed + void set_init_callback(std::function callback) { + init_success_callback = callback; + } + void set_erase_callback(std::function callback) { + erase_success_callback = callback; + } + void set_unlock_callback(std::function callback) { + unlock_success_callback = callback; + } + void set_write_callback(std::function callback) { + write_success_callback = callback; + } + void set_lock_callback(std::function callback) { + lock_success_callback = callback; + } + + auto storage_begin() const -> decltype(backing_storage.begin()) { + return backing_storage.begin(); + } + auto storage_end() const -> decltype(backing_storage.end()) { + return backing_storage.end(); + } + + auto storage_begin() -> decltype(backing_storage.begin()) { + return backing_storage.begin(); + } + auto storage_end() -> decltype(backing_storage.end()) { + return backing_storage.end(); + } + + auto log_begin() -> decltype(write_log.begin()) { + return write_log.begin(); + } + auto log_end() -> decltype(write_log.end()) { + return write_log.end(); + } + + auto log_begin() const -> decltype(write_log.begin()) { + return write_log.begin(); + } + auto log_end() const -> decltype(write_log.end()) { + return write_log.end(); + } +}; diff --git a/quantum/wear_leveling/tests/rules.mk b/quantum/wear_leveling/tests/rules.mk new file mode 100644 index 0000000000..4d7a964049 --- /dev/null +++ b/quantum/wear_leveling/tests/rules.mk @@ -0,0 +1,66 @@ +wear_leveling_common_DEFS := \ + -DWEAR_LEVELING_TESTS +wear_leveling_common_SRC := \ + $(LIB_PATH)/fnv/qmk_fnv_type_validation.c \ + $(LIB_PATH)/fnv/hash_32a.c \ + $(LIB_PATH)/fnv/hash_64a.c \ + $(QUANTUM_PATH)/wear_leveling/wear_leveling.c \ + $(QUANTUM_PATH)/wear_leveling/tests/backing_mocks.cpp +wear_leveling_common_INC := \ + $(LIB_PATH)/fnv \ + $(QUANTUM_PATH)/wear_leveling + +wear_leveling_general_DEFS := \ + $(wear_leveling_common_DEFS) \ + -DBACKING_STORE_WRITE_SIZE=2 \ + -DWEAR_LEVELING_BACKING_SIZE=48 \ + -DWEAR_LEVELING_LOGICAL_SIZE=16 +wear_leveling_general_SRC := \ + $(wear_leveling_common_SRC) \ + $(QUANTUM_PATH)/wear_leveling/tests/wear_leveling_general.cpp +wear_leveling_general_INC := \ + $(wear_leveling_common_INC) + +wear_leveling_2byte_optimized_writes_DEFS := \ + $(wear_leveling_common_DEFS) \ + -DBACKING_STORE_WRITE_SIZE=2 \ + -DWEAR_LEVELING_BACKING_SIZE=65536 \ + -DWEAR_LEVELING_LOGICAL_SIZE=32768 +wear_leveling_2byte_optimized_writes_SRC := \ + $(wear_leveling_common_SRC) \ + $(QUANTUM_PATH)/wear_leveling/tests/wear_leveling_2byte_optimized_writes.cpp +wear_leveling_2byte_optimized_writes_INC := \ + $(wear_leveling_common_INC) + +wear_leveling_2byte_DEFS := \ + $(wear_leveling_common_DEFS) \ + -DBACKING_STORE_WRITE_SIZE=2 \ + -DWEAR_LEVELING_BACKING_SIZE=48 \ + -DWEAR_LEVELING_LOGICAL_SIZE=16 +wear_leveling_2byte_SRC := \ + $(wear_leveling_common_SRC) \ + $(QUANTUM_PATH)/wear_leveling/tests/wear_leveling_2byte.cpp +wear_leveling_2byte_INC := \ + $(wear_leveling_common_INC) + +wear_leveling_4byte_DEFS := \ + $(wear_leveling_common_DEFS) \ + -DBACKING_STORE_WRITE_SIZE=4 \ + -DWEAR_LEVELING_BACKING_SIZE=48 \ + -DWEAR_LEVELING_LOGICAL_SIZE=16 +wear_leveling_4byte_SRC := \ + $(wear_leveling_common_SRC) \ + $(QUANTUM_PATH)/wear_leveling/tests/wear_leveling_4byte.cpp +wear_leveling_4byte_INC := \ + $(wear_leveling_common_INC) + +wear_leveling_8byte_DEFS := \ + $(wear_leveling_common_DEFS) \ + -DBACKING_STORE_WRITE_SIZE=8 \ + -DWEAR_LEVELING_BACKING_SIZE=48 \ + -DWEAR_LEVELING_LOGICAL_SIZE=16 +wear_leveling_8byte_SRC := \ + $(wear_leveling_common_SRC) \ + $(QUANTUM_PATH)/wear_leveling/tests/wear_leveling_8byte.cpp +wear_leveling_8byte_INC := \ + $(wear_leveling_common_INC) \ No newline at end of file diff --git a/quantum/wear_leveling/tests/testlist.mk b/quantum/wear_leveling/tests/testlist.mk new file mode 100644 index 0000000000..32cfc178b4 --- /dev/null +++ b/quantum/wear_leveling/tests/testlist.mk @@ -0,0 +1,6 @@ +TEST_LIST += \ + wear_leveling_general \ + wear_leveling_2byte_optimized_writes \ + wear_leveling_2byte \ + wear_leveling_4byte \ + wear_leveling_8byte diff --git a/quantum/wear_leveling/tests/wear_leveling_2byte.cpp b/quantum/wear_leveling/tests/wear_leveling_2byte.cpp new file mode 100644 index 0000000000..b749c32b04 --- /dev/null +++ b/quantum/wear_leveling/tests/wear_leveling_2byte.cpp @@ -0,0 +1,228 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "backing_mocks.hpp" + +class WearLeveling2Byte : public ::testing::Test { + protected: + void SetUp() override { + MockBackingStore::Instance().reset_instance(); + wear_leveling_init(); + } +}; + +static std::array verify_data; + +static wear_leveling_status_t test_write(const uint32_t address, const void* value, size_t length) { + memcpy(&verify_data[address], value, length); + return wear_leveling_write(address, value, length); +} + +/** + * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location. + */ +TEST_F(WearLeveling2Byte, FirstWriteOccursAfterHash) { + auto& inst = MockBackingStore::Instance(); + uint8_t test_value = 0x15; + test_write(0x02, &test_value, sizeof(test_value)); + EXPECT_EQ(inst.log_begin()->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address."; +} + +/** + * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location, after an erase has occurred. + */ +TEST_F(WearLeveling2Byte, FirstWriteOccursAfterHash_AfterErase) { + auto& inst = MockBackingStore::Instance(); + uint8_t test_value = 0x15; + wear_leveling_erase(); + test_write(0x02, &test_value, sizeof(test_value)); + EXPECT_EQ((inst.log_begin() + 1)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address."; +} + +/** + * This test forces consolidation by writing enough to the write log that it overflows, consolidating the data into the + * base logical area. + */ +TEST_F(WearLeveling2Byte, ConsolidationOverflow) { + auto& inst = MockBackingStore::Instance(); + + // Generate a test block of data which forces OPTIMIZED_64 writes + std::array testvalue; + + // Write the data + std::iota(testvalue.begin(), testvalue.end(), 0x20); + EXPECT_EQ(test_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_CONSOLIDATED) << "Write returned incorrect status"; + uint8_t dummy = 0x40; + EXPECT_EQ(test_write(0x04, &dummy, sizeof(dummy)), WEAR_LEVELING_SUCCESS) << "Write returned incorrect status"; + + // All writes are at address<64, so each logical byte written will generate 1 write log entry, thus 1 backing store write. + // Expected log: + // [0..11]: optimised64, backing address 0x18, logical address 0x00 + // [12]: erase + // [13..20]: consolidated data, backing address 0x00, logical address 0x00 + // [21..24]: FNV1a_64 result, backing address 0x10 + // [25]: optimised64, backing address 0x18, logical address 0x04 + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), 26); + + // Verify the backing store writes for the write log + std::size_t index; + write_log_entry_t e; + for (index = 0; index < 12; ++index) { + auto write_iter = inst.log_begin() + index; + EXPECT_EQ(write_iter->address, WEAR_LEVELING_LOGICAL_SIZE + 8 + (index * BACKING_STORE_WRITE_SIZE)) << "Invalid write log address"; + e.raw16[0] = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_OPTIMIZED_64) << "Invalid write log entry type"; + } + + // Verify the backing store erase + { + index = 12; + auto write_iter = inst.log_begin() + index; + e.raw16[0] = write_iter->value; + EXPECT_TRUE(write_iter->erased) << "Backing store erase did not occur as required"; + } + + // Verify the backing store writes for consolidation + for (index = 13; index < 21; ++index) { + auto write_iter = inst.log_begin() + index; + EXPECT_EQ(write_iter->address, (index - 13) * BACKING_STORE_WRITE_SIZE) << "Invalid write log entry address"; + } + + // Verify the FNV1a_64 write + { + EXPECT_EQ((inst.log_begin() + 21)->address, WEAR_LEVELING_LOGICAL_SIZE) << "Invalid write log address"; + e.raw16[0] = (inst.log_begin() + 21)->value; + e.raw16[1] = (inst.log_begin() + 22)->value; + e.raw16[2] = (inst.log_begin() + 23)->value; + e.raw16[3] = (inst.log_begin() + 24)->value; + EXPECT_EQ(e.raw64, fnv_64a_buf(testvalue.data(), testvalue.size(), FNV1A_64_INIT)) << "Invalid checksum"; // Note that checksum is based on testvalue, as we overwrote one byte and need to consult the consolidated data, not the current + } + + // Verify the final write + EXPECT_EQ((inst.log_begin() + 25)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid write log address"; + + // Verify the data is what we expected + std::array readback; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match"; + + // Re-init and re-read, verifying the reload capability + EXPECT_NE(wear_leveling_init(), WEAR_LEVELING_FAILED) << "Re-initialisation failed"; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match"; +} + +/** + * This test verifies multibyte readback gets canceled with an out-of-bounds address. + */ +TEST_F(WearLeveling2Byte, PlaybackReadbackMultibyte_OOB) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Invalid FNV1a_64 hash + (logstart + 0)->set(0); + (logstart + 1)->set(0); + (logstart + 2)->set(0); + (logstart + 3)->set(0); + + // Set up a 2-byte logical write of [0x11,0x12] at logical offset 0x01 + auto entry0 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2); + entry0.raw8[3] = 0x11; + entry0.raw8[4] = 0x12; + (logstart + 4)->set(~entry0.raw16[0]); + (logstart + 5)->set(~entry0.raw16[1]); + (logstart + 6)->set(~entry0.raw16[2]); + + // Set up a 2-byte logical write of [0x13,0x14] at logical offset 0x1000 (out of bounds) + auto entry1 = LOG_ENTRY_MAKE_MULTIBYTE(0x1000, 2); + entry1.raw8[3] = 0x13; + entry1.raw8[4] = 0x14; + (logstart + 7)->set(~entry1.raw16[0]); + (logstart + 8)->set(~entry1.raw16[1]); + (logstart + 9)->set(~entry1.raw16[2]); + + // Set up a 2-byte logical write of [0x15,0x16] at logical offset 0x01 + auto entry2 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2); + entry2.raw8[3] = 0x15; + entry2.raw8[4] = 0x16; + (logstart + 10)->set(~entry2.raw16[0]); + (logstart + 11)->set(~entry2.raw16[1]); + (logstart + 12)->set(~entry2.raw16[2]); + + EXPECT_EQ(inst.erasure_count(), 0) << "Invalid initial erase count"; + EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_CONSOLIDATED) << "Readback should have failed and triggered consolidation"; + EXPECT_EQ(inst.erasure_count(), 1) << "Invalid final erase count"; + + uint8_t buf[2]; + wear_leveling_read(0x01, buf, sizeof(buf)); + EXPECT_EQ(buf[0], 0x11) << "Readback should have maintained the previous pre-failure value from the write log"; + EXPECT_EQ(buf[1], 0x12) << "Readback should have maintained the previous pre-failure value from the write log"; +} + +/** + * This test verifies optimized 64 readback gets canceled with an out-of-bounds address. + */ +TEST_F(WearLeveling2Byte, PlaybackReadbackOptimized64_OOB) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Invalid FNV1a_64 hash + (logstart + 0)->set(0); + (logstart + 1)->set(0); + (logstart + 2)->set(0); + (logstart + 3)->set(0); + + // Set up a 1-byte logical write of 0x11 at logical offset 0x01 + auto entry0 = LOG_ENTRY_MAKE_OPTIMIZED_64(0x01, 0x11); + (logstart + 4)->set(~entry0.raw16[0]); + + // Set up a 1-byte logical write of 0x11 at logical offset 0x30 (out of bounds) + auto entry1 = LOG_ENTRY_MAKE_OPTIMIZED_64(0x30, 0x11); + (logstart + 5)->set(~entry1.raw16[0]); + + // Set up a 1-byte logical write of 0x12 at logical offset 0x01 + auto entry2 = LOG_ENTRY_MAKE_OPTIMIZED_64(0x01, 0x12); + (logstart + 6)->set(~entry2.raw16[0]); + + EXPECT_EQ(inst.erasure_count(), 0) << "Invalid initial erase count"; + EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_CONSOLIDATED) << "Readback should have failed and triggered consolidation"; + EXPECT_EQ(inst.erasure_count(), 1) << "Invalid final erase count"; + uint8_t tmp; + wear_leveling_read(0x01, &tmp, sizeof(tmp)); + EXPECT_EQ(tmp, 0x11) << "Readback should have maintained the previous pre-failure value from the write log"; +} + +/** + * This test verifies word 0/1 readback gets canceled with an out-of-bounds address. + */ +TEST_F(WearLeveling2Byte, PlaybackReadbackWord01_OOB) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Invalid FNV1a_64 hash + (logstart + 0)->set(0); + (logstart + 1)->set(0); + (logstart + 2)->set(0); + (logstart + 3)->set(0); + + // Set up a 1-byte logical write of 1 at logical offset 0x02 + auto entry0 = LOG_ENTRY_MAKE_WORD_01(0x02, 1); + (logstart + 4)->set(~entry0.raw16[0]); + + // Set up a 1-byte logical write of 1 at logical offset 0x1000 (out of bounds) + auto entry1 = LOG_ENTRY_MAKE_WORD_01(0x1000, 1); + (logstart + 5)->set(~entry1.raw16[0]); + + // Set up a 1-byte logical write of 0 at logical offset 0x02 + auto entry2 = LOG_ENTRY_MAKE_WORD_01(0x02, 0); + (logstart + 6)->set(~entry2.raw16[0]); + + EXPECT_EQ(inst.erasure_count(), 0) << "Invalid initial erase count"; + EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_CONSOLIDATED) << "Readback should have failed and triggered consolidation"; + EXPECT_EQ(inst.erasure_count(), 1) << "Invalid final erase count"; + uint8_t tmp; + wear_leveling_read(0x02, &tmp, sizeof(tmp)); + EXPECT_EQ(tmp, 1) << "Readback should have maintained the previous pre-failure value from the write log"; +} diff --git a/quantum/wear_leveling/tests/wear_leveling_2byte_optimized_writes.cpp b/quantum/wear_leveling/tests/wear_leveling_2byte_optimized_writes.cpp new file mode 100644 index 0000000000..0b03113c89 --- /dev/null +++ b/quantum/wear_leveling/tests/wear_leveling_2byte_optimized_writes.cpp @@ -0,0 +1,295 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "backing_mocks.hpp" + +class WearLeveling2ByteOptimizedWrites : public ::testing::Test { + protected: + void SetUp() override { + MockBackingStore::Instance().reset_instance(); + wear_leveling_init(); + } +}; + +static std::array verify_data; + +static wear_leveling_status_t test_write(const uint32_t address, const void* value, size_t length) { + memcpy(&verify_data[address], value, length); + return wear_leveling_write(address, value, length); +} + +/** + * This test ensures the correct number of backing store writes occurs with a multibyte write, given the input buffer size. + */ +TEST_F(WearLeveling2ByteOptimizedWrites, MultibyteBackingStoreWriteCounts) { + auto& inst = MockBackingStore::Instance(); + + for (std::size_t length = 1; length <= 5; ++length) { + // Clear things out + std::fill(verify_data.begin(), verify_data.end(), 0); + inst.reset_instance(); + wear_leveling_init(); + + // Generate a test block of data + std::vector testvalue(length); + std::iota(testvalue.begin(), testvalue.end(), 0x20); + + // Write the data + EXPECT_EQ(test_write(2000, testvalue.data(), testvalue.size()), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status"; + + std::size_t expected; + if (length > 3) { + expected = 4; + } else if (length > 1) { + expected = 3; + } else { + expected = 2; + } + + // Check that we got the expected number of write log entries + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), expected); + } +} + +/** + * This test runs through writing U16 values of `0` or `1` over the entire logical address range, to even addresses only. + * - Addresses <16384 will result in a single optimised backing write + * - Higher addresses will result in a multibyte write of 3 backing writes + */ +TEST_F(WearLeveling2ByteOptimizedWrites, WriteOneThenZeroToEvenAddresses) { + auto& inst = MockBackingStore::Instance(); + + // Only attempt writes for each address up to a limit that would NOT force a consolidated data write. + std::size_t writes_per_loop = (MOCK_WRITE_LOG_MAX_ENTRIES::value / 6) - 1; // Worst case is 6 writes for each pair of writes of 0/1 + std::size_t final_address; + for (uint32_t address = 0; address < WEAR_LEVELING_LOGICAL_SIZE; address += (writes_per_loop * 2)) { + // Clear things out + std::fill(verify_data.begin(), verify_data.end(), 0); + inst.reset_instance(); + wear_leveling_init(); + + // Loop through all the addresses in this range + std::size_t expected = 0; + for (uint32_t offset = 0; offset < (writes_per_loop * 2); offset += 2) { + // If we're about to exceed the limit of the logical store, skip the writes + if (address + offset + 2 > WEAR_LEVELING_LOGICAL_SIZE) { + break; + } + + // The default erased value of the wear-leveling cache is zero, so we write a one first, then a zero, to ensure a backing store write occurs. + uint16_t val = 1; + EXPECT_EQ(test_write(address + offset, &val, sizeof(val)), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status"; + val = 0; + EXPECT_EQ(test_write(address + offset, &val, sizeof(val)), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status"; + + std::size_t backing_store_writes_expected = 0; + if (address + offset < 16384) { + // A U16 value of 0/1 at an even address <16384 will result in 1 backing write each, so we need 2 backing writes for 2 logical writes + backing_store_writes_expected = 2; + } else { + // All other addresses result in a multibyte write (3 backing store writes) to write two local bytes of data + backing_store_writes_expected = 6; + } + + // Keep track of the total number of expected writes to the backing store + expected += backing_store_writes_expected; + + // Verify we're at the correct number of writes + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), expected) << "Write log doesn't match required number of backing store writes for address " << (address + offset); + + // Verify that the write log entries we expect are actually present + std::size_t write_index = expected - backing_store_writes_expected; + auto write_iter = inst.log_begin() + write_index; + write_log_entry_t e; + if (address + offset < 16384) { + // A U16 value of 0/1 at an even address <16384 will result in 1 backing write each, so we need 2 backing writes for 2 logical writes + for (std::size_t i = 0; i < 2; ++i) { + e.raw16[0] = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_WORD_01) << "Invalid write log entry type at " << (address + offset); + ++write_iter; + } + } else { + // Multibyte write + e.raw16[0] = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_MULTIBYTE) << "Invalid write log entry type at " << (address + offset); + EXPECT_EQ(LOG_ENTRY_MULTIBYTE_GET_LENGTH(e), 2) << "Invalid write log entry length at " << (address + offset); + ++write_iter; + } + + // Keep track of the final address written, so we can verify the entire logical range was handled + final_address = address + offset; + } + + // Verify the number of writes that occurred to the backing store + size_t backing_write_count = std::distance(inst.log_begin(), inst.log_end()); + EXPECT_EQ(backing_write_count, expected) << "Invalid write count at address " << address; + + // Verify the data is what we expected + std::array readback; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback for address " << address << " did not match"; + + // Re-init and re-read, testing the reload capability + EXPECT_NE(wear_leveling_init(), WEAR_LEVELING_FAILED) << "Re-initialisation failed"; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback for address " << address << " did not match"; + } + + // Verify the full range of the logical area got written + EXPECT_EQ(final_address, WEAR_LEVELING_LOGICAL_SIZE - 2) << "Invalid final write address"; +} + +/** + * This test runs through writing U16 values of `0` or `1` over the entire logical address range, to odd addresses only. + * - Addresses <63 will result in 2 optimised backing writes + * - Address 63 results in a single optimised backing write for the first logical byte, and a multibyte write of 2 backing writes for the second logical byte + * - Higher addresses will result in a multibyte write of 3 backing writes + */ +TEST_F(WearLeveling2ByteOptimizedWrites, WriteOneThenZeroToOddAddresses) { + auto& inst = MockBackingStore::Instance(); + + // Only attempt writes for each address up to a limit that would NOT force a consolidated data write. + std::size_t writes_per_loop = (MOCK_WRITE_LOG_MAX_ENTRIES::value / 6) - 1; // Worst case is 6 writes for each pair of writes of 0/1 + std::size_t final_address; + for (uint32_t address = 1; address < WEAR_LEVELING_LOGICAL_SIZE; address += (writes_per_loop * 2)) { + // Clear things out + std::fill(verify_data.begin(), verify_data.end(), 0); + inst.reset_instance(); + wear_leveling_init(); + + // Loop through all the addresses in this range + std::size_t expected = 0; + for (uint32_t offset = 0; offset < (writes_per_loop * 2); offset += 2) { + // If we're about to exceed the limit of the logical store, skip the writes + if (address + offset + 2 > WEAR_LEVELING_LOGICAL_SIZE) { + break; + } + + // The default erased value of the wear-leveling cache is zero, so we write a one first, then a zero, to ensure a backing store write occurs. + uint16_t val = 1; + EXPECT_EQ(test_write(address + offset, &val, sizeof(val)), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status"; + val = 0; + EXPECT_EQ(test_write(address + offset, &val, sizeof(val)), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status"; + + std::size_t backing_store_writes_expected = 0; + if (address + offset < 63) { + // A U16 value of 0/1 at an odd address <64 will result in 2 backing writes each, so we need 4 backing writes for 2 logical writes + backing_store_writes_expected = 4; + } else if (address + offset == 63) { + // If we're straddling the boundary for optimised bytes (addr==64), then the first logical byte is written using the optimised write (1 backing + // store write), and the second logical byte uses a multibyte write (2 backing store writes) + backing_store_writes_expected = 2 // First logical bytes written using optimised log entries + + 4; // Second logical bytes written using multibyte log entries + } else { + // All other addresses result in a multibyte write (3 backing store writes) to write two local bytes of data + backing_store_writes_expected = 6; + } + + // Keep track of the total number of expected writes to the backing store + expected += backing_store_writes_expected; + + // Verify we're at the correct number of writes + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), expected) << "Write log doesn't match required number of backing store writes for address " << (address + offset); + + // Verify that the write log entries we expect are actually present + std::size_t write_index = expected - backing_store_writes_expected; + auto write_iter = inst.log_begin() + write_index; + write_log_entry_t e; + if (address + offset < 63) { + // A U16 value of 0/1 at an odd address <64 will result in 2 backing writes each, so we need 4 backing writes for 2 logical writes + for (std::size_t i = 0; i < 4; ++i) { + e.raw16[0] = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_OPTIMIZED_64) << "Invalid write log entry type"; + ++write_iter; + } + } else if (address + offset == 63) { + // First log entry is the 64-addr optimised one + e.raw16[0] = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_OPTIMIZED_64) << "Invalid write log entry type"; + ++write_iter; + + // Second log entry is the multibyte entry for the second logical byte + e.raw16[0] = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_MULTIBYTE) << "Invalid write log entry type"; + EXPECT_EQ(LOG_ENTRY_MULTIBYTE_GET_LENGTH(e), 1) << "Invalid write log entry length"; + ++write_iter; + } else { + // Multibyte write + e.raw16[0] = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_MULTIBYTE) << "Invalid write log entry type"; + EXPECT_EQ(LOG_ENTRY_MULTIBYTE_GET_LENGTH(e), 2) << "Invalid write log entry length"; + ++write_iter; + } + + // Keep track of the final address written, so we can verify the entire logical range was handled + final_address = address + offset; + } + + // Verify the number of writes that occurred to the backing store + size_t backing_write_count = std::distance(inst.log_begin(), inst.log_end()); + EXPECT_EQ(backing_write_count, expected) << "Invalid write count at address " << address; + + // Verify the data is what we expected + std::array readback; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback for address " << address << " did not match"; + + // Re-init and re-read, testing the reload capability + EXPECT_NE(wear_leveling_init(), WEAR_LEVELING_FAILED) << "Re-initialisation failed"; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback for address " << address << " did not match"; + } + + // Verify the full range of the logical area got written + EXPECT_EQ(final_address, WEAR_LEVELING_LOGICAL_SIZE - 3) << "Invalid final write address"; +} + +/** + * This test verifies readback after playback of the write log, simulating power loss and reboot. + */ +TEST_F(WearLeveling2ByteOptimizedWrites, PlaybackReadbackOptimized64_Success) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Invalid FNV1a_64 hash + (logstart + 0)->set(0); + (logstart + 1)->set(0); + (logstart + 2)->set(0); + (logstart + 3)->set(0); + + // Set up a 1-byte logical write of 0x11 at logical offset 0x01 + auto entry0 = LOG_ENTRY_MAKE_OPTIMIZED_64(0x01, 0x11); + (logstart + 4)->set(~entry0.raw16[0]); // start at offset 4 to skip FNV1a_64 result + + wear_leveling_init(); + uint8_t tmp; + + wear_leveling_read(0x01, &tmp, sizeof(tmp)); + EXPECT_EQ(tmp, 0x11) << "Failed to read back the seeded data"; +} + +/** + * This test verifies readback after playback of the write log, simulating power loss and reboot. + */ +TEST_F(WearLeveling2ByteOptimizedWrites, PlaybackReadbackWord01_Success) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Invalid FNV1a_64 hash + (logstart + 0)->set(0); + (logstart + 1)->set(0); + (logstart + 2)->set(0); + (logstart + 3)->set(0); + + // Set up a 1-byte logical write of 1 at logical offset 0x02 + auto entry0 = LOG_ENTRY_MAKE_WORD_01(0x02, 1); + (logstart + 4)->set(~entry0.raw16[0]); // start at offset 4 to skip FNV1a_64 result + + wear_leveling_init(); + uint8_t tmp; + + wear_leveling_read(0x02, &tmp, sizeof(tmp)); + EXPECT_EQ(tmp, 1) << "Failed to read back the seeded data"; +} diff --git a/quantum/wear_leveling/tests/wear_leveling_4byte.cpp b/quantum/wear_leveling/tests/wear_leveling_4byte.cpp new file mode 100644 index 0000000000..54482c5fe7 --- /dev/null +++ b/quantum/wear_leveling/tests/wear_leveling_4byte.cpp @@ -0,0 +1,193 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "backing_mocks.hpp" + +class WearLeveling4Byte : public ::testing::Test { + protected: + void SetUp() override { + MockBackingStore::Instance().reset_instance(); + wear_leveling_init(); + } +}; + +static std::array verify_data; + +static wear_leveling_status_t test_write(const uint32_t address, const void* value, size_t length) { + memcpy(&verify_data[address], value, length); + return wear_leveling_write(address, value, length); +} + +/** + * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location. + */ +TEST_F(WearLeveling4Byte, FirstWriteOccursAfterHash) { + auto& inst = MockBackingStore::Instance(); + uint8_t test_value = 0x15; + test_write(0x02, &test_value, sizeof(test_value)); + EXPECT_EQ(inst.log_begin()->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address."; +} + +/** + * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location, after an erase has occurred. + */ +TEST_F(WearLeveling4Byte, FirstWriteOccursAfterHash_AfterErase) { + auto& inst = MockBackingStore::Instance(); + uint8_t test_value = 0x15; + wear_leveling_erase(); + test_write(0x02, &test_value, sizeof(test_value)); + EXPECT_EQ((inst.log_begin() + 1)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address."; +} + +/** + * This test ensures the correct number of backing store writes occurs with a multibyte write, given the input buffer size. + */ +TEST_F(WearLeveling4Byte, MultibyteBackingStoreWriteCounts) { + auto& inst = MockBackingStore::Instance(); + + for (std::size_t length = 1; length <= 5; ++length) { + // Clear things out + std::fill(verify_data.begin(), verify_data.end(), 0); + inst.reset_instance(); + wear_leveling_init(); + + // Generate a test block of data + std::vector testvalue(length); + std::iota(testvalue.begin(), testvalue.end(), 0x20); + + // Write the data + EXPECT_EQ(test_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status"; + + std::size_t expected; + if (length > 1) { + expected = 2; + } else { + expected = 1; + } + + // Check that we got the expected number of write log entries + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), expected); + } +} + +/** + * This test forces consolidation by writing enough to the write log that it overflows, consolidating the data into the + * base logical area. + */ +TEST_F(WearLeveling4Byte, ConsolidationOverflow) { + auto& inst = MockBackingStore::Instance(); + + // Generate a test block of data + std::array testvalue; + + // Write the data + std::iota(testvalue.begin(), testvalue.end(), 0x20); + EXPECT_EQ(test_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_CONSOLIDATED) << "Write returned incorrect status"; + uint8_t dummy = 0x40; + EXPECT_EQ(test_write(0x04, &dummy, sizeof(dummy)), WEAR_LEVELING_SUCCESS) << "Write returned incorrect status"; + + // Expected log: + // [0,1]: multibyte, 5 bytes, backing address 0x18, logical address 0x00 + // [2,3]: multibyte, 5 bytes, backing address 0x20, logical address 0x05 + // [4,5]: multibyte, 5 bytes, backing address 0x28, logical address 0x0A, triggers consolidation + // [6]: erase + // [7,8]: consolidated data, backing address 0x00, logical address 0x00 + // [9,10]: consolidated data, backing address 0x08, logical address 0x08 + // [11,12]: FNV1a_64 result, backing address 0x10 + // [13]: multibyte, 1 byte, backing address 0x18, logical address 0x04 + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), 14); + + // Verify the backing store writes for the write log + std::size_t index; + write_log_entry_t e; + for (index = 0; index < 6; ++index) { + auto write_iter = inst.log_begin() + index; + EXPECT_EQ(write_iter->address, WEAR_LEVELING_LOGICAL_SIZE + 8 + (index * BACKING_STORE_WRITE_SIZE)) << "Invalid write log address"; + + // If this is the backing store write that contains the metadata, verify it + if (index % 2 == 0) { + write_log_entry_t e; + e.raw64 = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_MULTIBYTE) << "Invalid write log entry type"; + } + } + + // Verify the backing store erase + { + index = 6; + auto write_iter = inst.log_begin() + index; + e.raw64 = write_iter->value; + EXPECT_TRUE(write_iter->erased) << "Backing store erase did not occur as required"; + } + + // Verify the backing store writes for consolidation + for (index = 7; index < 11; ++index) { + auto write_iter = inst.log_begin() + index; + EXPECT_EQ(write_iter->address, (index - 7) * BACKING_STORE_WRITE_SIZE) << "Invalid write log entry address"; + } + + // Verify the FNV1a_64 write + { + EXPECT_EQ((inst.log_begin() + 11)->address, WEAR_LEVELING_LOGICAL_SIZE) << "Invalid write log address"; + e.raw32[0] = (inst.log_begin() + 11)->value; + e.raw32[1] = (inst.log_begin() + 12)->value; + EXPECT_EQ(e.raw64, fnv_64a_buf(testvalue.data(), testvalue.size(), FNV1A_64_INIT)) << "Invalid checksum"; // Note that checksum is based on testvalue, as we overwrote one byte and need to consult the consolidated data, not the current + } + + // Verify the final write + EXPECT_EQ((inst.log_begin() + 13)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid write log address"; + + // Verify the data is what we expected + std::array readback; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match"; + + // Re-init and re-read, verifying the reload capability + EXPECT_NE(wear_leveling_init(), WEAR_LEVELING_FAILED) << "Re-initialisation failed"; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match"; +} + +/** + * This test verifies multibyte readback gets canceled with an out-of-bounds address. + */ +TEST_F(WearLeveling4Byte, PlaybackReadbackMultibyte_OOB) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Invalid FNV1a_64 hash + (logstart + 0)->set(0); + (logstart + 1)->set(0); + + // Set up a 2-byte logical write of [0x11,0x12] at logical offset 0x01 + auto entry0 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2); + entry0.raw8[3] = 0x11; + entry0.raw8[4] = 0x12; + (logstart + 2)->set(~entry0.raw32[0]); + (logstart + 3)->set(~entry0.raw32[1]); + + // Set up a 2-byte logical write of [0x13,0x14] at logical offset 0x1000 (out of bounds) + auto entry1 = LOG_ENTRY_MAKE_MULTIBYTE(0x1000, 2); + entry1.raw8[3] = 0x13; + entry1.raw8[4] = 0x14; + (logstart + 4)->set(~entry1.raw32[0]); + (logstart + 5)->set(~entry1.raw32[1]); + + // Set up a 2-byte logical write of [0x15,0x16] at logical offset 0x10 + auto entry2 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2); + entry2.raw8[3] = 0x15; + entry2.raw8[4] = 0x16; + (logstart + 6)->set(~entry2.raw32[0]); + (logstart + 7)->set(~entry2.raw32[1]); + + EXPECT_EQ(inst.erasure_count(), 0) << "Invalid initial erase count"; + EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_CONSOLIDATED) << "Readback should have failed and triggered consolidation"; + EXPECT_EQ(inst.erasure_count(), 1) << "Invalid final erase count"; + + uint8_t buf[2]; + wear_leveling_read(0x01, buf, sizeof(buf)); + EXPECT_EQ(buf[0], 0x11) << "Readback should have maintained the previous pre-failure value from the write log"; + EXPECT_EQ(buf[1], 0x12) << "Readback should have maintained the previous pre-failure value from the write log"; +} diff --git a/quantum/wear_leveling/tests/wear_leveling_8byte.cpp b/quantum/wear_leveling/tests/wear_leveling_8byte.cpp new file mode 100644 index 0000000000..c27c21d034 --- /dev/null +++ b/quantum/wear_leveling/tests/wear_leveling_8byte.cpp @@ -0,0 +1,178 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "backing_mocks.hpp" + +class WearLeveling8Byte : public ::testing::Test { + protected: + void SetUp() override { + MockBackingStore::Instance().reset_instance(); + wear_leveling_init(); + } +}; + +static std::array verify_data; + +static wear_leveling_status_t test_write(const uint32_t address, const void* value, size_t length) { + memcpy(&verify_data[address], value, length); + return wear_leveling_write(address, value, length); +} + +/** + * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location. + */ +TEST_F(WearLeveling8Byte, FirstWriteOccursAfterHash) { + auto& inst = MockBackingStore::Instance(); + uint8_t test_value = 0x15; + test_write(0x02, &test_value, sizeof(test_value)); + EXPECT_EQ(inst.log_begin()->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address."; +} + +/** + * This test verifies that the first write after initialisation occurs after the FNV1a_64 hash location, after an erase has occurred. + */ +TEST_F(WearLeveling8Byte, FirstWriteOccursAfterHash_AfterErase) { + auto& inst = MockBackingStore::Instance(); + uint8_t test_value = 0x15; + wear_leveling_erase(); + test_write(0x02, &test_value, sizeof(test_value)); + EXPECT_EQ((inst.log_begin() + 1)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid first write address."; +} + +/** + * This test ensures the correct number of backing store writes occurs with a multibyte write, given the input buffer size. + */ +TEST_F(WearLeveling8Byte, MultibyteBackingStoreWriteCounts) { + auto& inst = MockBackingStore::Instance(); + + for (std::size_t length = 1; length <= 5; ++length) { + // Clear things out + std::fill(verify_data.begin(), verify_data.end(), 0); + inst.reset_instance(); + wear_leveling_init(); + + // Generate a test block of data + std::vector testvalue(length); + std::iota(testvalue.begin(), testvalue.end(), 0x20); + + // Write the data + EXPECT_EQ(test_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_SUCCESS) << "Write failed with incorrect status"; + + // Check that we got the expected number of write log entries + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), 1); + } +} + +/** + * This test forces consolidation by writing enough to the write log that it overflows, consolidating the data into the + * base logical area. + */ +TEST_F(WearLeveling8Byte, ConsolidationOverflow) { + auto& inst = MockBackingStore::Instance(); + + // Generate a test block of data + std::array testvalue; + + // Write the data + std::iota(testvalue.begin(), testvalue.end(), 0x20); + EXPECT_EQ(test_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_CONSOLIDATED) << "Write returned incorrect status"; + uint8_t dummy = 0x40; + EXPECT_EQ(test_write(0x04, &dummy, sizeof(dummy)), WEAR_LEVELING_SUCCESS) << "Write returned incorrect status"; + + // Expected log: + // [0]: multibyte, 5 bytes, backing address 0x18, logical address 0x00 + // [1]: multibyte, 5 bytes, backing address 0x20, logical address 0x05 + // [2]: multibyte, 5 bytes, backing address 0x28, logical address 0x0A, triggers consolidation + // [3]: erase + // [4]: consolidated data, backing address 0x00, logical address 0x00 + // [5]: consolidated data, backing address 0x08, logical address 0x08 + // [6]: FNV1a_64 result, backing address 0x10 + // [7]: multibyte, 1 byte, backing address 0x18, logical address 0x04 + EXPECT_EQ(std::distance(inst.log_begin(), inst.log_end()), 8); + + // Verify the backing store writes for the write log + std::size_t index; + write_log_entry_t e; + for (index = 0; index < 3; ++index) { + auto write_iter = inst.log_begin() + index; + EXPECT_EQ(write_iter->address, WEAR_LEVELING_LOGICAL_SIZE + 8 + (index * BACKING_STORE_WRITE_SIZE)) << "Invalid write log address"; + + write_log_entry_t e; + e.raw64 = write_iter->value; + EXPECT_EQ(LOG_ENTRY_GET_TYPE(e), LOG_ENTRY_TYPE_MULTIBYTE) << "Invalid write log entry type"; + } + + // Verify the backing store erase + { + index = 3; + auto write_iter = inst.log_begin() + index; + e.raw64 = write_iter->value; + EXPECT_TRUE(write_iter->erased) << "Backing store erase did not occur as required"; + } + + // Verify the backing store writes for consolidation + for (index = 4; index < 6; ++index) { + auto write_iter = inst.log_begin() + index; + EXPECT_EQ(write_iter->address, (index - 4) * BACKING_STORE_WRITE_SIZE) << "Invalid write log entry address"; + } + + // Verify the FNV1a_64 write + { + EXPECT_EQ((inst.log_begin() + 6)->address, WEAR_LEVELING_LOGICAL_SIZE) << "Invalid write log address"; + e.raw64 = (inst.log_begin() + 6)->value; + EXPECT_EQ(e.raw64, fnv_64a_buf(testvalue.data(), testvalue.size(), FNV1A_64_INIT)) << "Invalid checksum"; // Note that checksum is based on testvalue, as we overwrote one byte and need to consult the consolidated data, not the current + } + + // Verify the final write + EXPECT_EQ((inst.log_begin() + 7)->address, WEAR_LEVELING_LOGICAL_SIZE + 8) << "Invalid write log address"; + + // Verify the data is what we expected + std::array readback; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match"; + + // Re-init and re-read, verifying the reload capability + EXPECT_NE(wear_leveling_init(), WEAR_LEVELING_FAILED) << "Re-initialisation failed"; + EXPECT_EQ(wear_leveling_read(0, readback.data(), WEAR_LEVELING_LOGICAL_SIZE), WEAR_LEVELING_SUCCESS) << "Failed to read back the saved data"; + EXPECT_TRUE(memcmp(readback.data(), verify_data.data(), WEAR_LEVELING_LOGICAL_SIZE) == 0) << "Readback did not match"; +} + +/** + * This test verifies multibyte readback gets canceled with an out-of-bounds address. + */ +TEST_F(WearLeveling8Byte, PlaybackReadbackMultibyte_OOB) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Invalid FNV1a_64 hash + (logstart + 0)->set(0); + + // Set up a 2-byte logical write of [0x11,0x12] at logical offset 0x01 + auto entry0 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2); + entry0.raw8[3] = 0x11; + entry0.raw8[4] = 0x12; + (logstart + 1)->set(~entry0.raw64); + + // Set up a 2-byte logical write of [0x13,0x14] at logical offset 0x1000 (out of bounds) + auto entry1 = LOG_ENTRY_MAKE_MULTIBYTE(0x1000, 2); + entry1.raw8[3] = 0x13; + entry1.raw8[4] = 0x14; + (logstart + 2)->set(~entry1.raw64); + + // Set up a 2-byte logical write of [0x15,0x16] at logical offset 0x10 + auto entry2 = LOG_ENTRY_MAKE_MULTIBYTE(0x01, 2); + entry2.raw8[3] = 0x15; + entry2.raw8[4] = 0x16; + (logstart + 3)->set(~entry2.raw64); + + EXPECT_EQ(inst.erasure_count(), 0) << "Invalid initial erase count"; + EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_CONSOLIDATED) << "Readback should have failed and triggered consolidation"; + EXPECT_EQ(inst.erasure_count(), 1) << "Invalid final erase count"; + + uint8_t buf[2]; + wear_leveling_read(0x01, buf, sizeof(buf)); + EXPECT_EQ(buf[0], 0x11) << "Readback should have maintained the previous pre-failure value from the write log"; + EXPECT_EQ(buf[1], 0x12) << "Readback should have maintained the previous pre-failure value from the write log"; +} diff --git a/quantum/wear_leveling/tests/wear_leveling_general.cpp b/quantum/wear_leveling/tests/wear_leveling_general.cpp new file mode 100644 index 0000000000..76a4bf7bf3 --- /dev/null +++ b/quantum/wear_leveling/tests/wear_leveling_general.cpp @@ -0,0 +1,204 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "backing_mocks.hpp" + +class WearLevelingGeneral : public ::testing::Test { + protected: + void SetUp() override { + MockBackingStore::Instance().reset_instance(); + wear_leveling_init(); + } +}; + +/** + * This test verifies that even if there is consolidated data present, if the checksum doesn't match then the cache is zero'd after reading the consolidated area, but before write log is played back. + */ +TEST_F(WearLevelingGeneral, InvalidChecksum_ConsolidatedDataIgnored) { + auto& inst = MockBackingStore::Instance(); + auto logstart = inst.storage_begin() + (WEAR_LEVELING_LOGICAL_SIZE / sizeof(backing_store_int_t)); + + // Generate a test block of data + std::array testvalue; + std::iota(testvalue.begin(), testvalue.end(), 0x20); + + // Write the data + EXPECT_EQ(wear_leveling_write(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_CONSOLIDATED) << "Write returned incorrect status"; + + // Invalidate the checksum + (logstart + 0)->erase(); + (logstart + 1)->erase(); + (logstart + 2)->erase(); + (logstart + 3)->erase(); + + // Set up a 1-byte logical write of [0x11] at logical offset 0x01 + auto entry0 = LOG_ENTRY_MAKE_OPTIMIZED_64(0x01, 0x11); + (logstart + 4)->set(~entry0.raw16[0]); + + // Re-init + EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_SUCCESS) << "Init returned incorrect status"; + EXPECT_EQ(wear_leveling_read(0, testvalue.data(), testvalue.size()), WEAR_LEVELING_SUCCESS) << "Failed to read"; + for (int i = 0; i < WEAR_LEVELING_LOGICAL_SIZE; ++i) { + EXPECT_EQ(testvalue[i], i == 0x01 ? 0x11 : 0x00) << "Invalid readback"; + } +} + +/** + * This test verifies that writing the same data multiple times does not result in subsequent writes to the backing store. + */ +TEST_F(WearLevelingGeneral, SameValue_SingleBackingWrite) { + auto& inst = MockBackingStore::Instance(); + + uint8_t test_val = 0x14; + EXPECT_EQ(wear_leveling_write(0x02, &test_val, sizeof(test_val)), WEAR_LEVELING_SUCCESS) << "First overall write operation should have succeeded"; + + uint64_t invoke_count = inst.unlock_invoke_count(); + uint64_t erase_count = inst.erase_invoke_count(); + uint64_t write_count = inst.write_invoke_count(); + uint64_t lock_count = inst.lock_invoke_count(); + + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(wear_leveling_write(0x02, &test_val, sizeof(test_val)), WEAR_LEVELING_SUCCESS) << "Subsequent overall write operation should have succeeded"; + + EXPECT_EQ(inst.unlock_invoke_count(), invoke_count) << "Unlock count should match"; + EXPECT_EQ(inst.erase_invoke_count(), erase_count) << "Erase count should match"; + EXPECT_EQ(inst.write_invoke_count(), write_count) << "Write count should match"; + EXPECT_EQ(inst.lock_invoke_count(), lock_count) << "Lock count should match"; + } +} + +/** + * This test verifies that no other invocations occur if `backing_store_init()` fails. + */ +TEST_F(WearLevelingGeneral, InitFailure) { + auto& inst = MockBackingStore::Instance(); + inst.reset_instance(); // make sure the counters are all zero + inst.set_init_callback([](std::uint64_t count) { return false; }); + + EXPECT_EQ(inst.erasure_count(), 0) << "Invalid initial erase count"; + EXPECT_EQ(wear_leveling_init(), WEAR_LEVELING_FAILED) << "Init should have failed"; + EXPECT_EQ(inst.erasure_count(), 0) << "Invalid final erase count"; + + EXPECT_EQ(inst.init_invoke_count(), 1) << "Init should have been invoked once"; + EXPECT_EQ(inst.unlock_invoke_count(), 0) << "Unlock should not have been invoked"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 0) << "Write should not have been invoked"; + EXPECT_EQ(inst.lock_invoke_count(), 0) << "Lock should not have been invoked"; +} + +/** + * This test verifies that no invocations occur if the supplied address is out of range while writing. + */ +TEST_F(WearLevelingGeneral, WriteFailure_OOB) { + auto& inst = MockBackingStore::Instance(); + + uint8_t test_val = 0x14; + EXPECT_EQ(wear_leveling_write(0x21349830, &test_val, sizeof(test_val)), WEAR_LEVELING_FAILED) << "Overall write operation should have failed"; + + EXPECT_EQ(inst.unlock_invoke_count(), 0) << "Unlock should not have been invoked"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 0) << "Write should not have been invoked"; + EXPECT_EQ(inst.lock_invoke_count(), 0) << "Lock should not have been invoked"; +} + +/** + * This test verifies that a single write occurs if the supplied address and data length hits the edge of the logical area. + */ +TEST_F(WearLevelingGeneral, WriteSuccess_BoundaryOK) { + auto& inst = MockBackingStore::Instance(); + + uint16_t test_val = 0x14; + EXPECT_EQ(wear_leveling_write(WEAR_LEVELING_LOGICAL_SIZE - sizeof(test_val), &test_val, sizeof(test_val)), WEAR_LEVELING_SUCCESS) << "Overall write operation should have succeeded"; + + EXPECT_EQ(inst.unlock_invoke_count(), 1) << "Unlock should have been invoked once"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 2) << "Write should have been invoked twice"; + EXPECT_EQ(inst.lock_invoke_count(), 1) << "Lock should have been invoked once"; +} + +/** + * This test verifies that no invocations occur if the supplied address and length would generate writes outside the logical range. + */ +TEST_F(WearLevelingGeneral, WriteFailure_BoundaryOverflow) { + auto& inst = MockBackingStore::Instance(); + + uint16_t test_val = 0x14; + EXPECT_EQ(wear_leveling_write(WEAR_LEVELING_LOGICAL_SIZE - sizeof(test_val) + 1, &test_val, sizeof(test_val)), WEAR_LEVELING_FAILED) << "Overall write operation should have failed"; + + EXPECT_EQ(inst.unlock_invoke_count(), 0) << "Unlock should not have been invoked"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 0) << "Write should not have been invoked"; + EXPECT_EQ(inst.lock_invoke_count(), 0) << "Lock should not have been invoked"; +} + +/** + * This test verifies that no invocations occur if the supplied address is out of range while reading. + */ +TEST_F(WearLevelingGeneral, ReadFailure_OOB) { + auto& inst = MockBackingStore::Instance(); + + uint8_t test_val = 0; + EXPECT_EQ(wear_leveling_read(0x21349830, &test_val, sizeof(test_val)), WEAR_LEVELING_FAILED) << "Overall read operation should have failed"; + + EXPECT_EQ(inst.unlock_invoke_count(), 0) << "Unlock should not have been invoked"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 0) << "Write should not have been invoked"; + EXPECT_EQ(inst.lock_invoke_count(), 0) << "Lock should not have been invoked"; +} + +/** + * This test verifies that no write invocations occur if `backing_store_unlock()` fails. + */ +TEST_F(WearLevelingGeneral, UnlockFailure_NoWrite) { + auto& inst = MockBackingStore::Instance(); + inst.set_unlock_callback([](std::uint64_t count) { return false; }); + + uint8_t test_val = 0x14; + EXPECT_EQ(wear_leveling_write(0x04, &test_val, sizeof(test_val)), WEAR_LEVELING_FAILED) << "Overall write operation should have failed"; + + EXPECT_EQ(inst.unlock_invoke_count(), 1) << "Unlock should have been invoked once"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 0) << "Write should not have been invoked"; + EXPECT_EQ(inst.lock_invoke_count(), 0) << "Lock should not have been invoked"; + + test_val = 0; + wear_leveling_read(0x04, &test_val, sizeof(test_val)); + EXPECT_EQ(test_val, 0x14) << "Readback should come from cache regardless of unlock failure"; +} + +/** + * This test verifies that no erase invocations occur if `backing_store_unlock()` fails. + */ +TEST_F(WearLevelingGeneral, UnlockFailure_NoErase) { + auto& inst = MockBackingStore::Instance(); + inst.set_unlock_callback([](std::uint64_t count) { return false; }); + + EXPECT_EQ(wear_leveling_erase(), WEAR_LEVELING_FAILED) << "Overall erase operation should have failed"; + + EXPECT_EQ(inst.unlock_invoke_count(), 1) << "Unlock should have been invoked once"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 0) << "Write should not have been invoked"; + EXPECT_EQ(inst.lock_invoke_count(), 0) << "Lock should not have been invoked"; +} + +/** + * This test verifies that only one write invocation occurs if `backing_store_write()` fails. + */ +TEST_F(WearLevelingGeneral, WriteFailure_NoSubsequentWrites) { + auto& inst = MockBackingStore::Instance(); + inst.set_write_callback([](std::uint64_t count, std::uint32_t address) { return false; }); + + uint8_t test_val = 0x14; + EXPECT_EQ(wear_leveling_write(0x04, &test_val, sizeof(test_val)), WEAR_LEVELING_FAILED) << "Overall write operation should have failed"; + + EXPECT_EQ(inst.unlock_invoke_count(), 1) << "Unlock should have been invoked once"; + EXPECT_EQ(inst.erase_invoke_count(), 0) << "Erase should not have been invoked"; + EXPECT_EQ(inst.write_invoke_count(), 1) << "Write should have been invoked once"; + EXPECT_EQ(inst.lock_invoke_count(), 1) << "Lock should have been invoked once"; + + test_val = 0; + wear_leveling_read(0x04, &test_val, sizeof(test_val)); + EXPECT_EQ(test_val, 0x14) << "Readback should come from cache regardless of unlock failure"; +} diff --git a/quantum/wear_leveling/wear_leveling.c b/quantum/wear_leveling/wear_leveling.c new file mode 100644 index 0000000000..8418ae77bf --- /dev/null +++ b/quantum/wear_leveling/wear_leveling.c @@ -0,0 +1,779 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "fnv.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +/* + This wear leveling algorithm is adapted from algorithms from previous + implementations in QMK, namely: + - Artur F. (http://engsta.com/stm32-flash-memory-eeprom-emulator/) + - Yiancar -- QMK's base implementation for STM32F303 + - Ilya Zhuravlev -- initial wear leveling algorithm + - Don Kjer -- increased flash density algorithm + - Nick Brassel (@tzarc) -- decoupled for use on other peripherals + + At this layer, it is assumed that any reads/writes from the backing store + have a "reset state" after erasure of zero. + It is up to the backing store to perform translation of values, such as + taking the complement in order to deal with flash memory's reset value. + + Terminology: + + - Backing store: this is the storage area used by the wear leveling + algorithm. + + - Backing size: this is the amount of storage provided by the backing + store for use by the wear leveling algorithm. + + - Backing write size: this is the minimum number of bytes the backing + store can write in a single operation. + + - Logical data: this is the externally-visible "emulated EEPROM" that + external subsystems "see" when performing reads/writes. + + - Logical size: this is the amount of storage available for use + externally. Effectively, the "size of the EEPROM". + + - Write log: this is a section of the backing store used to keep track + of modifications without overwriting existing data. This log is + "played back" on startup such that any subsequent reads are capable + of returning the latest data. + + - Consolidated data: this is a section of the backing store reserved for + use for the latest copy of logical data. This is only ever written + when the write log is full -- the latest values for the logical data + are written here and the write log is cleared. + + Configurables: + + - BACKING_STORE_WRITE_SIZE: The number of bytes requires for a write + operation. This is defined by the capabilities of the backing store. + + - WEAR_LEVELING_BACKING_SIZE: The number of bytes provided by the + backing store for use by the wear leveling algorithm. This is + defined by the capabilities of the backing store. This value must + also be at least twice the size of the logical size, as well as a + multiple of the logical size. + + - WEAR_LEVELING_LOGICAL_SIZE: The number of bytes externally visible + to other subsystems performing reads/writes. This must be a multiple + of the write size. + + General algorithm: + + During initialization: + * The contents of the consolidated data section are read into cache. + * The contents of the write log are "played back" and update the + cache accordingly. + + During reads: + * Logical data is served from the cache. + + During writes: + * The cache is updated with the new data. + * A new write log entry is appended to the log. + * If the log's full, data is consolidated and the write log cleared. + + Write log structure: + + The first 8 bytes of the write log are a FNV1a_64 hash of the contents + of the consolidated data area, in an attempt to detect and guard against + any data corruption. + + The write log follows the hash: + + Given that the algorithm needs to cater for 2-, 4-, and 8-byte writes, + a variable-length write log entry is used such that the minimal amount + of storage is used based off the backing store write size. + + Firstly, an empty log entry is expected to be all zeros. If the backing + store uses 0xFF for cleared bytes, it should return the complement, such + that this wear-leveling algorithm "receives" zeros. + + For multi-byte writes, up to 8 bytes will be used for each log entry, + depending on the size of backing store writes: + + ╔ Multi-byte Log Entry (2, 4-byte) ═╗ + ║00XXXYYY║YYYYYYYY║YYYYYYYY║AAAAAAAA║ + ║ └┬┘└┬┘║└──┬───┘║└──┬───┘║└──┬───┘║ + ║ LenAdd║ Address║ Address║Value[0]║ + ╚════════╩════════╩════════╩════════╝ + ╔ Multi-byte Log Entry (2-byte) ══════════════════════╗ + ║00XXXYYY║YYYYYYYY║YYYYYYYY║AAAAAAAA║BBBBBBBB║CCCCCCCC║ + ║ └┬┘└┬┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║ + ║ LenAdd║ Address║ Address║Value[0]║Value[1]║Value[2]║ + ╚════════╩════════╩════════╩════════╩════════╩════════╝ + ╔ Multi-byte Log Entry (2, 4, 8-byte) ══════════════════════════════════╗ + ║00XXXYYY║YYYYYYYY║YYYYYYYY║AAAAAAAA║BBBBBBBB║CCCCCCCC║DDDDDDDD║EEEEEEEE║ + ║ └┬┘└┬┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║ + ║ LenAdd║ Address║ Address║Value[0]║Value[1]║Value[2]║Value[3]║Value[4]║ + ╚════════╩════════╩════════╩════════╩════════╩════════╩════════╩════════╝ + + 19 bits are used for the address, which allows for a max logical size of + 512kB. Up to 5 bytes can be included in a single log entry. + + For 2-byte backing store writes, the last two bytes are optional + depending on the length of data to be written. Accordingly, either 3 + or 4 backing store write operations will occur. + For 4-byte backing store writes, either one or two write operations + occur, depending on the length. + For 8-byte backing store writes, one write operation occur. + + 2-byte backing store optimizations: + + For single byte writes, addresses between 0...63 are encoded in a single + backing store write operation. 4- and 8-byte backing stores do not have + this optimization as it does not minimize the number of bytes written. + + ╔ Byte-Entry ════╗ + ║01XXXXXXYYYYYYYY║ + ║ └─┬──┘└──┬───┘║ + ║ Address Value ║ + ╚════════════════╝ + 0 <= Address < 0x40 (64) + + A second optimization takes into account uint16_t writes of 0 or 1, + specifically catering for KC_NO and KC_TRANSPARENT in the dynamic keymap + subsystem. This is valid only for the first 16kB of logical data -- + addresses outside this range will use the multi-byte encoding above. + + ╔ U16-Encoded 0 ═╗ + ║100XXXXXXXXXXXXX║ + ║ │└─────┬─────┘║ + ║ │Address >> 1 ║ + ║ └── Value: 0 ║ + ╚════════════════╝ + 0 <= Address <= 0x3FFE (16382) + + ╔ U16-Encoded 1 ═╗ + ║101XXXXXXXXXXXXX║ + ║ │└─────┬─────┘║ + ║ │Address >> 1 ║ + ║ └── Value: 1 ║ + ╚════════════════╝ + 0 <= Address <= 0x3FFE (16382) */ + +/** + * Storage area for the wear-leveling cache. + */ +static struct __attribute__((__aligned__(BACKING_STORE_WRITE_SIZE))) { + __attribute__((__aligned__(BACKING_STORE_WRITE_SIZE))) uint8_t cache[(WEAR_LEVELING_LOGICAL_SIZE)]; + uint32_t write_address; + bool unlocked; +} wear_leveling; + +/** + * Locking helper: status + */ +typedef enum backing_store_lock_status_t { STATUS_FAILURE = 0, STATUS_SUCCESS, STATUS_UNCHANGED } backing_store_lock_status_t; + +/** + * Locking helper: unlock + */ +static inline backing_store_lock_status_t wear_leveling_unlock(void) { + if (wear_leveling.unlocked) { + return STATUS_UNCHANGED; + } + if (!backing_store_unlock()) { + return STATUS_FAILURE; + } + wear_leveling.unlocked = true; + return STATUS_SUCCESS; +} + +/** + * Locking helper: lock + */ +static inline backing_store_lock_status_t wear_leveling_lock(void) { + if (!wear_leveling.unlocked) { + return STATUS_UNCHANGED; + } + if (!backing_store_lock()) { + return STATUS_FAILURE; + } + wear_leveling.unlocked = false; + return STATUS_SUCCESS; +} + +/** + * Resets the cache, ensuring the write address is correctly initialised. + */ +static void wear_leveling_clear_cache(void) { + memset(wear_leveling.cache, 0, (WEAR_LEVELING_LOGICAL_SIZE)); + wear_leveling.write_address = (WEAR_LEVELING_LOGICAL_SIZE) + 8; // +8 is due to the FNV1a_64 of the consolidated buffer +} + +/** + * Reads the consolidated data from the backing store into the cache. + * Does not consider the write log. + */ +static wear_leveling_status_t wear_leveling_read_consolidated(void) { + wl_dprintf("Reading consolidated data\n"); + + wear_leveling_status_t status = WEAR_LEVELING_SUCCESS; + for (int address = 0; address < (WEAR_LEVELING_LOGICAL_SIZE); address += (BACKING_STORE_WRITE_SIZE)) { + backing_store_int_t *const loc = (backing_store_int_t *)&wear_leveling.cache[address]; + backing_store_int_t temp; + bool ok = backing_store_read(address, &temp); + if (!ok) { + wl_dprintf("Failed to read from backing store\n"); + status = WEAR_LEVELING_FAILED; + break; + } + *loc = temp; + } + + // Verify the FNV1a_64 result + if (status != WEAR_LEVELING_FAILED) { + uint64_t expected = fnv_64a_buf(wear_leveling.cache, (WEAR_LEVELING_LOGICAL_SIZE), FNV1A_64_INIT); + write_log_entry_t entry; +#if BACKING_STORE_WRITE_SIZE == 2 + backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 0, &entry.raw16[0]); + backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 2, &entry.raw16[1]); + backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 4, &entry.raw16[2]); + backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 6, &entry.raw16[3]); +#elif BACKING_STORE_WRITE_SIZE == 4 + backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 0, &entry.raw32[0]); + backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 4, &entry.raw32[1]); +#elif BACKING_STORE_WRITE_SIZE == 8 + backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 0, &entry.raw64); +#endif + // If we have a mismatch, clear the cache but do not flag a failure, + // which will cater for the completely clean MCU case. + if (entry.raw64 != expected) { + wear_leveling_clear_cache(); + } + } + + // If we failed for any reason, then clear the cache + if (status == WEAR_LEVELING_FAILED) { + wear_leveling_clear_cache(); + } + + return status; +} + +/** + * Writes the current cache to consolidated data at the beginning of the backing store. + * Does not clear the write log. + */ +static wear_leveling_status_t wear_leveling_write_consolidated(void) { + wl_dprintf("Writing consolidated data\n"); + + wear_leveling_status_t status = WEAR_LEVELING_CONSOLIDATED; + backing_store_lock_status_t lock_status = wear_leveling_unlock(); + for (int address = 0; address < (WEAR_LEVELING_LOGICAL_SIZE); address += (BACKING_STORE_WRITE_SIZE)) { + const backing_store_int_t value = *(backing_store_int_t *)&wear_leveling.cache[address]; + backing_store_int_t temp; + bool ok = backing_store_read(address, &temp); + if (!ok) { + wl_dprintf("Failed to read from backing store\n"); + status = WEAR_LEVELING_FAILED; + break; + } + if (temp != value) { + ok = backing_store_write(address, value); + if (!ok) { + wl_dprintf("Failed to write to backing store\n"); + status = WEAR_LEVELING_FAILED; + break; + } + } + } + + if (status != WEAR_LEVELING_FAILED) { + // Write out the FNV1a_64 result of the consolidated data + write_log_entry_t entry; + entry.raw64 = fnv_64a_buf(wear_leveling.cache, (WEAR_LEVELING_LOGICAL_SIZE), FNV1A_64_INIT); + do { +#if BACKING_STORE_WRITE_SIZE == 2 + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 0, entry.raw16[0])) { + status = WEAR_LEVELING_FAILED; + break; + } + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 2, entry.raw16[1])) { + status = WEAR_LEVELING_FAILED; + break; + } + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 4, entry.raw16[2])) { + status = WEAR_LEVELING_FAILED; + break; + } + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 6, entry.raw16[3])) { + status = WEAR_LEVELING_FAILED; + break; + } +#elif BACKING_STORE_WRITE_SIZE == 4 + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 0, entry.raw32[0])) { + status = WEAR_LEVELING_FAILED; + break; + } + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 4, entry.raw32[1])) { + status = WEAR_LEVELING_FAILED; + break; + } +#elif BACKING_STORE_WRITE_SIZE == 8 + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 0, entry.raw64)) { + status = WEAR_LEVELING_FAILED; + break; + } +#endif + } while (0); + } + + if (lock_status == STATUS_SUCCESS) { + wear_leveling_lock(); + } + return status; +} + +/** + * Forces a write of the current cache. + * Erases the backing store, including the write log. + * During this operation, there is the potential for data loss if a power loss occurs. + */ +static wear_leveling_status_t wear_leveling_consolidate_force(void) { + wl_dprintf("Erasing backing store\n"); + + // Erase the backing store. Expectation is that any un-written values that are read back after this call come back as zero. + bool ok = backing_store_erase(); + if (!ok) { + wl_dprintf("Failed to erase backing store\n"); + return WEAR_LEVELING_FAILED; + } + + // Write the cache to the first section of the backing store. + wear_leveling_status_t status = wear_leveling_write_consolidated(); + if (status == WEAR_LEVELING_FAILED) { + wl_dprintf("Failed to write consolidated data\n"); + } + + // Next write of the log occurs after the consolidated values at the start of the backing store. + wear_leveling.write_address = (WEAR_LEVELING_LOGICAL_SIZE) + 8; // +8 due to the FNV1a_64 of the consolidated area + + return status; +} + +/** + * Potential write of the current cache to the backing store. + * Skipped if the current write log position is not at the end of the backing store. + * During this operation, there is the potential for data loss if a power loss occurs. + * + * @return true if consolidation occurred + */ +static wear_leveling_status_t wear_leveling_consolidate_if_needed(void) { + if (wear_leveling.write_address >= (WEAR_LEVELING_BACKING_SIZE)) { + return wear_leveling_consolidate_force(); + } + + return WEAR_LEVELING_SUCCESS; +} + +/** + * Appends the supplied fixed-width entry to the write log, optionally consolidating if the log is full. + * + * @return true if consolidation occurred + */ +static wear_leveling_status_t wear_leveling_append_raw(backing_store_int_t value) { + bool ok = backing_store_write(wear_leveling.write_address, value); + if (!ok) { + wl_dprintf("Failed to write to backing store\n"); + return WEAR_LEVELING_FAILED; + } + wear_leveling.write_address += (BACKING_STORE_WRITE_SIZE); + return wear_leveling_consolidate_if_needed(); +} + +/** + * Handles writing multi_byte-encoded data to the backing store. + * + * @return true if consolidation occurred + */ +static wear_leveling_status_t wear_leveling_write_raw_multibyte(uint32_t address, const void *value, size_t length) { + const uint8_t * p = value; + write_log_entry_t log = LOG_ENTRY_MAKE_MULTIBYTE(address, length); + for (size_t i = 0; i < length; ++i) { + log.raw8[3 + i] = p[i]; + } + + // Write to the backing store. See the multi-byte log format in the documentation header at the top of the file. + wear_leveling_status_t status; +#if BACKING_STORE_WRITE_SIZE == 2 + status = wear_leveling_append_raw(log.raw16[0]); + if (status != WEAR_LEVELING_SUCCESS) { + return status; + } + + status = wear_leveling_append_raw(log.raw16[1]); + if (status != WEAR_LEVELING_SUCCESS) { + return status; + } + + if (length > 1) { + status = wear_leveling_append_raw(log.raw16[2]); + if (status != WEAR_LEVELING_SUCCESS) { + return status; + } + } + + if (length > 3) { + status = wear_leveling_append_raw(log.raw16[3]); + if (status != WEAR_LEVELING_SUCCESS) { + return status; + } + } +#elif BACKING_STORE_WRITE_SIZE == 4 + status = wear_leveling_append_raw(log.raw32[0]); + if (status != WEAR_LEVELING_SUCCESS) { + return status; + } + + if (length > 1) { + status = wear_leveling_append_raw(log.raw32[1]); + if (status != WEAR_LEVELING_SUCCESS) { + return status; + } + } +#elif BACKING_STORE_WRITE_SIZE == 8 + status = wear_leveling_append_raw(log.raw64); + if (status != WEAR_LEVELING_SUCCESS) { + return status; + } +#endif + return status; +} + +/** + * Handles the actual writing of logical data into the write log section of the backing store. + */ +static wear_leveling_status_t wear_leveling_write_raw(uint32_t address, const void *value, size_t length) { + const uint8_t * p = value; + size_t remaining = length; + wear_leveling_status_t status = WEAR_LEVELING_SUCCESS; + while (remaining > 0) { +#if BACKING_STORE_WRITE_SIZE == 2 + // Small-write optimizations - uint16_t, 0 or 1, address is even, address <16384: + if (remaining >= 2 && address % 2 == 0 && address < 16384) { + const uint16_t v = *(const uint16_t *)p; + if (v == 0 || v == 1) { + const write_log_entry_t log = LOG_ENTRY_MAKE_WORD_01(address, v); + status = wear_leveling_append_raw(log.raw16[0]); + if (status != WEAR_LEVELING_SUCCESS) { + // If consolidation occurred, then the cache has already been written to the consolidated area. No need to continue. + // If a failure occurred, pass it on. + return status; + } + + remaining -= 2; + address += 2; + p += 2; + continue; + } + } + + // Small-write optimizations - address<64: + if (address < 64) { + const write_log_entry_t log = LOG_ENTRY_MAKE_OPTIMIZED_64(address, *p); + status = wear_leveling_append_raw(log.raw16[0]); + if (status != WEAR_LEVELING_SUCCESS) { + // If consolidation occurred, then the cache has already been written to the consolidated area. No need to continue. + // If a failure occurred, pass it on. + return status; + } + + remaining--; + address++; + p++; + continue; + } +#endif // BACKING_STORE_WRITE_SIZE == 2 + const size_t this_length = remaining >= LOG_ENTRY_MULTIBYTE_MAX_BYTES ? LOG_ENTRY_MULTIBYTE_MAX_BYTES : remaining; + status = wear_leveling_write_raw_multibyte(address, p, this_length); + if (status != WEAR_LEVELING_SUCCESS) { + // If consolidation occurred, then the cache has already been written to the consolidated area. No need to continue. + // If a failure occurred, pass it on. + return status; + } + remaining -= this_length; + address += (uint32_t)this_length; + p += this_length; + } + + return status; +} + +/** + * "Replays" the write log from the backing store, updating the local cache with updated values. + */ +static wear_leveling_status_t wear_leveling_playback_log(void) { + wl_dprintf("Playback write log\n"); + + wear_leveling_status_t status = WEAR_LEVELING_SUCCESS; + bool cancel_playback = false; + uint32_t address = (WEAR_LEVELING_LOGICAL_SIZE) + 8; // +8 due to the FNV1a_64 of the consolidated area + while (!cancel_playback && address < (WEAR_LEVELING_BACKING_SIZE)) { + backing_store_int_t value; + bool ok = backing_store_read(address, &value); + if (!ok) { + wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + if (value == 0) { + wl_dprintf("Found empty slot, no more log entries\n"); + cancel_playback = true; + break; + } + + // If we got a nonzero value, then we need to increment the address to ensure next write occurs at next location + address += (BACKING_STORE_WRITE_SIZE); + + // Read from the write log + write_log_entry_t log; +#if BACKING_STORE_WRITE_SIZE == 2 + log.raw16[0] = value; +#elif BACKING_STORE_WRITE_SIZE == 4 + log.raw32[0] = value; +#elif BACKING_STORE_WRITE_SIZE == 8 + log.raw64 = value; +#endif + + switch (LOG_ENTRY_GET_TYPE(log)) { + case LOG_ENTRY_TYPE_MULTIBYTE: { +#if BACKING_STORE_WRITE_SIZE == 2 + ok = backing_store_read(address, &log.raw16[1]); + if (!ok) { + wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + address += (BACKING_STORE_WRITE_SIZE); +#endif // BACKING_STORE_WRITE_SIZE == 2 + const uint32_t a = LOG_ENTRY_MULTIBYTE_GET_ADDRESS(log); + const uint8_t l = LOG_ENTRY_MULTIBYTE_GET_LENGTH(log); + + if (a + l > (WEAR_LEVELING_LOGICAL_SIZE)) { + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + +#if BACKING_STORE_WRITE_SIZE == 2 + if (l > 1) { + ok = backing_store_read(address, &log.raw16[2]); + if (!ok) { + wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + address += (BACKING_STORE_WRITE_SIZE); + } + if (l > 3) { + ok = backing_store_read(address, &log.raw16[3]); + if (!ok) { + wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + address += (BACKING_STORE_WRITE_SIZE); + } +#elif BACKING_STORE_WRITE_SIZE == 4 + if (l > 1) { + ok = backing_store_read(address, &log.raw32[1]); + if (!ok) { + wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + address += (BACKING_STORE_WRITE_SIZE); + } +#endif + + memcpy(&wear_leveling.cache[a], &log.raw8[3], l); + } break; +#if BACKING_STORE_WRITE_SIZE == 2 + case LOG_ENTRY_TYPE_OPTIMIZED_64: { + const uint32_t a = LOG_ENTRY_OPTIMIZED_64_GET_ADDRESS(log); + const uint8_t v = LOG_ENTRY_OPTIMIZED_64_GET_VALUE(log); + + if (a >= (WEAR_LEVELING_LOGICAL_SIZE)) { + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + + wear_leveling.cache[a] = v; + } break; + case LOG_ENTRY_TYPE_WORD_01: { + const uint32_t a = LOG_ENTRY_WORD_01_GET_ADDRESS(log); + const uint8_t v = LOG_ENTRY_WORD_01_GET_VALUE(log); + + if (a + 1 >= (WEAR_LEVELING_LOGICAL_SIZE)) { + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + break; + } + + wear_leveling.cache[a + 0] = v; + wear_leveling.cache[a + 1] = 0; + } break; +#endif // BACKING_STORE_WRITE_SIZE == 2 + default: { + cancel_playback = true; + status = WEAR_LEVELING_FAILED; + } break; + } + } + + // We've reached the end of the log, so we're at the new write location + wear_leveling.write_address = address; + + if (status == WEAR_LEVELING_FAILED) { + // If we had a failure during readback, assume we're corrupted -- force a consolidation with the data we already have + status = wear_leveling_consolidate_force(); + } else { + // Consolidate the cache + write log if required + status = wear_leveling_consolidate_if_needed(); + } + + return status; +} + +/** + * Wear-leveling initialization + */ +wear_leveling_status_t wear_leveling_init(void) { + wl_dprintf("Init\n"); + + // Reset the cache + wear_leveling_clear_cache(); + + // Initialise the backing store + if (!backing_store_init()) { + // If it failed, clear the cache and return with failure + wear_leveling_clear_cache(); + return WEAR_LEVELING_FAILED; + } + + // Read the previous consolidated values, then replay the existing write log so that the cache has the "live" values + wear_leveling_status_t status = wear_leveling_read_consolidated(); + if (status == WEAR_LEVELING_FAILED) { + // If it failed, clear the cache and return with failure + wear_leveling_clear_cache(); + return status; + } + + status = wear_leveling_playback_log(); + if (status == WEAR_LEVELING_FAILED) { + // If it failed, clear the cache and return with failure + wear_leveling_clear_cache(); + return status; + } + + return status; +} + +/** + * Wear-leveling erase. + * Post-condition: any reads from the backing store directly after an erase operation must come back as zero. + */ +wear_leveling_status_t wear_leveling_erase(void) { + wl_dprintf("Erase\n"); + + // Unlock the backing store + backing_store_lock_status_t lock_status = wear_leveling_unlock(); + if (lock_status == STATUS_FAILURE) { + wear_leveling_lock(); + return WEAR_LEVELING_FAILED; + } + + // Perform the erase + bool ret = backing_store_erase(); + wear_leveling_clear_cache(); + + // Lock the backing store if we acquired the lock successfully + if (lock_status == STATUS_SUCCESS) { + ret &= (wear_leveling_lock() != STATUS_FAILURE); + } + + return ret ? WEAR_LEVELING_SUCCESS : WEAR_LEVELING_FAILED; +} + +/** + * Writes logical data into the backing store. Skips writes if there are no changes to values. + */ +wear_leveling_status_t wear_leveling_write(const uint32_t address, const void *value, size_t length) { + wl_assert(address + length <= (WEAR_LEVELING_LOGICAL_SIZE)); + if (address + length > (WEAR_LEVELING_LOGICAL_SIZE)) { + return WEAR_LEVELING_FAILED; + } + + wl_dprintf("Write "); + wl_dump(address, value, length); + + // Skip write if there's no change compared to the current cached value + if (memcmp(value, &wear_leveling.cache[address], length) == 0) { + return true; + } + + // Update the cache before writing to the backing store -- if we hit the end of the backing store during writes to the log then we'll force a consolidation in-line + memcpy(&wear_leveling.cache[address], value, length); + + // Unlock the backing store + backing_store_lock_status_t lock_status = wear_leveling_unlock(); + if (lock_status == STATUS_FAILURE) { + wear_leveling_lock(); + return WEAR_LEVELING_FAILED; + } + + // Perform the actual write + wear_leveling_status_t status = wear_leveling_write_raw(address, value, length); + switch (status) { + case WEAR_LEVELING_CONSOLIDATED: + case WEAR_LEVELING_FAILED: + // If the write triggered consolidation, or the write failed, then nothing else needs to occur. + break; + + case WEAR_LEVELING_SUCCESS: + // Consolidate the cache + write log if required + status = wear_leveling_consolidate_if_needed(); + break; + + default: + // Unsure how we'd get here... + status = WEAR_LEVELING_FAILED; + break; + } + + if (lock_status == STATUS_SUCCESS) { + if (wear_leveling_lock() == STATUS_FAILURE) { + status = WEAR_LEVELING_FAILED; + } + } + + return status; +} + +/** + * Reads logical data from the cache. + */ +wear_leveling_status_t wear_leveling_read(const uint32_t address, void *value, size_t length) { + wl_assert(address + length <= (WEAR_LEVELING_LOGICAL_SIZE)); + if (address + length > (WEAR_LEVELING_LOGICAL_SIZE)) { + return WEAR_LEVELING_FAILED; + } + + // Only need to copy from the cache + memcpy(value, &wear_leveling.cache[address], length); + + wl_dprintf("Read "); + wl_dump(address, value, length); + return WEAR_LEVELING_SUCCESS; +} diff --git a/quantum/wear_leveling/wear_leveling.h b/quantum/wear_leveling/wear_leveling.h new file mode 100644 index 0000000000..6641bc49b3 --- /dev/null +++ b/quantum/wear_leveling/wear_leveling.h @@ -0,0 +1,54 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once +#include +#include + +/** + * @typedef Status returned from any wear-leveling API. + */ +typedef enum wear_leveling_status_t { + WEAR_LEVELING_FAILED, //< Invocation failed + WEAR_LEVELING_SUCCESS, //< Invocation succeeded + WEAR_LEVELING_CONSOLIDATED //< Invocation succeeded, consolidation occurred +} wear_leveling_status_t; + +/** + * Wear-leveling initialization + * + * @return Status of the request + */ +wear_leveling_status_t wear_leveling_init(void); + +/** + * Wear-leveling erasure. + * + * Clears the wear-leveling area, with the definition that the "reset state" of all data is zero. + * + * @return Status of the request + */ +wear_leveling_status_t wear_leveling_erase(void); + +/** + * Writes logical data into the backing store. + * + * Skips writes if there are no changes to written values. The entire written block is considered when attempting to + * determine if an overwrite should occur -- if there is any data mismatch the entire block will be written to the log, + * not just the changed bytes. + * + * @param address[in] the logical address to write data + * @param value[in] pointer to the source buffer + * @param length[in] length of the data + * @return Status of the request + */ +wear_leveling_status_t wear_leveling_write(uint32_t address, const void* value, size_t length); + +/** + * Reads logical data from the cache. + * + * @param address[in] the logical address to read data + * @param value[out] pointer to the destination buffer + * @param length[in] length of the data + * @return Status of the request + */ +wear_leveling_status_t wear_leveling_read(uint32_t address, void* value, size_t length); diff --git a/quantum/wear_leveling/wear_leveling_internal.h b/quantum/wear_leveling/wear_leveling_internal.h new file mode 100644 index 0000000000..74b43932df --- /dev/null +++ b/quantum/wear_leveling/wear_leveling_internal.h @@ -0,0 +1,145 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifdef __cplusplus +# define _Static_assert static_assert +#endif + +#include +#include + +#if BACKING_STORE_WRITE_SIZE == 2 +typedef uint16_t backing_store_int_t; +#elif BACKING_STORE_WRITE_SIZE == 4 +typedef uint32_t backing_store_int_t; +#elif BACKING_STORE_WRITE_SIZE == 8 +typedef uint64_t backing_store_int_t; +#else +# error Invalid BACKING_STORE_WRITE_SIZE, needs to be 2/4/8. +#endif + +#ifndef WEAR_LEVELING_BACKING_SIZE +# error WEAR_LEVELING_BACKING_SIZE was not set. +#endif + +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# error WEAR_LEVELING_LOGICAL_SIZE was not set. +#endif + +#ifdef WEAR_LEVELING_DEBUG_OUTPUT +# include +# define wl_dprintf(...) printf("Wear leveling: " __VA_ARGS__) +# define wl_dump(address, value, length) \ + do { \ + printf("[0x%04X]: ", (int)(address)); \ + const uint8_t* p = (const uint8_t*)(value); \ + for (int i = 0; i < (length); ++i) { \ + printf(" %02X", (int)p[i]); \ + } \ + printf("\n"); \ + } while (0) +#else +# define wl_dprintf(...) \ + do { \ + } while (0) +# define wl_dump(...) \ + do { \ + } while (0) +#endif // WEAR_LEVELING_DEBUG_OUTPUT + +#ifdef WEAR_LEVELING_ASSERTS +# include +# define wl_assert(...) assert(__VA_ARGS__) +#else +# define wl_assert(...) \ + do { \ + } while (0) +#endif // WEAR_LEVELING_ASSERTS + +// Compile-time validation of configurable options +_Static_assert(WEAR_LEVELING_BACKING_SIZE >= (WEAR_LEVELING_LOGICAL_SIZE * 2), "Total backing size must be at least twice the size of the logical size"); +_Static_assert(WEAR_LEVELING_LOGICAL_SIZE % BACKING_STORE_WRITE_SIZE == 0, "Logical size must be a multiple of write size"); +_Static_assert(WEAR_LEVELING_BACKING_SIZE % WEAR_LEVELING_LOGICAL_SIZE == 0, "Backing size must be a multiple of logical size"); + +// Backing Store API, to be implemented elsewhere by flash driver etc. +bool backing_store_init(void); +bool backing_store_unlock(void); +bool backing_store_erase(void); +bool backing_store_write(uint32_t address, backing_store_int_t value); +bool backing_store_lock(void); +bool backing_store_read(uint32_t address, backing_store_int_t* value); + +/** + * Helper type used to contain a write log entry. + */ +typedef union write_log_entry_t { + uint64_t raw64; + uint32_t raw32[2]; + uint16_t raw16[4]; + uint8_t raw8[8]; +} write_log_entry_t; + +_Static_assert(sizeof(write_log_entry_t) == 8, "Wear leveling write log entry size was not 8"); + +/** + * Log entry type discriminator. + */ +enum { + // 0x00 -- Multi-byte storage type + LOG_ENTRY_TYPE_MULTIBYTE, + + // 0x01 -- 2-byte backing store write optimization: address < 64 + LOG_ENTRY_TYPE_OPTIMIZED_64, + + // 0x02 -- 2-byte backing store write optimization: word-encoded 0/1 values + LOG_ENTRY_TYPE_WORD_01, + + LOG_ENTRY_TYPES +}; + +_Static_assert(LOG_ENTRY_TYPES <= (1 << 2), "Too many log entry types to fit into 2 bits of storage"); + +#define BITMASK_FOR_BITCOUNT(n) ((1 << (n)) - 1) + +#define LOG_ENTRY_GET_TYPE(entry) (((entry).raw8[0] >> 6) & BITMASK_FOR_BITCOUNT(2)) + +#define LOG_ENTRY_MULTIBYTE_MAX_BYTES 5 +#define LOG_ENTRY_MULTIBYTE_GET_ADDRESS(entry) (((((uint32_t)((entry).raw8[0])) & BITMASK_FOR_BITCOUNT(3)) << 16) | (((uint32_t)((entry).raw8[1])) << 8) | (entry).raw8[2]) +#define LOG_ENTRY_MULTIBYTE_GET_LENGTH(entry) ((uint8_t)(((entry).raw8[0] >> 3) & BITMASK_FOR_BITCOUNT(3))) +#define LOG_ENTRY_MAKE_MULTIBYTE(address, length) \ + (write_log_entry_t) { \ + .raw8 = { \ + [0] = (((((uint8_t)LOG_ENTRY_TYPE_MULTIBYTE) & BITMASK_FOR_BITCOUNT(2)) << 6) /* type */ \ + | ((((uint8_t)(length)) & BITMASK_FOR_BITCOUNT(3)) << 3) /* length */ \ + | ((((uint8_t)((address) >> 16))) & BITMASK_FOR_BITCOUNT(3)) /* address */ \ + ), \ + [1] = (((uint8_t)((address) >> 8)) & BITMASK_FOR_BITCOUNT(8)), /* address */ \ + [2] = (((uint8_t)(address)) & BITMASK_FOR_BITCOUNT(8)), /* address */ \ + } \ + } + +#define LOG_ENTRY_OPTIMIZED_64_GET_ADDRESS(entry) ((uint32_t)((entry).raw8[0] & BITMASK_FOR_BITCOUNT(6))) +#define LOG_ENTRY_OPTIMIZED_64_GET_VALUE(entry) ((entry).raw8[1]) +#define LOG_ENTRY_MAKE_OPTIMIZED_64(address, value) \ + (write_log_entry_t) { \ + .raw8 = { \ + [0] = (((((uint8_t)LOG_ENTRY_TYPE_OPTIMIZED_64) & BITMASK_FOR_BITCOUNT(2)) << 6) /* type */ \ + | ((((uint8_t)(address))) & BITMASK_FOR_BITCOUNT(6)) /* address */ \ + ), \ + [1] = ((uint8_t)(value)), /* value */ \ + } \ + } + +#define LOG_ENTRY_WORD_01_GET_ADDRESS(entry) ((((uint32_t)(((entry).raw8[0]) & BITMASK_FOR_BITCOUNT(5))) << 9) | (((uint32_t)((entry).raw8[1])) << 1)) +#define LOG_ENTRY_WORD_01_GET_VALUE(entry) ((uint8_t)((entry).raw8[0] >> 5) & BITMASK_FOR_BITCOUNT(1)) +#define LOG_ENTRY_MAKE_WORD_01(address, value) \ + (write_log_entry_t) { \ + .raw8 = { \ + [0] = (((((uint8_t)LOG_ENTRY_TYPE_WORD_01) & BITMASK_FOR_BITCOUNT(2)) << 6) /* type */ \ + | (((((uint8_t)((value) ? 1 : 0))) & BITMASK_FOR_BITCOUNT(1)) << 5) /* value */ \ + | ((((uint8_t)((address) >> 9))) & BITMASK_FOR_BITCOUNT(5)) /* address */ \ + ), \ + [1] = (uint8_t)((address) >> 1), /* address */ \ + } \ + } -- cgit v1.2.3 From dcdc7290e5e800689876c4d3ba393e926f966fbe Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Wed, 29 Jun 2022 09:25:03 +0100 Subject: RGB Matrix Heatmap - Skip positions with NO_LED (#17488) --- quantum/rgb_matrix/animations/typing_heatmap_anim.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'quantum') diff --git a/quantum/rgb_matrix/animations/typing_heatmap_anim.h b/quantum/rgb_matrix/animations/typing_heatmap_anim.h index cfc3fc015b..a05c07760e 100644 --- a/quantum/rgb_matrix/animations/typing_heatmap_anim.h +++ b/quantum/rgb_matrix/animations/typing_heatmap_anim.h @@ -18,8 +18,14 @@ void process_rgb_matrix_typing_heatmap(uint8_t row, uint8_t col) { // Limit effect to pressed keys g_rgb_frame_buffer[row][col] = qadd8(g_rgb_frame_buffer[row][col], 32); # else + if (g_led_config.matrix_co[row][col] == NO_LED) { // skip as pressed key doesn't have an led position + return; + } for (uint8_t i_row = 0; i_row < MATRIX_ROWS; i_row++) { for (uint8_t i_col = 0; i_col < MATRIX_COLS; i_col++) { + if (g_led_config.matrix_co[i_row][i_col] == NO_LED) { // skip as target key doesn't have an led position + continue; + } if (i_row == row && i_col == col) { g_rgb_frame_buffer[row][col] = qadd8(g_rgb_frame_buffer[row][col], 32); } else { -- cgit v1.2.3 From 34e244cecf62afb30ee5a4362867f24b03675691 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Thu, 30 Jun 2022 07:42:23 +1000 Subject: Wear-leveling EEPROM drivers: `embedded_flash`, `spi_flash`, `legacy` (#17376) --- builddefs/build_keyboard.mk | 16 +++ builddefs/common_features.mk | 44 ++++++- docs/_summary.md | 1 + docs/eeprom_driver.md | 83 ++++++++++-- drivers/eeprom/eeprom_wear_leveling.c | 23 ++++ drivers/wear_leveling/wear_leveling_flash_spi.c | 101 +++++++++++++++ .../wear_leveling/wear_leveling_flash_spi_config.h | 34 +++++ .../drivers/wear_leveling/wear_leveling_efl.c | 140 +++++++++++++++++++++ .../wear_leveling/wear_leveling_efl_config.h | 50 ++++++++ .../drivers/wear_leveling/wear_leveling_legacy.c | 59 +++++++++ .../wear_leveling/wear_leveling_legacy_config.h | 67 ++++++++++ platforms/chibios/platform.mk | 5 + platforms/eeprom.h | 2 + quantum/wear_leveling/wear_leveling.c | 97 +++++++------- quantum/wear_leveling/wear_leveling_internal.h | 16 ++- 15 files changed, 667 insertions(+), 71 deletions(-) create mode 100644 drivers/eeprom/eeprom_wear_leveling.c create mode 100644 drivers/wear_leveling/wear_leveling_flash_spi.c create mode 100644 drivers/wear_leveling/wear_leveling_flash_spi_config.h create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h (limited to 'quantum') diff --git a/builddefs/build_keyboard.mk b/builddefs/build_keyboard.mk index 2b9ec48e70..b5616a438f 100644 --- a/builddefs/build_keyboard.mk +++ b/builddefs/build_keyboard.mk @@ -13,6 +13,14 @@ endif include paths.mk include $(BUILDDEFS_PATH)/message.mk +# Helper to add defines with a 'QMK_' prefix +define add_qmk_prefix_defs + ifdef $1 + # Need to cater for 'STM32L4xx+' + OPT_DEFS += -DQMK_$(2)="$($1)" -DQMK_$(2)_$(shell echo $($1) | sed -e 's@+@Plus@g' -e 's@[^a-zA-Z0-9]@_@g' | tr '[:lower:]' '[:upper:]') + endif +endef + # Set the qmk cli to use QMK_BIN ?= qmk @@ -438,6 +446,14 @@ else include $(TMK_PATH)/protocol/$(PLATFORM_KEY).mk endif +# Setup definitions based on the selected MCU +$(eval $(call add_qmk_prefix_defs,MCU_ORIG,MCU)) +$(eval $(call add_qmk_prefix_defs,MCU_ARCH,MCU_ARCH)) +$(eval $(call add_qmk_prefix_defs,MCU_PORT_NAME,MCU_PORT_NAME)) +$(eval $(call add_qmk_prefix_defs,MCU_FAMILY,MCU_FAMILY)) +$(eval $(call add_qmk_prefix_defs,MCU_SERIES,MCU_SERIES)) +$(eval $(call add_qmk_prefix_defs,BOARD,BOARD)) + # TODO: remove this bodge? PROJECT_DEFS := $(OPT_DEFS) PROJECT_INC := $(VPATH) $(EXTRAINCDIRS) $(KEYBOARD_PATHS) diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 552171fe68..b447c6743d 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -173,7 +173,7 @@ ifeq ($(strip $(QUANTUM_PAINTER_ENABLE)), yes) include $(QUANTUM_DIR)/painter/rules.mk endif -VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi +VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi wear_leveling EEPROM_DRIVER ?= vendor ifeq ($(filter $(EEPROM_DRIVER),$(VALID_EEPROM_DRIVER_TYPES)),) $(call CATASTROPHIC_ERROR,Invalid EEPROM_DRIVER,EEPROM_DRIVER="$(EEPROM_DRIVER)" is not a valid EEPROM driver) @@ -186,6 +186,10 @@ else # Custom EEPROM implementation -- only needs to implement init/erase/read_block/write_block OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_CUSTOM SRC += eeprom_driver.c + else ifeq ($(strip $(EEPROM_DRIVER)), wear_leveling) + # Wear-leveling EEPROM implementation + OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING + SRC += eeprom_driver.c eeprom_wear_leveling.c else ifeq ($(strip $(EEPROM_DRIVER)), i2c) # External I2C EEPROM implementation OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_I2C @@ -237,17 +241,47 @@ else endif endif +VALID_WEAR_LEVELING_DRIVER_TYPES := custom embedded_flash spi_flash legacy +WEAR_LEVELING_DRIVER ?= none +ifneq ($(strip $(WEAR_LEVELING_DRIVER)),none) + ifeq ($(filter $(WEAR_LEVELING_DRIVER),$(VALID_WEAR_LEVELING_DRIVER_TYPES)),) + $(call CATASTROPHIC_ERROR,Invalid WEAR_LEVELING_DRIVER,WEAR_LEVELING_DRIVER="$(WEAR_LEVELING_DRIVER)" is not a valid wear leveling driver) + else + FNV_ENABLE := yes + OPT_DEFS += -DWEAR_LEVELING_ENABLE + OPT_DEFS += -DWEAR_LEVELING_$(strip $(shell echo $(WEAR_LEVELING_DRIVER) | tr '[:lower:]' '[:upper:]')) + COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/wear_leveling + COMMON_VPATH += $(DRIVER_PATH)/wear_leveling + COMMON_VPATH += $(QUANTUM_DIR)/wear_leveling + SRC += wear_leveling.c + ifeq ($(strip $(WEAR_LEVELING_DRIVER)), embedded_flash) + OPT_DEFS += -DHAL_USE_EFL + SRC += wear_leveling_efl.c + POST_CONFIG_H += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/wear_leveling/wear_leveling_efl_config.h + else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), spi_flash) + FLASH_DRIVER := spi + SRC += wear_leveling_flash_spi.c + POST_CONFIG_H += $(DRIVER_PATH)/wear_leveling/wear_leveling_flash_spi_config.h + else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), legacy) + COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash + SRC += flash_stm32.c wear_leveling_legacy.c + POST_CONFIG_H += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/wear_leveling/wear_leveling_legacy_config.h + endif + endif +endif + VALID_FLASH_DRIVER_TYPES := spi -FLASH_DRIVER ?= no -ifneq ($(strip $(FLASH_DRIVER)), no) +FLASH_DRIVER ?= none +ifneq ($(strip $(FLASH_DRIVER)), none) ifeq ($(filter $(FLASH_DRIVER),$(VALID_FLASH_DRIVER_TYPES)),) - $(error FLASH_DRIVER="$(FLASH_DRIVER)" is not a valid FLASH driver) + $(call CATASTROPHIC_ERROR,Invalid FLASH_DRIVER,FLASH_DRIVER="$(FLASH_DRIVER)" is not a valid flash driver) else OPT_DEFS += -DFLASH_ENABLE - ifeq ($(strip $(FLASH_DRIVER)), spi) + ifeq ($(strip $(FLASH_DRIVER)),spi) OPT_DEFS += -DFLASH_DRIVER -DFLASH_SPI COMMON_VPATH += $(DRIVER_PATH)/flash SRC += flash_spi.c + QUANTUM_LIB_SRC += spi_master.c endif endif endif diff --git a/docs/_summary.md b/docs/_summary.md index 78d7f30ea4..e6d636402b 100644 --- a/docs/_summary.md +++ b/docs/_summary.md @@ -146,6 +146,7 @@ * [SPI Driver](spi_driver.md) * [WS2812 Driver](ws2812_driver.md) * [EEPROM Driver](eeprom_driver.md) + * [Flash Driver](flash_driver.md) * ['serial' Driver](serial_driver.md) * [UART Driver](uart_driver.md) * [GPIO Controls](gpio_control.md) diff --git a/docs/eeprom_driver.md b/docs/eeprom_driver.md index 306ebacb3f..de2eaf2e5b 100644 --- a/docs/eeprom_driver.md +++ b/docs/eeprom_driver.md @@ -2,12 +2,15 @@ The EEPROM driver can be swapped out depending on the needs of the keyboard, or whether extra hardware is present. +Selecting the EEPROM driver is done in your keyboard's `rules.mk`: + Driver | Description -----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- `EEPROM_DRIVER = vendor` (default) | Uses the on-chip driver provided by the chip manufacturer. For AVR, this is provided by avr-libc. This is supported on ARM for a subset of chips -- STM32F3xx, STM32F1xx, and STM32F072xB will be emulated by writing to flash. STM32L0xx and STM32L1xx will use the onboard dedicated true EEPROM. Other chips will generally act as "transient" below. `EEPROM_DRIVER = i2c` | Supports writing to I2C-based 24xx EEPROM chips. See the driver section below. `EEPROM_DRIVER = spi` | Supports writing to SPI-based 25xx EEPROM chips. See the driver section below. `EEPROM_DRIVER = transient` | Fake EEPROM driver -- supports reading/writing to RAM, and will be discarded when power is lost. +`EEPROM_DRIVER = wear_leveling` | Frontend driver for the wear_leveling system, allowing for EEPROM emulation on top of flash -- both in-MCU and external SPI NOR flash. ## Vendor Driver Configuration :id=vendor-eeprom-driver-configuration @@ -55,13 +58,13 @@ MB85RC256V FRAM | `#define EEPROM_I2C_MB85RC256V` | There's no way to determine if there is an SPI EEPROM actually responding. Generally, this will result in reads of nothing but zero. @@ -74,3 +77,69 @@ The only configurable item for the transient EEPROM driver is its size: `#define TRANSIENT_EEPROM_SIZE` | Total size of the EEPROM storage in bytes | 64 Default values and extended descriptions can be found in `drivers/eeprom/eeprom_transient.h`. + +## Wear-leveling Driver Configuration :id=wear_leveling-eeprom-driver-configuration + +The wear-leveling driver uses an algorithm to minimise the number of erase cycles on the underlying MCU flash memory. + +There is no specific configuration for this driver, but the wear-leveling system used by this driver may need configuration. See the [wear-leveling configuration](#wear_leveling-configuration) section for more information. + +# Wear-leveling Configuration :id=wear_leveling-configuration + +The wear-leveling driver has a few possible _backing stores_ that may be used by adding to your keyboard's `rules.mk` file: + +Driver | Description +----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +`WEAR_LEVELING_DRIVER = embedded_flash` | This driver is used for emulating EEPROM by writing to embedded flash on the MCU. +`WEAR_LEVELING_DRIVER = spi_flash` | This driver is used to address external SPI NOR Flash peripherals. +`WEAR_LEVELING_DRIVER = legacy` | This driver is the "legacy" emulated EEPROM provided in historical revisions of QMK. Currently used for STM32F0xx and STM32F4x1, but slated for deprecation and removal once `embedded_flash` support for those MCU families is complete. + +!> All wear-leveling drivers require an amount of RAM equivalent to the selected logical EEPROM size. Increasing the size to 32kB of EEPROM requires 32kB of RAM, which a significant number of MCUs simply do not have. + +## Wear-leveling Embedded Flash Driver Configuration :id=wear_leveling-efl-driver-configuration + +This driver performs writes to the embedded flash storage embedded in the MCU. In most circumstances, the last few of sectors of flash are used in order to minimise the likelihood of collision with program code. + +Configurable options in your keyboard's `config.h`: + +`config.h` override | Default | Description +-----------------------------------------|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +`#define WEAR_LEVELING_EFL_FIRST_SECTOR` | _unset_ | The first sector on the MCU to use. By default this is not defined and calculated at runtime based on the MCU. However, different flash sizes on MCUs may require custom configuration. +`#define WEAR_LEVELING_EFL_FLASH_SIZE` | _unset_ | Allows overriding the flash size available for use for wear-leveling. Under normal circumstances this is automatically calculated and should not need to be overridden. Specifying a size larger than the amount actually available in flash will usually prevent the MCU from booting. +`#define WEAR_LEVELING_LOGICAL_SIZE` | `1024` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM. +`#define WEAR_LEVELING_BACKING_SIZE` | `2048` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size. +`#define BACKING_STORE_WRITE_SIZE` | _automatic_ | The byte width of the underlying write used on the MCU, and is usually automatically determined from the selected MCU family. If an error occurs in the auto-detection, you'll need to consult the MCU's datasheet and determine this value, specifying it directly. + +!> If your MCU does not boot after swapping to the EFL wear-leveling driver, it's likely that the flash size is incorrectly detected, usually as an MCU with larger flash and may require overriding. + +## Wear-leveling SPI Flash Driver Configuration :id=wear_leveling-flash_spi-driver-configuration + +This driver performs writes to an external SPI NOR Flash peripheral. It also requires a working configuration for the SPI NOR Flash peripheral -- see the [flash driver](flash_driver.md) documentation for more information. + +Configurable options in your keyboard's `config.h`: + +`config.h` override | Default | Description +----------------------------------------------------|--------------------------------|-------------------------------------------------------------------------------------------------------------------------------- +`#define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT` | `1` | Number of blocks in the external flash used by the wear-leveling algorithm. +`#define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET` | `0` | The index first block in the external flash used by the wear-leveling algorithm. +`#define WEAR_LEVELING_LOGICAL_SIZE` | `((block_count*block_size)/2)` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM. Result must be <= 64kB. +`#define WEAR_LEVELING_BACKING_SIZE` | `(block_count*block_size)` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size. +`#define BACKING_STORE_WRITE_SIZE` | `8` | The write width used whenever a write is performed on the external flash peripheral. + +!> There is currently a limit of 64kB for the EEPROM subsystem within QMK, so using a larger flash is not going to be beneficial as the logical size cannot be increased beyond 65536. The backing size may be increased to a larger value, but erase timing may suffer as a result. + +## Wear-leveling Legacy EEPROM Emulation Driver Configuration :id=wear_leveling-legacy-driver-configuration + +This driver performs writes to the embedded flash storage embedded in the MCU much like the normal Embedded Flash Driver, and is only for use with STM32F0xx and STM32F4x1 devices. This flash implementation is still currently provided as the EFL driver is currently non-functional for the previously mentioned families. + +By default, `1024` bytes of emulated EEPROM is provided: + +MCU | EEPROM Provided | Flash Used +----------|-----------------|-------------- +STM32F042 | `1024` bytes | `2048` bytes +STM32F070 | `1024` bytes | `2048` bytes +STM32F072 | `1024` bytes | `2048` bytes +STM32F401 | `1024` bytes | `16384` bytes +STM32F411 | `1024` bytes | `16384` bytes + +Under normal circumstances configuration of this driver requires intimate knowledge of the MCU's flash structure -- reconfiguration is at your own risk and will require referring to the code. \ No newline at end of file diff --git a/drivers/eeprom/eeprom_wear_leveling.c b/drivers/eeprom/eeprom_wear_leveling.c new file mode 100644 index 0000000000..bd77eef35c --- /dev/null +++ b/drivers/eeprom/eeprom_wear_leveling.c @@ -0,0 +1,23 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + +#include "eeprom_driver.h" +#include "wear_leveling.h" + +void eeprom_driver_init(void) { + wear_leveling_init(); +} + +void eeprom_driver_erase(void) { + wear_leveling_erase(); +} + +void eeprom_read_block(void *buf, const void *addr, size_t len) { + wear_leveling_read((uint32_t)addr, buf, len); +} + +void eeprom_write_block(const void *buf, void *addr, size_t len) { + wear_leveling_write((uint32_t)addr, buf, len); +} diff --git a/drivers/wear_leveling/wear_leveling_flash_spi.c b/drivers/wear_leveling/wear_leveling_flash_spi.c new file mode 100644 index 0000000000..6191f8bf09 --- /dev/null +++ b/drivers/wear_leveling/wear_leveling_flash_spi.c @@ -0,0 +1,101 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "util.h" +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT +# define WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT 32 +#endif // WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT + +bool backing_store_init(void) { + bs_dprintf("Init\n"); + flash_init(); + return true; +} + +bool backing_store_unlock(void) { + bs_dprintf("Unlock\n"); + // No-op -- handled by the flash driver as it is. + return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT + uint32_t start = timer_read32(); +#endif + + bool ret = true; + for (int i = 0; i < (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT); ++i) { + flash_status_t status = flash_erase_block(((WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) + i) * (EXTERNAL_FLASH_BLOCK_SIZE)); + if (status != FLASH_STATUS_SUCCESS) { + ret = false; + break; + } + } + + bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); + return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { + return backing_store_write_bulk(address, &value, 1); +} + +bool backing_store_lock(void) { + bs_dprintf("Lock \n"); + // No-op -- handled by the flash driver as it is. + return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { + return backing_store_read_bulk(address, value, 1); +} + +bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + bs_dprintf("Read "); + uint32_t offset = (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) * (EXTERNAL_FLASH_BLOCK_SIZE) + address; + flash_status_t status = flash_read_block(offset, values, sizeof(backing_store_int_t) * item_count); + if (status == FLASH_STATUS_SUCCESS) { + for (size_t i = 0; i < item_count; ++i) { + values[i] = ~values[i]; + } + wl_dump(offset, values, sizeof(backing_store_int_t) * item_count); + } + return status == FLASH_STATUS_SUCCESS; +} + +bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + uint32_t offset = (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) * (EXTERNAL_FLASH_BLOCK_SIZE) + address; + size_t index = 0; + backing_store_int_t temp[WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT]; + do { + // Copy out the block of data we want to transmit first + size_t this_loop = MIN(item_count, WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT); + for (size_t i = 0; i < this_loop; ++i) { + temp[i] = values[index + i]; + } + + bs_dprintf("Write "); + wl_dump(offset, temp, sizeof(backing_store_int_t) * this_loop); + + // Take the complement instead + for (size_t i = 0; i < this_loop; ++i) { + temp[i] = ~temp[i]; + } + + // Write out the block + if (flash_write_block(offset, temp, sizeof(backing_store_int_t) * this_loop) != FLASH_STATUS_SUCCESS) { + return false; + } + + offset += this_loop * sizeof(backing_store_int_t); + index += this_loop; + item_count -= this_loop; + } while (item_count > 0); + + return true; +} diff --git a/drivers/wear_leveling/wear_leveling_flash_spi_config.h b/drivers/wear_leveling/wear_leveling_flash_spi_config.h new file mode 100644 index 0000000000..394370daa3 --- /dev/null +++ b/drivers/wear_leveling/wear_leveling_flash_spi_config.h @@ -0,0 +1,34 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +# include +# include +# include "flash_spi.h" +#endif + +// Use 1 block -- check the config for the SPI flash to determine how big it is +#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT +# define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT 1 +#endif // WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT + +// Start at the first block of the external flash +#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET +# define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET 0 +#endif // WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET + +// 8-byte writes by default +#ifndef BACKING_STORE_WRITE_SIZE +# define BACKING_STORE_WRITE_SIZE 8 +#endif + +// The space allocated by the block +#ifndef WEAR_LEVELING_BACKING_SIZE +# define WEAR_LEVELING_BACKING_SIZE ((EXTERNAL_FLASH_BLOCK_SIZE) * (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT)) +#endif // WEAR_LEVELING_BACKING_SIZE + +// Use half of the backing size for logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# define WEAR_LEVELING_LOGICAL_SIZE ((WEAR_LEVELING_BACKING_SIZE) / 2) +#endif // WEAR_LEVELING_LOGICAL_SIZE diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c new file mode 100644 index 0000000000..4b5639ee4a --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c @@ -0,0 +1,140 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +static flash_offset_t base_offset = UINT32_MAX; + +#if defined(WEAR_LEVELING_EFL_FIRST_SECTOR) +static flash_sector_t first_sector = WEAR_LEVELING_EFL_FIRST_SECTOR; +#else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) +static flash_sector_t first_sector = UINT16_MAX; +#endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + +static flash_sector_t sector_count = UINT16_MAX; +static BaseFlash * flash; + +#ifndef WEAR_LEVELING_EFL_FIRST_SECTOR +// "Automatic" detection of the flash size -- ideally ChibiOS would have this already, but alas, it doesn't. +static inline uint32_t detect_flash_size(void) { +# if defined(WEAR_LEVELING_EFL_FLASH_SIZE) + return WEAR_LEVELING_EFL_FLASH_SIZE; +# elif defined(FLASH_BANK_SIZE) + return FLASH_BANK_SIZE; +# elif defined(FLASH_SIZE) + return FLASH_SIZE; +# elif defined(FLASHSIZE_BASE) +# if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_GD32VF103) + return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes +# elif defined(QMK_MCU_SERIES_STM32L1XX) +# error This MCU family has an uncommon flash size register definition and has not been implemented. Perhaps try using the true EEPROM on the MCU instead? +# endif +# else +# error Unknown flash size definition. + return 0; +# endif +} +#endif // WEAR_LEVELING_EFL_FIRST_SECTOR + +bool backing_store_init(void) { + bs_dprintf("Init\n"); + flash = (BaseFlash *)&EFLD1; + + const flash_descriptor_t *desc = flashGetDescriptor(flash); + uint32_t counter = 0; + +#if defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + + // Work out how many sectors we want to use, working forwards from the first sector specified + for (flash_sector_t i = 0; i < desc->sectors_count - first_sector; ++i) { + counter += flashGetSectorSize(flash, first_sector + i); + if (counter >= (WEAR_LEVELING_BACKING_SIZE)) { + sector_count = i + 1; + base_offset = flashGetSectorOffset(flash, first_sector); + break; + } + } + if (sector_count == UINT16_MAX || base_offset >= flash_size) { + // We didn't get the required number of sectors. Can't do anything here. Fault. + chSysHalt("Invalid sector count intended to be used with wear_leveling"); + } + +#else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + + // Work out how many sectors we want to use, working backwards from the end of the flash + uint32_t flash_size = detect_flash_size(); + flash_sector_t last_sector = desc->sectors_count; + for (flash_sector_t i = 0; i < desc->sectors_count; ++i) { + first_sector = desc->sectors_count - i - 1; + if (flashGetSectorOffset(flash, first_sector) >= flash_size) { + last_sector = first_sector; + continue; + } + counter += flashGetSectorSize(flash, first_sector); + if (counter >= (WEAR_LEVELING_BACKING_SIZE)) { + sector_count = last_sector - first_sector; + base_offset = flashGetSectorOffset(flash, first_sector); + break; + } + } + +#endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + + return true; +} + +bool backing_store_unlock(void) { + bs_dprintf("Unlock\n"); + return eflStart(&EFLD1, NULL) == HAL_RET_SUCCESS; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT + uint32_t start = timer_read32(); +#endif + + bool ret = true; + flash_error_t status; + for (int i = 0; i < sector_count; ++i) { + // Kick off the sector erase + status = flashStartEraseSector(flash, first_sector + i); + if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) { + ret = false; + } + + // Wait for the erase to complete + status = flashWaitErase(flash); + if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) { + ret = false; + } + } + + bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); + return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { + uint32_t offset = (base_offset + address); + bs_dprintf("Write "); + wl_dump(offset, &value, sizeof(value)); + value = ~value; + return flashProgram(flash, offset, sizeof(value), (const uint8_t *)&value) == FLASH_NO_ERROR; +} + +bool backing_store_lock(void) { + bs_dprintf("Lock \n"); + eflStop(&EFLD1); + return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { + uint32_t offset = (base_offset + address); + backing_store_int_t *loc = (backing_store_int_t *)offset; + *value = ~(*loc); + bs_dprintf("Read "); + wl_dump(offset, value, sizeof(backing_store_int_t)); + return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h new file mode 100644 index 0000000000..9e38c2965d --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h @@ -0,0 +1,50 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +# include +#endif + +// Work out how many bytes per write to internal flash +#ifndef BACKING_STORE_WRITE_SIZE +// These need to match EFL's XXXXXX_FLASH_LINE_SIZE, see associated code in `lib/chibios/os/hal/ports/**/hal_efl_lld.c`, +// or associated `stm32_registry.h` for the MCU in question (or equivalent for the family). +# if defined(QMK_MCU_SERIES_GD32VF103) +# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +# elif defined(QMK_MCU_FAMILY_NUC123) +# define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c +# elif defined(QMK_MCU_FAMILY_STM32) +# if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file +# define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE) +# else +# if defined(QMK_MCU_SERIES_STM32F1XX) +# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32F3XX) +# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32F4XX) +# define BACKING_STORE_WRITE_SIZE (1 << STM32_FLASH_PSIZE) // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32L4XX) +# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32G0XX) +# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32G4XX) +# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +# else +# error "ChibiOS hasn't defined STM32_FLASH_LINE_SIZE, and could not automatically determine BACKING_STORE_WRITE_SIZE" // normally defined in stm32_registry.h, should be set by STM32_FLASH_LINE_SIZE +# endif +# endif +# else +# error "Could not automatically determine BACKING_STORE_WRITE_SIZE" +# endif +#endif + +// 2kB backing space allocated +#ifndef WEAR_LEVELING_BACKING_SIZE +# define WEAR_LEVELING_BACKING_SIZE 2048 +#endif // WEAR_LEVELING_BACKING_SIZE + +// 1kB logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# define WEAR_LEVELING_LOGICAL_SIZE 1024 +#endif // WEAR_LEVELING_LOGICAL_SIZE diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c new file mode 100644 index 0000000000..87126c4467 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c @@ -0,0 +1,59 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" +#include "flash_stm32.h" + +bool backing_store_init(void) { + bs_dprintf("Init\n"); + return true; +} + +bool backing_store_unlock(void) { + bs_dprintf("Unlock\n"); + FLASH_Unlock(); + return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT + uint32_t start = timer_read32(); +#endif + + bool ret = true; + FLASH_Status status; + for (int i = 0; i < (WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT); ++i) { + status = FLASH_ErasePage(WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS + (i * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))); + if (status != FLASH_COMPLETE) { + ret = false; + } + } + + bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); + return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { + uint32_t offset = ((WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS) + address); + bs_dprintf("Write "); + wl_dump(offset, &value, sizeof(backing_store_int_t)); + return FLASH_ProgramHalfWord(offset, ~value) == FLASH_COMPLETE; +} + +bool backing_store_lock(void) { + bs_dprintf("Lock \n"); + FLASH_Lock(); + return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t* value) { + uint32_t offset = ((WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS) + address); + backing_store_int_t* loc = (backing_store_int_t*)offset; + *value = ~(*loc); + bs_dprintf("Read "); + wl_dump(offset, loc, sizeof(backing_store_int_t)); + return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h new file mode 100644 index 0000000000..1e4691a6c0 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h @@ -0,0 +1,67 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +// Work out the page size to use +#ifndef WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE +# if defined(QMK_MCU_STM32F042) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 1024 +# elif defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 2048 +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 16384 +# endif +#endif + +// Work out how much flash space we have +#ifndef WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE +# define WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) // in kB +#endif + +// The base location of program memory +#ifndef WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE +# define WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE 0x08000000 +#endif + +// The number of pages to use +#ifndef WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT +# if defined(QMK_MCU_STM32F042) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 2 +# elif defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 1 +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 1 +# endif +#endif + +// The origin of the emulated eeprom +#ifndef WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS +# if defined(QMK_MCU_STM32F042) || defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS ((uintptr_t)(WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE) + WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE * 1024 - (WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT * WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE)) +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# if defined(BOOTLOADER_STM32) +# define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (1 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +16k +# elif defined(BOOTLOADER_TINYUF2) +# define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (3 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +48k +# endif +# endif +#endif + +// 2-byte writes +#ifndef BACKING_STORE_WRITE_SIZE +# define BACKING_STORE_WRITE_SIZE 2 +#endif + +// The amount of space to use for the entire set of emulation +#ifndef WEAR_LEVELING_BACKING_SIZE +# if defined(QMK_MCU_STM32F042) || defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_BACKING_SIZE 2048 +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# define WEAR_LEVELING_BACKING_SIZE 16384 +# endif +#endif + +// The logical amount of eeprom available +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# define WEAR_LEVELING_LOGICAL_SIZE 1024 +#endif diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index a30ca62bf5..72428a762f 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -94,6 +94,11 @@ ifeq ("$(wildcard $(PLATFORM_MK))","") endif endif +# If no MCU architecture specified, use the MCU instead (allows for mcu_selection.mk to swap to cortex-m0 etc.) +ifeq ("$(MCU_ARCH)","") + MCU_ARCH = $(MCU) +endif + include $(STARTUP_MK) include $(PORT_V) include $(PLATFORM_MK) diff --git a/platforms/eeprom.h b/platforms/eeprom.h index 091e6e4400..8cb7e342dc 100644 --- a/platforms/eeprom.h +++ b/platforms/eeprom.h @@ -27,6 +27,8 @@ void eeprom_update_block(const void *__src, void *__dst, size_t __n); # error EEPROM_SIZE has not been defined for custom driver. # endif # define TOTAL_EEPROM_BYTE_COUNT (EEPROM_SIZE) +#elif defined(EEPROM_WEAR_LEVELING) +# define TOTAL_EEPROM_BYTE_COUNT (WEAR_LEVELING_LOGICAL_SIZE) #elif defined(EEPROM_TRANSIENT) # include "eeprom_transient.h" # define TOTAL_EEPROM_BYTE_COUNT (TRANSIENT_EEPROM_SIZE) diff --git a/quantum/wear_leveling/wear_leveling.c b/quantum/wear_leveling/wear_leveling.c index 8418ae77bf..0a519639ea 100644 --- a/quantum/wear_leveling/wear_leveling.c +++ b/quantum/wear_leveling/wear_leveling.c @@ -213,36 +213,29 @@ static wear_leveling_status_t wear_leveling_read_consolidated(void) { wl_dprintf("Reading consolidated data\n"); wear_leveling_status_t status = WEAR_LEVELING_SUCCESS; - for (int address = 0; address < (WEAR_LEVELING_LOGICAL_SIZE); address += (BACKING_STORE_WRITE_SIZE)) { - backing_store_int_t *const loc = (backing_store_int_t *)&wear_leveling.cache[address]; - backing_store_int_t temp; - bool ok = backing_store_read(address, &temp); - if (!ok) { - wl_dprintf("Failed to read from backing store\n"); - status = WEAR_LEVELING_FAILED; - break; - } - *loc = temp; + if (!backing_store_read_bulk(0, (backing_store_int_t *)wear_leveling.cache, sizeof(wear_leveling.cache) / sizeof(backing_store_int_t))) { + wl_dprintf("Failed to read from backing store\n"); + status = WEAR_LEVELING_FAILED; } // Verify the FNV1a_64 result if (status != WEAR_LEVELING_FAILED) { uint64_t expected = fnv_64a_buf(wear_leveling.cache, (WEAR_LEVELING_LOGICAL_SIZE), FNV1A_64_INIT); write_log_entry_t entry; + wl_dprintf("Reading checksum\n"); #if BACKING_STORE_WRITE_SIZE == 2 - backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 0, &entry.raw16[0]); - backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 2, &entry.raw16[1]); - backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 4, &entry.raw16[2]); - backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 6, &entry.raw16[3]); + backing_store_read_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw16, 4); #elif BACKING_STORE_WRITE_SIZE == 4 - backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 0, &entry.raw32[0]); - backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 4, &entry.raw32[1]); + backing_store_read_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw32, 2); #elif BACKING_STORE_WRITE_SIZE == 8 backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 0, &entry.raw64); #endif // If we have a mismatch, clear the cache but do not flag a failure, // which will cater for the completely clean MCU case. - if (entry.raw64 != expected) { + if (entry.raw64 == expected) { + wl_dprintf("Checksum matches, consolidated data is correct\n"); + } else { + wl_dprintf("Checksum mismatch, clearing cache\n"); wear_leveling_clear_cache(); } } @@ -258,64 +251,36 @@ static wear_leveling_status_t wear_leveling_read_consolidated(void) { /** * Writes the current cache to consolidated data at the beginning of the backing store. * Does not clear the write log. + * Pre-condition: this is just after an erase, so we can write directly without reading. */ static wear_leveling_status_t wear_leveling_write_consolidated(void) { wl_dprintf("Writing consolidated data\n"); - wear_leveling_status_t status = WEAR_LEVELING_CONSOLIDATED; backing_store_lock_status_t lock_status = wear_leveling_unlock(); - for (int address = 0; address < (WEAR_LEVELING_LOGICAL_SIZE); address += (BACKING_STORE_WRITE_SIZE)) { - const backing_store_int_t value = *(backing_store_int_t *)&wear_leveling.cache[address]; - backing_store_int_t temp; - bool ok = backing_store_read(address, &temp); - if (!ok) { - wl_dprintf("Failed to read from backing store\n"); - status = WEAR_LEVELING_FAILED; - break; - } - if (temp != value) { - ok = backing_store_write(address, value); - if (!ok) { - wl_dprintf("Failed to write to backing store\n"); - status = WEAR_LEVELING_FAILED; - break; - } - } + wear_leveling_status_t status = WEAR_LEVELING_CONSOLIDATED; + if (!backing_store_write_bulk(0, (backing_store_int_t *)wear_leveling.cache, sizeof(wear_leveling.cache) / sizeof(backing_store_int_t))) { + wl_dprintf("Failed to write to backing store\n"); + status = WEAR_LEVELING_FAILED; } if (status != WEAR_LEVELING_FAILED) { // Write out the FNV1a_64 result of the consolidated data write_log_entry_t entry; entry.raw64 = fnv_64a_buf(wear_leveling.cache, (WEAR_LEVELING_LOGICAL_SIZE), FNV1A_64_INIT); + wl_dprintf("Writing checksum\n"); do { #if BACKING_STORE_WRITE_SIZE == 2 - if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 0, entry.raw16[0])) { - status = WEAR_LEVELING_FAILED; - break; - } - if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 2, entry.raw16[1])) { - status = WEAR_LEVELING_FAILED; - break; - } - if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 4, entry.raw16[2])) { - status = WEAR_LEVELING_FAILED; - break; - } - if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 6, entry.raw16[3])) { + if (!backing_store_write_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw16, 4)) { status = WEAR_LEVELING_FAILED; break; } #elif BACKING_STORE_WRITE_SIZE == 4 - if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 0, entry.raw32[0])) { - status = WEAR_LEVELING_FAILED; - break; - } - if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 4, entry.raw32[1])) { + if (!backing_store_write_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw32, 2)) { status = WEAR_LEVELING_FAILED; break; } #elif BACKING_STORE_WRITE_SIZE == 8 - if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE) + 0, entry.raw64)) { + if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE), entry.raw64)) { status = WEAR_LEVELING_FAILED; break; } @@ -777,3 +742,27 @@ wear_leveling_status_t wear_leveling_read(const uint32_t address, void *value, s wl_dump(address, value, length); return WEAR_LEVELING_SUCCESS; } + +/** + * Weak implementation of bulk read, drivers can implement more optimised implementations. + */ +__attribute__((weak)) bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + for (size_t i = 0; i < item_count; ++i) { + if (!backing_store_read(address + (i * BACKING_STORE_WRITE_SIZE), &values[i])) { + return false; + } + } + return true; +} + +/** + * Weak implementation of bulk write, drivers can implement more optimised implementations. + */ +__attribute__((weak)) bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + for (size_t i = 0; i < item_count; ++i) { + if (!backing_store_write(address + (i * BACKING_STORE_WRITE_SIZE), values[i])) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/quantum/wear_leveling/wear_leveling_internal.h b/quantum/wear_leveling/wear_leveling_internal.h index 74b43932df..e83f9b22ea 100644 --- a/quantum/wear_leveling/wear_leveling_internal.h +++ b/quantum/wear_leveling/wear_leveling_internal.h @@ -28,21 +28,25 @@ typedef uint64_t backing_store_int_t; #endif #ifdef WEAR_LEVELING_DEBUG_OUTPUT -# include -# define wl_dprintf(...) printf("Wear leveling: " __VA_ARGS__) +# include +# define bs_dprintf(...) dprintf("Backing store: " __VA_ARGS__) +# define wl_dprintf(...) dprintf("Wear leveling: " __VA_ARGS__) # define wl_dump(address, value, length) \ do { \ - printf("[0x%04X]: ", (int)(address)); \ + dprintf("[0x%04X]: ", (int)(address)); \ const uint8_t* p = (const uint8_t*)(value); \ for (int i = 0; i < (length); ++i) { \ - printf(" %02X", (int)p[i]); \ + dprintf(" %02X", (int)p[i]); \ } \ - printf("\n"); \ + dprintf("\n"); \ } while (0) #else # define wl_dprintf(...) \ do { \ } while (0) +# define bs_dprintf(...) \ + do { \ + } while (0) # define wl_dump(...) \ do { \ } while (0) @@ -67,8 +71,10 @@ bool backing_store_init(void); bool backing_store_unlock(void); bool backing_store_erase(void); bool backing_store_write(uint32_t address, backing_store_int_t value); +bool backing_store_write_bulk(uint32_t address, backing_store_int_t* values, size_t item_count); // weak implementation already provided, optimized implementation can be implemented by driver bool backing_store_lock(void); bool backing_store_read(uint32_t address, backing_store_int_t* value); +bool backing_store_read_bulk(uint32_t address, backing_store_int_t* values, size_t item_count); // weak implementation already provided, optimized implementation can be implemented by driver /** * Helper type used to contain a write log entry. -- cgit v1.2.3 From d7173967087e022d20d1f9c812b1b668e9d3f71b Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 30 Jun 2022 13:19:27 +0200 Subject: [Core] Add Raspberry Pi RP2040 support (#14877) * Disable RESET keycode because of naming conflicts * Add Pico SDK as submodule * Add RP2040 build support to QMK * Adjust USB endpoint structs for RP2040 * Add RP2040 bootloader and double-tap reset routine * Add generic and pro micro RP2040 boards * Add RP2040 onekey keyboard * Add WS2812 PIO DMA enabled driver and documentation Supports regular and open-drain output configuration. RP2040 GPIOs are sadly not 5V tolerant, so this is a bit use-less or needs extra hardware or you take the risk to fry your hardware. * Adjust SIO Driver for RP2040 * Adjust I2C Driver for RP2040 * Adjust SPI Driver for RP2040 * Add PIO serial driver and documentation * Add general RP2040 documentation * Apply suggestions from code review Co-authored-by: Nick Brassel Co-authored-by: Nick Brassel --- .gitmodules | 3 + Makefile | 1 + builddefs/bootloader.mk | 4 + builddefs/common_features.mk | 4 +- builddefs/mcu_selection.mk | 35 ++ data/schemas/definitions.jsonschema | 4 + data/schemas/keyboard.jsonschema | 4 +- docs/_summary.md | 1 + docs/compatible_microcontrollers.md | 6 + docs/flashing.md | 39 ++ docs/platformdev_rp2040.md | 125 ++++++ docs/serial_driver.md | 41 +- docs/ws2812_driver.md | 62 ++- keyboards/handwired/onekey/onekey.c | 11 + keyboards/handwired/onekey/rp2040/config.h | 17 + keyboards/handwired/onekey/rp2040/readme.md | 12 + keyboards/handwired/onekey/rp2040/rules.mk | 3 + lib/pico-sdk | 1 + lib/python/qmk/constants.py | 2 +- platforms/chibios/_pin_defs.h | 5 + .../boards/GENERIC_PROMICRO_RP2040/board/board.mk | 9 + .../boards/GENERIC_PROMICRO_RP2040/configs/board.h | 12 + .../GENERIC_PROMICRO_RP2040/configs/chconf.h | 13 + .../GENERIC_PROMICRO_RP2040/configs/config.h | 62 +++ .../GENERIC_PROMICRO_RP2040/configs/mcuconf.h | 98 +++++ .../boards/GENERIC_RP_RP2040/board/board.mk | 9 + .../boards/GENERIC_RP_RP2040/configs/board.h | 12 + .../boards/GENERIC_RP_RP2040/configs/chconf.h | 13 + .../boards/GENERIC_RP_RP2040/configs/mcuconf.h | 98 +++++ platforms/chibios/bootloaders/rp2040.c | 57 +++ platforms/chibios/chibios_config.h | 21 + platforms/chibios/drivers/serial_usart.c | 28 +- platforms/chibios/drivers/spi_master.c | 31 +- .../drivers/vendor/RP/RP2040/serial_vendor.c | 457 +++++++++++++++++++++ .../drivers/vendor/RP/RP2040/ws2812_vendor.c | 189 +++++++++ platforms/chibios/flash.mk | 2 + platforms/chibios/platform.mk | 15 +- platforms/chibios/vendors/RP/RP2040.mk | 285 +++++++++++++ platforms/chibios/vendors/RP/_pin_defs.h | 37 ++ platforms/chibios/vendors/RP/pico_sdk_shims.c | 9 + platforms/chibios/vendors/RP/stage2_bootloaders.c | 174 ++++++++ quantum/keymap.h | 5 + tmk_core/protocol/chibios/usb_main.c | 106 ++--- 43 files changed, 2026 insertions(+), 96 deletions(-) create mode 100644 docs/platformdev_rp2040.md create mode 100644 keyboards/handwired/onekey/rp2040/config.h create mode 100644 keyboards/handwired/onekey/rp2040/readme.md create mode 100644 keyboards/handwired/onekey/rp2040/rules.mk create mode 160000 lib/pico-sdk create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h create mode 100644 platforms/chibios/bootloaders/rp2040.c create mode 100644 platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c create mode 100644 platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c create mode 100644 platforms/chibios/vendors/RP/RP2040.mk create mode 100644 platforms/chibios/vendors/RP/_pin_defs.h create mode 100644 platforms/chibios/vendors/RP/pico_sdk_shims.c create mode 100644 platforms/chibios/vendors/RP/stage2_bootloaders.c (limited to 'quantum') diff --git a/.gitmodules b/.gitmodules index 681693a5a4..48c7035afa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,3 +18,6 @@ [submodule "lib/printf"] path = lib/printf url = https://github.com/qmk/printf +[submodule "lib/pico-sdk"] + path = lib/pico-sdk + url = https://github.com/qmk/pico-sdk.git diff --git a/Makefile b/Makefile index 4c2e6a04dc..fc6d016448 100644 --- a/Makefile +++ b/Makefile @@ -401,6 +401,7 @@ ifndef SKIP_GIT if [ ! -e lib/lufa ]; then git submodule sync lib/lufa && git submodule update --depth 50 --init lib/lufa; fi if [ ! -e lib/vusb ]; then git submodule sync lib/vusb && git submodule update --depth 50 --init lib/vusb; fi if [ ! -e lib/printf ]; then git submodule sync lib/printf && git submodule update --depth 50 --init lib/printf; fi + if [ ! -e lib/pico-sdk ]; then git submodule sync lib/pico-sdk && git submodule update --depth 50 --init lib/pico-sdk; fi git submodule status --recursive 2>/dev/null | \ while IFS= read -r x; do \ case "$$x" in \ diff --git a/builddefs/bootloader.mk b/builddefs/bootloader.mk index eba8e280e4..3d4c03b01c 100644 --- a/builddefs/bootloader.mk +++ b/builddefs/bootloader.mk @@ -200,6 +200,10 @@ ifeq ($(strip $(BOOTLOADER)), tinyuf2) OPT_DEFS += -DBOOTLOADER_TINYUF2 BOOTLOADER_TYPE = tinyuf2 endif +ifeq ($(strip $(BOOTLOADER)), rp2040) + OPT_DEFS += -DBOOTLOADER_RP2040 + BOOTLOADER_TYPE = rp2040 +endif ifeq ($(strip $(BOOTLOADER)), halfkay) OPT_DEFS += -DBOOTLOADER_HALFKAY BOOTLOADER_TYPE = halfkay diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index b447c6743d..2edc1bdef0 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -547,7 +547,7 @@ ifeq ($(strip $(BACKLIGHT_ENABLE)), yes) endif endif -VALID_WS2812_DRIVER_TYPES := bitbang pwm spi i2c +VALID_WS2812_DRIVER_TYPES := bitbang pwm spi i2c vendor WS2812_DRIVER ?= bitbang ifeq ($(strip $(WS2812_DRIVER_REQUIRED)), yes) @@ -637,7 +637,7 @@ ifneq ($(strip $(DEBOUNCE_TYPE)), custom) endif -VALID_SERIAL_DRIVER_TYPES := bitbang usart +VALID_SERIAL_DRIVER_TYPES := bitbang usart vendor SERIAL_DRIVER ?= bitbang ifeq ($(filter $(SERIAL_DRIVER),$(VALID_SERIAL_DRIVER_TYPES)),) diff --git a/builddefs/mcu_selection.mk b/builddefs/mcu_selection.mk index d5fb731e08..d676e0c06a 100644 --- a/builddefs/mcu_selection.mk +++ b/builddefs/mcu_selection.mk @@ -116,6 +116,41 @@ ifneq ($(findstring MK66FX1M0, $(MCU)),) BOARD ?= PJRC_TEENSY_3_6 endif +ifneq ($(findstring RP2040, $(MCU)),) + # Cortex version + MCU = cortex-m0plus + + # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7 + CHIBIOS_PORT = ARMv6-M-RP2 + + ## chip/board settings + # - the next two should match the directories in + # /os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES) + # OR + # /os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES) + MCU_FAMILY = RP + MCU_SERIES = RP2040 + + # Linker script to use + # - it should exist either in /os/common/ports/ARMCMx/compilers/GCC/ld/ + # or /ld/ + STARTUPLD_CONTRIB = $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/ld + MCU_LDSCRIPT ?= RP2040_FLASH + LDFLAGS += -L $(STARTUPLD_CONTRIB) + + # Startup code to use + # - it should exist in /os/common/startup/ARMCMx/compilers/GCC/mk/ + MCU_STARTUP ?= rp2040 + + # Board: it should exist either in /os/hal/boards/, + # /boards/, or drivers/boards/ + BOARD ?= GENERIC_PROMICRO_RP2040 + + # Default UF2 Bootloader settings + UF2_FAMILY ?= RP2040 + FIRMWARE_FORMAT ?= uf2 +endif + ifneq ($(findstring STM32F042, $(MCU)),) # Cortex version MCU = cortex-m0 diff --git a/data/schemas/definitions.jsonschema b/data/schemas/definitions.jsonschema index 2cf76a351c..8b68a58482 100644 --- a/data/schemas/definitions.jsonschema +++ b/data/schemas/definitions.jsonschema @@ -101,6 +101,10 @@ "type": "string", "pattern": "^LINE_PIN\\d{1,2}$" }, + { + "type": "string", + "pattern": "^GP\\d{1,2}$" + }, { "type": "integer" }, diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema index ec5377b3b3..8aca807e38 100644 --- a/data/schemas/keyboard.jsonschema +++ b/data/schemas/keyboard.jsonschema @@ -42,7 +42,7 @@ }, "processor": { "type": "string", - "enum": ["cortex-m0", "cortex-m0plus", "cortex-m3", "cortex-m4", "MKL26Z64", "MK20DX128", "MK20DX256", "MK66FX1M0", "STM32F042", "STM32F072", "STM32F103", "STM32F303", "STM32F401", "STM32F405", "STM32F407", "STM32F411", "STM32F446", "STM32G431", "STM32G474", "STM32L412", "STM32L422", "STM32L432", "STM32L433", "STM32L442", "STM32L443", "GD32VF103", "WB32F3G71", "WB32FQ95", "atmega16u2", "atmega32u2", "atmega16u4", "atmega32u4", "at90usb162", "at90usb646", "at90usb647", "at90usb1286", "at90usb1287", "atmega32a", "atmega328p", "atmega328", "attiny85", "unknown"] + "enum": ["cortex-m0", "cortex-m0plus", "cortex-m3", "cortex-m4", "MKL26Z64", "MK20DX128", "MK20DX256", "MK66FX1M0", "RP2040", "STM32F042", "STM32F072", "STM32F103", "STM32F303", "STM32F401", "STM32F405", "STM32F407", "STM32F411", "STM32F446", "STM32G431", "STM32G474", "STM32L412", "STM32L422", "STM32L432", "STM32L433", "STM32L442", "STM32L443", "GD32VF103", "WB32F3G71", "WB32FQ95", "atmega16u2", "atmega32u2", "atmega16u4", "atmega32u4", "at90usb162", "at90usb646", "at90usb647", "at90usb1286", "at90usb1287", "atmega32a", "atmega328p", "atmega328", "attiny85", "unknown"] }, "audio": { "type": "object", @@ -86,7 +86,7 @@ }, "bootloader": { "type": "string", - "enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "custom", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2"], + "enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "custom", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2", "rp2040"], }, "bootloader_instructions": { "type": "string", diff --git a/docs/_summary.md b/docs/_summary.md index e6d636402b..da007bccb6 100644 --- a/docs/_summary.md +++ b/docs/_summary.md @@ -165,6 +165,7 @@ * Arm/ChibiOS * [Selecting an MCU](platformdev_selecting_arm_mcu.md) * [Early initialization](platformdev_chibios_earlyinit.md) + * [Raspberry Pi RP2040](platformdev_rp2040.md) * QMK Reference * [Contributing to QMK](contributing.md) diff --git a/docs/compatible_microcontrollers.md b/docs/compatible_microcontrollers.md index cee8986829..a594fe0620 100644 --- a/docs/compatible_microcontrollers.md +++ b/docs/compatible_microcontrollers.md @@ -65,6 +65,12 @@ You can also use any ARM chip with USB that [ChibiOS](https://www.chibios.org) s * [MK66FX1M0](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/k-series-cortex-m4/k6x-ethernet/kinetis-k66-180-mhz-dual-high-speed-full-speed-usbs-2mb-flash-microcontrollers-mcus-based-on-arm-cortex-m4-core:K66_180) * PJRC Teensy 3.6 +### Raspberry Pi + +* [RP2040](https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html) + +For a detailed overview about the RP2040 support by QMK see the [dedicated RP2040 page](platformdev_rp2040.md). + ## Atmel ATSAM There is limited support for one of Atmel's ATSAM microcontrollers, that being the [ATSAMD51J18A](https://www.microchip.com/wwwproducts/en/ATSAMD51J18A) used by the [Massdrop keyboards](https://github.com/qmk/qmk_firmware/tree/master/keyboards/massdrop). However, it is not recommended to design a board with this microcontroller as the support is quite specialized to Massdrop hardware. diff --git a/docs/flashing.md b/docs/flashing.md index dfb255f2dc..5e5dcb34e4 100644 --- a/docs/flashing.md +++ b/docs/flashing.md @@ -362,3 +362,42 @@ CLI Flashing sequence: ### `make` Targets * `:uf2-split-left` and `:uf2-split-right`: Flashes the firmware but also sets the handedness setting in EEPROM by generating a side specific firmware. + +## Raspberry Pi RP2040 UF2 + +The `rules.mk` setting for this bootloader is `rp2040`, and can be specified at the keymap or user level. + +To ensure compatibility with the rp2040 bootloader, make sure this block is present in your `rules.mk`: + +```make +# Bootloader selection +BOOTLOADER = rp2040 +``` + +Compatible flashers: + +* Any application able to copy a file from one place to another, such as _macOS Finder_ or _Windows Explorer_. + +Flashing sequence: + +1. Enter the bootloader using any of the following methods: + * Tap the `QK_BOOTLOADER` keycode + * Hold the `BOOTSEL` button on the PCB while plugin in the usb cable. + * Double-tap the `RESET` button on the PCB1. +2. Wait for the OS to detect the device +3. Copy the .uf2 file to the new USB disk +4. Wait for the keyboard to become available + +or + +CLI Flashing sequence: + +1. Enter the bootloader using any of the following methods: + * Tap the `QK_BOOTLOADER` keycode + * Hold the `BOOTSEL` button on the PCB while plugin in the usb cable. + * Double-tap the `RESET` button on the PCB1. +2. Wait for the OS to detect the device +3. Flash via QMK CLI eg. `qmk flash --keyboard handwired/onekey/rpi_pico --keymap default` +4. Wait for the keyboard to become available + +1: This works only if QMK was compiled with `RP2040_BOOTLOADER_DOUBLE_TAP_RESET` defined. diff --git a/docs/platformdev_rp2040.md b/docs/platformdev_rp2040.md new file mode 100644 index 0000000000..9426efa29a --- /dev/null +++ b/docs/platformdev_rp2040.md @@ -0,0 +1,125 @@ +# Raspberry Pi RP2040 + +The following table shows the current driver status for peripherals on RP2040 MCUs: + +| System | Support | +| ------------------------------------ | ---------------------------------------------- | +| [ADC driver](adc_driver.md) | Support planned (no ETA) | +| [Audio](audio_driver.md) | Support planned (no ETA) | +| [I2C driver](i2c_driver.md) | :heavy_check_mark: | +| [SPI driver](spi_driver.md) | :heavy_check_mark: | +| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver | +| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver | +| [EEPROM emulation](eeprom_driver.md) | Support planned (no ETA) | +| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver | +| [UART driver](uart_driver.md) | Support planned (no ETA) | + +## GPIO + +Raspberry Pi Pico pinout +Sparkfun RP2040 Pro Micro pinout + +!> The GPIO pins of the RP2040 are not 5V tolerant! + +### Pin nomenclature + +To address individual pins on the RP2040, QMK uses the `GPx` abbreviation -- where the `x` stands for the GPIO number of the pin. This number can likely be found on the official pinout diagram of your board. Note that these GPIO numbers match the RP2040 MCU datasheet, and don't necessarily match the number you see printed on the board. For instance the Raspberry Pi Pico uses numbers from 1 to 40 for their pins, but these are not identical to the RP2040's GPIO numbers. So if you want to use the pin 11 of the Pico for your keyboard, you would refer to it as `GP8` in the config files. + +### Alternate functions + +The RP2040 features flexible GPIO function multiplexing, this means that every pin can be connected to nearly all the internal peripherals like I2C, SPI, UART or PWM. This allows for flexible PCB designs that are much less restricted in the selection of GPIO pins. To find out which pin can use which peripheral refer to the official [Raspberry PI RP2040 datasheet](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#page=14) section 1.4.3 GPIO functions. + +## Selecting hardware peripherals and drivers + +QMK RP2040 support builds upon ChibiOS and thus follows their convention for activating drivers and associated hardware peripherals. These tables only give a quick overview which values have to be used, please refer to the ChibiOS specific sections on the driver pages. + +### I2C Driver + +| RP2040 Peripheral | `mcuconf.h` values | `I2C_DRIVER` | +| ----------------- | ------------------ | ------------ | +| `I2C0` | `RP_I2C_USE_I2C0` | `I2CD1` | +| `I2C1` | `RP_I2C_USE_I2C1` | `I2CD2` | + +To configure the I2C driver please read the [ChibiOS/ARM](i2c_driver.md#arm-configuration) section. + +### SPI Driver + +| RP2040 Peripheral | `mcuconf.h` values | `SPI_DRIVER` | +| ----------------- | ------------------ | ------------ | +| `SPI0` | `RP_SPI_USE_SPI0` | `SPID0` | +| `SPI1` | `RP_SPI_USE_SPI1` | `SPID1` | + +To configure the SPI driver please read the [ChibiOS/ARM](spi_driver.md#chibiosarm-configuration) section. + +## Double-tap reset boot-loader entry :id=double-tap + +The double-tap reset mechanism is an alternate way in QMK to enter the embedded mass storage UF2 boot-loader of the RP2040. It enables bootloader entry by a fast double-tap of the reset pin on start up, which is similar to the behavior of AVR Pro Micros. This feature activated by default for the Pro Micro RP2040 board, but has to be configured for other boards. To activate it, add the following options to your keyboards `config.h` file: + +```c +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET // Activates the double-tap behavior +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 200U // Timeout window in ms in which the double tap can occur. +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK 0U // Specify a optional status led which blinks when entering the bootloader +``` + +## Pre-defined RP2040 boards + +QMK defines two boards that you can choose from to base your RP2040 powered keyboard upon. These boards provide pre-configured default pins and drivers. + +### Generic Pro Micro RP2040 + +This is the default board that is chosen, unless any other RP2040 board is selected in your keyboards `rules.mk` file. It assumes a pin layout for the I2C, SPI and Serial drivers which is identical to the Sparkfun Pro Micro RP2040, however all values can be overwritten by defining them in your keyboards `config.h` file. The [double-tap](#double-tap) reset to enter boot-loader behavior is activated by default. + + +| Driver configuration define | Value | +| -------------------------------------------------------------------------- | ------------------------------------ | +| **I2C driver** | | +| `I2C_DRIVER` | `I2CD2` | +| `I2C1_SDA_PIN` | `GP2` | +| `I2C1_SCL_PIN` | `GP3` | +| **SPI driver** | | +| `SPI_DRIVER` | `SPID0` | +| `SPI_SCK_PIN` | `GP18` | +| `SPI_MISO_PIN` | `GP20` | +| `SPI_MOSI_PIN` | `GP19` | +| **Serial driver** | | +| `SERIAL_USART_DRIVER` ([SIO Driver](serial_driver.md#the-sio-driver) only) | `SIOD0` | +| `SOFT_SERIAL_PIN` | undefined, use `SERIAL_USART_TX_PIN` | +| `SERIAL_USART_TX_PIN` | `GP0` | +| `SERIAL_USART_RX_PIN` | `GP1` | + +?> The pin-outs of Adafruit's KB2040 and Boardsource's Blok both deviate from the Sparkfun Pro Micro RP2040. Lookup the pin-out of these boards and adjust your keyboards pin definition accordingly if you want to use these boards. + +### Generic RP2040 board + +This board can be chosen as a base for RP2040 keyboards which configure all necessary pins and drivers themselves and do not wish to leverage the configuration matching the Generic Pro Micro RP2040 board. Thus it doesn't provide any pre-configured pins or drivers. To select this board add the following line to your keyboards `rules.mk` file. + +```make +BOARD = GENERIC_RP_RP2040 +``` + +## Split keyboard support + +Split keyboards are fully supported using the [serial driver](serial_driver.md) in both full-duplex and half-duplex configurations. Two driver subsystems are supported by the RP2040, the hardware UART based `SIO` and the Programmable IO based `PIO` driver. + +| Feature | [SIO Driver](serial_driver.md#the-sio-driver) | [PIO Driver](serial_driver.md#the-pio-driver) | +| ----------------------------- | --------------------------------------------- | --------------------------------------------- | +| Half-Duplex operation | | :heavy_check_mark: | +| Full-Duplex operation | :heavy_check_mark: | :heavy_check_mark: | +| `TX` and `RX` pin swapping | | :heavy_check_mark: | +| Any GPIO as `TX` and `RX` pin | Only UART capable pins | :heavy_check_mark: | +| Simple configuration | | :heavy_check_mark: | + +The `PIO` driver is much more flexible then the `SIO` driver, the only "downside" is the usage of `PIO` resources which in turn are not available for advanced user programs. Under normal circumstances, this resource allocation will be a non-issue. + +## RP2040 second stage bootloader selection + +As the RP2040 does not have any internal flash memory it depends on an external SPI flash memory chip to store and execute instructions from. To successfully interact with a wide variety of these chips a second stage bootloader that is compatible with the chosen external flash memory has to be supplied with each firmware image. By default an `W25Q080` compatible bootloader is assumed, but others can be chosen by adding one of the defines listed in the table below to your keyboards `config.h` file. + +| Compatible with flash chip | Selection | +| :------------------------- | ---------------------------------- | +| W25Q080 | Selected by default | +| AT25SF128A | `#define RP2040_FLASH_AT25SF128A` | +| GD25Q64CS | `#define RP2040_FLASH_GD25Q64CS` | +| W25X10CL | `#define RP2040_FLASH_W25X10CL` | +| IS25LP080 | `#define RP2040_FLASH_IS25LP080` | +| Generic 03H flash | `#define RP2040_FLASH_GENERIC_03H` | diff --git a/docs/serial_driver.md b/docs/serial_driver.md index 7c0daec9b1..fff63109a1 100644 --- a/docs/serial_driver.md +++ b/docs/serial_driver.md @@ -74,11 +74,11 @@ Targeting ARM boards based on ChibiOS, where communication is offloaded to a USA +-------+ +-------+ ``` -Only one GPIO pin is needed for the Half-duplex driver, as only one wire is used for receiving and transmitting data. This pin is refereed to as the `SERIAL_USART_TX_PIN` in the configuration. Take care that the pin you chose can act as the TX pin of the USART peripheral. A simple TRS or USB cable provides enough conductors for this driver to work. As the split connection is configured to work in open-drain mode, an **external pull-up resistor is needed to keep the line high**. Resistor values of 1.5kΩ to 8.2kΩ are known to work. +Only one GPIO pin is needed for the Half-duplex driver, as only one wire is used for receiving and transmitting data. This pin is referred to as the `SERIAL_USART_TX_PIN` in the configuration. Take care that the pin you chose can act as the TX pin of the USART peripheral. A simple TRS or USB cable provides enough conductors for this driver to work. As the split connection is configured to work in open-drain mode, an **external pull-up resistor is needed to keep the line high**. Resistor values of 1.5kΩ to 8.2kΩ are known to work. ### Setup -To use the Half-duplex driver follow these steps to activate it. +To use the Half-duplex driver follow these steps to activate it. If you target the Raspberry Pi RP2040 PIO implementation skip step 1. 1. Change the `SERIAL_DRIVER` to `usart` in your keyboards `rules.mk` file: @@ -86,7 +86,13 @@ To use the Half-duplex driver follow these steps to activate it. SERIAL_DRIVER = usart ``` -2. Configure the hardware of your keyboard via the `config.h` file: +2. (RP2040 PIO only!) Change the `SERIAL_DRIVER` to `vendor` in your keyboards `rules.mk` file: + +```make +SERIAL_DRIVER = vendor +``` + +3. Configure the hardware of your keyboard via the `config.h` file: ```c #define SERIAL_USART_TX_PIN B6 // The GPIO pin that is used split communication. @@ -99,7 +105,7 @@ For STM32 MCUs several GPIO configuration options can be changed as well. See th #define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7 ``` -3. Decide either for ChibiOS `SERIAL` or `SIO` subsystem, see the section ["Choosing a ChibiOS driver subsystem"](#choosing-a-chibios-driver-subsystem). +1. Decide either for `SERIAL`, `SIO` or `PIO` subsystem, see the section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
@@ -125,11 +131,11 @@ Targeting ARM boards based on ChibiOS where communication is offloaded to an USA Two GPIO pins are needed for the Full-duplex driver, as two distinct wires are used for receiving and transmitting data. The pin transmitting data is the `TX` pin and refereed to as the `SERIAL_USART_TX_PIN`, the pin receiving data is the `RX` pin and refereed to as the `SERIAL_USART_RX_PIN` in this configuration. Please note that `TX` pin of the master half has to be connected with the `RX` pin of the slave half and the `RX` pin of the master half has to be connected with the `TX` pin of the slave half! Usually this pin swap has to be done outside of the MCU e.g. with cables or on the PCB. Some MCUs like the STM32F303 used on the Proton-C allow this pin swap directly inside the MCU. A simple TRRS or USB cable provides enough conductors for this driver to work. -To use this driver the usart peripherals `TX` and `RX` pins must be configured with the correct Alternate-functions. If you are using a Proton-C everything is already setup, same is true for STM32F103 MCUs. For MCUs which are using a modern flexible GPIO configuration you have to specify these by setting `SERIAL_USART_TX_PAL_MODE` and `SERIAL_USART_RX_PAL_MODE`. Reefer to the corresponding datasheets of your MCU or find those settings in the section ["Alternate Functions for selected STM32 MCUs"](#alternate-functions-for-selected-stm32-mcus). +To use this driver the usart peripherals `TX` and `RX` pins must be configured with the correct Alternate-functions. If you are using a Proton-C everything is already setup, same is true for STM32F103 MCUs. For MCUs which are using a modern flexible GPIO configuration you have to specify these by setting `SERIAL_USART_TX_PAL_MODE` and `SERIAL_USART_RX_PAL_MODE`. Refer to the corresponding datasheets of your MCU or find those settings in the section ["Alternate Functions for selected STM32 MCUs"](#alternate-functions-for-selected-stm32-mcus). ### Setup -To use the Full-duplex driver follow these steps to activate it. +To use the Full-duplex driver follow these steps to activate it. If you target the Raspberry Pi RP2040 PIO implementation skip step 1. 1. Change the `SERIAL_DRIVER` to `usart` in your keyboards `rules.mk` file: @@ -137,7 +143,13 @@ To use the Full-duplex driver follow these steps to activate it. SERIAL_DRIVER = usart ``` -2. Configure the hardware of your keyboard via the `config.h` file: +2. (RP2040 PIO only!) Change the `SERIAL_DRIVER` to `vendor` in your keyboards `rules.mk` file: + +```make +SERIAL_DRIVER = vendor +``` + +3. Configure the hardware of your keyboard via the `config.h` file: ```c #define SERIAL_USART_FULL_DUPLEX // Enable full duplex operation mode. @@ -153,11 +165,11 @@ For STM32 MCUs several GPIO configuration options, including the ability for `TX #define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7 ``` -3. Decide either for ChibiOS `SERIAL` or `SIO` subsystem, see the section ["Choosing a ChibiOS driver subsystem"](#choosing-a-chibios-driver-subsystem). +1. Decide either for `SERIAL`, `SIO` or `PIO` subsystem, see the section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
-## Choosing a ChibiOS driver subsystem +## Choosing a driver subsystem ### The `SERIAL` driver @@ -219,6 +231,17 @@ Where 'n' matches the peripheral number of your selected USART on the MCU. #define SERIAL_USART_DRIVER SIOD3 ``` +### The `PIO` driver + +The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using the integrated PIO peripheral and is therefore only available on this MCU. Because of the flexible nature of the PIO peripherals, **any** GPIO pin can be used as a `TX` or `RX` pin. Half-duplex and Full-duplex operation is fully supported. The Half-duplex operation mode uses the built-in pull-ups and GPIO manipulation on the RP2040 to drive the line high by default. An external pull-up is therefore not necessary. + +Configure the hardware via your config.h: +```c +#define SERIAL_PIO_USE_PIO1 // Force the usage of PIO1 peripheral, by default the Serial implementation uses the PIO0 peripheral +``` + +The Serial PIO program uses 2 state machines, 13 instructions and the complete interrupt handler of the PIO peripheral it is running on. +
## Advanced Configuration diff --git a/docs/ws2812_driver.md b/docs/ws2812_driver.md index 8acac0b3aa..54e6e77d81 100644 --- a/docs/ws2812_driver.md +++ b/docs/ws2812_driver.md @@ -11,11 +11,12 @@ These LEDs are called "addressable" because instead of using a wire per color, e ## Supported Driver Types | | AVR | ARM | -|----------|--------------------|--------------------| +| -------- | ------------------ | ------------------ | | bit bang | :heavy_check_mark: | :heavy_check_mark: | | I2C | :heavy_check_mark: | | | SPI | | :heavy_check_mark: | | PWM | | :heavy_check_mark: | +| PIO | | :heavy_check_mark: | ## Driver configuration @@ -33,11 +34,11 @@ The default setting is 280 µs, which should work for most cases, but this can b Some variants of the WS2812 may have their color components in a different physical or logical order. For example, the WS2812B-2020 has physically swapped red and green LEDs, which causes the wrong color to be displayed, because the default order of the bytes sent over the wire is defined as GRB. In this case, you can change the byte order by defining `WS2812_BYTE_ORDER` as one of the following values: -|Byte order |Known devices | -|---------------------------------|-----------------------------| -|`WS2812_BYTE_ORDER_GRB` (default)|Most WS2812's, SK6812, SK6805| -|`WS2812_BYTE_ORDER_RGB` |WS2812B-2020 | -|`WS2812_BYTE_ORDER_BGR` |TM1812 | +| Byte order | Known devices | +| --------------------------------- | ----------------------------- | +| `WS2812_BYTE_ORDER_GRB` (default) | Most WS2812's, SK6812, SK6805 | +| `WS2812_BYTE_ORDER_RGB` | WS2812B-2020 | +| `WS2812_BYTE_ORDER_BGR` | TM1812 | ### Bitbang @@ -54,13 +55,13 @@ WS2812_DRIVER = bitbang The WS2812 LED communication topology depends on a serialized timed window. Different versions of the addressable LEDs have differing requirements for the timing parameters, for instance, of the SK6812. You can tune these parameters through the definition of the following macros: -| Macro |Default | AVR | ARM | -|---------------------|--------------------------------------------|--------------------|--------------------| -|`WS2812_TIMING` |`1250` | :heavy_check_mark: | :heavy_check_mark: | -|`WS2812_T0H` |`350` | :heavy_check_mark: | :heavy_check_mark: | -|`WS2812_T0L` |`WS2812_TIMING - WS2812_T0H` | | :heavy_check_mark: | -|`WS2812_T1H` |`900` | :heavy_check_mark: | :heavy_check_mark: | -|`WS2812_T1L` |`WS2812_TIMING - WS2812_T1H` | | :heavy_check_mark: | +| Macro | Default | AVR | ARM | +| --------------- | ---------------------------- | ------------------ | ------------------ | +| `WS2812_TIMING` | `1250` | :heavy_check_mark: | :heavy_check_mark: | +| `WS2812_T0H` | `350` | :heavy_check_mark: | :heavy_check_mark: | +| `WS2812_T0L` | `WS2812_TIMING - WS2812_T0H` | | :heavy_check_mark: | +| `WS2812_T1H` | `900` | :heavy_check_mark: | :heavy_check_mark: | +| `WS2812_T1L` | `WS2812_TIMING - WS2812_T1H` | | :heavy_check_mark: | ### I2C Targeting boards where WS2812 support is offloaded to a 2nd MCU. Currently the driver is limited to AVR given the known consumers are ps2avrGB/BMC. To configure it, add this to your rules.mk: @@ -107,16 +108,16 @@ To adjust the baudrate at which the SPI peripheral is configured, users will nee Only divisors of 2, 4, 8, 16, 32, 64, 128 and 256 are supported by hardware. -|Define |Default|Description | -|--------------------|-------|-------------------------------------| -|`WS2812_SPI_DIVISOR`|`16` |SPI source clock peripheral divisor | +| Define | Default | Description | +| -------------------- | ------- | ----------------------------------- | +| `WS2812_SPI_DIVISOR` | `16` | SPI source clock peripheral divisor | #### Testing Notes While not an exhaustive list, the following table provides the scenarios that have been partially validated: | | SPI1 | SPI2 | SPI3 | -|------|---------------------------------------------|-----------------------------------------|-----------------------| +| ---- | ------------------------------------------- | --------------------------------------- | --------------------- | | f072 | ? | B15 :heavy_check_mark: (needs SCK: B13) | N/A | | f103 | A7 :heavy_check_mark: | B15 :heavy_check_mark: | N/A | | f303 | A7 :heavy_check_mark: B5 :heavy_check_mark: | B15 :heavy_check_mark: | B5 :heavy_check_mark: | @@ -150,15 +151,32 @@ You must also turn on the PWM feature in your halconf.h and mcuconf.h While not an exhaustive list, the following table provides the scenarios that have been partially validated: -| | Status | -|-|-| -| f072 | ? | -| f103 | :heavy_check_mark: | -| f303 | :heavy_check_mark: | +| | Status | +| --------- | ------------------ | +| f072 | ? | +| f103 | :heavy_check_mark: | +| f303 | :heavy_check_mark: | | f401/f411 | :heavy_check_mark: | *Other supported ChibiOS boards and/or pins may function, it will be highly chip and configuration dependent.* +### PIO + +Targeting Raspberry Pi RP2040 boards only where WS2812 support is offloaded to an dedicated PIO implementation. This offloads processing of the WS2812 protocol from the MCU to a dedicated PIO program using DMA transfers. + +To configure it, add this to your rules.mk: + +```make +WS2812_DRIVER = vendor +``` + +Configure the hardware via your config.h: +```c +#define WS2812_PIO_USE_PIO1 // Force the usage of PIO1 peripheral, by default the WS2812 implementation uses the PIO0 peripheral +``` + +The WS2812 PIO programm uses 1 state machine, 4 instructions and does not use any interrupt handlers. + ### Push Pull and Open Drain Configuration The default configuration is a push pull on the defined pin. This can be configured for bitbang, PWM and SPI. diff --git a/keyboards/handwired/onekey/onekey.c b/keyboards/handwired/onekey/onekey.c index cbd67012ce..a29f9ea6d0 100644 --- a/keyboards/handwired/onekey/onekey.c +++ b/keyboards/handwired/onekey/onekey.c @@ -1 +1,12 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + #include "onekey.h" + +void keyboard_post_init_kb(void) { + debug_enable = true; + debug_matrix = true; + debug_keyboard = true; + debug_mouse = true; + keyboard_post_init_user(); +} diff --git a/keyboards/handwired/onekey/rp2040/config.h b/keyboards/handwired/onekey/rp2040/config.h new file mode 100644 index 0000000000..f5a122e91b --- /dev/null +++ b/keyboards/handwired/onekey/rp2040/config.h @@ -0,0 +1,17 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "config_common.h" + +#define PRODUCT Onekey Raspberry Pi RP2040 +#define MATRIX_COL_PINS { GP4 } +#define MATRIX_ROW_PINS { GP5 } +#define DEBUG_MATRIX_SCAN_RATE + +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED GP25 +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U + +#define RGB_DI_PIN A1 diff --git a/keyboards/handwired/onekey/rp2040/readme.md b/keyboards/handwired/onekey/rp2040/readme.md new file mode 100644 index 0000000000..9014479f8d --- /dev/null +++ b/keyboards/handwired/onekey/rp2040/readme.md @@ -0,0 +1,12 @@ +# Raspberry Pi 2040 onekey + +To trigger keypress, short together pins *GP4* and *GP5*. + +Double-tap reset to enter bootloader mode. Copy the built uf2 file to the device by dragging the file to the new USB disk. + +## Supported Hardware + +* Raspberry Pi Pico +* SparkFun Pro Micro - RP2040 +* Adafruit KB2040 - RP2040 Kee Boar +* ...and many more RP2040 based development boards diff --git a/keyboards/handwired/onekey/rp2040/rules.mk b/keyboards/handwired/onekey/rp2040/rules.mk new file mode 100644 index 0000000000..646402d0bb --- /dev/null +++ b/keyboards/handwired/onekey/rp2040/rules.mk @@ -0,0 +1,3 @@ +# MCU name +MCU = RP2040 +BOOTLOADER = rp2040 diff --git a/lib/pico-sdk b/lib/pico-sdk new file mode 160000 index 0000000000..07edde8e49 --- /dev/null +++ b/lib/pico-sdk @@ -0,0 +1 @@ +Subproject commit 07edde8e49890d2172bbc272aacc119f999df063 diff --git a/lib/python/qmk/constants.py b/lib/python/qmk/constants.py index a54d9058bc..be85a1dbff 100644 --- a/lib/python/qmk/constants.py +++ b/lib/python/qmk/constants.py @@ -14,7 +14,7 @@ QMK_FIRMWARE_UPSTREAM = 'qmk/qmk_firmware' MAX_KEYBOARD_SUBFOLDERS = 5 # Supported processor types -CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK66FX1M0', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95' +CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK66FX1M0', 'RP2040', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95' LUFA_PROCESSORS = 'at90usb162', 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None VUSB_PROCESSORS = 'atmega32a', 'atmega328p', 'atmega328', 'attiny85' diff --git a/platforms/chibios/_pin_defs.h b/platforms/chibios/_pin_defs.h index 0d96e2fc3b..414c9e3d11 100644 --- a/platforms/chibios/_pin_defs.h +++ b/platforms/chibios/_pin_defs.h @@ -21,6 +21,11 @@ # include #endif +/* Include the vendor specific pin defs */ +#if __has_include_next("_pin_defs.h") +# include_next "_pin_defs.h" +#endif + #define A0 PAL_LINE(GPIOA, 0) #define A1 PAL_LINE(GPIOA, 1) #define A2 PAL_LINE(GPIOA, 2) diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040 + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h new file mode 100644 index 0000000000..b4363595d0 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h @@ -0,0 +1,12 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include_next "board.h" + +#undef BOARD_RP_PICO_RP2040 +#define BOARD_GENERIC_PROMICRO_RP2040 + +#undef BOARD_NAME +#define BOARD_NAME "Pro Micro RP2040" diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h @@ -0,0 +1,13 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define CH_CFG_SMP_MODE TRUE +#define CH_CFG_ST_RESOLUTION 32 +#define CH_CFG_ST_FREQUENCY 1000000 +#define CH_CFG_INTERVALS_SIZE 32 +#define CH_CFG_TIME_TYPES_SIZE 32 +#define CH_CFG_ST_TIMEDELTA 20 + +#include_next diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h new file mode 100644 index 0000000000..7fe9b654e1 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h @@ -0,0 +1,62 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +/**====================== + ** I2C Driver + *========================**/ + +#if !defined(I2C_DRIVER) +# define I2C_DRIVER I2CD2 +#endif + +#if !defined(I2C1_SDA_PIN) +# define I2C1_SDA_PIN GP2 +#endif + +#if !defined(I2C1_SCL_PIN) +# define I2C1_SCL_PIN GP3 +#endif + +/**====================== + ** SPI Driver + *========================**/ + +#if !defined(SPI_DRIVER) +# define SPI_DRIVER SPID0 +#endif + +#if !defined(SPI_SCK_PIN) +# define SPI_SCK_PIN GP18 +#endif + +#if !defined(SPI_MISO_PIN) +# define SPI_MISO_PIN GP20 +#endif + +#if !defined(SPI_MOSI_PIN) +# define SPI_MOSI_PIN GP19 +#endif + +/**====================== + ** SERIAL Driver + *========================**/ + +#if !defined(SERIAL_USART_DRIVER) +# define SERIAL_USART_DRIVER SIOD0 +#endif + +#if !defined(SERIAL_USART_TX_PIN) && !defined(SOFT_SERIAL_PIN) +# define SERIAL_USART_TX_PIN GP0 +#endif + +#if !defined(SERIAL_USART_RX_PIN) +# define SERIAL_USART_RX_PIN GP1 +#endif + +/**====================== + ** Double-tap + *========================**/ + +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h new file mode 100644 index 0000000000..8348e5312f --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h @@ -0,0 +1,98 @@ +/* + ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_USB0_PRIORITY 3 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 + +/* + * ADC driver system settings. + */ +#define RP_ADC_USE_ADC1 FALSE + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 TRUE +#define RP_SIO_USE_UART1 FALSE + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 TRUE +#define RP_SPI_USE_SPI1 FALSE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 FALSE +#define RP_I2C_USE_I2C1 TRUE +#define RP_I2C_BUSY_TIMEOUT 50 +#define RP_I2C_ADDRESS_MODE_10BIT FALSE + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USBD0 TRUE +#define RP_USB_FORCE_VBUS_DETECT TRUE +#define RP_USE_EXTERNAL_VBUS_DETECT FALSE +#define RP_USB_USE_SOF_INTR TRUE +#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE + +#endif /* MCUCONF_H */ diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040 + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h new file mode 100644 index 0000000000..052050c944 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h @@ -0,0 +1,12 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include_next "board.h" + +#undef BOARD_RP_PICO_RP2040 +#define BOARD_GENERIC_RP2040 + +#undef BOARD_NAME +#define BOARD_NAME "Generic Raspberry Pi RP2040" diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h @@ -0,0 +1,13 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define CH_CFG_SMP_MODE TRUE +#define CH_CFG_ST_RESOLUTION 32 +#define CH_CFG_ST_FREQUENCY 1000000 +#define CH_CFG_INTERVALS_SIZE 32 +#define CH_CFG_TIME_TYPES_SIZE 32 +#define CH_CFG_ST_TIMEDELTA 20 + +#include_next diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h new file mode 100644 index 0000000000..9d8dc61aac --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h @@ -0,0 +1,98 @@ +/* + ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_USB0_PRIORITY 3 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 + +/* + * ADC driver system settings. + */ +#define RP_ADC_USE_ADC1 FALSE + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 FALSE +#define RP_SIO_USE_UART1 FALSE + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 FALSE +#define RP_SPI_USE_SPI1 FALSE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 FALSE +#define RP_I2C_USE_I2C1 FALSE +#define RP_I2C_BUSY_TIMEOUT 50 +#define RP_I2C_ADDRESS_MODE_10BIT FALSE + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USBD0 TRUE +#define RP_USB_FORCE_VBUS_DETECT TRUE +#define RP_USE_EXTERNAL_VBUS_DETECT FALSE +#define RP_USB_USE_SOF_INTR TRUE +#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE + +#endif /* MCUCONF_H */ diff --git a/platforms/chibios/bootloaders/rp2040.c b/platforms/chibios/bootloaders/rp2040.c new file mode 100644 index 0000000000..13a54036ef --- /dev/null +++ b/platforms/chibios/bootloaders/rp2040.c @@ -0,0 +1,57 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "hal.h" +#include "bootloader.h" +#include "pico/bootrom.h" + +#if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED) +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK 0U +#else +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK (1U << RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED) +#endif + +__attribute__((weak)) void mcu_reset(void) { + NVIC_SystemReset(); +} +void bootloader_jump(void) { + reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U); +} + +void enter_bootloader_mode_if_requested(void) {} + +#if defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET) +# if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT) +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 200U +# endif + +// Needs to be located in a RAM section that is never initialized on boot to +// preserve its value on reset +static volatile uint32_t __attribute__((section(".ram0.bootloader_magic"))) magic_location; +const uint32_t magic_token = 0xCAFEB0BA; + +// We can not use the __early_init / enter_bootloader_mode_if_requested hook as +// we depend on an already initialized system with usable memory regions and +// populated function pointer tables to the optimized math functions in the +// bootrom. This function is called just prior to main. +void __late_init(void) { + // All clocks have to be enabled before jumping to the bootloader function, + // otherwise the bootrom will be stuck infinitely. + clocks_init(); + + if (magic_location != magic_token) { + magic_location = magic_token; + // ChibiOS is not initialized at this point, so sleeping is only + // possible via busy waiting. The internal timer peripheral is running + // at this point with a precision of 1us. + chSysPolledDelayX(MS2RTC(1 * MHZ, RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT)); + magic_location = 0; + return; + } + + magic_location = 0; + reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U); +} + +#endif diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index a7098f2713..1571bd5cd3 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -19,6 +19,27 @@ # define SPLIT_USB_DETECT // Force this on when dedicated pin is not used #endif +#if defined(MCU_RP) +# define CPU_CLOCK RP_CORE_CLK + +# define USE_GPIOV1 +# define PAL_OUTPUT_TYPE_OPENDRAIN _Static_assert(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible"); + +# define usb_lld_endpoint_fields + +# define I2C1_SCL_PAL_MODE (PAL_MODE_ALTERNATE_I2C | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_PUE | PAL_RP_PAD_DRIVE4) +# define I2C1_SDA_PAL_MODE I2C1_SCL_PAL_MODE + +# define USE_I2CV1_CONTRIB +# if !defined(I2C1_CLOCK_SPEED) +# define I2C1_CLOCK_SPEED 400000 +# endif + +# define SPI_SCK_PAL_MODE (PAL_MODE_ALTERNATE_SPI | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_DRIVE4) +# define SPI_MOSI_PAL_MODE SPI_SCK_PAL_MODE +# define SPI_MISO_PAL_MODE SPI_SCK_PAL_MODE +#endif + // STM32 compatibility #if defined(MCU_STM32) # define CPU_CLOCK STM32_SYSCLK diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index f76afb5db4..6581a5b6e9 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c @@ -8,12 +8,12 @@ #if defined(SERIAL_USART_CONFIG) static QMKSerialConfig serial_config = SERIAL_USART_CONFIG; -#else +#elif defined(MCU_STM32) /* STM32 MCUs */ static QMKSerialConfig serial_config = { # if HAL_USE_SERIAL - .speed = (SERIAL_USART_SPEED), /* baudrate - mandatory */ + .speed = (SERIAL_USART_SPEED), # else - .baud = (SERIAL_USART_SPEED), /* baudrate - mandatory */ + .baud = (SERIAL_USART_SPEED), # endif .cr1 = (SERIAL_USART_CR1), .cr2 = (SERIAL_USART_CR2), @@ -23,6 +23,19 @@ static QMKSerialConfig serial_config = { .cr3 = (SERIAL_USART_CR3) # endif }; +#elif defined(MCU_RP) /* Raspberry Pi MCUs */ +/* USART in 8E2 config with RX and TX FIFOs enabled. */ +// clang-format off +static QMKSerialConfig serial_config = { + .baud = (SERIAL_USART_SPEED), + .UARTLCR_H = UART_UARTLCR_H_WLEN_8BITS | UART_UARTLCR_H_PEN | UART_UARTLCR_H_STP2 | UART_UARTLCR_H_FEN, + .UARTCR = 0U, + .UARTIFLS = UART_UARTIFLS_RXIFLSEL_1_8F | UART_UARTIFLS_TXIFLSEL_1_8E, + .UARTDMACR = 0U +}; +// clang-format on +#else +# error MCU Familiy not supported by default, supply your own serial_config by defining SERIAL_USART_CONFIG in your keyboard files. #endif static QMKSerialDriver* serial_driver = (QMKSerialDriver*)&SERIAL_USART_DRIVER; @@ -156,7 +169,7 @@ inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t * @brief Initiate pins for USART peripheral. Half-duplex configuration. */ __attribute__((weak)) void usart_init(void) { -# if defined(MCU_STM32) +# if defined(MCU_STM32) /* STM32 MCUs */ # if defined(USE_GPIOV1) palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); # else @@ -166,6 +179,8 @@ __attribute__((weak)) void usart_init(void) { # if defined(USART_REMAP) USART_REMAP; # endif +# elif defined(MCU_RP) /* Raspberry Pi MCUs */ +# error Half-duplex with the SIO driver is not supported due to hardware limitations on the RP2040, switch to the PIO driver which has half-duplex support. # else # pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files." # endif @@ -177,7 +192,7 @@ __attribute__((weak)) void usart_init(void) { * @brief Initiate pins for USART peripheral. Full-duplex configuration. */ __attribute__((weak)) void usart_init(void) { -# if defined(MCU_STM32) +# if defined(MCU_STM32) /* STM32 MCUs */ # if defined(USE_GPIOV1) palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL); palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT); @@ -189,6 +204,9 @@ __attribute__((weak)) void usart_init(void) { # if defined(USART_REMAP) USART_REMAP; # endif +# elif defined(MCU_RP) /* Raspberry Pi MCUs */ + palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_UART); + palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE_UART); # else # pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files." # endif diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index ce69e7f0ac..f9974d9f6b 100644 --- a/platforms/chibios/drivers/spi_master.c +++ b/platforms/chibios/drivers/spi_master.c @@ -20,7 +20,7 @@ static pin_t currentSlavePin = NO_PIN; -#if defined(K20x) || defined(KL2x) +#if defined(K20x) || defined(KL2x) || defined(RP2040) static SPIConfig spiConfig = {NULL, 0, 0, 0}; #else static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0}; @@ -167,7 +167,36 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { spiConfig.SPI_CPOL = SPI_CPOL_High; break; } +#elif defined(MCU_RP) + if (lsbFirst) { + osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first."); + } + + // Motorola frame format and 8bit transfer data size. + spiConfig.SSPCR0 = SPI_SSPCR0_FRF_MOTOROLA | SPI_SSPCR0_DSS_8BIT; + // Serial output clock = (ck_sys or ck_peri) / (SSPCPSR->CPSDVSR * (1 + + // SSPCR0->SCR)). SCR is always set to zero, as QMK SPI API expects the + // passed divisor to be the only value to divide the input clock by. + spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254 + switch (mode) { + case 0: + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge + break; + case 1: + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low + spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition + break; + case 2: + spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge + break; + case 3: + spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high + spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition + break; + } #else spiConfig.cr1 = 0; diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c new file mode 100644 index 0000000000..949fc6dd93 --- /dev/null +++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c @@ -0,0 +1,457 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "serial_usart.h" +#include "serial_protocol.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" + +#if !defined(MCU_RP) +# error PIO Driver is only available for Raspberry Pi 2040 MCUs! +#endif + +static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout); +static inline bool send_impl(const uint8_t* source, const size_t size); +static inline void pio_serve_interrupt(void); + +#define MSG_PIO_ERROR ((msg_t)(-3)) + +#if defined(SERIAL_PIO_USE_PIO1) +static const PIO pio = pio1; + +OSAL_IRQ_HANDLER(RP_PIO1_IRQ_0_HANDLER) { + OSAL_IRQ_PROLOGUE(); + pio_serve_interrupt(); + OSAL_IRQ_EPILOGUE(); +} +#else +static const PIO pio = pio0; + +OSAL_IRQ_HANDLER(RP_PIO0_IRQ_0_HANDLER) { + OSAL_IRQ_PROLOGUE(); + pio_serve_interrupt(); + OSAL_IRQ_EPILOGUE(); +} +#endif + +#define UART_TX_WRAP_TARGET 0 +#define UART_TX_WRAP 3 + +// clang-format off +#if defined(SERIAL_USART_FULL_DUPLEX) +static const uint16_t uart_tx_program_instructions[] = { + // .wrap_target + 0x9fa0, // 0: pull block side 1 [7] + 0xf727, // 1: set x, 7 side 0 [7] + 0x6001, // 2: out pins, 1 + 0x0642, // 3: jmp x--, 2 [6] + // .wrap +}; +#else +static const uint16_t uart_tx_program_instructions[] = { + // .wrap_target + 0x9fa0, // 0: pull block side 1 [7] + 0xf727, // 1: set x, 7 side 0 [7] + 0x6081, // 2: out pindirs, 1 + 0x0642, // 3: jmp x--, 2 [6] + // .wrap +}; +#endif +// clang-format on + +static const pio_program_t uart_tx_program = { + .instructions = uart_tx_program_instructions, + .length = 4, + .origin = -1, +}; + +#define UART_RX_WRAP_TARGET 0 +#define UART_RX_WRAP 8 + +// clang-format off +static const uint16_t uart_rx_program_instructions[] = { + // .wrap_target + 0x2020, // 0: wait 0 pin, 0 + 0xea27, // 1: set x, 7 [10] + 0x4001, // 2: in pins, 1 + 0x0642, // 3: jmp x--, 2 [6] + 0x00c8, // 4: jmp pin, 8 + 0xc020, // 5: irq wait 0 + 0x20a0, // 6: wait 1 pin, 0 + 0x0000, // 7: jmp 0 + 0x8020, // 8: push block + // .wrap +}; +// clang-format on + +static const pio_program_t uart_rx_program = { + .instructions = uart_rx_program_instructions, + .length = 9, + .origin = -1, +}; + +thread_reference_t rx_thread = NULL; +static int rx_state_machine = -1; + +thread_reference_t tx_thread = NULL; +static int tx_state_machine = -1; + +void pio_serve_interrupt(void) { + uint32_t irqs = pio->ints0; + + // The RX FIFO is not empty any more, therefore wake any sleeping rx thread + if (irqs & (PIO_IRQ0_INTF_SM0_RXNEMPTY_BITS << rx_state_machine)) { + // Disable rx not empty interrupt + pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, false); + + osalSysLockFromISR(); + osalThreadResumeI(&rx_thread, MSG_OK); + osalSysUnlockFromISR(); + } + + // The TX FIFO is not full any more, therefore wake any sleeping tx thread + if (irqs & (PIO_IRQ0_INTF_SM0_TXNFULL_BITS << tx_state_machine)) { + // Disable tx not full interrupt + pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, false); + osalSysLockFromISR(); + osalThreadResumeI(&tx_thread, MSG_OK); + osalSysUnlockFromISR(); + } + + // IRQ 0 is set on framing or break errors by the rx state machine + if (pio_interrupt_get(pio, 0UL)) { + pio_interrupt_clear(pio, 0UL); + + osalSysLockFromISR(); + osalThreadResumeI(&rx_thread, MSG_PIO_ERROR); + osalSysUnlockFromISR(); + } +} + +#if !defined(SERIAL_USART_FULL_DUPLEX) +// The internal pull-ups of the RP2040 are rather weakish with a range of 50k to +// 80k, which in turn do not provide enough current to guarantee fast signal rise +// times with a parasitic capacitance of greater than 100pf. In real world +// applications, like split keyboards which might have vias in the signal path +// or long PCB traces, this prevents a successful communication. The solution +// is to temporarily augment the weak pull ups from the receiving side by +// driving the tx pin high. On the receiving side the lowest possible drive +// strength is chosen because the transmitting side must still be able to drive +// the signal low. With this configuration the rise times are fast enough and +// the generated low level with 360mV will generate a logical zero. +static inline void enter_rx_state(void) { + osalSysLock(); + // Wait for the transmitting state machines FIFO to run empty. At this point + // the last byte has been pulled from the transmitting state machines FIFO + // into the output shift register. We have to wait a tiny bit more until + // this byte is transmitted, before we can turn on the receiving state + // machine again. + while (!pio_sm_is_tx_fifo_empty(pio, tx_state_machine)) { + } + // Wait for ~11 bits, 1 start bit + 8 data bits + 1 stop bit + 1 bit + // headroom. + chSysPolledDelayX(US2RTC(1 * MHZ, (1000000U * 11 / SERIAL_USART_SPEED))); + // Disable tx state machine to not interfere with our tx pin manipulation + pio_sm_set_enabled(pio, tx_state_machine, false); + gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_2MA); + pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << SERIAL_USART_TX_PIN, 1U << SERIAL_USART_TX_PIN); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, false); + pio_sm_set_enabled(pio, rx_state_machine, true); + osalSysUnlock(); +} + +static inline void leave_rx_state(void) { + osalSysLock(); + // In Half-duplex operation the tx pin dual-functions as sender and + // receiver. To not receive the data we will send, we disable the receiving + // state machine. + pio_sm_set_enabled(pio, rx_state_machine, false); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, true); + pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U, 1U << SERIAL_USART_TX_PIN); + gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_12MA); + pio_sm_restart(pio, tx_state_machine); + pio_sm_set_enabled(pio, tx_state_machine, true); + osalSysUnlock(); +} +#else +// All this trickery is gladly not necessary for full-duplex. +static inline void enter_rx_state(void) {} +static inline void leave_rx_state(void) {} +#endif + +/** + * @brief Clear the RX and TX hardware FIFOs of the state machines. + */ +inline void serial_transport_driver_clear(void) { + osalSysLock(); + pio_sm_clear_fifos(pio, rx_state_machine); + pio_sm_clear_fifos(pio, tx_state_machine); + osalSysUnlock(); +} + +static inline msg_t sync_tx(sysinterval_t timeout) { + msg_t msg = MSG_OK; + osalSysLock(); + while (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) { + pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true); + msg = osalThreadSuspendTimeoutS(&tx_thread, timeout); + if (msg < MSG_OK) { + break; + } + } + osalSysUnlock(); + return msg; +} + +static inline bool send_impl(const uint8_t* source, const size_t size) { + size_t send = 0; + msg_t msg; + while (send < size) { + msg = sync_tx(TIME_MS2I(SERIAL_USART_TIMEOUT)); + if (msg < MSG_OK) { + return false; + } + + osalSysLock(); + while (send < size) { + if (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) { + break; + } + if (send >= size) { + break; + } + pio_sm_put(pio, tx_state_machine, (uint32_t)(*source)); + source++; + send++; + } + osalSysUnlock(); + } + + return send == size; +} + +/** + * @brief Blocking send of buffer with timeout. + * + * @return true Send success. + * @return false Send failed. + */ +inline bool serial_transport_send(const uint8_t* source, const size_t size) { + leave_rx_state(); + bool result = send_impl(source, size); + enter_rx_state(); + + return result; +} + +static inline msg_t sync_rx(sysinterval_t timeout) { + msg_t msg = MSG_OK; + osalSysLock(); + while (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) { + pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true); + msg = osalThreadSuspendTimeoutS(&rx_thread, timeout); + if (msg < MSG_OK) { + break; + } + } + osalSysUnlock(); + return msg; +} + +static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout) { + size_t read = 0U; + + while (read < size) { + msg_t msg = sync_rx(timeout); + if (msg < MSG_OK) { + return false; + } + osalSysLock(); + while (true) { + if (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) { + break; + } + if (read >= size) { + break; + } + *destination++ = *((uint8_t*)&pio->rxf[rx_state_machine] + 3U); + read++; + } + osalSysUnlock(); + } + + return read == size; +} + +/** + * @brief Blocking receive of size * bytes with timeout. + * + * @return true Receive success. + * @return false Receive failed, e.g. by timeout. + */ +inline bool serial_transport_receive(uint8_t* destination, const size_t size) { + return receive_impl(destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)); +} + +/** + * @brief Blocking receive of size * bytes. + * + * @return true Receive success. + * @return false Receive failed. + */ +inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t size) { + return receive_impl(destination, size, TIME_INFINITE); +} + +static inline void pio_tx_init(pin_t tx_pin) { + uint pio_idx = pio_get_index(pio); + uint offset = pio_add_program(pio, &uart_tx_program); + +#if defined(SERIAL_USART_FULL_DUPLEX) + // clang-format off + iomode_t tx_pin_mode = PAL_RP_GPIO_OE | + PAL_RP_PAD_SLEWFAST | + PAL_RP_PAD_DRIVE4 | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << tx_pin, 1U << tx_pin); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true); +#else + // clang-format off + iomode_t tx_pin_mode = PAL_RP_PAD_IE | + PAL_RP_GPIO_OE | + PAL_RP_PAD_SCHMITT | + PAL_RP_PAD_PUE | + PAL_RP_PAD_SLEWFAST | + PAL_RP_PAD_DRIVE12 | + PAL_RP_IOCTRL_OEOVER_DRVINVPERI | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U << tx_pin, 1U << tx_pin); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true); +#endif + + palSetLineMode(tx_pin, tx_pin_mode); + + pio_sm_config config = pio_get_default_sm_config(); + sm_config_set_wrap(&config, offset + UART_TX_WRAP_TARGET, offset + UART_TX_WRAP); +#if defined(SERIAL_USART_FULL_DUPLEX) + sm_config_set_sideset(&config, 2, true, false); +#else + sm_config_set_sideset(&config, 2, true, true); +#endif + // OUT shifts to right, no autopull + sm_config_set_out_shift(&config, true, false, 32); + // We are mapping both OUT and side-set to the same pin, because sometimes + // we need to assert user data onto the pin (with OUT) and sometimes + // assert constant values (start/stop bit) + sm_config_set_out_pins(&config, tx_pin, 1); + sm_config_set_sideset_pins(&config, tx_pin); + // We only need TX, so get an 8-deep FIFO! + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED); + sm_config_set_clkdiv(&config, div); + pio_sm_init(pio, tx_state_machine, offset, &config); + pio_sm_set_enabled(pio, tx_state_machine, true); +} + +static inline void pio_rx_init(pin_t rx_pin) { + uint offset = pio_add_program(pio, &uart_rx_program); + +#if defined(SERIAL_USART_FULL_DUPLEX) + uint pio_idx = pio_get_index(pio); + pio_sm_set_consecutive_pindirs(pio, rx_state_machine, rx_pin, 1, false); + // clang-format off + iomode_t rx_pin_mode = PAL_RP_PAD_IE | + PAL_RP_PAD_SCHMITT | + PAL_RP_PAD_PUE | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + palSetLineMode(rx_pin, rx_pin_mode); +#endif + + pio_sm_config config = pio_get_default_sm_config(); + sm_config_set_wrap(&config, offset + UART_RX_WRAP_TARGET, offset + UART_RX_WRAP); + sm_config_set_in_pins(&config, rx_pin); // for WAIT, IN + sm_config_set_jmp_pin(&config, rx_pin); // for JMP + // Shift to right, autopush disabled + sm_config_set_in_shift(&config, true, false, 32); + // Deeper FIFO as we're not doing any TX + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED); + sm_config_set_clkdiv(&config, div); + pio_sm_init(pio, rx_state_machine, offset, &config); + pio_sm_set_enabled(pio, rx_state_machine, true); +} + +static inline void pio_init(pin_t tx_pin, pin_t rx_pin) { + uint pio_idx = pio_get_index(pio); + + /* Get PIOx peripheral out of reset state. */ + hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1); + + tx_state_machine = pio_claim_unused_sm(pio, true); + if (tx_state_machine < 0) { + dprintln("ERROR: Failed to acquire state machine for serial transmission!"); + return; + } + pio_tx_init(tx_pin); + + rx_state_machine = pio_claim_unused_sm(pio, true); + if (rx_state_machine < 0) { + dprintln("ERROR: Failed to acquire state machine for serial reception!"); + return; + } + pio_rx_init(rx_pin); + + // Enable error flag IRQ source for rx state machine + pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true); + pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true); + pio_set_irq0_source_enabled(pio, pis_interrupt0, true); + + // Enable PIO specific interrupt vector +#if defined(SERIAL_PIO_USE_PIO1) + nvicEnableVector(RP_PIO1_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY); +#else + nvicEnableVector(RP_PIO0_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY); +#endif + + enter_rx_state(); +} + +/** + * @brief PIO driver specific initialization function for the master side. + */ +void serial_transport_driver_master_init(void) { +#if defined(SERIAL_USART_FULL_DUPLEX) + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_RX_PIN; +#else + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_TX_PIN; +#endif + +#if defined(SERIAL_USART_PIN_SWAP) + pio_init(rx_pin, tx_pin); +#else + pio_init(tx_pin, rx_pin); +#endif +} + +/** + * @brief PIO driver specific initialization function for the slave side. + */ +void serial_transport_driver_slave_init(void) { +#if defined(SERIAL_USART_FULL_DUPLEX) + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_RX_PIN; +#else + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_TX_PIN; +#endif + + pio_init(tx_pin, rx_pin); +} diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c new file mode 100644 index 0000000000..bc34eded14 --- /dev/null +++ b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c @@ -0,0 +1,189 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "ws2812.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" + +#if !defined(MCU_RP) +# error PIO Driver is only available for Raspberry Pi 2040 MCUs! +#endif + +#if defined(WS2812_PIO_USE_PIO1) +static const PIO pio = pio1; +#else +static const PIO pio = pio0; +#endif + +#if !defined(RP_DMA_PRIORITY_WS2812) +# define RP_DMA_PRIORITY_WS2812 12 +#endif + +static int state_machine = -1; + +#define WS2812_WRAP_TARGET 0 +#define WS2812_WRAP 3 + +#define WS2812_T1 2 +#define WS2812_T2 5 +#define WS2812_T3 3 + +#if defined(WS2812_EXTERNAL_PULLUP) + +# pragma message "The GPIOs of the RP2040 are NOT 5V tolerant! Make sure to NOT apply any voltage over 3.3V to the RGB data pin." + +// clang-format off +static const uint16_t ws2812_program_instructions[] = { + // .wrap_target + 0x7221, // 0: out x, 1 side 1 [2] + 0x0123, // 1: jmp !x, 3 side 0 [1] + 0x0400, // 2: jmp 0 side 0 [4] + 0xb442, // 3: nop side 1 [4] + // .wrap +}; + +#else + +static const uint16_t ws2812_program_instructions[] = { + // .wrap_target + 0x6221, // 0: out x, 1 side 0 [2] + 0x1123, // 1: jmp !x, 3 side 1 [1] + 0x1400, // 2: jmp 0 side 1 [4] + 0xa442, // 3: nop side 0 [4] + // .wrap +}; +// clang-format on +#endif + +static const pio_program_t ws2812_program = { + .instructions = ws2812_program_instructions, + .length = 4, + .origin = -1, +}; + +static uint32_t WS2812_BUFFER[RGBLED_NUM]; +static const rp_dma_channel_t* WS2812_DMA_CHANNEL; + +bool ws2812_init(void) { + uint pio_idx = pio_get_index(pio); + /* Get PIOx peripheral out of reset state. */ + hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1); + + // clang-format off + iomode_t rgb_pin_mode = PAL_RP_PAD_SLEWFAST | + PAL_RP_GPIO_OE | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + + palSetLineMode(RGB_DI_PIN, rgb_pin_mode); + + state_machine = pio_claim_unused_sm(pio, true); + if (state_machine < 0) { + dprintln("ERROR: Failed to acquire state machine for WS2812 output!"); + return false; + } + + uint offset = pio_add_program(pio, &ws2812_program); + + pio_sm_set_consecutive_pindirs(pio, state_machine, RGB_DI_PIN, 1, true); + + pio_sm_config config = pio_get_default_sm_config(); + sm_config_set_wrap(&config, offset + WS2812_WRAP_TARGET, offset + WS2812_WRAP); + sm_config_set_sideset_pins(&config, RGB_DI_PIN); + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX); + +#if defined(WS2812_EXTERNAL_PULLUP) + /* Instruct side-set to change the pin-directions instead of outputting + * a logic level. We generate our levels the following way: + * + * 1: Set RGB data pin to high impedance input and let the pull-up drive the + * signal high. + * + * 0: Set RGB data pin to low impedance output and drive the pin low. + */ + sm_config_set_sideset(&config, 1, false, true); +#else + sm_config_set_sideset(&config, 1, false, false); +#endif + +#if defined(RGBW) + sm_config_set_out_shift(&config, false, true, 32); +#else + sm_config_set_out_shift(&config, false, true, 24); +#endif + + int cycles_per_bit = WS2812_T1 + WS2812_T2 + WS2812_T3; + float div = clock_get_hz(clk_sys) / (800.0f * KHZ * cycles_per_bit); + sm_config_set_clkdiv(&config, div); + + pio_sm_init(pio, state_machine, offset, &config); + pio_sm_set_enabled(pio, state_machine, true); + + WS2812_DMA_CHANNEL = dmaChannelAlloc(RP_DMA_CHANNEL_ID_ANY, RP_DMA_PRIORITY_WS2812, NULL, NULL); + + // clang-format off + uint32_t mode = DMA_CTRL_TRIG_INCR_READ | + DMA_CTRL_TRIG_DATA_SIZE_WORD | + DMA_CTRL_TRIG_IRQ_QUIET | + DMA_CTRL_TRIG_TREQ_SEL(pio_idx == 0 ? state_machine : state_machine + 8); + // clang-format on + + dmaChannelSetModeX(WS2812_DMA_CHANNEL, mode); + dmaChannelSetDestinationX(WS2812_DMA_CHANNEL, (uint32_t)&pio->txf[state_machine]); + return true; +} + +/** + * @brief Convert RGBW value into WS2812 compatible 32-bit data word. + */ +__always_inline static uint32_t rgbw8888_to_u32(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) { +#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) + return ((uint32_t)green << 24) | ((uint32_t)red << 16) | ((uint32_t)blue << 8) | ((uint32_t)white); +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB) + return ((uint32_t)red << 24) | ((uint32_t)green << 16) | ((uint32_t)blue << 8) | ((uint32_t)white); +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR) + return ((uint32_t)blue << 24) | ((uint32_t)green << 16) | ((uint32_t)red << 8) | ((uint32_t)white); +#endif +} + +static inline void sync_ws2812_transfer(void) { + if (unlikely(dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine))) { + fast_timer_t start = timer_read_fast(); + do { + // Abort the synchronization if we have to wait longer than the total + // count of LEDs in millisecounds. This is safely much longer than it + // would take to push all the data out. + if (unlikely(timer_elapsed_fast(start) > RGBLED_NUM)) { + dprintln("ERROR: WS2812 DMA transfer has stalled, aborting!"); + dmaChannelDisableX(WS2812_DMA_CHANNEL); + return; + } + + } while (dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine)); + // We wait for the WS2812 chain to reset after all data has been pushed + // out. + wait_us(WS2812_TRST_US); + } +} + +void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { + static bool is_initialized = false; + if (unlikely(!is_initialized)) { + is_initialized = ws2812_init(); + } + + sync_ws2812_transfer(); + + for (int i = 0; i < leds; i++) { +#if defined(RGBW) + WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, ledarray[i].w); +#else + WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, 0); +#endif + } + + dmaChannelSetSourceX(WS2812_DMA_CHANNEL, (uint32_t)WS2812_BUFFER); + dmaChannelSetCounterX(WS2812_DMA_CHANNEL, leds); + dmaChannelEnableX(WS2812_DMA_CHANNEL); +} diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk index 86bbc22943..790c4f3316 100644 --- a/platforms/chibios/flash.mk +++ b/platforms/chibios/flash.mk @@ -108,6 +108,8 @@ else ifeq ($(strip $(BOOTLOADER)),kiibohd) $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) else ifeq ($(strip $(BOOTLOADER)),tinyuf2) $(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY) +else ifeq ($(strip $(BOOTLOADER)),rp2040) + $(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY) else ifeq ($(strip $(MCU_FAMILY)),KINETIS) $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY) else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062) diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 72428a762f..32b8c5a946 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -88,9 +88,9 @@ ifeq ("$(MCU_PORT_NAME)","") endif ifeq ("$(wildcard $(PLATFORM_MK))","") - PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk + PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk ifeq ("$(wildcard $(PLATFORM_MK))","") - PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk + PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk endif endif @@ -287,6 +287,17 @@ EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \ $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \ $(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH) +# +# QMK specific MCU family support selection. +############################################################################## +ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk)","") + # Either by MCU series e.g. STM32/STM32F1xx.mk or... + include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk +else ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk)","") + # By MCU family e.g. STM32/STM32.mk + include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk +endif + # # ChibiOS-Contrib ############################################################################## diff --git a/platforms/chibios/vendors/RP/RP2040.mk b/platforms/chibios/vendors/RP/RP2040.mk new file mode 100644 index 0000000000..1aa925cb15 --- /dev/null +++ b/platforms/chibios/vendors/RP/RP2040.mk @@ -0,0 +1,285 @@ +# +# Raspberry Pi RP2040 specific drivers +############################################################################## +COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/vendor/$(MCU_FAMILY)/$(MCU_SERIES) + +ifeq ($(strip $(WS2812_DRIVER)), vendor) + OPT_DEFS += -DRP_DMA_REQUIRED=TRUE +endif + +# +# Raspberry Pi Pico SDK Support +############################################################################## +ADEFS += -DCRT0_VTOR_INIT=1 \ + -DCRT0_EXTRA_CORES_NUMBER=0 + +CFLAGS += -DPICO_NO_FPGA_CHECK \ + -DNDEBUG + +# +# Pico SDK source and header files needed by QMK and ChibiOS +############################################################################## +PICOSDKROOT := $(TOP_DIR)/lib/pico-sdk + +PICOSDKSRC = $(PICOSDKROOT)/src/rp2_common/hardware_clocks/clocks.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_pll/pll.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_pio/pio.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_gpio/gpio.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_claim/claim.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/watchdog.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_xosc/xosc.c \ + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/bootrom.c + +PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \ + $(PICOSDKROOT)/src/common/pico_base/include \ + $(PICOSDKROOT)/src/rp2_common/pico_platform/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_base/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_clocks/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_claim/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_gpio/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_irq/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_pll/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_pio/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_sync/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_resets/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_xosc/include \ + $(PICOSDKROOT)/src/rp2040/hardware_regs/include \ + $(PICOSDKROOT)/src/rp2040/hardware_structs/include \ + $(PICOSDKROOT)/src/boards/include \ + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include + +PLATFORM_SRC += $(PICOSDKSRC) +EXTRAINCDIRS += $(PICOSDKINC) + +PLATFORM_RP2040_PATH := $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY) + +PLATFORM_SRC += $(PLATFORM_RP2040_PATH)/stage2_bootloaders.c \ + $(PLATFORM_RP2040_PATH)/pico_sdk_shims.c + +EXTRAINCDIRS += $(PLATFORM_RP2040_PATH) + +# +# RP2040 optimized compiler intrinsics +############################################################################## + +# Enables optimized Compiler intrinsics which are located in the RP2040 +# bootrom. This needs startup code and linker script support from ChibiOS, +# which is WIP. Therefore disabled by default for now. +RP2040_INTRINSICS_ENABLED ?= no +ifeq ($(strip $(RP2040_INTRINSICS_ENABLED)), yes) + PICOSDKINTRINSICSSRC = $(PICOSDKROOT)/src/rp2_common/pico_float/float_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_float/float_math.c \ + $(PICOSDKROOT)/src/rp2_common/pico_float/float_init_rom.c \ + $(PICOSDKROOT)/src/rp2_common/pico_float/float_v1_rom_shim.S \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_math.c \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_init_rom.c \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_v1_rom_shim.S \ + $(PICOSDKROOT)/src/rp2_common/pico_divider/divider.S \ + $(PICOSDKROOT)/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_malloc/pico_malloc.c \ + $(PICOSDKROOT)/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S + + PICOSDKINTRINSICSINC = $(PICOSDKROOT)/src/common/pico_base/include \ + $(PICOSDKROOT)/src/rp2_common/pico_platfrom/include \ + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_divider/include \ + $(PICOSDKROOT)/src/rp2_common/pico_float/include \ + $(PICOSDKROOT)/src/rp2_common/pico_double/include \ + $(PICOSDKROOT)/src/rp2_common/pico_malloc/include + + OPT_DEFS += -DPICO_FLOAT_SUPPORT_ROM_V1=0 -DPICO_DOUBLE_SUPPORT_ROM_V1=0 + + CFLAGS += -Wl,--defsym=__StackLimit=__heap_end__ + CFLAGS += -Wl,--defsym=__unhandled_user_irq=_unhandled_exception + CFLAGS += -Wl,--build-id=none + + # single precision floating point intrinsics + OPT_DEFS += -DPICO_FLOAT_IN_RAM=1 + OPT_DEFS += -DPICO_FLOAT_PROPAGATE_NANS=0 + + CFLAGS += -Wl,--wrap=__aeabi_fdiv + CFLAGS += -Wl,--wrap=__aeabi_fmul + CFLAGS += -Wl,--wrap=__aeabi_frsub + CFLAGS += -Wl,--wrap=__aeabi_fsub + CFLAGS += -Wl,--wrap=__aeabi_cfcmpeq + CFLAGS += -Wl,--wrap=__aeabi_cfrcmple + CFLAGS += -Wl,--wrap=__aeabi_cfcmple + CFLAGS += -Wl,--wrap=__aeabi_fcmpeq + CFLAGS += -Wl,--wrap=__aeabi_fcmplt + CFLAGS += -Wl,--wrap=__aeabi_fcmple + CFLAGS += -Wl,--wrap=__aeabi_fcmpge + CFLAGS += -Wl,--wrap=__aeabi_fcmpgt + CFLAGS += -Wl,--wrap=__aeabi_fcmpun + CFLAGS += -Wl,--wrap=__aeabi_i2f + CFLAGS += -Wl,--wrap=__aeabi_l2f + CFLAGS += -Wl,--wrap=__aeabi_ui2f + CFLAGS += -Wl,--wrap=__aeabi_ul2f + CFLAGS += -Wl,--wrap=__aeabi_i2f + CFLAGS += -Wl,--wrap=__aeabi_f2iz + CFLAGS += -Wl,--wrap=__aeabi_f2lz + CFLAGS += -Wl,--wrap=__aeabi_f2uiz + CFLAGS += -Wl,--wrap=__aeabi_f2ulz + CFLAGS += -Wl,--wrap=__aeabi_f2d + CFLAGS += -Wl,--wrap=sqrtf + CFLAGS += -Wl,--wrap=cosf + CFLAGS += -Wl,--wrap=sinf + CFLAGS += -Wl,--wrap=tanf + CFLAGS += -Wl,--wrap=atan2f + CFLAGS += -Wl,--wrap=expf + CFLAGS += -Wl,--wrap=logf + CFLAGS += -Wl,--wrap=ldexpf + CFLAGS += -Wl,--wrap=copysignf + CFLAGS += -Wl,--wrap=truncf + CFLAGS += -Wl,--wrap=floorf + CFLAGS += -Wl,--wrap=ceilf + CFLAGS += -Wl,--wrap=roundf + CFLAGS += -Wl,--wrap=sincosf + CFLAGS += -Wl,--wrap=asinf + CFLAGS += -Wl,--wrap=acosf + CFLAGS += -Wl,--wrap=atanf + CFLAGS += -Wl,--wrap=sinhf + CFLAGS += -Wl,--wrap=coshf + CFLAGS += -Wl,--wrap=tanhf + CFLAGS += -Wl,--wrap=asinhf + CFLAGS += -Wl,--wrap=acoshf + CFLAGS += -Wl,--wrap=atanhf + CFLAGS += -Wl,--wrap=exp2f + CFLAGS += -Wl,--wrap=log2f + CFLAGS += -Wl,--wrap=exp10f + CFLAGS += -Wl,--wrap=log10f + CFLAGS += -Wl,--wrap=powf + CFLAGS += -Wl,--wrap=powintf + CFLAGS += -Wl,--wrap=hypotf + CFLAGS += -Wl,--wrap=cbrtf + CFLAGS += -Wl,--wrap=fmodf + CFLAGS += -Wl,--wrap=dremf + CFLAGS += -Wl,--wrap=remainderf + CFLAGS += -Wl,--wrap=remquof + CFLAGS += -Wl,--wrap=expm1f + CFLAGS += -Wl,--wrap=log1pf + CFLAGS += -Wl,--wrap=fmaf + + # double precision floating point intrinsics + OPT_DEFS += -DPICO_DOUBLE_IN_RAM=1 + OPT_DEFS += -DPICO_DOUBLE_PROPAGATE_NANS=0 + + CFLAGS += -Wl,--wrap=__aeabi_dadd + CFLAGS += -Wl,--wrap=__aeabi_ddiv + CFLAGS += -Wl,--wrap=__aeabi_dmul + CFLAGS += -Wl,--wrap=__aeabi_drsub + CFLAGS += -Wl,--wrap=__aeabi_dsub + CFLAGS += -Wl,--wrap=__aeabi_cdcmpeq + CFLAGS += -Wl,--wrap=__aeabi_cdrcmple + CFLAGS += -Wl,--wrap=__aeabi_cdcmple + CFLAGS += -Wl,--wrap=__aeabi_dcmpeq + CFLAGS += -Wl,--wrap=__aeabi_dcmplt + CFLAGS += -Wl,--wrap=__aeabi_dcmple + CFLAGS += -Wl,--wrap=__aeabi_dcmpge + CFLAGS += -Wl,--wrap=__aeabi_dcmpgt + CFLAGS += -Wl,--wrap=__aeabi_dcmpun + CFLAGS += -Wl,--wrap=__aeabi_i2d + CFLAGS += -Wl,--wrap=__aeabi_l2d + CFLAGS += -Wl,--wrap=__aeabi_ui2d + CFLAGS += -Wl,--wrap=__aeabi_ul2d + CFLAGS += -Wl,--wrap=__aeabi_d2iz + CFLAGS += -Wl,--wrap=__aeabi_d2lz + CFLAGS += -Wl,--wrap=__aeabi_d2uiz + CFLAGS += -Wl,--wrap=__aeabi_d2ulz + CFLAGS += -Wl,--wrap=__aeabi_d2f + CFLAGS += -Wl,--wrap=sqrt + CFLAGS += -Wl,--wrap=cos + CFLAGS += -Wl,--wrap=sin + CFLAGS += -Wl,--wrap=tan + CFLAGS += -Wl,--wrap=atan2 + CFLAGS += -Wl,--wrap=exp + CFLAGS += -Wl,--wrap=log + CFLAGS += -Wl,--wrap=ldexp + CFLAGS += -Wl,--wrap=copysign + CFLAGS += -Wl,--wrap=trunc + CFLAGS += -Wl,--wrap=floor + CFLAGS += -Wl,--wrap=ceil + CFLAGS += -Wl,--wrap=round + CFLAGS += -Wl,--wrap=sincos + CFLAGS += -Wl,--wrap=asin + CFLAGS += -Wl,--wrap=acos + CFLAGS += -Wl,--wrap=atan + CFLAGS += -Wl,--wrap=sinh + CFLAGS += -Wl,--wrap=cosh + CFLAGS += -Wl,--wrap=tanh + CFLAGS += -Wl,--wrap=asinh + CFLAGS += -Wl,--wrap=acosh + CFLAGS += -Wl,--wrap=atanh + CFLAGS += -Wl,--wrap=exp2 + CFLAGS += -Wl,--wrap=log2 + CFLAGS += -Wl,--wrap=exp10 + CFLAGS += -Wl,--wrap=log10 + CFLAGS += -Wl,--wrap=pow + CFLAGS += -Wl,--wrap=powint + CFLAGS += -Wl,--wrap=hypot + CFLAGS += -Wl,--wrap=cbrt + CFLAGS += -Wl,--wrap=fmod + CFLAGS += -Wl,--wrap=drem + CFLAGS += -Wl,--wrap=remainder + CFLAGS += -Wl,--wrap=remquo + CFLAGS += -Wl,--wrap=expm1 + CFLAGS += -Wl,--wrap=log1p + CFLAGS += -Wl,--wrap=fma + + # bit operation intrinsics + OPT_DEFS += -DPICO_BITS_IN_RAM=1 + + CFLAGS += -Wl,--wrap=__clzsi2 + CFLAGS += -Wl,--wrap=__clzsi2 + CFLAGS += -Wl,--wrap=__clzdi2 + CFLAGS += -Wl,--wrap=__ctzsi2 + CFLAGS += -Wl,--wrap=__ctzdi2 + CFLAGS += -Wl,--wrap=__popcountsi2 + CFLAGS += -Wl,--wrap=__popcountdi2 + CFLAGS += -Wl,--wrap=__clz + CFLAGS += -Wl,--wrap=__clzl + CFLAGS += -Wl,--wrap=__clzsi2 + CFLAGS += -Wl,--wrap=__clzll + + # integer division intrinsics + OPT_DEFS += -DPICO_DIVIDER_IN_RAM=1 + OPT_DEFS += -DPICO_DIVIDER_DISABLE_INTERRUPTS=1 + + CFLAGS += -Wl,--wrap=__aeabi_idiv + CFLAGS += -Wl,--wrap=__aeabi_idivmod + CFLAGS += -Wl,--wrap=__aeabi_ldivmod + CFLAGS += -Wl,--wrap=__aeabi_uidiv + CFLAGS += -Wl,--wrap=__aeabi_uidivmod + CFLAGS += -Wl,--wrap=__aeabi_uldivmod + + # 64bit integer intrinsics + OPT_DEFS += -DPICO_INT64_OPS_IN_RAM=1 + + CFLAGS += -Wl,--wrap=__aeabi_lmul + + # malloc and friends functions + OPT_DEFS += -DPICO_USE_MALLOC_MUTEX=0 + OPT_DEFS += -DPICO_DEBUG_MALLOC=0 + OPT_DEFS ?= -DPICO_MALLOC_PANIC=0 + + CFLAGS += -Wl,--wrap=malloc + CFLAGS += -Wl,--wrap=calloc + CFLAGS += -Wl,--wrap=free + + # memory operation intrinsics + OPT_DEFS += -DPICO_MEM_IN_RAM=1 + + CFLAGS += -Wl,--wrap=memcpy + CFLAGS += -Wl,--wrap=memset + CFLAGS += -Wl,--wrap=__aeabi_memcpy + CFLAGS += -Wl,--wrap=__aeabi_memset + CFLAGS += -Wl,--wrap=__aeabi_memcpy4 + CFLAGS += -Wl,--wrap=__aeabi_memset4 + CFLAGS += -Wl,--wrap=__aeabi_memcpy8 + CFLAGS += -Wl,--wrap=__aeabi_memset8 + + PLATFORM_SRC += $(PICOSDKINTRINSICSSRC) + EXTRAINCDIRS += $(PICOSDKINTRINSICSINC) +endif diff --git a/platforms/chibios/vendors/RP/_pin_defs.h b/platforms/chibios/vendors/RP/_pin_defs.h new file mode 100644 index 0000000000..4241845369 --- /dev/null +++ b/platforms/chibios/vendors/RP/_pin_defs.h @@ -0,0 +1,37 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +/* RP2040 GPIO Numbering */ +#define GP0 0U +#define GP1 1U +#define GP2 2U +#define GP3 3U +#define GP4 4U +#define GP5 5U +#define GP6 6U +#define GP7 7U +#define GP8 8U +#define GP9 9U +#define GP10 10U +#define GP11 11U +#define GP12 12U +#define GP13 13U +#define GP14 14U +#define GP15 15U +#define GP16 16U +#define GP17 17U +#define GP18 18U +#define GP19 19U +#define GP20 20U +#define GP21 21U +#define GP22 22U +#define GP23 23U +#define GP24 24U +#define GP25 25U +#define GP26 26U +#define GP27 27U +#define GP28 28U +#define GP29 29U +#define GP30 30U diff --git a/platforms/chibios/vendors/RP/pico_sdk_shims.c b/platforms/chibios/vendors/RP/pico_sdk_shims.c new file mode 100644 index 0000000000..f6e3943928 --- /dev/null +++ b/platforms/chibios/vendors/RP/pico_sdk_shims.c @@ -0,0 +1,9 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include + +void panic(const char *fmt, ...) { + chSysHalt(fmt); +} diff --git a/platforms/chibios/vendors/RP/stage2_bootloaders.c b/platforms/chibios/vendors/RP/stage2_bootloaders.c new file mode 100644 index 0000000000..f22112fca9 --- /dev/null +++ b/platforms/chibios/vendors/RP/stage2_bootloaders.c @@ -0,0 +1,174 @@ +// ---------------------------------------------------------------------------- +// Pre-compiled second stage boot code for RP2040. +// +// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd. +// SPDX-License-Identifier: BSD-3-Clause +// ---------------------------------------------------------------------------- + +#include + +#define BOOTLOADER_SECTION __attribute__ ((used, section (".boot2"))) + +#if defined(RP2040_FLASH_AT25SF128A) + +uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = { + 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, + 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, + 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, + 0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20, + 0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, + 0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66, + 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, + 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, + 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, + 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, + 0x19, 0x66, 0x20, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, + 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, + 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49, + 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, + 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, + 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, + 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00, + 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0x20, + 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xdd, 0xc0, 0xb5 +}; + +#elif defined(RP2040_FLASH_GD25Q64CS) + +uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = { + 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, + 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, + 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, + 0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20, + 0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, + 0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66, + 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, + 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, + 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, + 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xe7, 0x21, + 0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, + 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, + 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49, + 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, + 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, + 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, + 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00, + 0x21, 0x12, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x10, 0x00, 0xa0, + 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe2, 0xd9, 0xa2, 0xb5 +}; + +#elif defined(RP2040_FLASH_W25X10CL) + +uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = { + 0x00, 0xb5, 0x14, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, + 0x12, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x11, 0x49, 0x12, 0x48, + 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xbb, 0x21, 0x19, 0x66, 0x02, 0x21, + 0x19, 0x66, 0x08, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd0, 0x00, 0x21, + 0x99, 0x60, 0x0c, 0x49, 0x0a, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, + 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x08, 0x48, 0x09, 0x49, + 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x3f, 0x00, 0x1d, 0x12, 0x00, 0x00, + 0xf4, 0x00, 0x00, 0x18, 0x1e, 0x10, 0x00, 0x20, 0x00, 0x01, 0x00, 0x10, + 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x81, 0x53, 0x9a +}; + +#elif defined(RP2040_FLASH_IS25LP080) + +uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = { + 0x00, 0xb5, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, + 0x29, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x28, 0x48, 0x00, 0xf0, + 0x42, 0xf8, 0x28, 0x4a, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, 0x19, 0x66, + 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20, + 0x1a, 0x66, 0x00, 0xf0, 0x2b, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x1f, 0x48, + 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, + 0x99, 0x60, 0x1d, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x1c, 0x49, + 0x1c, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, + 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, + 0x17, 0x49, 0x16, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, + 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x14, 0x48, 0x14, 0x49, 0x08, 0x60, + 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, + 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, + 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, + 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, + 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x33, 0x43, 0xb2 +}; + +#elif defined(RP2040_FLASH_GENERIC_03H) + +uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = { + 0x00, 0xb5, 0x0c, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, + 0x0a, 0x49, 0x19, 0x60, 0x0a, 0x49, 0x0b, 0x48, 0x01, 0x60, 0x00, 0x21, + 0x59, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, + 0x00, 0x47, 0x07, 0x48, 0x07, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, + 0x08, 0x88, 0x08, 0x47, 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x1f, 0x00, + 0x18, 0x02, 0x00, 0x03, 0xf4, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x10, + 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0xec, 0x21, 0x0d +}; + +#else + +uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = { + 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, + 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, + 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, + 0x99, 0x50, 0x2b, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20, + 0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21, + 0x19, 0x66, 0x00, 0xf0, 0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, + 0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, + 0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, + 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, + 0x00, 0x21, 0x59, 0x60, 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, + 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, + 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, + 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, + 0x12, 0x48, 0x13, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, + 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, + 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, + 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, + 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, + 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x0b, 0x8f, 0xd5 +}; + +#endif diff --git a/quantum/keymap.h b/quantum/keymap.h index 081bc54ebe..edff484129 100644 --- a/quantum/keymap.h +++ b/quantum/keymap.h @@ -46,6 +46,11 @@ along with this program. If not, see . #include "quantum_keycodes.h" +// Gross hack, remove me and change RESET keycode to QK_BOOT +#if defined(MCU_RP) +# undef RESET +#endif + // translates key to keycode uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index 19e2e858fc..4bb6949b4f 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c @@ -32,6 +32,7 @@ #include "usb_main.h" #include "host.h" +#include "chibios_config.h" #include "debug.h" #include "suspend.h" #ifdef SLEEP_LED_ENABLE @@ -91,6 +92,13 @@ uint8_t extra_report_blank[3] = {0}; * --------------------------------------------------------- */ +/* USB Low Level driver specific endpoint fields */ +#if !defined(usb_lld_endpoint_fields) +# define usb_lld_endpoint_fields \ + 2, /* IN multiplier */ \ + NULL, /* SETUP buffer (not a SETUP endpoint) */ +#endif + /* HID specific constants */ #define HID_GET_REPORT 0x01 #define HID_GET_IDLE 0x02 @@ -121,16 +129,15 @@ static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype static USBInEndpointState kbd_ep_state; /* keyboard endpoint initialization structure (IN) - see USBEndpointConfig comment at top of file */ static const USBEndpointConfig kbd_ep_config = { - USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ - NULL, /* SETUP packet notification callback */ - kbd_in_cb, /* IN notification callback */ - NULL, /* OUT notification callback */ - KEYBOARD_EPSIZE, /* IN maximum packet size */ - 0, /* OUT maximum packet size */ - &kbd_ep_state, /* IN Endpoint state */ - NULL, /* OUT endpoint state */ - 2, /* IN multiplier */ - NULL /* SETUP buffer (not a SETUP endpoint) */ + USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ + NULL, /* SETUP packet notification callback */ + kbd_in_cb, /* IN notification callback */ + NULL, /* OUT notification callback */ + KEYBOARD_EPSIZE, /* IN maximum packet size */ + 0, /* OUT maximum packet size */ + &kbd_ep_state, /* IN Endpoint state */ + NULL, /* OUT endpoint state */ + usb_lld_endpoint_fields /* USB driver specific endpoint fields */ }; #endif @@ -140,16 +147,15 @@ static USBInEndpointState mouse_ep_state; /* mouse endpoint initialization structure (IN) - see USBEndpointConfig comment at top of file */ static const USBEndpointConfig mouse_ep_config = { - USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ - NULL, /* SETUP packet notification callback */ - mouse_in_cb, /* IN notification callback */ - NULL, /* OUT notification callback */ - MOUSE_EPSIZE, /* IN maximum packet size */ - 0, /* OUT maximum packet size */ - &mouse_ep_state, /* IN Endpoint state */ - NULL, /* OUT endpoint state */ - 2, /* IN multiplier */ - NULL /* SETUP buffer (not a SETUP endpoint) */ + USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ + NULL, /* SETUP packet notification callback */ + mouse_in_cb, /* IN notification callback */ + NULL, /* OUT notification callback */ + MOUSE_EPSIZE, /* IN maximum packet size */ + 0, /* OUT maximum packet size */ + &mouse_ep_state, /* IN Endpoint state */ + NULL, /* OUT endpoint state */ + usb_lld_endpoint_fields /* USB driver specific endpoint fields */ }; #endif @@ -159,16 +165,15 @@ static USBInEndpointState shared_ep_state; /* shared endpoint initialization structure (IN) - see USBEndpointConfig comment at top of file */ static const USBEndpointConfig shared_ep_config = { - USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ - NULL, /* SETUP packet notification callback */ - shared_in_cb, /* IN notification callback */ - NULL, /* OUT notification callback */ - SHARED_EPSIZE, /* IN maximum packet size */ - 0, /* OUT maximum packet size */ - &shared_ep_state, /* IN Endpoint state */ - NULL, /* OUT endpoint state */ - 2, /* IN multiplier */ - NULL /* SETUP buffer (not a SETUP endpoint) */ + USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ + NULL, /* SETUP packet notification callback */ + shared_in_cb, /* IN notification callback */ + NULL, /* OUT notification callback */ + SHARED_EPSIZE, /* IN maximum packet size */ + 0, /* OUT maximum packet size */ + &shared_ep_state, /* IN Endpoint state */ + NULL, /* OUT endpoint state */ + usb_lld_endpoint_fields /* USB driver specific endpoint fields */ }; #endif @@ -251,29 +256,27 @@ typedef struct { .queue_capacity_in = stream##_IN_CAPACITY, .queue_capacity_out = stream##_OUT_CAPACITY, \ .in_ep_config = \ { \ - stream##_IN_MODE, /* Interrupt EP */ \ - NULL, /* SETUP packet notification callback */ \ - qmkusbDataTransmitted, /* IN notification callback */ \ - NULL, /* OUT notification callback */ \ - stream##_EPSIZE, /* IN maximum packet size */ \ - 0, /* OUT maximum packet size */ \ - NULL, /* IN Endpoint state */ \ - NULL, /* OUT endpoint state */ \ - 2, /* IN multiplier */ \ - NULL /* SETUP buffer (not a SETUP endpoint) */ \ + stream##_IN_MODE, /* Interrupt EP */ \ + NULL, /* SETUP packet notification callback */ \ + qmkusbDataTransmitted, /* IN notification callback */ \ + NULL, /* OUT notification callback */ \ + stream##_EPSIZE, /* IN maximum packet size */ \ + 0, /* OUT maximum packet size */ \ + NULL, /* IN Endpoint state */ \ + NULL, /* OUT endpoint state */ \ + usb_lld_endpoint_fields /* USB driver specific endpoint fields */ \ }, \ .out_ep_config = \ { \ - stream##_OUT_MODE, /* Interrupt EP */ \ - NULL, /* SETUP packet notification callback */ \ - NULL, /* IN notification callback */ \ - qmkusbDataReceived, /* OUT notification callback */ \ - 0, /* IN maximum packet size */ \ - stream##_EPSIZE, /* OUT maximum packet size */ \ - NULL, /* IN Endpoint state */ \ - NULL, /* OUT endpoint state */ \ - 2, /* IN multiplier */ \ - NULL, /* SETUP buffer (not a SETUP endpoint) */ \ + stream##_OUT_MODE, /* Interrupt EP */ \ + NULL, /* SETUP packet notification callback */ \ + NULL, /* IN notification callback */ \ + qmkusbDataReceived, /* OUT notification callback */ \ + 0, /* IN maximum packet size */ \ + stream##_EPSIZE, /* OUT maximum packet size */ \ + NULL, /* IN Endpoint state */ \ + NULL, /* OUT endpoint state */ \ + usb_lld_endpoint_fields /* USB driver specific endpoint fields */ \ }, \ .int_ep_config = \ { \ @@ -285,8 +288,7 @@ typedef struct { 0, /* OUT maximum packet size */ \ NULL, /* IN Endpoint state */ \ NULL, /* OUT endpoint state */ \ - 2, /* IN multiplier */ \ - NULL, /* SETUP buffer (not a SETUP endpoint) */ \ + usb_lld_endpoint_fields /* USB driver specific endpoint fields */ \ }, \ .config = { \ .usbp = &USB_DRIVER, \ -- cgit v1.2.3 From b67ae67687b00ffb11ef9c4652e7f7f77b0c7b6d Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Sat, 2 Jul 2022 13:20:45 +1000 Subject: [QP] Add ILI9488 support. (#17438) --- docs/quantum_painter.md | 25 ++++++ drivers/painter/gc9a01/qp_gc9a01.c | 9 +- drivers/painter/ili9xxx/qp_ili9163.c | 9 +- drivers/painter/ili9xxx/qp_ili9341.c | 9 +- drivers/painter/ili9xxx/qp_ili9488.c | 120 +++++++++++++++++++++++++++ drivers/painter/ili9xxx/qp_ili9488.h | 37 +++++++++ drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h | 1 + drivers/painter/ssd1351/qp_ssd1351.c | 4 +- drivers/painter/st77xx/qp_st7789.c | 9 +- drivers/painter/tft_panel/qp_tft_panel.c | 60 +++++++------- drivers/painter/tft_panel/qp_tft_panel.h | 16 ++-- quantum/painter/qp.h | 4 + quantum/painter/rules.mk | 13 ++- 13 files changed, 252 insertions(+), 64 deletions(-) create mode 100644 drivers/painter/ili9xxx/qp_ili9488.c create mode 100644 drivers/painter/ili9xxx/qp_ili9488.h (limited to 'quantum') diff --git a/docs/quantum_painter.md b/docs/quantum_painter.md index a3705b62ce..2386a70933 100644 --- a/docs/quantum_painter.md +++ b/docs/quantum_painter.md @@ -24,6 +24,7 @@ Hardware supported: | GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = gc9a01_spi` | | ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9163_spi` | | ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9341_spi` | +| ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9488_spi` | | SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ssd1351_spi` | | ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = st7789_spi` | @@ -654,6 +655,30 @@ The maximum number of displays can be configured by changing the following in yo #define ILI9341_NUM_DEVICES 3 ``` +### ILI9488 :id=qp-driver-ili9488 + +Enabling support for the ILI9488 in Quantum Painter is done by adding the following to `rules.mk`: + +```make +QUANTUM_PAINTER_ENABLE = yes +QUANTUM_PAINTER_DRIVERS = ili9488_spi +``` + +Creating a ILI9488 device in firmware can then be done with the following API: + +```c +painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); +``` + +The device handle returned from the `qp_ili9488_make_spi_device` function can be used to perform all other drawing operations. + +The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): + +```c +// 3 displays: +#define ILI9488_NUM_DEVICES 3 +``` + ### SSD1351 :id=qp-driver-ssd1351 Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`: diff --git a/drivers/painter/gc9a01/qp_gc9a01.c b/drivers/painter/gc9a01/qp_gc9a01.c index ad76d58b07..37700a28a4 100644 --- a/drivers/painter/gc9a01/qp_gc9a01.c +++ b/drivers/painter/gc9a01/qp_gc9a01.c @@ -102,12 +102,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t gc9a01_driver_vtable = { .flush = qp_tft_panel_flush, .pixdata = qp_tft_panel_pixdata, .viewport = qp_tft_panel_viewport, - .palette_convert = qp_tft_panel_palette_convert, - .append_pixels = qp_tft_panel_append_pixels, + .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, + .append_pixels = qp_tft_panel_append_pixels_rgb565, }, - .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, - .num_window_bytes = 2, - .swap_window_coords = false, + .num_window_bytes = 2, + .swap_window_coords = false, .opcodes = { .display_on = GC9A01_CMD_DISPLAY_ON, diff --git a/drivers/painter/ili9xxx/qp_ili9163.c b/drivers/painter/ili9xxx/qp_ili9163.c index beaac0fbb5..14363c7d04 100644 --- a/drivers/painter/ili9xxx/qp_ili9163.c +++ b/drivers/painter/ili9xxx/qp_ili9163.c @@ -67,12 +67,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9163_driver_vtable = .flush = qp_tft_panel_flush, .pixdata = qp_tft_panel_pixdata, .viewport = qp_tft_panel_viewport, - .palette_convert = qp_tft_panel_palette_convert, - .append_pixels = qp_tft_panel_append_pixels, + .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, + .append_pixels = qp_tft_panel_append_pixels_rgb565, }, - .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, - .num_window_bytes = 2, - .swap_window_coords = false, + .num_window_bytes = 2, + .swap_window_coords = false, .opcodes = { .display_on = ILI9XXX_CMD_DISPLAY_ON, diff --git a/drivers/painter/ili9xxx/qp_ili9341.c b/drivers/painter/ili9xxx/qp_ili9341.c index 1f41dcfc0b..9608f109bd 100644 --- a/drivers/painter/ili9xxx/qp_ili9341.c +++ b/drivers/painter/ili9xxx/qp_ili9341.c @@ -74,12 +74,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9341_driver_vtable = .flush = qp_tft_panel_flush, .pixdata = qp_tft_panel_pixdata, .viewport = qp_tft_panel_viewport, - .palette_convert = qp_tft_panel_palette_convert, - .append_pixels = qp_tft_panel_append_pixels, + .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, + .append_pixels = qp_tft_panel_append_pixels_rgb565, }, - .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, - .num_window_bytes = 2, - .swap_window_coords = false, + .num_window_bytes = 2, + .swap_window_coords = false, .opcodes = { .display_on = ILI9XXX_CMD_DISPLAY_ON, diff --git a/drivers/painter/ili9xxx/qp_ili9488.c b/drivers/painter/ili9xxx/qp_ili9488.c new file mode 100644 index 0000000000..55cf9f896f --- /dev/null +++ b/drivers/painter/ili9xxx/qp_ili9488.c @@ -0,0 +1,120 @@ +// Copyright 2021 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qp_internal.h" +#include "qp_comms.h" +#include "qp_ili9488.h" +#include "qp_ili9xxx_opcodes.h" +#include "qp_tft_panel.h" + +#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE +# include +#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common + +// Driver storage +tft_panel_dc_reset_painter_device_t ili9488_drivers[ILI9488_NUM_DEVICES] = {0}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Initialization + +bool qp_ili9488_init(painter_device_t device, painter_rotation_t rotation) { + // clang-format off + const uint8_t ili9488_init_sequence[] = { + // Command, Delay, N, Data[N] + ILI9XXX_CMD_RESET, 120, 0, + ILI9XXX_SET_PGAMMA, 0, 15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F, + ILI9XXX_SET_NGAMMA, 0, 15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F, + ILI9XXX_SET_POWER_CTL_1, 0, 2, 0x17, 0x15, + ILI9XXX_SET_POWER_CTL_2, 0, 1, 0x41, + ILI9XXX_SET_VCOM_CTL_1, 0, 3, 0x00, 0x12, 0x80, + ILI9XXX_SET_PIX_FMT, 0, 1, 0x66, + ILI9XXX_SET_RGB_IF_SIG_CTL, 0, 1, 0x80, + ILI9XXX_SET_FRAME_CTL_NORMAL, 0, 1, 0xA0, + ILI9XXX_SET_INVERSION_CTL, 0, 1, 0x02, + ILI9XXX_SET_FUNCTION_CTL, 0, 2, 0x02, 0x02, + ILI9XXX_SET_IMAGE_FUNCTION, 0, 1, 0x00, + ILI9XXX_SET_PUMP_RATIO_CTL, 0, 4, 0xA9, 0x51, 0x2C, 0x82, + ILI9XXX_CMD_SLEEP_OFF, 5, 0, + ILI9XXX_CMD_DISPLAY_ON, 20, 0 + }; + // clang-format on + qp_comms_bulk_command_sequence(device, ili9488_init_sequence, sizeof(ili9488_init_sequence)); + + // Configure the rotation (i.e. the ordering and direction of memory writes in GRAM) + const uint8_t madctl[] = { + [QP_ROTATION_0] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MY, + [QP_ROTATION_90] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MX | ILI9XXX_MADCTL_MV | ILI9XXX_MADCTL_MY, + [QP_ROTATION_180] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MX, + [QP_ROTATION_270] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MV, + }; + qp_comms_command_databyte(device, ILI9XXX_SET_MEM_ACS_CTL, madctl[rotation]); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Driver vtable + +const struct tft_panel_dc_reset_painter_driver_vtable_t ili9488_driver_vtable = { + .base = + { + .init = qp_ili9488_init, + .power = qp_tft_panel_power, + .clear = qp_tft_panel_clear, + .flush = qp_tft_panel_flush, + .pixdata = qp_tft_panel_pixdata, + .viewport = qp_tft_panel_viewport, + .palette_convert = qp_tft_panel_palette_convert_rgb888, + .append_pixels = qp_tft_panel_append_pixels_rgb888, + }, + .num_window_bytes = 2, + .swap_window_coords = false, + .opcodes = + { + .display_on = ILI9XXX_CMD_DISPLAY_ON, + .display_off = ILI9XXX_CMD_DISPLAY_OFF, + .set_column_address = ILI9XXX_SET_COL_ADDR, + .set_row_address = ILI9XXX_SET_PAGE_ADDR, + .enable_writes = ILI9XXX_SET_MEM, + }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SPI + +#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE + +// Factory function for creating a handle to the ILI9488 device +painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode) { + for (uint32_t i = 0; i < ILI9488_NUM_DEVICES; ++i) { + tft_panel_dc_reset_painter_device_t *driver = &ili9488_drivers[i]; + if (!driver->base.driver_vtable) { + driver->base.driver_vtable = (const struct painter_driver_vtable_t *)&ili9488_driver_vtable; + driver->base.comms_vtable = (const struct painter_comms_vtable_t *)&spi_comms_with_dc_vtable; + driver->base.native_bits_per_pixel = 24; // RGB888 + driver->base.panel_width = panel_width; + driver->base.panel_height = panel_height; + driver->base.rotation = QP_ROTATION_0; + driver->base.offset_x = 0; + driver->base.offset_y = 0; + + // SPI and other pin configuration + driver->base.comms_config = &driver->spi_dc_reset_config; + driver->spi_dc_reset_config.spi_config.chip_select_pin = chip_select_pin; + driver->spi_dc_reset_config.spi_config.divisor = spi_divisor; + driver->spi_dc_reset_config.spi_config.lsb_first = false; + driver->spi_dc_reset_config.spi_config.mode = spi_mode; + driver->spi_dc_reset_config.dc_pin = dc_pin; + driver->spi_dc_reset_config.reset_pin = reset_pin; + return (painter_device_t)driver; + } + } + return NULL; +} + +#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/drivers/painter/ili9xxx/qp_ili9488.h b/drivers/painter/ili9xxx/qp_ili9488.h new file mode 100644 index 0000000000..21b8f03322 --- /dev/null +++ b/drivers/painter/ili9xxx/qp_ili9488.h @@ -0,0 +1,37 @@ +// Copyright 2021 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "gpio.h" +#include "qp_internal.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter ILI9488 configurables (add to your keyboard's config.h) + +#ifndef ILI9488_NUM_DEVICES +/** + * @def This controls the maximum number of ILI9488 devices that Quantum Painter can communicate with at any one time. + * Increasing this number allows for multiple displays to be used. + */ +# define ILI9488_NUM_DEVICES 1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter ILI9488 device factories + +#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE +/** + * Factory method for an ILI9488 SPI LCD device. + * + * @param panel_width[in] the width of the display panel + * @param panel_height[in] the height of the display panel + * @param chip_select_pin[in] the GPIO pin used for SPI chip select + * @param dc_pin[in] the GPIO pin used for D/C control + * @param reset_pin[in] the GPIO pin used for RST + * @param spi_divisor[in] the SPI divisor to use when communicating with the display + * @param spi_mode[in] the SPI mode to use when communicating with the display + * @return the device handle used with all drawing routines in Quantum Painter + */ +painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); +#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE diff --git a/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h b/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h index 1fa395cb89..47bb703648 100644 --- a/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h +++ b/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h @@ -85,6 +85,7 @@ #define ILI9XXX_SET_NGAMMA 0xE1 // Set negative gamma #define ILI9XXX_SET_DGAMMA_CTL_1 0xE2 // Set digital gamma ctl 1 #define ILI9XXX_SET_DGAMMA_CTL_2 0xE3 // Set digital gamma ctl 2 +#define ILI9XXX_SET_IMAGE_FUNCTION 0xE9 // Set image function #define ILI9XXX_ENABLE_3_GAMMA 0xF2 // Enable 3 gamma #define ILI9XXX_SET_IF_CTL 0xF6 // Set interface control #define ILI9XXX_SET_PUMP_RATIO_CTL 0xF7 // Set pump ratio control diff --git a/drivers/painter/ssd1351/qp_ssd1351.c b/drivers/painter/ssd1351/qp_ssd1351.c index 970e7e67f3..67854133aa 100644 --- a/drivers/painter/ssd1351/qp_ssd1351.c +++ b/drivers/painter/ssd1351/qp_ssd1351.c @@ -71,8 +71,8 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ssd1351_driver_vtable = .flush = qp_tft_panel_flush, .pixdata = qp_tft_panel_pixdata, .viewport = qp_tft_panel_viewport, - .palette_convert = qp_tft_panel_palette_convert, - .append_pixels = qp_tft_panel_append_pixels, + .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, + .append_pixels = qp_tft_panel_append_pixels_rgb565, }, .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, .num_window_bytes = 1, diff --git a/drivers/painter/st77xx/qp_st7789.c b/drivers/painter/st77xx/qp_st7789.c index d005ece050..49e8436c29 100644 --- a/drivers/painter/st77xx/qp_st7789.c +++ b/drivers/painter/st77xx/qp_st7789.c @@ -90,12 +90,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t st7789_driver_vtable = { .flush = qp_tft_panel_flush, .pixdata = qp_tft_panel_pixdata, .viewport = qp_tft_panel_viewport, - .palette_convert = qp_tft_panel_palette_convert, - .append_pixels = qp_tft_panel_append_pixels, + .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, + .append_pixels = qp_tft_panel_append_pixels_rgb565, }, - .rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped, - .num_window_bytes = 2, - .swap_window_coords = false, + .num_window_bytes = 2, + .swap_window_coords = false, .opcodes = { .display_on = ST77XX_CMD_DISPLAY_ON, diff --git a/drivers/painter/tft_panel/qp_tft_panel.c b/drivers/painter/tft_panel/qp_tft_panel.c index 4d636c9509..ad83b6c792 100644 --- a/drivers/painter/tft_panel/qp_tft_panel.c +++ b/drivers/painter/tft_panel/qp_tft_panel.c @@ -9,29 +9,6 @@ #define BYTE_SWAP(x) (((((uint16_t)(x)) >> 8) & 0x00FF) | ((((uint16_t)(x)) << 8) & 0xFF00)) -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Native pixel format conversion - -uint16_t qp_rgb888_to_rgb565(uint8_t r, uint8_t g, uint8_t b) { - uint16_t rgb565 = (((uint16_t)r) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)b) >> 3); - return rgb565; -} - -uint16_t qp_rgb888_to_rgb565_swapped(uint8_t r, uint8_t g, uint8_t b) { - uint16_t rgb565 = (((uint16_t)r) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)b) >> 3); - return BYTE_SWAP(rgb565); -} - -uint16_t qp_rgb888_to_bgr565(uint8_t r, uint8_t g, uint8_t b) { - uint16_t bgr565 = (((uint16_t)b) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)r) >> 3); - return bgr565; -} - -uint16_t qp_rgb888_to_bgr565_swapped(uint8_t r, uint8_t g, uint8_t b) { - uint16_t bgr565 = (((uint16_t)b) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)r) >> 3); - return BYTE_SWAP(bgr565); -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Quantum Painter API implementations @@ -105,26 +82,49 @@ bool qp_tft_panel_viewport(painter_device_t device, uint16_t left, uint16_t top, // Stream pixel data to the current write position in GRAM bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) { - qp_comms_send(device, pixel_data, native_pixel_count * sizeof(uint16_t)); + struct painter_driver_t *driver = (struct painter_driver_t *)device; + qp_comms_send(device, pixel_data, native_pixel_count * driver->native_bits_per_pixel / 8); return true; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Convert supplied palette entries into their native equivalents -bool qp_tft_panel_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { - struct painter_driver_t * driver = (struct painter_driver_t *)device; - struct tft_panel_dc_reset_painter_driver_vtable_t *vtable = (struct tft_panel_dc_reset_painter_driver_vtable_t *)driver->driver_vtable; + +bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { for (int16_t i = 0; i < palette_size; ++i) { - RGB rgb = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v}); - palette[i].rgb565 = vtable->rgb888_to_native16bit(rgb.r, rgb.g, rgb.b); + RGB rgb = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v}); + uint16_t rgb565 = (((uint16_t)rgb.r) >> 3) << 11 | (((uint16_t)rgb.g) >> 2) << 5 | (((uint16_t)rgb.b) >> 3); + palette[i].rgb565 = BYTE_SWAP(rgb565); } return true; } +bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { + for (int16_t i = 0; i < palette_size; ++i) { + RGB rgb = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v}); + palette[i].rgb888.r = rgb.r; + palette[i].rgb888.g = rgb.g; + palette[i].rgb888.b = rgb.b; + } + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Append pixels to the target location, keyed by the pixel index -bool qp_tft_panel_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { + +bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { uint16_t *buf = (uint16_t *)target_buffer; for (uint32_t i = 0; i < pixel_count; ++i) { buf[pixel_offset + i] = palette[palette_indices[i]].rgb565; } return true; } + +bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { + for (uint32_t i = 0; i < pixel_count; ++i) { + target_buffer[(pixel_offset + i) * 3 + 0] = palette[palette_indices[i]].rgb888.r; + target_buffer[(pixel_offset + i) * 3 + 1] = palette[palette_indices[i]].rgb888.g; + target_buffer[(pixel_offset + i) * 3 + 2] = palette[palette_indices[i]].rgb888.b; + } + return true; +} diff --git a/drivers/painter/tft_panel/qp_tft_panel.h b/drivers/painter/tft_panel/qp_tft_panel.h index 6eddfc503d..3cb015891b 100644 --- a/drivers/painter/tft_panel/qp_tft_panel.h +++ b/drivers/painter/tft_panel/qp_tft_panel.h @@ -11,15 +11,10 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Common TFT panel implementation using D/C, and RST pins. -typedef uint16_t (*rgb888_to_native_uint16_t)(uint8_t r, uint8_t g, uint8_t b); - // Driver vtable with extras struct tft_panel_dc_reset_painter_driver_vtable_t { struct painter_driver_vtable_t base; // must be first, so it can be cast to/from the painter_driver_vtable_t* type - // Conversion function for palette entries - rgb888_to_native_uint16_t rgb888_to_native16bit; - // Number of bytes for transmitting x/y coordinates uint8_t num_window_bytes; @@ -58,10 +53,9 @@ bool qp_tft_panel_clear(painter_device_t device); bool qp_tft_panel_flush(painter_device_t device); bool qp_tft_panel_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom); bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count); -bool qp_tft_panel_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette); -bool qp_tft_panel_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices); -uint16_t qp_rgb888_to_rgb565(uint8_t r, uint8_t g, uint8_t b); -uint16_t qp_rgb888_to_rgb565_swapped(uint8_t r, uint8_t g, uint8_t b); -uint16_t qp_rgb888_to_bgr565(uint8_t r, uint8_t g, uint8_t b); -uint16_t qp_rgb888_to_bgr565_swapped(uint8_t r, uint8_t g, uint8_t b); +bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette); +bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette); + +bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices); +bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices); diff --git a/quantum/painter/qp.h b/quantum/painter/qp.h index e1c14d156c..47f077d0cf 100644 --- a/quantum/painter/qp.h +++ b/quantum/painter/qp.h @@ -440,6 +440,10 @@ int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, pai # include "qp_ili9341.h" #endif // QUANTUM_PAINTER_ILI9341_ENABLE +#ifdef QUANTUM_PAINTER_ILI9488_ENABLE +# include "qp_ili9488.h" +#endif // QUANTUM_PAINTER_ILI9488_ENABLE + #ifdef QUANTUM_PAINTER_ST7789_ENABLE # include "qp_st7789.h" #endif // QUANTUM_PAINTER_ST7789_ENABLE diff --git a/quantum/painter/rules.mk b/quantum/painter/rules.mk index 9115d3d406..675a1a5460 100644 --- a/quantum/painter/rules.mk +++ b/quantum/painter/rules.mk @@ -3,7 +3,7 @@ QUANTUM_PAINTER_DRIVERS ?= QUANTUM_PAINTER_ANIMATIONS_ENABLE ?= yes # The list of permissible drivers that can be listed in QUANTUM_PAINTER_DRIVERS -VALID_QUANTUM_PAINTER_DRIVERS := ili9163_spi ili9341_spi st7789_spi gc9a01_spi ssd1351_spi +VALID_QUANTUM_PAINTER_DRIVERS := ili9163_spi ili9341_spi ili9488_spi st7789_spi gc9a01_spi ssd1351_spi #------------------------------------------------------------------------------- @@ -61,6 +61,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)),ili9488_spi) + QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes + QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes + OPT_DEFS += -DQUANTUM_PAINTER_ILI9488_ENABLE -DQUANTUM_PAINTER_ILI9488_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_ili9488.c \ + else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),st7789_spi) QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes -- cgit v1.2.3 From 5846b40f7444af96b0d8ddf3af9b558193c2475d Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Sat, 2 Jul 2022 15:18:50 +1000 Subject: RP2040 emulated EEPROM. (#17519) --- builddefs/common_features.mk | 10 +- builddefs/mcu_selection.mk | 2 +- docs/eeprom_driver.md | 17 +- docs/platformdev_rp2040.md | 22 +- .../boards/common/ld/RP2040_FLASH_TIMECRIT.ld | 117 +++++++++++ .../common/ld/RP2040_rules_data_with_timecrit.ld | 46 +++++ .../wear_leveling/wear_leveling_rp2040_flash.c | 221 +++++++++++++++++++++ .../wear_leveling_rp2040_flash_config.h | 32 +++ platforms/chibios/platform.mk | 3 + platforms/chibios/vendors/RP/RP2040.mk | 2 + platforms/chibios/vendors/RP/pico_sdk_shims.c | 4 + platforms/chibios/vendors/RP/stage2_bootloaders.c | 12 +- quantum/wear_leveling/wear_leveling.c | 4 +- 13 files changed, 470 insertions(+), 22 deletions(-) create mode 100644 platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld create mode 100644 platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 2edc1bdef0..c11e5688e3 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -220,6 +220,11 @@ else # True EEPROM on STM32L0xx, L1xx OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_STM32_L0_L1 SRC += eeprom_driver.c eeprom_stm32_L0_L1.c + else ifneq ($(filter $(MCU_SERIES),RP2040),) + # Wear-leveling EEPROM implementation, backed by RP2040 flash + OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING + SRC += eeprom_driver.c eeprom_wear_leveling.c + WEAR_LEVELING_DRIVER = rp2040_flash else ifneq ($(filter $(MCU_SERIES),KL2x K20x),) # Teensy EEPROM implementations OPT_DEFS += -DEEPROM_TEENSY @@ -241,7 +246,7 @@ else endif endif -VALID_WEAR_LEVELING_DRIVER_TYPES := custom embedded_flash spi_flash legacy +VALID_WEAR_LEVELING_DRIVER_TYPES := custom embedded_flash spi_flash rp2040_flash legacy WEAR_LEVELING_DRIVER ?= none ifneq ($(strip $(WEAR_LEVELING_DRIVER)),none) ifeq ($(filter $(WEAR_LEVELING_DRIVER),$(VALID_WEAR_LEVELING_DRIVER_TYPES)),) @@ -262,6 +267,9 @@ ifneq ($(strip $(WEAR_LEVELING_DRIVER)),none) FLASH_DRIVER := spi SRC += wear_leveling_flash_spi.c POST_CONFIG_H += $(DRIVER_PATH)/wear_leveling/wear_leveling_flash_spi_config.h + else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), rp2040_flash) + SRC += wear_leveling_rp2040_flash.c + POST_CONFIG_H += $(DRIVER_PATH)/wear_leveling/wear_leveling_rp2040_flash_config.h else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), legacy) COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash SRC += flash_stm32.c wear_leveling_legacy.c diff --git a/builddefs/mcu_selection.mk b/builddefs/mcu_selection.mk index d676e0c06a..135f663c14 100644 --- a/builddefs/mcu_selection.mk +++ b/builddefs/mcu_selection.mk @@ -135,7 +135,7 @@ ifneq ($(findstring RP2040, $(MCU)),) # - it should exist either in /os/common/ports/ARMCMx/compilers/GCC/ld/ # or /ld/ STARTUPLD_CONTRIB = $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/ld - MCU_LDSCRIPT ?= RP2040_FLASH + MCU_LDSCRIPT ?= RP2040_FLASH_TIMECRIT LDFLAGS += -L $(STARTUPLD_CONTRIB) # Startup code to use diff --git a/docs/eeprom_driver.md b/docs/eeprom_driver.md index de2eaf2e5b..50d8bcb7b3 100644 --- a/docs/eeprom_driver.md +++ b/docs/eeprom_driver.md @@ -92,6 +92,7 @@ Driver | Description ----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ `WEAR_LEVELING_DRIVER = embedded_flash` | This driver is used for emulating EEPROM by writing to embedded flash on the MCU. `WEAR_LEVELING_DRIVER = spi_flash` | This driver is used to address external SPI NOR Flash peripherals. +`WEAR_LEVELING_DRIVER = rp2040_flash` | This driver is used to write to the same storage the RP2040 executes code from. `WEAR_LEVELING_DRIVER = legacy` | This driver is the "legacy" emulated EEPROM provided in historical revisions of QMK. Currently used for STM32F0xx and STM32F4x1, but slated for deprecation and removal once `embedded_flash` support for those MCU families is complete. !> All wear-leveling drivers require an amount of RAM equivalent to the selected logical EEPROM size. Increasing the size to 32kB of EEPROM requires 32kB of RAM, which a significant number of MCUs simply do not have. @@ -128,6 +129,20 @@ Configurable options in your keyboard's `config.h`: !> There is currently a limit of 64kB for the EEPROM subsystem within QMK, so using a larger flash is not going to be beneficial as the logical size cannot be increased beyond 65536. The backing size may be increased to a larger value, but erase timing may suffer as a result. +## Wear-leveling RP2040 Driver Configuration :id=wear_leveling-rp2040-driver-configuration + +This driver performs writes to the same underlying storage that the RP2040 executes its code. + +Configurable options in your keyboard's `config.h`: + +`config.h` override | Default | Description +------------------------------------------|----------------------------|-------------------------------------------------------------------------------------------------------------------------------- +`#define WEAR_LEVELING_RP2040_FLASH_SIZE` | `PICO_FLASH_SIZE_BYTES` | Number of bytes of flash on the board. +`#define WEAR_LEVELING_RP2040_FLASH_BASE` | `(flash_size-sector_size)` | The byte-wise location that the backing storage should be located. +`#define WEAR_LEVELING_LOGICAL_SIZE` | `4096` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM. +`#define WEAR_LEVELING_BACKING_SIZE` | `8192` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size as well as the sector size. +`#define BACKING_STORE_WRITE_SIZE` | `2` | The write width used whenever a write is performed on the external flash peripheral. + ## Wear-leveling Legacy EEPROM Emulation Driver Configuration :id=wear_leveling-legacy-driver-configuration This driver performs writes to the embedded flash storage embedded in the MCU much like the normal Embedded Flash Driver, and is only for use with STM32F0xx and STM32F4x1 devices. This flash implementation is still currently provided as the EFL driver is currently non-functional for the previously mentioned families. @@ -142,4 +157,4 @@ STM32F072 | `1024` bytes | `2048` bytes STM32F401 | `1024` bytes | `16384` bytes STM32F411 | `1024` bytes | `16384` bytes -Under normal circumstances configuration of this driver requires intimate knowledge of the MCU's flash structure -- reconfiguration is at your own risk and will require referring to the code. \ No newline at end of file +Under normal circumstances configuration of this driver requires intimate knowledge of the MCU's flash structure -- reconfiguration is at your own risk and will require referring to the code. diff --git a/docs/platformdev_rp2040.md b/docs/platformdev_rp2040.md index 9426efa29a..d690ebebf8 100644 --- a/docs/platformdev_rp2040.md +++ b/docs/platformdev_rp2040.md @@ -2,17 +2,17 @@ The following table shows the current driver status for peripherals on RP2040 MCUs: -| System | Support | -| ------------------------------------ | ---------------------------------------------- | -| [ADC driver](adc_driver.md) | Support planned (no ETA) | -| [Audio](audio_driver.md) | Support planned (no ETA) | -| [I2C driver](i2c_driver.md) | :heavy_check_mark: | -| [SPI driver](spi_driver.md) | :heavy_check_mark: | -| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver | -| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver | -| [EEPROM emulation](eeprom_driver.md) | Support planned (no ETA) | -| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver | -| [UART driver](uart_driver.md) | Support planned (no ETA) | +| System | Support | +| ---------------------------------------------------------------- | ---------------------------------------------- | +| [ADC driver](adc_driver.md) | Support planned (no ETA) | +| [Audio](audio_driver.md) | Support planned (no ETA) | +| [I2C driver](i2c_driver.md) | :heavy_check_mark: | +| [SPI driver](spi_driver.md) | :heavy_check_mark: | +| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver | +| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver | +| [EEPROM emulation](eeprom_driver.md#wear_leveling-configuration) | :heavy_check_mark: | +| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver | +| [UART driver](uart_driver.md) | Support planned (no ETA) | ## GPIO diff --git a/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld b/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld new file mode 100644 index 0000000000..66ed4ce086 --- /dev/null +++ b/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld @@ -0,0 +1,117 @@ +/* + ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * RP2040 memory setup. + */ +MEMORY +{ + flash0 (rx) : org = 0x00000000, len = 16k /* ROM */ + flash1 (rx) : org = 0x10000000, len = DEFINED(FLASH_LEN) ? FLASH_LEN : 2048k /* XIP */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x20000000, len = 256k /* SRAM0 striped */ + ram1 (wx) : org = 0x00000000, len = 256k /* SRAM0 non striped */ + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k /* SRAM4 */ + ram5 (wx) : org = 0x20041000, len = 4k /* SRAM5 */ + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x20041f00, len = 256 /* SRAM5 boot */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram4); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram4); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > flash1 +} + +/* Generic rules inclusion.*/ +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE RP2040_rules_code_with_boot2.ld +INCLUDE RP2040_rules_data_with_timecrit.ld +INCLUDE rules_memory.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld b/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld new file mode 100644 index 0000000000..a9a47be983 --- /dev/null +++ b/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld @@ -0,0 +1,46 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +SECTIONS +{ + .data : ALIGN(4) + { + PROVIDE(_textdata = LOADADDR(.data)); + PROVIDE(_data = .); + __textdata_base__ = LOADADDR(.data); + __data_base__ = .; + *(vtable) + *(.time_critical*) + . = ALIGN(4); + *(.data) + *(.data.*) + *(.ramtext) + . = ALIGN(4); + PROVIDE(_edata = .); + __data_end__ = .; + } > DATA_RAM AT > DATA_RAM_LMA + + .bss (NOLOAD) : ALIGN(4) + { + __bss_base__ = .; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + PROVIDE(end = .); + } > BSS_RAM +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c new file mode 100644 index 0000000000..640628e1e9 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2022 Nick Brassel (@tzarc) + * Copyright (c) 2022 Stefan Kerkmann (@KarlK90) + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/bootrom.h" +#include "hardware/flash.h" +#include "hardware/sync.h" +#include "hardware/structs/ssi.h" +#include "hardware/structs/ioqspi.h" + +#include +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +#ifndef WEAR_LEVELING_RP2040_FLASH_BULK_COUNT +# define WEAR_LEVELING_RP2040_FLASH_BULK_COUNT 64 +#endif // WEAR_LEVELING_RP2040_FLASH_BULK_COUNT + +#define FLASHCMD_PAGE_PROGRAM 0x02 +#define FLASHCMD_READ_STATUS 0x05 +#define FLASHCMD_WRITE_ENABLE 0x06 + +extern uint8_t BOOT2_ROM[256]; +static uint32_t BOOT2_ROM_RAM[64]; + +static ssi_hw_t *const ssi = (ssi_hw_t *)XIP_SSI_BASE; + +// Sanity check +check_hw_layout(ssi_hw_t, ssienr, SSI_SSIENR_OFFSET); +check_hw_layout(ssi_hw_t, spi_ctrlr0, SSI_SPI_CTRLR0_OFFSET); + +static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) { + ((void (*)(void))BOOT2_ROM_RAM + 1)(); +} + +// Bitbanging the chip select using IO overrides, in case RAM-resident IRQs +// are still running, and the FIFO bottoms out. (the bootrom does the same) +static void __no_inline_not_in_flash_func(flash_cs_force)(bool high) { + uint32_t field_val = high ? IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW; + hw_write_masked(&ioqspi_hw->io[1].ctrl, field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB, IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS); +} + +// Also allow any unbounded loops to check whether the above abort condition +// was asserted, and terminate early +static int __no_inline_not_in_flash_func(flash_was_aborted)(void) { + return *(io_rw_32 *)(IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET) & IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS; +} + +// Put bytes from one buffer, and get bytes into another buffer. +// These can be the same buffer. +// If tx is NULL then send zeroes. +// If rx is NULL then all read data will be dropped. +// +// If rx_skip is nonzero, this many bytes will first be consumed from the FIFO, +// before reading a further count bytes into *rx. +// E.g. if you have written a command+address just before calling this function. +static void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx, uint8_t *rx, size_t count, size_t rx_skip) { + // Make sure there is never more data in flight than the depth of the RX + // FIFO. Otherwise, when we are interrupted for long periods, hardware + // will overflow the RX FIFO. + const uint max_in_flight = 16 - 2; // account for data internal to SSI + size_t tx_count = count; + size_t rx_count = count; + while (tx_count || rx_skip || rx_count) { + // NB order of reads, for pessimism rather than optimism + uint32_t tx_level = ssi_hw->txflr; + uint32_t rx_level = ssi_hw->rxflr; + bool did_something = false; // Expect this to be folded into control flow, not register + if (tx_count && tx_level + rx_level < max_in_flight) { + ssi->dr0 = (uint32_t)(tx ? *tx++ : 0); + --tx_count; + did_something = true; + } + if (rx_level) { + uint8_t rxbyte = ssi->dr0; + did_something = true; + if (rx_skip) { + --rx_skip; + } else { + if (rx) *rx++ = rxbyte; + --rx_count; + } + } + // APB load costs 4 cycles, so only do it on idle loops (our budget is + // 48 cyc/byte) + if (!did_something && __builtin_expect(flash_was_aborted(), 0)) break; + } + flash_cs_force(1); +} + +// Convenience wrapper for above +// (And it's hard for the debug host to get the tight timing between +// cmd DR0 write and the remaining data) +static void __no_inline_not_in_flash_func(_flash_do_cmd)(uint8_t cmd, const uint8_t *tx, uint8_t *rx, size_t count) { + flash_cs_force(0); + ssi->dr0 = cmd; + flash_put_get(tx, rx, count, 1); +} + +// Timing of this one is critical, so do not expose the symbol to debugger etc +static void __no_inline_not_in_flash_func(flash_put_cmd_addr)(uint8_t cmd, uint32_t addr) { + flash_cs_force(0); + addr |= cmd << 24; + for (int i = 0; i < 4; ++i) { + ssi->dr0 = addr >> 24; + addr <<= 8; + } +} + +// Poll the flash status register until the busy bit (LSB) clears +static void __no_inline_not_in_flash_func(flash_wait_ready)(void) { + uint8_t stat; + do { + _flash_do_cmd(FLASHCMD_READ_STATUS, NULL, &stat, 1); + } while (stat & 0x1 && !flash_was_aborted()); +} + +// Set the WEL bit (needed before any program/erase operation) +static void __no_inline_not_in_flash_func(flash_enable_write)(void) { + _flash_do_cmd(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0); +} + +static void __no_inline_not_in_flash_func(pico_program_bulk)(uint32_t flash_address, backing_store_int_t *values, size_t item_count) { + rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); + rom_flash_exit_xip_fn flash_exit_xip = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); + rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); + assert(connect_internal_flash && flash_exit_xip && flash_flush_cache); + + static backing_store_int_t bulk_write_buffer[WEAR_LEVELING_RP2040_FLASH_BULK_COUNT]; + + while (item_count) { + size_t batch_size = MIN(item_count, WEAR_LEVELING_RP2040_FLASH_BULK_COUNT); + for (size_t i = 0; i < batch_size; i++, values++, item_count--) { + bulk_write_buffer[i] = ~(*values); + } + __compiler_memory_barrier(); + + connect_internal_flash(); + flash_exit_xip(); + flash_enable_write(); + + flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, flash_address); + flash_put_get((uint8_t *)bulk_write_buffer, NULL, batch_size * sizeof(backing_store_int_t), 4); + flash_wait_ready(); + flash_address += batch_size * sizeof(backing_store_int_t); + + flash_flush_cache(); + flash_enable_xip_via_boot2(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// QMK Wear-Leveling Backing Store implementation + +static int interrupts; + +bool backing_store_init(void) { + bs_dprintf("Init\n"); + memcpy(BOOT2_ROM_RAM, BOOT2_ROM, sizeof(BOOT2_ROM)); + __compiler_memory_barrier(); + return true; +} + +bool backing_store_unlock(void) { + bs_dprintf("Unlock\n"); + return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT + uint32_t start = timer_read32(); +#endif + + // Ensure the backing size can be cleanly subtracted from the flash size without alignment issues. + _Static_assert((WEAR_LEVELING_BACKING_SIZE) % (FLASH_SECTOR_SIZE) == 0, "Backing size must be a multiple of FLASH_SECTOR_SIZE"); + + interrupts = save_and_disable_interrupts(); + flash_range_erase((WEAR_LEVELING_RP2040_FLASH_BASE), (WEAR_LEVELING_BACKING_SIZE)); + restore_interrupts(interrupts); + + bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); + return true; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { + return backing_store_write_bulk(address, &value, 1); +} + +bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address; + bs_dprintf("Write "); + wl_dump(offset, values, sizeof(backing_store_int_t) * item_count); + interrupts = save_and_disable_interrupts(); + pico_program_bulk(offset, values, item_count); + restore_interrupts(interrupts); + return true; +} + +bool backing_store_lock(void) { + return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { + return backing_store_read_bulk(address, value, 1); +} + +bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address; + backing_store_int_t *loc = (backing_store_int_t *)((XIP_BASE) + offset); + for (size_t i = 0; i < item_count; ++i) { + values[i] = ~loc[i]; + } + bs_dprintf("Read "); + wl_dump(offset, values, item_count * sizeof(backing_store_int_t)); + return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h new file mode 100644 index 0000000000..93a9aa0372 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h @@ -0,0 +1,32 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +# include "hardware/flash.h" +#endif + +// 2-byte writes +#ifndef BACKING_STORE_WRITE_SIZE +# define BACKING_STORE_WRITE_SIZE 2 +#endif + +// 64kB backing space allocated +#ifndef WEAR_LEVELING_BACKING_SIZE +# define WEAR_LEVELING_BACKING_SIZE 8192 +#endif // WEAR_LEVELING_BACKING_SIZE + +// 32kB logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# define WEAR_LEVELING_LOGICAL_SIZE 4096 +#endif // WEAR_LEVELING_LOGICAL_SIZE + +// Define how much flash space we have (defaults to lib/pico-sdk/src/boards/include/boards/***) +#ifndef WEAR_LEVELING_RP2040_FLASH_SIZE +# define WEAR_LEVELING_RP2040_FLASH_SIZE (PICO_FLASH_SIZE_BYTES) +#endif + +// Define the location of emulated EEPROM +#ifndef WEAR_LEVELING_RP2040_FLASH_BASE +# define WEAR_LEVELING_RP2040_FLASH_BASE ((WEAR_LEVELING_RP2040_FLASH_SIZE) - (WEAR_LEVELING_BACKING_SIZE)) +#endif diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 32b8c5a946..63cc1a4b33 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -351,8 +351,11 @@ SHARED_CFLAGS = -fomit-frame-pointer \ -fno-common \ -fshort-wchar +LDSCRIPT_PATH := $(shell dirname "$(LDSCRIPT)") + # Shared Linker flags for all toolchains SHARED_LDFLAGS = -T $(LDSCRIPT) \ + -L $(LDSCRIPT_PATH) \ -Wl,--gc-sections \ -nostartfiles diff --git a/platforms/chibios/vendors/RP/RP2040.mk b/platforms/chibios/vendors/RP/RP2040.mk index 1aa925cb15..de426c9c40 100644 --- a/platforms/chibios/vendors/RP/RP2040.mk +++ b/platforms/chibios/vendors/RP/RP2040.mk @@ -24,6 +24,7 @@ PICOSDKROOT := $(TOP_DIR)/lib/pico-sdk PICOSDKSRC = $(PICOSDKROOT)/src/rp2_common/hardware_clocks/clocks.c \ $(PICOSDKROOT)/src/rp2_common/hardware_pll/pll.c \ $(PICOSDKROOT)/src/rp2_common/hardware_pio/pio.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_flash/flash.c \ $(PICOSDKROOT)/src/rp2_common/hardware_gpio/gpio.c \ $(PICOSDKROOT)/src/rp2_common/hardware_claim/claim.c \ $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/watchdog.c \ @@ -36,6 +37,7 @@ PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \ $(PICOSDKROOT)/src/rp2_common/hardware_base/include \ $(PICOSDKROOT)/src/rp2_common/hardware_clocks/include \ $(PICOSDKROOT)/src/rp2_common/hardware_claim/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_flash/include \ $(PICOSDKROOT)/src/rp2_common/hardware_gpio/include \ $(PICOSDKROOT)/src/rp2_common/hardware_irq/include \ $(PICOSDKROOT)/src/rp2_common/hardware_pll/include \ diff --git a/platforms/chibios/vendors/RP/pico_sdk_shims.c b/platforms/chibios/vendors/RP/pico_sdk_shims.c index f6e3943928..239155c086 100644 --- a/platforms/chibios/vendors/RP/pico_sdk_shims.c +++ b/platforms/chibios/vendors/RP/pico_sdk_shims.c @@ -7,3 +7,7 @@ void panic(const char *fmt, ...) { chSysHalt(fmt); } + +void hard_assertion_failure(void) { + panic("hard assert"); +} diff --git a/platforms/chibios/vendors/RP/stage2_bootloaders.c b/platforms/chibios/vendors/RP/stage2_bootloaders.c index af679a0dc7..e65b0a5802 100644 --- a/platforms/chibios/vendors/RP/stage2_bootloaders.c +++ b/platforms/chibios/vendors/RP/stage2_bootloaders.c @@ -13,7 +13,7 @@ #if defined(RP2040_FLASH_AT25SF128A) -uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, @@ -40,7 +40,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = { #elif defined(RP2040_FLASH_GD25Q64CS) -uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, @@ -67,7 +67,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = { #elif defined(RP2040_FLASH_W25X10CL) -uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x14, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x12, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x11, 0x49, 0x12, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xbb, 0x21, 0x19, 0x66, 0x02, 0x21, @@ -94,7 +94,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = { #elif defined(RP2040_FLASH_IS25LP080) -uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x29, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x28, 0x48, 0x00, 0xf0, 0x42, 0xf8, 0x28, 0x4a, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, 0x19, 0x66, @@ -121,7 +121,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = { #elif defined(RP2040_FLASH_GENERIC_03H) -uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x0c, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x0a, 0x49, 0x19, 0x60, 0x0a, 0x49, 0x0b, 0x48, 0x01, 0x60, 0x00, 0x21, 0x59, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, @@ -148,7 +148,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = { #else -uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, diff --git a/quantum/wear_leveling/wear_leveling.c b/quantum/wear_leveling/wear_leveling.c index 0a519639ea..429df45df5 100644 --- a/quantum/wear_leveling/wear_leveling.c +++ b/quantum/wear_leveling/wear_leveling.c @@ -421,7 +421,7 @@ static wear_leveling_status_t wear_leveling_write_raw(uint32_t address, const vo #if BACKING_STORE_WRITE_SIZE == 2 // Small-write optimizations - uint16_t, 0 or 1, address is even, address <16384: if (remaining >= 2 && address % 2 == 0 && address < 16384) { - const uint16_t v = *(const uint16_t *)p; + const uint16_t v = ((uint16_t)p[1]) << 8 | p[0]; // don't just dereference a uint16_t here -- if unaligned it generates faults on some MCUs if (v == 0 || v == 1) { const write_log_entry_t log = LOG_ENTRY_MAKE_WORD_01(address, v); status = wear_leveling_append_raw(log.raw16[0]); @@ -765,4 +765,4 @@ __attribute__((weak)) bool backing_store_write_bulk(uint32_t address, backing_st } } return true; -} \ No newline at end of file +} -- cgit v1.2.3 From 9dc7b9d40cfa199875cdc9e2e05b15d3f463b415 Mon Sep 17 00:00:00 2001 From: "FREEWING.JP" Date: Sat, 2 Jul 2022 20:48:26 +0900 Subject: Added Wait time to sending each Keys for Dynamic Macros function (#16800) Co-authored-by: Joel Challis --- docs/feature_dynamic_macros.md | 1 + docs/ja/feature_dynamic_macros.md | 1 + quantum/process_keycode/process_dynamic_macro.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'quantum') diff --git a/docs/feature_dynamic_macros.md b/docs/feature_dynamic_macros.md index 01f2a0ca40..0660e0c065 100644 --- a/docs/feature_dynamic_macros.md +++ b/docs/feature_dynamic_macros.md @@ -35,6 +35,7 @@ There are a number of options added that should allow some additional degree of |`DYNAMIC_MACRO_SIZE` |128 |Sets the amount of memory that Dynamic Macros can use. This is a limited resource, dependent on the controller. | |`DYNAMIC_MACRO_USER_CALL` |*Not defined* |Defining this falls back to using the user `keymap.c` file to trigger the macro behavior. | |`DYNAMIC_MACRO_NO_NESTING` |*Not Defined* |Defining this disables the ability to call a macro from another macro (nested macros). | +|`DYNAMIC_MACRO_DELAY` |*Not Defined* |Sets the waiting time (ms unit) when sending each key. | If the LEDs start blinking during the recording with each keypress, it means there is no more space for the macro in the macro buffer. To fit the macro in, either make the other macro shorter (they share the same buffer) or increase the buffer size by adding the `DYNAMIC_MACRO_SIZE` define in your `config.h` (default value: 128; please read the comments for it in the header). diff --git a/docs/ja/feature_dynamic_macros.md b/docs/ja/feature_dynamic_macros.md index 951b903127..3cff788007 100644 --- a/docs/ja/feature_dynamic_macros.md +++ b/docs/ja/feature_dynamic_macros.md @@ -40,6 +40,7 @@ QMK はその場で作られた一時的なマクロをサポートします。 | `DYNAMIC_MACRO_SIZE` | 128 | 動的マクロが使用できるメモリ量を設定します。これは限られたリソースであり、コントローラに依存します。 | | `DYNAMIC_MACRO_USER_CALL` | *定義なし* | これを定義すると、ユーザの `keymap.c` ファイルを使ってマクロが起動されます。 | | `DYNAMIC_MACRO_NO_NESTING` | *定義なし* | これを定義すると、別のマクロからマクロを呼び出す(入れ子になったマクロ)機能を無効にします。 | +| `DYNAMIC_MACRO_DELAY` | *定義なし* | 各キーを送信する時の待ち時間(ms単位)を設定します。 | 記録中にキーを押すたびに LED が点滅し始めた場合は、マクロバッファにマクロを入れるスペースがもう無いことを意味します。マクロを入れるには、他のマクロ(それらは同じバッファを共有します)を短くするか、`config.h` に `DYNAMIC_MACRO_SIZE` 定義を追加することでバッファを増やします(デフォルト値: 128; ヘッダ内のコメントを読んでください)。 diff --git a/quantum/process_keycode/process_dynamic_macro.c b/quantum/process_keycode/process_dynamic_macro.c index a1ada2d5a2..a7555fdd40 100644 --- a/quantum/process_keycode/process_dynamic_macro.c +++ b/quantum/process_keycode/process_dynamic_macro.c @@ -86,6 +86,9 @@ void dynamic_macro_play(keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_ while (macro_buffer != macro_end) { process_record(macro_buffer); macro_buffer += direction; +#ifdef DYNAMIC_MACRO_DELAY + wait_ms(DYNAMIC_MACRO_DELAY); +#endif } clear_keyboard(); -- cgit v1.2.3 From 0112938140b4a59904f4b0b8c3893588410013cb Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Sat, 2 Jul 2022 13:57:05 +0200 Subject: Expose the time of the last change to the LED state (#17222) --- quantum/led.c | 12 +++++++++++- quantum/led.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/led.c b/quantum/led.c index c5ddbc22c5..444d38f751 100644 --- a/quantum/led.c +++ b/quantum/led.c @@ -15,6 +15,7 @@ */ #include "led.h" #include "host.h" +#include "timer.h" #include "debug.h" #include "gpio.h" @@ -54,6 +55,14 @@ static void handle_backlight_caps_lock(led_t led_state) { } #endif +static uint32_t last_led_modification_time = 0; +uint32_t last_led_activity_time(void) { + return last_led_modification_time; +} +uint32_t last_led_activity_elapsed(void) { + return timer_elapsed32(last_led_modification_time); +} + /** \brief Lock LED set callback - keymap/user level * * \deprecated Use led_update_user() instead. @@ -174,7 +183,8 @@ void led_task(void) { // update LED uint8_t led_status = host_keyboard_leds(); if (last_led_status != led_status) { - last_led_status = led_status; + last_led_status = led_status; + last_led_modification_time = timer_read32(); if (debug_keyboard) { debug("led_task: "); diff --git a/quantum/led.h b/quantum/led.h index 934d25312c..b8262cbd8e 100644 --- a/quantum/led.h +++ b/quantum/led.h @@ -61,6 +61,9 @@ void led_set_kb(uint8_t usb_led); bool led_update_user(led_t led_state); bool led_update_kb(led_t led_state); +uint32_t last_led_activity_time(void); // Timestamp of the LED activity +uint32_t last_led_activity_elapsed(void); // Number of milliseconds since the last LED activity + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 8b78fac4511cd006b7be92e5789d29de6118fad3 Mon Sep 17 00:00:00 2001 From: torkel104 Date: Sat, 2 Jul 2022 14:03:40 +0200 Subject: Fix keys being discarded after using the leader key (#17287) --- quantum/process_keycode/process_leader.c | 1 + 1 file changed, 1 insertion(+) (limited to 'quantum') diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c index c2fd02e5c7..ae00b3227a 100644 --- a/quantum/process_keycode/process_leader.c +++ b/quantum/process_keycode/process_leader.c @@ -64,6 +64,7 @@ bool process_leader(uint16_t keycode, keyrecord_t *record) { } else { leading = false; leader_end(); + return true; } # ifdef LEADER_PER_KEY_TIMING leader_time = timer_read(); -- cgit v1.2.3 From 871eeae4eab476cb64b40e0636ec19deeea79525 Mon Sep 17 00:00:00 2001 From: Osamu Aoki Date: Sat, 2 Jul 2022 21:08:48 +0900 Subject: PoC: Swap Escape and Caps (#16336) --- docs/keycodes.md | 3 +++ docs/keycodes_magic.md | 3 +++ quantum/command.c | 2 ++ quantum/keycode_config.c | 4 ++++ quantum/keycode_config.h | 1 + quantum/process_keycode/process_magic.c | 10 ++++++++++ quantum/quantum_keycodes.h | 8 ++++++++ 7 files changed, 31 insertions(+) (limited to 'quantum') diff --git a/docs/keycodes.md b/docs/keycodes.md index bd5af32dd3..37e9d00392 100644 --- a/docs/keycodes.md +++ b/docs/keycodes.md @@ -337,6 +337,9 @@ See also: [Magic Keycodes](keycodes_magic.md) |`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control | |`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control | |`MAGIC_TOGGLE_CONTROL_CAPSLOCK` |`CL_TOGG`|Toggle Caps Lock and Left Control swap | +|`MAGIC_SWAP_ESCAPE_CAPSLOCK` |`EC_SWAP`|Swap Caps Lock and Escape | +|`MAGIC_UNSWAP_ESCAPE_CAPSLOCK` |`EC_NORM`|Unswap Caps Lock and Escape | +|`MAGIC_TOGGLE_ESCAPE_CAPSLOCK` |`EC_TOGG`|Toggle Caps Lock and Escape swap | |`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control | |`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control | |`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI | diff --git a/docs/keycodes_magic.md b/docs/keycodes_magic.md index 01eb69168e..982a301630 100644 --- a/docs/keycodes_magic.md +++ b/docs/keycodes_magic.md @@ -7,6 +7,9 @@ |`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control | |`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control | |`MAGIC_TOGGLE_CONTROL_CAPSLOCK` |`CL_TOGG`|Toggle Caps Lock and Left Control swap | +|`MAGIC_SWAP_ESCAPE_CAPSLOCK` |`EC_SWAP`|Swap Caps Lock and Escape | +|`MAGIC_UNSWAP_ESCAPE_CAPSLOCK` |`EC_NORM`|Unswap Caps Lock and Escape | +|`MAGIC_TOGGLE_ESCAPE_CAPSLOCK` |`EC_TOGG`|Toggle Caps Lock and Escape swap | |`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control | |`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control | |`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI | diff --git a/quantum/command.c b/quantum/command.c index f90d73207c..2e94cb44b8 100644 --- a/quantum/command.c +++ b/quantum/command.c @@ -282,6 +282,7 @@ static void print_eeconfig(void) { ".swap_grave_esc: %u\n" ".swap_backslash_backspace: %u\n" ".nkro: %u\n" + ".swap_escape_capslock: %u\n" , kc.raw , kc.swap_control_capslock @@ -294,6 +295,7 @@ static void print_eeconfig(void) { , kc.swap_grave_esc , kc.swap_backslash_backspace , kc.nkro + , kc.swap_escape_capslock ); /* clang-format on */ # ifdef BACKLIGHT_ENABLE diff --git a/quantum/keycode_config.c b/quantum/keycode_config.c index dd2a17e242..5b5cc5d28e 100644 --- a/quantum/keycode_config.c +++ b/quantum/keycode_config.c @@ -29,6 +29,8 @@ uint16_t keycode_config(uint16_t keycode) { case KC_LOCKING_CAPS_LOCK: if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) { return KC_LEFT_CTRL; + } else if (keymap_config.swap_escape_capslock) { + return KC_ESCAPE; } return keycode; case KC_LEFT_CTRL: @@ -96,6 +98,8 @@ uint16_t keycode_config(uint16_t keycode) { case KC_ESCAPE: if (keymap_config.swap_grave_esc) { return KC_GRAVE; + } else if (keymap_config.swap_escape_capslock) { + return KC_CAPS_LOCK; } return KC_ESCAPE; case KC_BACKSLASH: diff --git a/quantum/keycode_config.h b/quantum/keycode_config.h index a2cb025ed2..81a8e61471 100644 --- a/quantum/keycode_config.h +++ b/quantum/keycode_config.h @@ -38,6 +38,7 @@ typedef union { bool swap_lctl_lgui : 1; bool swap_rctl_rgui : 1; bool oneshot_enable : 1; + bool swap_escape_capslock : 1; }; } keymap_config_t; diff --git a/quantum/process_keycode/process_magic.c b/quantum/process_keycode/process_magic.c index 10161adda3..ae60f29bf5 100644 --- a/quantum/process_keycode/process_magic.c +++ b/quantum/process_keycode/process_magic.c @@ -45,12 +45,16 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) { case MAGIC_SWAP_LCTL_LGUI ... MAGIC_EE_HANDS_RIGHT: case MAGIC_TOGGLE_GUI: case MAGIC_TOGGLE_CONTROL_CAPSLOCK: + case MAGIC_SWAP_ESCAPE_CAPSLOCK ... MAGIC_TOGGLE_ESCAPE_CAPSLOCK: /* keymap config */ keymap_config.raw = eeconfig_read_keymap(); switch (keycode) { case MAGIC_SWAP_CONTROL_CAPSLOCK: keymap_config.swap_control_capslock = true; break; + case MAGIC_SWAP_ESCAPE_CAPSLOCK: + keymap_config.swap_escape_capslock = true; + break; case MAGIC_CAPSLOCK_TO_CONTROL: keymap_config.capslock_to_control = true; break; @@ -94,6 +98,9 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) { case MAGIC_UNSWAP_CONTROL_CAPSLOCK: keymap_config.swap_control_capslock = false; break; + case MAGIC_UNSWAP_ESCAPE_CAPSLOCK: + keymap_config.swap_escape_capslock = false; + break; case MAGIC_UNCAPSLOCK_TO_CONTROL: keymap_config.capslock_to_control = false; break; @@ -172,6 +179,9 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) { case MAGIC_TOGGLE_CONTROL_CAPSLOCK: keymap_config.swap_control_capslock = !keymap_config.swap_control_capslock; break; + case MAGIC_TOGGLE_ESCAPE_CAPSLOCK: + keymap_config.swap_escape_capslock = !keymap_config.swap_escape_capslock; + break; } eeconfig_update_keymap(keymap_config.raw); diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index 869826ce19..456fad6f1b 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -605,6 +605,10 @@ enum quantum_keycodes { CAPS_WORD, + MAGIC_SWAP_ESCAPE_CAPSLOCK, + MAGIC_UNSWAP_ESCAPE_CAPSLOCK, + MAGIC_TOGGLE_ESCAPE_CAPSLOCK, + // Start of custom keycode range for keyboards and keymaps - always leave at the end SAFE_RANGE }; @@ -756,6 +760,10 @@ enum quantum_keycodes { #define CL_CAPS MAGIC_UNCAPSLOCK_TO_CONTROL #define CL_TOGG MAGIC_TOGGLE_CONTROL_CAPSLOCK +#define EC_SWAP MAGIC_SWAP_ESCAPE_CAPSLOCK +#define EC_NORM MAGIC_UNSWAP_ESCAPE_CAPSLOCK +#define EC_TOGG MAGIC_TOGGLE_ESCAPE_CAPSLOCK + #define LCG_SWP MAGIC_SWAP_LCTL_LGUI #define LCG_NRM MAGIC_UNSWAP_LCTL_LGUI #define RCG_SWP MAGIC_SWAP_RCTL_RGUI -- cgit v1.2.3 From 3ecb0a80af9e4ce4194a34032642933641730706 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sat, 2 Jul 2022 22:10:08 +1000 Subject: Feature-ify Send String (#17275) --- builddefs/common_features.mk | 8 +- docs/_summary.md | 1 + docs/feature_macros.md | 2 + docs/feature_send_string.md | 224 +++++++++ quantum/process_keycode/process_auto_shift.c | 2 + .../process_keycode/process_dynamic_tapping_term.c | 2 + quantum/quantum.h | 5 +- quantum/send_string.c | 322 ------------- quantum/send_string.h | 54 --- quantum/send_string/send_string.c | 324 +++++++++++++ quantum/send_string/send_string.h | 152 +++++++ quantum/send_string/send_string_keycodes.h | 434 ++++++++++++++++++ quantum/send_string_keycodes.h | 505 --------------------- 13 files changed, 1152 insertions(+), 883 deletions(-) create mode 100644 docs/feature_send_string.md delete mode 100644 quantum/send_string.c delete mode 100644 quantum/send_string.h create mode 100644 quantum/send_string/send_string.c create mode 100644 quantum/send_string/send_string.h create mode 100644 quantum/send_string/send_string_keycodes.h delete mode 100644 quantum/send_string_keycodes.h (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index c11e5688e3..5cc4508307 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -15,7 +15,6 @@ QUANTUM_SRC += \ $(QUANTUM_DIR)/quantum.c \ - $(QUANTUM_DIR)/send_string.c \ $(QUANTUM_DIR)/bitwise.c \ $(QUANTUM_DIR)/led.c \ $(QUANTUM_DIR)/action.c \ @@ -774,6 +773,13 @@ ifeq ($(strip $(MAGIC_ENABLE)), yes) OPT_DEFS += -DMAGIC_KEYCODE_ENABLE endif +SEND_STRING_ENABLE ?= yes +ifeq ($(strip $(SEND_STRING_ENABLE)), yes) + OPT_DEFS += -DSEND_STRING_ENABLE + COMMON_VPATH += $(QUANTUM_DIR)/send_string + SRC += $(QUANTUM_DIR)/send_string/send_string.c +endif + ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes) SRC += $(QUANTUM_DIR)/process_keycode/process_auto_shift.c OPT_DEFS += -DAUTO_SHIFT_ENABLE diff --git a/docs/_summary.md b/docs/_summary.md index da007bccb6..b5746ff6de 100644 --- a/docs/_summary.md +++ b/docs/_summary.md @@ -84,6 +84,7 @@ * [One Shot Keys](one_shot_keys.md) * [Pointing Device](feature_pointing_device.md) * [Raw HID](feature_rawhid.md) + * [Send String](feature_send_string.md) * [Sequencer](feature_sequencer.md) * [Swap Hands](feature_swap_hands.md) * [Tap Dance](feature_tap_dance.md) diff --git a/docs/feature_macros.md b/docs/feature_macros.md index 78bc4ba0a5..f5b163d5df 100644 --- a/docs/feature_macros.md +++ b/docs/feature_macros.md @@ -106,6 +106,8 @@ Only basic keycodes (prefixed by `KC_`) are supported. Do not include the `KC_` ### `SEND_STRING()` & `process_record_user` +See also: [Send String](feature_send_string.md) + Sometimes you want a key to type out words or phrases. For the most common situations, we've provided `SEND_STRING()`, which will type out a string (i.e. a sequence of characters) for you. All ASCII characters that are easily translatable to a keycode are supported (e.g. `qmk 123\n\t`). Here is an example `keymap.c` for a two-key keyboard: diff --git a/docs/feature_send_string.md b/docs/feature_send_string.md new file mode 100644 index 0000000000..67df0224e9 --- /dev/null +++ b/docs/feature_send_string.md @@ -0,0 +1,224 @@ +# Send String + +The Send String API is part of QMK's macro system. It allows for sequences of keystrokes to be sent automatically. + +The full ASCII character set is supported, along with all of the keycodes in the Basic Keycode range (as these are the only ones that will actually be sent to the host). + +?> Unicode characters are **not** supported with this API -- see the [Unicode](feature_unicode.md) feature instead. + +## Usage + +Send String is enabled by default, so there is usually no need for any special setup. However, if it is disabled, add the following to your `rules.mk`: + +```make +SEND_STRING_ENABLE = yes +``` + +## Basic Configuration + +Add the following to your `config.h`: + +|Define |Default |Description | +|-----------------|----------------|------------------------------------------------------------------------------------------------------------| +|`SENDSTRING_BELL`|*Not defined* |If the [Audio](feature_audio.md) feature is enabled, the `\a` character (ASCII `BEL`) will beep the speaker.| +|`BELL_SOUND` |`TERMINAL_SOUND`|The song to play when the `\a` character is encountered. By default, this is an eighth note of C5. | + +## Keycodes + +The Send String functions accept C string literals, but specific keycodes can be injected with the below macros. All of the keycodes in the [Basic Keycode range](keycodes_basic.md) are supported (as these are the only ones that will actually be sent to the host), but with an `X_` prefix instead of `KC_`. + +|Macro |Description | +|--------------|-------------------------------------------------------------------| +|`SS_TAP(x)` |Send a keydown, then keyup, event for the given Send String keycode| +|`SS_DOWN(x)` |Send a keydown event for the given Send String keycode | +|`SS_UP(x)` |Send a keyup event for the given Send String keycode | +|`SS_DELAY(ms)`|Wait for `ms` milliseconds | + +The following characters are also mapped to their respective keycodes for convenience: + +|Character|Hex |ASCII|Keycode | +|---------|------|-----|--------------| +|`\b` |`\x08`|`BS` |`KC_BACKSPACE`| +|`\e` |`\x09`|`ESC`|`KC_ESCAPE` | +|`\n` |`\x0A`|`LF` |`KC_ENTER` | +|`\t` |`\x1B`|`TAB`|`KC_TAB` | +| |`\x7F`|`DEL`|`KC_DELETE` | + +### Language Support + +By default, Send String assumes your OS keyboard layout is set to US ANSI. If you are using a different keyboard layout, you can [override the lookup tables used to convert ASCII characters to keystrokes](reference_keymap_extras.md#sendstring-support). + +## Examples + +### Hello World + +A simple custom keycode which types out "Hello, world!" and the Enter key when pressed. + +Add the following to your `keymap.c`: + +```c +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case SS_HELLO: + if (record->event.pressed) { + SEND_STRING("Hello, world!\n"); + } + return false; + } + + return true; +} +``` + +### Keycode Injection + +This example types out opening and closing curly braces, then taps the left arrow key to move the cursor between the two. + +```c +SEND_STRING("{}" SS_TAP(X_LEFT)); +``` + +This example types Ctrl+A, then Ctrl+C, without releasing Ctrl. + +```c +SEND_STRING(SS_LCTL("ac")); +``` + +## API + +### `void send_string(const char *string)` + +Type out a string of ASCII characters. + +This function simply calls `send_string_with_delay(string, 0)`. + +#### Arguments + + - `const char *string` + The string to type out. + +--- + +### `void send_string_with_delay(const char *string, uint8_t interval)` + +Type out a string of ASCII characters, with a delay between each character. + +#### Arguments + + - `const char *string` + The string to type out. + - `uint8_t interval` + The amount of time, in milliseconds, to wait before typing the next character. + +--- + +### `void send_string_P(const char *string)` + +Type out a PROGMEM string of ASCII characters. + +On ARM devices, this function is simply an alias for `send_string_with_delay(string, 0)`. + +#### Arguments + + - `const char *string` + The string to type out. + +--- + +### `void send_string_with_delay_P(const char *string, uint8_t interval)` + +Type out a PROGMEM string of ASCII characters, with a delay between each character. + +On ARM devices, this function is simply an alias for `send_string_with_delay(string, interval)`. + +#### Arguments + + - `const char *string` + The string to type out. + - `uint8_t interval` + The amount of time, in milliseconds, to wait before typing the next character. + +--- + +### `void send_char(char ascii_code)` + +Type out an ASCII character. + +#### Arguments + + - `char ascii_code` + The character to type. + +--- + +### `void send_dword(uint32_t number)` + +Type out an eight digit (unsigned 32-bit) hexadecimal value. + +The format is `[0-9a-f]{8}`, eg. `00000000` through `ffffffff`. + +#### Arguments + + - `uint32_t number` + The value to type, from 0 to 4,294,967,295. + +--- + +### `void send_word(uint16_t number)` + +Type out a four digit (unsigned 16-bit) hexadecimal value. + +The format is `[0-9a-f]{4}`, eg. `0000` through `ffff`. + +#### Arguments + + - `uint16_t number` + The value to type, from 0 to 65,535. + +--- + +### `void send_byte(uint8_t number)` + +Type out a two digit (8-bit) hexadecimal value. + +The format is `[0-9a-f]{2}`, eg. `00` through `ff`. + +#### Arguments + + - `uint8_t number` + The value to type, from 0 to 255. + +--- + +### `void send_nibble(uint8_t number)` + +Type out a single hexadecimal digit. + +The format is `[0-9a-f]{1}`, eg. `0` through `f`. + +#### Arguments + + - `uint8_t number` + The value to type, from 0 to 15. + +--- + +### `void tap_random_base64(void)` + +Type a pseudorandom character from the set `A-Z`, `a-z`, `0-9`, `+` and `/`. + +--- + +### `SEND_STRING(string)` + +Shortcut macro for `send_string_with_delay_P(PSTR(string), 0)`. + +On ARM devices, this define evaluates to `send_string_with_delay(string, 0)`. + +--- + +### `SEND_STRING_DELAY(string, interval)` + +Shortcut macro for `send_string_with_delay_P(PSTR(string), interval)`. + +On ARM devices, this define evaluates to `send_string_with_delay(string, interval)`. diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index e6a7c01f2a..8cb45bc0ae 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -325,11 +325,13 @@ void autoshift_disable(void) { # ifndef AUTO_SHIFT_NO_SETUP void autoshift_timer_report(void) { +# ifdef SEND_STRING_ENABLE char display[8]; snprintf(display, 8, "\n%d\n", autoshift_timeout); send_string((const char *)display); +# endif } # endif diff --git a/quantum/process_keycode/process_dynamic_tapping_term.c b/quantum/process_keycode/process_dynamic_tapping_term.c index bdc5529e33..b682f34da6 100644 --- a/quantum/process_keycode/process_dynamic_tapping_term.c +++ b/quantum/process_keycode/process_dynamic_tapping_term.c @@ -22,12 +22,14 @@ #endif static void tapping_term_report(void) { +#ifdef SEND_STRING_ENABLE const char *tapping_term_str = get_u16_str(g_tapping_term, ' '); // Skip padding spaces while (*tapping_term_str == ' ') { tapping_term_str++; } send_string(tapping_term_str); +#endif } bool process_dynamic_tapping_term(uint16_t keycode, keyrecord_t *record) { diff --git a/quantum/quantum.h b/quantum/quantum.h index 8a7a20c706..f3a8a323c7 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -49,7 +49,6 @@ #include "action_util.h" #include "action_tapping.h" #include "print.h" -#include "send_string.h" #include "suspend.h" #include #include @@ -169,6 +168,10 @@ extern layer_state_t layer_state; # include "hd44780.h" #endif +#ifdef SEND_STRING_ENABLE +# include "send_string.h" +#endif + #ifdef HAPTIC_ENABLE # include "haptic.h" # include "process_haptic.h" diff --git a/quantum/send_string.c b/quantum/send_string.c deleted file mode 100644 index 0de12ba12d..0000000000 --- a/quantum/send_string.c +++ /dev/null @@ -1,322 +0,0 @@ -/* Copyright 2021 - * - * 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 . - */ - -#include - -#include "quantum.h" - -#include "send_string.h" - -#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL) -# include "audio.h" -# ifndef BELL_SOUND -# define BELL_SOUND TERMINAL_SOUND -# endif -float bell_song[][2] = SONG(BELL_SOUND); -#endif - -// clang-format off - -/* Bit-Packed look-up table to convert an ASCII character to whether - * [Shift] needs to be sent with the keycode. - */ -__attribute__((weak)) 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, 1, 1, 1, 1, 0), - KCLUT_ENTRY(1, 1, 1, 1, 0, 0, 0, 0), - KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), - KCLUT_ENTRY(0, 0, 1, 0, 1, 0, 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, 1, 1, 1, 1), - KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 1, 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, 1, 1, 1, 1, 0) -}; - -/* Bit-Packed look-up table to convert an ASCII character to whether - * [AltGr] needs to be sent with the keycode. - */ -__attribute__((weak)) 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(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) -}; - -/* Bit-Packed look-up table to convert an ASCII character to whether - * [Space] needs to be sent after the keycode - */ -__attribute__((weak)) 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, 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) -}; - -/* Look-up table to convert an ASCII character to a keycode. - */ -__attribute__((weak)) 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, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, - // ( ) * + , - . / - KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, - // 0 1 2 3 4 5 6 7 - KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, - // 8 9 : ; < = > ? - KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, - // @ A B C D E F G - KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, - // H I J K L M N O - KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, - // P Q R S T U V W - KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, - // X Y Z [ \ ] ^ _ - KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, - // ` a b c d e f g - KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, - // h i j k l m n o - KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, - // p q r s t u v w - KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, - // x y z { | } ~ DEL - KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL -}; - -// clang-format on - -// Note: we bit-pack in "reverse" order to optimize loading -#define PGM_LOADBIT(mem, pos) ((pgm_read_byte(&((mem)[(pos) / 8])) >> ((pos) % 8)) & 0x01) - -void send_string(const char *str) { - send_string_with_delay(str, 0); -} - -void send_string_P(const char *str) { - send_string_with_delay_P(str, 0); -} - -void send_string_with_delay(const char *str, uint8_t interval) { - while (1) { - char ascii_code = *str; - if (!ascii_code) break; - if (ascii_code == SS_QMK_PREFIX) { - ascii_code = *(++str); - if (ascii_code == SS_TAP_CODE) { - // tap - uint8_t keycode = *(++str); - tap_code(keycode); - } else if (ascii_code == SS_DOWN_CODE) { - // down - uint8_t keycode = *(++str); - register_code(keycode); - } else if (ascii_code == SS_UP_CODE) { - // up - uint8_t keycode = *(++str); - unregister_code(keycode); - } else if (ascii_code == SS_DELAY_CODE) { - // delay - int ms = 0; - uint8_t keycode = *(++str); - while (isdigit(keycode)) { - ms *= 10; - ms += keycode - '0'; - keycode = *(++str); - } - while (ms--) - wait_ms(1); - } - } else { - send_char(ascii_code); - } - ++str; - // interval - { - uint8_t ms = interval; - while (ms--) - wait_ms(1); - } - } -} - -void send_string_with_delay_P(const char *str, uint8_t interval) { - while (1) { - char ascii_code = pgm_read_byte(str); - if (!ascii_code) break; - if (ascii_code == SS_QMK_PREFIX) { - ascii_code = pgm_read_byte(++str); - if (ascii_code == SS_TAP_CODE) { - // tap - uint8_t keycode = pgm_read_byte(++str); - tap_code(keycode); - } else if (ascii_code == SS_DOWN_CODE) { - // down - uint8_t keycode = pgm_read_byte(++str); - register_code(keycode); - } else if (ascii_code == SS_UP_CODE) { - // up - uint8_t keycode = pgm_read_byte(++str); - unregister_code(keycode); - } else if (ascii_code == SS_DELAY_CODE) { - // delay - int ms = 0; - uint8_t keycode = pgm_read_byte(++str); - while (isdigit(keycode)) { - ms *= 10; - ms += keycode - '0'; - keycode = pgm_read_byte(++str); - } - while (ms--) - wait_ms(1); - } - } else { - send_char(ascii_code); - } - ++str; - // interval - { - uint8_t ms = interval; - while (ms--) - wait_ms(1); - } - } -} - -void send_char(char ascii_code) { -#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL) - if (ascii_code == '\a') { // BEL - PLAY_SONG(bell_song); - return; - } -#endif - - uint8_t keycode = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]); - bool is_shifted = PGM_LOADBIT(ascii_to_shift_lut, (uint8_t)ascii_code); - bool is_altgred = PGM_LOADBIT(ascii_to_altgr_lut, (uint8_t)ascii_code); - bool is_dead = PGM_LOADBIT(ascii_to_dead_lut, (uint8_t)ascii_code); - - if (is_shifted) { - register_code(KC_LSFT); - } - if (is_altgred) { - register_code(KC_RALT); - } - tap_code(keycode); - if (is_altgred) { - unregister_code(KC_RALT); - } - if (is_shifted) { - unregister_code(KC_LSFT); - } - if (is_dead) { - tap_code(KC_SPACE); - } -} - -void send_dword(uint32_t number) { - send_word(number >> 16); - send_word(number & 0xFFFFUL); -} - -void send_word(uint16_t number) { - send_byte(number >> 8); - send_byte(number & 0xFF); -} - -void send_byte(uint8_t number) { - send_nibble(number >> 4); - send_nibble(number & 0xF); -} - -void send_nibble(uint8_t number) { - switch (number & 0xF) { - case 0 ... 9: - send_char(number + '0'); - break; - case 10 ... 15: - send_char(number - 10 + 'a'); - break; - } -} - -void tap_random_base64(void) { -#if defined(__AVR_ATmega32U4__) - uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64; -#else - uint8_t key = rand() % 64; -#endif - switch (key) { - case 0 ... 25: - send_char(key + 'A'); - break; - case 26 ... 51: - send_char(key - 26 + 'a'); - break; - case 52: - send_char('0'); - break; - case 53 ... 61: - send_char(key - 53 + '1'); - break; - case 62: - send_char('+'); - break; - case 63: - send_char('/'); - break; - } -} diff --git a/quantum/send_string.h b/quantum/send_string.h deleted file mode 100644 index b90e6f6890..0000000000 --- a/quantum/send_string.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright 2021 - * - * 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 . - */ - -#include - -#include "progmem.h" -#include "send_string_keycodes.h" - -#define SEND_STRING(string) send_string_P(PSTR(string)) -#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval) - -// Look-Up Tables (LUTs) to convert ASCII character to keycode sequence. -extern const uint8_t ascii_to_shift_lut[16]; -extern const uint8_t ascii_to_altgr_lut[16]; -extern const uint8_t ascii_to_dead_lut[16]; -extern const uint8_t ascii_to_keycode_lut[128]; - -// clang-format off -#define KCLUT_ENTRY(a, b, c, d, e, f, g, h) \ - ( ((a) ? 1 : 0) << 0 \ - | ((b) ? 1 : 0) << 1 \ - | ((c) ? 1 : 0) << 2 \ - | ((d) ? 1 : 0) << 3 \ - | ((e) ? 1 : 0) << 4 \ - | ((f) ? 1 : 0) << 5 \ - | ((g) ? 1 : 0) << 6 \ - | ((h) ? 1 : 0) << 7 ) -// clang-format on - -void send_string(const char *str); -void send_string_with_delay(const char *str, uint8_t interval); -void send_string_P(const char *str); -void send_string_with_delay_P(const char *str, uint8_t interval); -void send_char(char ascii_code); - -void send_dword(uint32_t number); -void send_word(uint16_t number); -void send_byte(uint8_t number); -void send_nibble(uint8_t number); - -void tap_random_base64(void); diff --git a/quantum/send_string/send_string.c b/quantum/send_string/send_string.c new file mode 100644 index 0000000000..818a52f6dc --- /dev/null +++ b/quantum/send_string/send_string.c @@ -0,0 +1,324 @@ +/* Copyright 2021 + * + * 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 . + */ + +#include + +#include "quantum.h" + +#include "send_string.h" + +#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL) +# include "audio.h" +# ifndef BELL_SOUND +# define BELL_SOUND TERMINAL_SOUND +# endif +float bell_song[][2] = SONG(BELL_SOUND); +#endif + +// clang-format off + +/* Bit-Packed look-up table to convert an ASCII character to whether + * [Shift] needs to be sent with the keycode. + */ +__attribute__((weak)) 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, 1, 1, 1, 1, 0), + KCLUT_ENTRY(1, 1, 1, 1, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 1, 0, 1, 0, 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, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 1, 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, 1, 1, 1, 1, 0) +}; + +/* Bit-Packed look-up table to convert an ASCII character to whether + * [AltGr] needs to be sent with the keycode. + */ +__attribute__((weak)) 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(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) +}; + +/* Bit-Packed look-up table to convert an ASCII character to whether + * [Space] needs to be sent after the keycode + */ +__attribute__((weak)) 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, 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) +}; + +/* Look-up table to convert an ASCII character to a keycode. + */ +__attribute__((weak)) 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, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, + // ( ) * + , - . / + KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, + // 0 1 2 3 4 5 6 7 + KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, + // 8 9 : ; < = > ? + KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, + // @ A B C D E F G + KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + // H I J K L M N O + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + // P Q R S T U V W + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + // X Y Z [ \ ] ^ _ + KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, + // ` a b c d e f g + KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + // h i j k l m n o + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + // p q r s t u v w + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + // x y z { | } ~ DEL + KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL +}; + +// clang-format on + +// Note: we bit-pack in "reverse" order to optimize loading +#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); +} + +void send_string_with_delay(const char *string, uint8_t interval) { + while (1) { + char ascii_code = *string; + if (!ascii_code) break; + if (ascii_code == SS_QMK_PREFIX) { + ascii_code = *(++string); + if (ascii_code == SS_TAP_CODE) { + // tap + uint8_t keycode = *(++string); + tap_code(keycode); + } else if (ascii_code == SS_DOWN_CODE) { + // down + uint8_t keycode = *(++string); + register_code(keycode); + } else if (ascii_code == SS_UP_CODE) { + // up + uint8_t keycode = *(++string); + unregister_code(keycode); + } else if (ascii_code == SS_DELAY_CODE) { + // delay + int ms = 0; + uint8_t keycode = *(++string); + while (isdigit(keycode)) { + ms *= 10; + ms += keycode - '0'; + keycode = *(++string); + } + while (ms--) + wait_ms(1); + } + } else { + send_char(ascii_code); + } + ++string; + // interval + { + uint8_t ms = interval; + while (ms--) + wait_ms(1); + } + } +} + +void send_char(char ascii_code) { +#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL) + if (ascii_code == '\a') { // BEL + PLAY_SONG(bell_song); + return; + } +#endif + + uint8_t keycode = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]); + bool is_shifted = PGM_LOADBIT(ascii_to_shift_lut, (uint8_t)ascii_code); + bool is_altgred = PGM_LOADBIT(ascii_to_altgr_lut, (uint8_t)ascii_code); + bool is_dead = PGM_LOADBIT(ascii_to_dead_lut, (uint8_t)ascii_code); + + if (is_shifted) { + register_code(KC_LEFT_SHIFT); + } + if (is_altgred) { + register_code(KC_RIGHT_ALT); + } + tap_code(keycode); + if (is_altgred) { + unregister_code(KC_RIGHT_ALT); + } + if (is_shifted) { + unregister_code(KC_LEFT_SHIFT); + } + if (is_dead) { + tap_code(KC_SPACE); + } +} + +void send_dword(uint32_t number) { + send_word(number >> 16); + send_word(number & 0xFFFFUL); +} + +void send_word(uint16_t number) { + send_byte(number >> 8); + send_byte(number & 0xFF); +} + +void send_byte(uint8_t number) { + send_nibble(number >> 4); + send_nibble(number & 0xF); +} + +void send_nibble(uint8_t number) { + switch (number & 0xF) { + case 0 ... 9: + send_char(number + '0'); + break; + case 10 ... 15: + send_char(number - 10 + 'a'); + break; + } +} + +void tap_random_base64(void) { +#if defined(__AVR_ATmega32U4__) + uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64; +#else + uint8_t key = rand() % 64; +#endif + switch (key) { + case 0 ... 25: + send_char(key + 'A'); + break; + case 26 ... 51: + send_char(key - 26 + 'a'); + break; + case 52: + send_char('0'); + break; + case 53 ... 61: + send_char(key - 53 + '1'); + break; + case 62: + send_char('+'); + break; + case 63: + send_char('/'); + break; + } +} + +#if defined(__AVR__) +void send_string_P(const char *string) { + send_string_with_delay_P(string, 0); +} + +void send_string_with_delay_P(const char *string, uint8_t interval) { + while (1) { + char ascii_code = pgm_read_byte(string); + if (!ascii_code) break; + if (ascii_code == SS_QMK_PREFIX) { + ascii_code = pgm_read_byte(++string); + if (ascii_code == SS_TAP_CODE) { + // tap + uint8_t keycode = pgm_read_byte(++string); + tap_code(keycode); + } else if (ascii_code == SS_DOWN_CODE) { + // down + uint8_t keycode = pgm_read_byte(++string); + register_code(keycode); + } else if (ascii_code == SS_UP_CODE) { + // up + uint8_t keycode = pgm_read_byte(++string); + unregister_code(keycode); + } else if (ascii_code == SS_DELAY_CODE) { + // delay + int ms = 0; + uint8_t keycode = pgm_read_byte(++string); + while (isdigit(keycode)) { + ms *= 10; + ms += keycode - '0'; + keycode = pgm_read_byte(++string); + } + while (ms--) + wait_ms(1); + } + } else { + send_char(ascii_code); + } + ++string; + // interval + { + uint8_t ms = interval; + while (ms--) + wait_ms(1); + } + } +} +#endif diff --git a/quantum/send_string/send_string.h b/quantum/send_string/send_string.h new file mode 100644 index 0000000000..4eb55b88dc --- /dev/null +++ b/quantum/send_string/send_string.h @@ -0,0 +1,152 @@ +/* Copyright 2021 + * + * 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 . + */ + +/** + * \defgroup send_string + * + * Send String API. These functions allow you to create macros by typing out sequences of keystrokes. + * \{ + */ + +#include + +#include "progmem.h" +#include "send_string_keycodes.h" + +// Look-Up Tables (LUTs) to convert ASCII character to keycode sequence. +extern const uint8_t ascii_to_shift_lut[16]; +extern const uint8_t ascii_to_altgr_lut[16]; +extern const uint8_t ascii_to_dead_lut[16]; +extern const uint8_t ascii_to_keycode_lut[128]; + +// clang-format off +#define KCLUT_ENTRY(a, b, c, d, e, f, g, h) \ + ( ((a) ? 1 : 0) << 0 \ + | ((b) ? 1 : 0) << 1 \ + | ((c) ? 1 : 0) << 2 \ + | ((d) ? 1 : 0) << 3 \ + | ((e) ? 1 : 0) << 4 \ + | ((f) ? 1 : 0) << 5 \ + | ((g) ? 1 : 0) << 6 \ + | ((h) ? 1 : 0) << 7 ) +// clang-format on + +/** + * \brief Type out a string of ASCII characters. + * + * This function simply calls `send_string_with_delay(string, 0)`. + * + * Most keycodes from the basic keycode range are also supported by way of a special sequence - see `send_string_keycodes.h`. + * + * \param string The string to type out. + */ +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. + */ +void send_string_with_delay(const char *string, uint8_t interval); + +/** + * \brief Type out an ASCII character. + * + * \param ascii_code The character to type. + */ +void send_char(char ascii_code); + +/** + * \brief Type out an eight digit (unsigned 32-bit) hexadecimal value. + * + * The format is `[0-9a-f]{8}`, eg. `00000000` through `ffffffff`. + * + * \param number The value to type, from 0 to 4,294,967,295. + */ +void send_dword(uint32_t number); + +/** + * \brief Type out a four digit (unsigned 16-bit) hexadecimal value. + * + * The format is `[0-9a-f]{4}`, eg. `0000` through `ffff`. + * + * \param number The value to type, from 0 to 65,535. + */ +void send_word(uint16_t number); + +/** + * \brief Type out a two digit (8-bit) hexadecimal value. + * + * The format is `[0-9a-f]{2}`, eg. `00` through `ff`. + * + * \param number The value to type, from 0 to 255. + */ +void send_byte(uint8_t number); + +/** + * \brief Type out a single hexadecimal digit. + * + * The format is `[0-9a-f]{1}`, eg. `0` through `f`. + * + * \param number The value to type, from 0 to 15. + */ +void send_nibble(uint8_t number); + +/** + * \brief Type a pseudorandom character from the set `A-Z`, `a-z`, `0-9`, `+` and `/`. + */ +void tap_random_base64(void); + +#if defined(__AVR__) || defined(__DOXYGEN__) +/** + * \brief Type out a PROGMEM string of ASCII characters. + * + * On ARM devices, this function is simply an alias for send_string_with_delay(string, 0). + * + * \param string The string to type out. + */ +void send_string_P(const char *string); + +/** + * \brief Type out a PROGMEM string of ASCII characters, with a delay between each character. + * + * On ARM devices, this function is simply an alias for send_string_with_delay(string, interval). + * + * \param string The string to type out. + * \param interval The amount of time, in milliseconds, to wait before typing the next character. + */ +void send_string_with_delay_P(const char *string, uint8_t interval); +#else +# define send_string_P(string) send_string_with_delay(string, 0) +# define send_string_with_delay_P(string, interval) send_string_with_delay(string, interval) +#endif + +/** + * \brief Shortcut macro for send_string_with_delay_P(PSTR(string), 0). + * + * On ARM devices, this define evaluates to send_string_with_delay(string, 0). + */ +#define SEND_STRING(string) send_string_with_delay_P(PSTR(string), 0) + +/** + * \brief Shortcut macro for send_string_with_delay_P(PSTR(string), interval). + * + * On ARM devices, this define evaluates to send_string_with_delay(string, interval). + */ +#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval) + +/** \} */ diff --git a/quantum/send_string/send_string_keycodes.h b/quantum/send_string/send_string_keycodes.h new file mode 100644 index 0000000000..7017e03d5a --- /dev/null +++ b/quantum/send_string/send_string_keycodes.h @@ -0,0 +1,434 @@ +/* Copyright 2019 + * + * 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 . + */ + +#pragma once + +// clang-format off + +/* Punctuation */ +#define X_ENT X_ENTER +#define X_ESC X_ESCAPE +#define X_BSPC X_BSPACE +#define X_SPC X_SPACE +#define X_MINS X_MINUS +#define X_EQL X_EQUAL +#define X_LBRC X_LBRACKET +#define X_RBRC X_RBRACKET +#define X_BSLS X_BSLASH +#define X_NUHS X_NONUS_HASH +#define X_SCLN X_SCOLON +#define X_QUOT X_QUOTE +#define X_GRV X_GRAVE +#define X_COMM X_COMMA +#define X_SLSH X_SLASH +#define X_NUBS X_NONUS_BSLASH + +/* Lock Keys */ +#define X_CLCK X_CAPSLOCK +#define X_CAPS X_CAPSLOCK +#define X_SLCK X_SCROLLLOCK +#define X_NLCK X_NUMLOCK +#define X_LCAP X_LOCKING_CAPS +#define X_LNUM X_LOCKING_NUM +#define X_LSCR X_LOCKING_SCROLL + +/* Commands */ +#define X_PSCR X_PSCREEN +#define X_PAUS X_PAUSE +#define X_BRK X_PAUSE +#define X_INS X_INSERT +#define X_DEL X_DELETE +#define X_PGDN X_PGDOWN +#define X_RGHT X_RIGHT +#define X_APP X_APPLICATION +#define X_EXEC X_EXECUTE +#define X_SLCT X_SELECT +#define X_AGIN X_AGAIN +#define X_PSTE X_PASTE +#define X_ERAS X_ALT_ERASE +#define X_CLR X_CLEAR + +/* Keypad */ +#define X_PSLS X_KP_SLASH +#define X_PAST X_KP_ASTERISK +#define X_PMNS X_KP_MINUS +#define X_PPLS X_KP_PLUS +#define X_PENT X_KP_ENTER +#define X_P1 X_KP_1 +#define X_P2 X_KP_2 +#define X_P3 X_KP_3 +#define X_P4 X_KP_4 +#define X_P5 X_KP_5 +#define X_P6 X_KP_6 +#define X_P7 X_KP_7 +#define X_P8 X_KP_8 +#define X_P9 X_KP_9 +#define X_P0 X_KP_0 +#define X_PDOT X_KP_DOT +#define X_PEQL X_KP_EQUAL +#define X_PCMM X_KP_COMMA + +/* Japanese specific */ +#define X_ZKHK X_GRAVE +#define X_RO X_INT1 +#define X_KANA X_INT2 +#define X_JYEN X_INT3 +#define X_HENK X_INT4 +#define X_MHEN X_INT5 + +/* Korean specific */ +#define X_HAEN X_LANG1 +#define X_HANJ X_LANG2 + +/* Modifiers */ +#define X_LCTL X_LCTRL +#define X_LSFT X_LSHIFT +#define X_LOPT X_LALT +#define X_LCMD X_LGUI +#define X_LWIN X_LGUI +#define X_RCTL X_RCTRL +#define X_RSFT X_RSHIFT +#define X_ALGR X_RALT +#define X_ROPT X_RALT +#define X_RCMD X_RGUI +#define X_RWIN X_RGUI + +/* Generic Desktop Page (0x01) */ +#define X_PWR X_SYSTEM_POWER +#define X_SLEP X_SYSTEM_SLEEP +#define X_WAKE X_SYSTEM_WAKE + +/* Consumer Page (0x0C) */ +#define X_MUTE X_AUDIO_MUTE +#define X_VOLU X_AUDIO_VOL_UP +#define X_VOLD X_AUDIO_VOL_DOWN +#define X_MNXT X_MEDIA_NEXT_TRACK +#define X_MPRV X_MEDIA_PREV_TRACK +#define X_MSTP X_MEDIA_STOP +#define X_MPLY X_MEDIA_PLAY_PAUSE +#define X_MSEL X_MEDIA_SELECT +#define X_EJCT X_MEDIA_EJECT +#define X_CALC X_CALCULATOR +#define X_MYCM X_MY_COMPUTER +#define X_WSCH X_WWW_SEARCH +#define X_WHOM X_WWW_HOME +#define X_WBAK X_WWW_BACK +#define X_WFWD X_WWW_FORWARD +#define X_WSTP X_WWW_STOP +#define X_WREF X_WWW_REFRESH +#define X_WFAV X_WWW_FAVORITES +#define X_MFFD X_MEDIA_FAST_FORWARD +#define X_MRWD X_MEDIA_REWIND +#define X_BRIU X_BRIGHTNESS_UP +#define X_BRID X_BRIGHTNESS_DOWN + +/* System Specific */ +#define X_BRMU X_PAUSE +#define X_BRMD X_SCROLLLOCK + +/* Mouse Keys */ +#define X_MS_U X_MS_UP +#define X_MS_D X_MS_DOWN +#define X_MS_L X_MS_LEFT +#define X_MS_R X_MS_RIGHT +#define X_BTN1 X_MS_BTN1 +#define X_BTN2 X_MS_BTN2 +#define X_BTN3 X_MS_BTN3 +#define X_BTN4 X_MS_BTN4 +#define X_BTN5 X_MS_BTN5 +#define X_WH_U X_MS_WH_UP +#define X_WH_D X_MS_WH_DOWN +#define X_WH_L X_MS_WH_LEFT +#define X_WH_R X_MS_WH_RIGHT +#define X_ACL0 X_MS_ACCEL0 +#define X_ACL1 X_MS_ACCEL1 +#define X_ACL2 X_MS_ACCEL2 + +/* Keyboard/Keypad Page (0x07) */ +#define X_A 04 +#define X_B 05 +#define X_C 06 +#define X_D 07 +#define X_E 08 +#define X_F 09 +#define X_G 0a +#define X_H 0b +#define X_I 0c +#define X_J 0d +#define X_K 0e +#define X_L 0f +#define X_M 10 +#define X_N 11 +#define X_O 12 +#define X_P 13 +#define X_Q 14 +#define X_R 15 +#define X_S 16 +#define X_T 17 +#define X_U 18 +#define X_V 19 +#define X_W 1a +#define X_X 1b +#define X_Y 1c +#define X_Z 1d +#define X_1 1e +#define X_2 1f +#define X_3 20 +#define X_4 21 +#define X_5 22 +#define X_6 23 +#define X_7 24 +#define X_8 25 +#define X_9 26 +#define X_0 27 +#define X_ENTER 28 +#define X_ESCAPE 29 +#define X_BSPACE 2a +#define X_TAB 2b +#define X_SPACE 2c +#define X_MINUS 2d +#define X_EQUAL 2e +#define X_LBRACKET 2f +#define X_RBRACKET 30 +#define X_BSLASH 31 +#define X_NONUS_HASH 32 +#define X_SCOLON 33 +#define X_QUOTE 34 +#define X_GRAVE 35 +#define X_COMMA 36 +#define X_DOT 37 +#define X_SLASH 38 +#define X_CAPSLOCK 39 +#define X_F1 3a +#define X_F2 3b +#define X_F3 3c +#define X_F4 3d +#define X_F5 3e +#define X_F6 3f +#define X_F7 40 +#define X_F8 41 +#define X_F9 42 +#define X_F10 43 +#define X_F11 44 +#define X_F12 45 +#define X_PSCREEN 46 +#define X_SCROLLLOCK 47 +#define X_PAUSE 48 +#define X_INSERT 49 +#define X_HOME 4a +#define X_PGUP 4b +#define X_DELETE 4c +#define X_END 4d +#define X_PGDOWN 4e +#define X_RIGHT 4f +#define X_LEFT 50 +#define X_DOWN 51 +#define X_UP 52 +#define X_NUMLOCK 53 +#define X_KP_SLASH 54 +#define X_KP_ASTERISK 55 +#define X_KP_MINUS 56 +#define X_KP_PLUS 57 +#define X_KP_ENTER 58 +#define X_KP_1 59 +#define X_KP_2 5a +#define X_KP_3 5b +#define X_KP_4 5c +#define X_KP_5 5d +#define X_KP_6 5e +#define X_KP_7 5f +#define X_KP_8 60 +#define X_KP_9 61 +#define X_KP_0 62 +#define X_KP_DOT 63 +#define X_NONUS_BSLASH 64 +#define X_APPLICATION 65 +#define X_POWER 66 +#define X_KP_EQUAL 67 +#define X_F13 68 +#define X_F14 69 +#define X_F15 6a +#define X_F16 6b +#define X_F17 6c +#define X_F18 6d +#define X_F19 6e +#define X_F20 6f +#define X_F21 70 +#define X_F22 71 +#define X_F23 72 +#define X_F24 73 +#define X_EXECUTE 74 +#define X_HELP 75 +#define X_MENU 76 +#define X_SELECT 77 +#define X_STOP 78 +#define X_AGAIN 79 +#define X_UNDO 7a +#define X_CUT 7b +#define X_COPY 7c +#define X_PASTE 7d +#define X_FIND 7e +#define X__MUTE 7f +#define X__VOLUP 80 +#define X__VOLDOWN 81 +#define X_LOCKING_CAPS 82 +#define X_LOCKING_NUM 83 +#define X_LOCKING_SCROLL 84 +#define X_KP_COMMA 85 +#define X_KP_EQUAL_AS400 86 +#define X_INT1 87 +#define X_INT2 88 +#define X_INT3 89 +#define X_INT4 8a +#define X_INT5 8b +#define X_INT6 8c +#define X_INT7 8d +#define X_INT8 8e +#define X_INT9 8f +#define X_LANG1 90 +#define X_LANG2 91 +#define X_LANG3 92 +#define X_LANG4 93 +#define X_LANG5 94 +#define X_LANG6 95 +#define X_LANG7 96 +#define X_LANG8 97 +#define X_LANG9 98 +#define X_ALT_ERASE 99 +#define X_SYSREQ 9a +#define X_CANCEL 9b +#define X_CLEAR 9c +#define X_PRIOR 9d +#define X_RETURN 9e +#define X_SEPARATOR 9f +#define X_OUT a0 +#define X_OPER a1 +#define X_CLEAR_AGAIN a2 +#define X_CRSEL a3 +#define X_EXSEL a4 + +/* Modifiers */ +#define X_LCTRL e0 +#define X_LSHIFT e1 +#define X_LALT e2 +#define X_LGUI e3 +#define X_RCTRL e4 +#define X_RSHIFT e5 +#define X_RALT e6 +#define X_RGUI e7 + +/* Media and Function keys */ +/* Generic Desktop Page (0x01) */ +#define X_SYSTEM_POWER a5 +#define X_SYSTEM_SLEEP a6 +#define X_SYSTEM_WAKE a7 + +/* Consumer Page (0x0C) */ +#define X_AUDIO_MUTE a8 +#define X_AUDIO_VOL_UP a9 +#define X_AUDIO_VOL_DOWN aa +#define X_MEDIA_NEXT_TRACK ab +#define X_MEDIA_PREV_TRACK ac +#define X_MEDIA_STOP ad +#define X_MEDIA_PLAY_PAUSE ae +#define X_MEDIA_SELECT af +#define X_MEDIA_EJECT b0 +#define X_MAIL b1 +#define X_CALCULATOR b2 +#define X_MY_COMPUTER b3 +#define X_WWW_SEARCH b4 +#define X_WWW_HOME b5 +#define X_WWW_BACK b6 +#define X_WWW_FORWARD b7 +#define X_WWW_STOP b8 +#define X_WWW_REFRESH b9 +#define X_WWW_FAVORITES ba +#define X_MEDIA_FAST_FORWARD bb +#define X_MEDIA_REWIND bc +#define X_BRIGHTNESS_UP bd +#define X_BRIGHTNESS_DOWN be + +/* Mouse Buttons (unallocated range in HID spec) */ +#ifdef VIA_ENABLE +#define X_MS_UP f0 +#define X_MS_DOWN f1 +#define X_MS_LEFT f2 +#define X_MS_RIGHT f3 +#define X_MS_BTN1 f4 +#define X_MS_BTN2 f5 +#define X_MS_BTN3 f6 +#define X_MS_BTN4 f7 +#define X_MS_BTN5 f8 +#define X_MS_BTN6 f8 +#define X_MS_BTN7 f8 +#define X_MS_BTN8 f8 +#else +#define X_MS_UP ed +#define X_MS_DOWN ee +#define X_MS_LEFT ef +#define X_MS_RIGHT f0 +#define X_MS_BTN1 f1 +#define X_MS_BTN2 f2 +#define X_MS_BTN3 f3 +#define X_MS_BTN4 f4 +#define X_MS_BTN5 f5 +#define X_MS_BTN6 f6 +#define X_MS_BTN7 f7 +#define X_MS_BTN8 f8 +#endif +#define X_MS_WH_UP f9 +#define X_MS_WH_DOWN fa +#define X_MS_WH_LEFT fb +#define X_MS_WH_RIGHT fc +#define X_MS_ACCEL0 fd +#define X_MS_ACCEL1 fe +#define X_MS_ACCEL2 ff + +// Send string macros +#define STRINGIZE(z) #z +#define ADD_SLASH_X(y) STRINGIZE(\x##y) +#define SYMBOL_STR(x) ADD_SLASH_X(x) + +#define SS_QMK_PREFIX 1 + +#define SS_TAP_CODE 1 +#define SS_DOWN_CODE 2 +#define SS_UP_CODE 3 +#define SS_DELAY_CODE 4 + +#define SS_TAP(keycode) "\1\1" SYMBOL_STR(keycode) +#define SS_DOWN(keycode) "\1\2" SYMBOL_STR(keycode) +#define SS_UP(keycode) "\1\3" SYMBOL_STR(keycode) +#define SS_DELAY(msecs) "\1\4" STRINGIZE(msecs) "|" + +// `string` arguments must not be parenthesized +#define SS_LCTL(string) SS_DOWN(X_LCTL) string SS_UP(X_LCTL) +#define SS_LSFT(string) SS_DOWN(X_LSFT) string SS_UP(X_LSFT) +#define SS_LALT(string) SS_DOWN(X_LALT) string SS_UP(X_LALT) +#define SS_LGUI(string) SS_DOWN(X_LGUI) string SS_UP(X_LGUI) +#define SS_LCMD(string) SS_LGUI(string) +#define SS_LWIN(string) SS_LGUI(string) + +#define SS_RCTL(string) SS_DOWN(X_RCTL) string SS_UP(X_RCTL) +#define SS_RSFT(string) SS_DOWN(X_RSFT) string SS_UP(X_RSFT) +#define SS_RALT(string) SS_DOWN(X_RALT) string SS_UP(X_RALT) +#define SS_RGUI(string) SS_DOWN(X_RGUI) string SS_UP(X_RGUI) +#define SS_ALGR(string) SS_RALT(string) +#define SS_RCMD(string) SS_RGUI(string) +#define SS_RWIN(string) SS_RGUI(string) + +// DEPRECATED +#define SS_LCTRL(string) SS_LCTL(string) diff --git a/quantum/send_string_keycodes.h b/quantum/send_string_keycodes.h deleted file mode 100644 index b35bf66b7b..0000000000 --- a/quantum/send_string_keycodes.h +++ /dev/null @@ -1,505 +0,0 @@ -/* Copyright 2019 - * - * 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 . - */ - -#pragma once - -// clang-format off - -/* Punctuation */ -#define X_ENT X_ENTER -#define X_ESC X_ESCAPE -#define X_BSPC X_BACKSPACE -#define X_SPC X_SPACE -#define X_MINS X_MINUS -#define X_EQL X_EQUAL -#define X_LBRC X_LEFT_BRACKET -#define X_RBRC X_RIGHT_BRACKET -#define X_BSLS X_BACKSLASH -#define X_NUHS X_NONUS_HASH -#define X_SCLN X_SEMICOLON -#define X_QUOT X_QUOTE -#define X_GRV X_GRAVE -#define X_COMM X_COMMA -#define X_SLSH X_SLASH -#define X_NUBS X_NONUS_BACKSLASH - -/* Lock Keys */ -#define X_CAPS X_CAPS_LOCK -#define X_SCRL X_SCROLL_LOCK -#define X_NUM X_NUM_LOCK -#define X_LCAP X_LOCKING_CAPS_LOCK -#define X_LNUM X_LOCKING_NUM_LOCK -#define X_LSCR X_LOCKING_SCROLL_LOCK - -/* Commands */ -#define X_PSCR X_PRINT_SCREEN -#define X_PAUS X_PAUSE -#define X_BRK X_PAUSE -#define X_INS X_INSERT -#define X_PGUP X_PAGE_UP -#define X_DEL X_DELETE -#define X_PGDN X_PAGE_DOWN -#define X_RGHT X_RIGHT -#define X_APP X_APPLICATION -#define X_EXEC X_EXECUTE -#define X_SLCT X_SELECT -#define X_AGIN X_AGAIN -#define X_PSTE X_PASTE -#define X_ERAS X_ALTERNATE_ERASE -#define X_SYRQ X_SYSTEM_REQUEST -#define X_CNCL X_CANCEL -#define X_CLR X_CLEAR -#define X_PRIR X_PRIOR -#define X_RETN X_RETURN -#define X_SEPR X_SEPARATOR -#define X_CLAG X_CLEAR_AGAIN -#define X_CRSL X_CRSEL -#define X_EXSL X_EXSEL - -/* Keypad */ -#define X_PSLS X_KP_SLASH -#define X_PAST X_KP_ASTERISK -#define X_PMNS X_KP_MINUS -#define X_PPLS X_KP_PLUS -#define X_PENT X_KP_ENTER -#define X_P1 X_KP_1 -#define X_P2 X_KP_2 -#define X_P3 X_KP_3 -#define X_P4 X_KP_4 -#define X_P5 X_KP_5 -#define X_P6 X_KP_6 -#define X_P7 X_KP_7 -#define X_P8 X_KP_8 -#define X_P9 X_KP_9 -#define X_P0 X_KP_0 -#define X_PDOT X_KP_DOT -#define X_PEQL X_KP_EQUAL -#define X_PCMM X_KP_COMMA - -/* Language Specific */ -#define X_INT1 X_INTERNATIONAL_1 -#define X_INT2 X_INTERNATIONAL_2 -#define X_INT3 X_INTERNATIONAL_3 -#define X_INT4 X_INTERNATIONAL_4 -#define X_INT5 X_INTERNATIONAL_5 -#define X_INT6 X_INTERNATIONAL_6 -#define X_INT7 X_INTERNATIONAL_7 -#define X_INT8 X_INTERNATIONAL_8 -#define X_INT9 X_INTERNATIONAL_9 -#define X_LNG1 X_LANGUAGE_1 -#define X_LNG2 X_LANGUAGE_2 -#define X_LNG3 X_LANGUAGE_3 -#define X_LNG4 X_LANGUAGE_4 -#define X_LNG5 X_LANGUAGE_5 -#define X_LNG6 X_LANGUAGE_6 -#define X_LNG7 X_LANGUAGE_7 -#define X_LNG8 X_LANGUAGE_8 -#define X_LNG9 X_LANGUAGE_9 - -/* Modifiers */ -#define X_LCTL X_LEFT_CTRL -#define X_LSFT X_LEFT_SHIFT -#define X_LALT X_LEFT_ALT -#define X_LOPT X_LEFT_ALT -#define X_LGUI X_LEFT_GUI -#define X_LCMD X_LEFT_GUI -#define X_LWIN X_LEFT_GUI -#define X_RCTL X_RIGHT_CTRL -#define X_RSFT X_RIGHT_SHIFT -#define X_RALT X_RIGHT_ALT -#define X_ALGR X_RIGHT_ALT -#define X_ROPT X_RIGHT_ALT -#define X_RGUI X_RIGHT_GUI -#define X_RCMD X_RIGHT_GUI -#define X_RWIN X_RIGHT_GUI - -/* Generic Desktop Page (0x01) */ -#define X_PWR X_SYSTEM_POWER -#define X_SLEP X_SYSTEM_SLEEP -#define X_WAKE X_SYSTEM_WAKE - -/* Consumer Page (0x0C) */ -#define X_MUTE X_AUDIO_MUTE -#define X_VOLU X_AUDIO_VOL_UP -#define X_VOLD X_AUDIO_VOL_DOWN -#define X_MNXT X_MEDIA_NEXT_TRACK -#define X_MPRV X_MEDIA_PREV_TRACK -#define X_MSTP X_MEDIA_STOP -#define X_MPLY X_MEDIA_PLAY_PAUSE -#define X_MSEL X_MEDIA_SELECT -#define X_EJCT X_MEDIA_EJECT -#define X_CALC X_CALCULATOR -#define X_MYCM X_MY_COMPUTER -#define X_WSCH X_WWW_SEARCH -#define X_WHOM X_WWW_HOME -#define X_WBAK X_WWW_BACK -#define X_WFWD X_WWW_FORWARD -#define X_WSTP X_WWW_STOP -#define X_WREF X_WWW_REFRESH -#define X_WFAV X_WWW_FAVORITES -#define X_MFFD X_MEDIA_FAST_FORWARD -#define X_MRWD X_MEDIA_REWIND -#define X_BRIU X_BRIGHTNESS_UP -#define X_BRID X_BRIGHTNESS_DOWN - -/* System Specific */ -#define X_BRMU X_PAUSE -#define X_BRMD X_SCROLL_LOCK - -/* Mouse Keys */ -#define X_MS_U X_MS_UP -#define X_MS_D X_MS_DOWN -#define X_MS_L X_MS_LEFT -#define X_MS_R X_MS_RIGHT -#define X_BTN1 X_MS_BTN1 -#define X_BTN2 X_MS_BTN2 -#define X_BTN3 X_MS_BTN3 -#define X_BTN4 X_MS_BTN4 -#define X_BTN5 X_MS_BTN5 -#define X_BTN6 X_MS_BTN6 -#define X_BTN7 X_MS_BTN7 -#define X_BTN8 X_MS_BTN8 -#define X_WH_U X_MS_WH_UP -#define X_WH_D X_MS_WH_DOWN -#define X_WH_L X_MS_WH_LEFT -#define X_WH_R X_MS_WH_RIGHT -#define X_ACL0 X_MS_ACCEL0 -#define X_ACL1 X_MS_ACCEL1 -#define X_ACL2 X_MS_ACCEL2 - -/* Keyboard/Keypad Page (0x07) */ -#define X_A 04 -#define X_B 05 -#define X_C 06 -#define X_D 07 -#define X_E 08 -#define X_F 09 -#define X_G 0a -#define X_H 0b -#define X_I 0c -#define X_J 0d -#define X_K 0e -#define X_L 0f -#define X_M 10 -#define X_N 11 -#define X_O 12 -#define X_P 13 -#define X_Q 14 -#define X_R 15 -#define X_S 16 -#define X_T 17 -#define X_U 18 -#define X_V 19 -#define X_W 1a -#define X_X 1b -#define X_Y 1c -#define X_Z 1d -#define X_1 1e -#define X_2 1f -#define X_3 20 -#define X_4 21 -#define X_5 22 -#define X_6 23 -#define X_7 24 -#define X_8 25 -#define X_9 26 -#define X_0 27 -#define X_ENTER 28 -#define X_ESCAPE 29 -#define X_BACKSPACE 2a -#define X_TAB 2b -#define X_SPACE 2c -#define X_MINUS 2d -#define X_EQUAL 2e -#define X_LEFT_BRACKET 2f -#define X_RIGHT_BRACKET 30 -#define X_BACKSLASH 31 -#define X_NONUS_HASH 32 -#define X_SEMICOLON 33 -#define X_QUOTE 34 -#define X_GRAVE 35 -#define X_COMMA 36 -#define X_DOT 37 -#define X_SLASH 38 -#define X_CAPS_LOCK 39 -#define X_F1 3a -#define X_F2 3b -#define X_F3 3c -#define X_F4 3d -#define X_F5 3e -#define X_F6 3f -#define X_F7 40 -#define X_F8 41 -#define X_F9 42 -#define X_F10 43 -#define X_F11 44 -#define X_F12 45 -#define X_PRINT_SCREEN 46 -#define X_SCROLL_LOCK 47 -#define X_PAUSE 48 -#define X_INSERT 49 -#define X_HOME 4a -#define X_PAGE_UP 4b -#define X_DELETE 4c -#define X_END 4d -#define X_PAGE_DOWN 4e -#define X_RIGHT 4f -#define X_LEFT 50 -#define X_DOWN 51 -#define X_UP 52 -#define X_NUM_LOCK 53 -#define X_KP_SLASH 54 -#define X_KP_ASTERISK 55 -#define X_KP_MINUS 56 -#define X_KP_PLUS 57 -#define X_KP_ENTER 58 -#define X_KP_1 59 -#define X_KP_2 5a -#define X_KP_3 5b -#define X_KP_4 5c -#define X_KP_5 5d -#define X_KP_6 5e -#define X_KP_7 5f -#define X_KP_8 60 -#define X_KP_9 61 -#define X_KP_0 62 -#define X_KP_DOT 63 -#define X_NONUS_BACKSLASH 64 -#define X_APPLICATION 65 -#define X_KB_POWER 66 -#define X_KP_EQUAL 67 -#define X_F13 68 -#define X_F14 69 -#define X_F15 6a -#define X_F16 6b -#define X_F17 6c -#define X_F18 6d -#define X_F19 6e -#define X_F20 6f -#define X_F21 70 -#define X_F22 71 -#define X_F23 72 -#define X_F24 73 -#define X_EXECUTE 74 -#define X_HELP 75 -#define X_MENU 76 -#define X_SELECT 77 -#define X_STOP 78 -#define X_AGAIN 79 -#define X_UNDO 7a -#define X_CUT 7b -#define X_COPY 7c -#define X_PASTE 7d -#define X_FIND 7e -#define X_KB_MUTE 7f -#define X_KB_VOLUME_UP 80 -#define X_KB_VOLUME_DOWN 81 -#define X_LOCKING_CAPS_LOCK 82 -#define X_LOCKING_NUM_LOCK 83 -#define X_LOCKING_SCROLL_LOCK 84 -#define X_KP_COMMA 85 -#define X_KP_EQUAL_AS400 86 -#define X_INTERNATIONAL_1 87 -#define X_INTERNATIONAL_2 88 -#define X_INTERNATIONAL_3 89 -#define X_INTERNATIONAL_4 8a -#define X_INTERNATIONAL_5 8b -#define X_INTERNATIONAL_6 8c -#define X_INTERNATIONAL_7 8d -#define X_INTERNATIONAL_8 8e -#define X_INTERNATIONAL_9 8f -#define X_LANGUAGE_1 90 -#define X_LANGUAGE_2 91 -#define X_LANGUAGE_3 92 -#define X_LANGUAGE_4 93 -#define X_LANGUAGE_5 94 -#define X_LANGUAGE_6 95 -#define X_LANGUAGE_7 96 -#define X_LANGUAGE_8 97 -#define X_LANGUAGE_9 98 -#define X_ALTERNATE_ERASE 99 -#define X_SYSTEM_REQUEST 9a -#define X_CANCEL 9b -#define X_CLEAR 9c -#define X_PRIOR 9d -#define X_RETURN 9e -#define X_SEPARATOR 9f -#define X_OUT a0 -#define X_OPER a1 -#define X_CLEAR_AGAIN a2 -#define X_CRSEL a3 -#define X_EXSEL a4 - -/* Modifiers */ -#define X_LEFT_CTRL e0 -#define X_LEFT_SHIFT e1 -#define X_LEFT_ALT e2 -#define X_LEFT_GUI e3 -#define X_RIGHT_CTRL e4 -#define X_RIGHT_SHIFT e5 -#define X_RIGHT_ALT e6 -#define X_RIGHT_GUI e7 - -/* Media and Function keys */ -/* Generic Desktop Page (0x01) */ -#define X_SYSTEM_POWER a5 -#define X_SYSTEM_SLEEP a6 -#define X_SYSTEM_WAKE a7 - -/* Consumer Page (0x0C) */ -#define X_AUDIO_MUTE a8 -#define X_AUDIO_VOL_UP a9 -#define X_AUDIO_VOL_DOWN aa -#define X_MEDIA_NEXT_TRACK ab -#define X_MEDIA_PREV_TRACK ac -#define X_MEDIA_STOP ad -#define X_MEDIA_PLAY_PAUSE ae -#define X_MEDIA_SELECT af -#define X_MEDIA_EJECT b0 -#define X_MAIL b1 -#define X_CALCULATOR b2 -#define X_MY_COMPUTER b3 -#define X_WWW_SEARCH b4 -#define X_WWW_HOME b5 -#define X_WWW_BACK b6 -#define X_WWW_FORWARD b7 -#define X_WWW_STOP b8 -#define X_WWW_REFRESH b9 -#define X_WWW_FAVORITES ba -#define X_MEDIA_FAST_FORWARD bb -#define X_MEDIA_REWIND bc -#define X_BRIGHTNESS_UP bd -#define X_BRIGHTNESS_DOWN be - -/* Mouse Buttons (unallocated range in HID spec) */ -#ifdef VIA_ENABLE -#define X_MS_UP f0 -#define X_MS_DOWN f1 -#define X_MS_LEFT f2 -#define X_MS_RIGHT f3 -#define X_MS_BTN1 f4 -#define X_MS_BTN2 f5 -#define X_MS_BTN3 f6 -#define X_MS_BTN4 f7 -#define X_MS_BTN5 f8 -#define X_MS_BTN6 f8 -#define X_MS_BTN7 f8 -#define X_MS_BTN8 f8 -#else -#define X_MS_UP ed -#define X_MS_DOWN ee -#define X_MS_LEFT ef -#define X_MS_RIGHT f0 -#define X_MS_BTN1 f1 -#define X_MS_BTN2 f2 -#define X_MS_BTN3 f3 -#define X_MS_BTN4 f4 -#define X_MS_BTN5 f5 -#define X_MS_BTN6 f6 -#define X_MS_BTN7 f7 -#define X_MS_BTN8 f8 -#endif -#define X_MS_WH_UP f9 -#define X_MS_WH_DOWN fa -#define X_MS_WH_LEFT fb -#define X_MS_WH_RIGHT fc -#define X_MS_ACCEL0 fd -#define X_MS_ACCEL1 fe -#define X_MS_ACCEL2 ff - -// Send string macros -#define STRINGIZE(z) #z -#define ADD_SLASH_X(y) STRINGIZE(\x##y) -#define SYMBOL_STR(x) ADD_SLASH_X(x) - -#define SS_QMK_PREFIX 1 - -#define SS_TAP_CODE 1 -#define SS_DOWN_CODE 2 -#define SS_UP_CODE 3 -#define SS_DELAY_CODE 4 - -#define SS_TAP(keycode) "\1\1" SYMBOL_STR(keycode) -#define SS_DOWN(keycode) "\1\2" SYMBOL_STR(keycode) -#define SS_UP(keycode) "\1\3" SYMBOL_STR(keycode) -#define SS_DELAY(msecs) "\1\4" STRINGIZE(msecs) "|" - -// `string` arguments must not be parenthesized -#define SS_LCTL(string) SS_DOWN(X_LCTL) string SS_UP(X_LCTL) -#define SS_LSFT(string) SS_DOWN(X_LSFT) string SS_UP(X_LSFT) -#define SS_LALT(string) SS_DOWN(X_LALT) string SS_UP(X_LALT) -#define SS_LGUI(string) SS_DOWN(X_LGUI) string SS_UP(X_LGUI) -#define SS_LCMD(string) SS_LGUI(string) -#define SS_LWIN(string) SS_LGUI(string) - -#define SS_RCTL(string) SS_DOWN(X_RCTL) string SS_UP(X_RCTL) -#define SS_RSFT(string) SS_DOWN(X_RSFT) string SS_UP(X_RSFT) -#define SS_RALT(string) SS_DOWN(X_RALT) string SS_UP(X_RALT) -#define SS_RGUI(string) SS_DOWN(X_RGUI) string SS_UP(X_RGUI) -#define SS_ALGR(string) SS_RALT(string) -#define SS_RCMD(string) SS_RGUI(string) -#define SS_RWIN(string) SS_RGUI(string) - -// DEPRECATED -#define X_BSPACE X_BACKSPACE -#define X_LBRACKET X_LEFT_BRACKET -#define X_RBRACKET X_RIGHT_BRACKET -#define X_BSLASH X_BACKSLASH -#define X_SCOLON X_SEMICOLON -#define X_CAPSLOCK X_CAPS_LOCK -#define X_PSCREEN X_PRINT_SCREEN -#define X_SCROLLLOCK X_SCROLL_LOCK -#define X_PGDOWN X_PAGE_DOWN -#define X_NUMLOCK X_NUM_LOCK -#define X_NONUS_BSLASH X_NONUS_BACKSLASH -#define X_POWER X_KB_POWER -#define X__MUTE X_KB_MUTE -#define X__VOLUP X_KB_VOLUME_UP -#define X__VOLDOWN X_KB_VOLUME_DOWN -#define X_LOCKING_CAPS X_LOCKING_CAPS_LOCK -#define X_LOCKING_NUM X_LOCKING_NUM_LOCK -#define X_LOCKING_SCROLL X_LOCKING_SCROLL_LOCK -#define X_LANG1 X_LANGUAGE_1 -#define X_LANG2 X_LANGUAGE_2 -#define X_LANG3 X_LANGUAGE_3 -#define X_LANG4 X_LANGUAGE_4 -#define X_LANG5 X_LANGUAGE_5 -#define X_LANG6 X_LANGUAGE_6 -#define X_LANG7 X_LANGUAGE_7 -#define X_LANG8 X_LANGUAGE_8 -#define X_LANG9 X_LANGUAGE_9 -#define X_ALT_ERASE X_ALTERNATE_ERASE -#define X_SYSREQ X_SYSTEM_REQUEST - -#define X_LCTRL X_LEFT_CTRL -#define X_LSHIFT X_LEFT_SHIFT -#define X_RCTRL X_RIGHT_CTRL -#define X_RSHIFT X_RIGHT_SHIFT - -#define X_ZKHK X_GRAVE -#define X_RO X_INTERNATIONAL_1 -#define X_KANA X_INTERNATIONAL_2 -#define X_JYEN X_INTERNATIONAL_3 -#define X_HENK X_INTERNATIONAL_4 -#define X_MHEN X_INTERNATIONAL_5 -#define X_HAEN X_LANGUAGE_1 -#define X_HANJ X_LANGUAGE_2 - -#define X_CLCK X_CAPS_LOCK -#define X_SLCK X_SCROLL_LOCK -#define X_NLCK X_NUM_LOCK - -#define SS_LCTRL(string) SS_LCTL(string) -- cgit v1.2.3 From b8e8a20ca64327d0c5276f87a9dddc8e83cee0de Mon Sep 17 00:00:00 2001 From: Marek Wyborski <9861955+mwyborski@users.noreply.github.com> Date: Sat, 2 Jul 2022 14:12:41 +0200 Subject: Improve ENCODER_DEFAULT_POS to recognize lost ticks (#16932) --- quantum/encoder.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'quantum') diff --git a/quantum/encoder.c b/quantum/encoder.c index 105bed0147..5f8a7ce080 100644 --- a/quantum/encoder.c +++ b/quantum/encoder.c @@ -163,27 +163,38 @@ static bool encoder_update(uint8_t index, uint8_t state) { 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) { - encoder_value[index]++; - changed = true; +#endif + + encoder_value[index]++; + changed = true; #ifdef ENCODER_MAP_ENABLE - encoder_exec_mapping(index, ENCODER_COUNTER_CLOCKWISE); + 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 - encoder_value[index]--; - changed = true; +#endif + encoder_value[index]--; + changed = true; #ifdef ENCODER_MAP_ENABLE - encoder_exec_mapping(index, ENCODER_CLOCKWISE); + encoder_exec_mapping(index, ENCODER_CLOCKWISE); #else // ENCODER_MAP_ENABLE encoder_update_kb(index, ENCODER_CLOCKWISE); #endif // ENCODER_MAP_ENABLE - } - encoder_pulses[i] %= resolution; + } + encoder_pulses[i] %= resolution; #ifdef ENCODER_DEFAULT_POS - if ((state & 0x3) == ENCODER_DEFAULT_POS) { encoder_pulses[i] = 0; } #endif -- cgit v1.2.3 From 0e5d67145a649480fd49a72712997feb6303a471 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Tue, 5 Jul 2022 08:58:35 +1000 Subject: Allow for `keymaps` array to be implemented in a file other than `$(KEYMAP_C)` (#17559) --- builddefs/build_keyboard.mk | 6 ++++++ quantum/keymap_introspection.c | 5 +++++ users/manna-harbour_miryoku/post_rules.mk | 2 -- users/manna-harbour_miryoku/rules.mk | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) (limited to 'quantum') diff --git a/builddefs/build_keyboard.mk b/builddefs/build_keyboard.mk index b5616a438f..fe95dcaf15 100644 --- a/builddefs/build_keyboard.mk +++ b/builddefs/build_keyboard.mk @@ -400,6 +400,12 @@ endif OPT_DEFS += -DKEYMAP_C=\"$(KEYMAP_C)\" +# If a keymap or userspace places their keymap array in another file instead, allow for it to be included +# !!NOTE!! -- For this to work, the source file cannot be part of $(SRC), so users should not add it via `SRC += ` +ifneq ($(strip $(INTROSPECTION_KEYMAP_C)),) +OPT_DEFS += -DINTROSPECTION_KEYMAP_C=\"$(strip $(INTROSPECTION_KEYMAP_C))\" +endif + # project specific files SRC += \ $(KEYBOARD_SRC) \ diff --git a/quantum/keymap_introspection.c b/quantum/keymap_introspection.c index 9628b41eef..7a96f802ef 100644 --- a/quantum/keymap_introspection.c +++ b/quantum/keymap_introspection.c @@ -4,6 +4,11 @@ // Pull the actual keymap code so that we can inspect stuff from it #include KEYMAP_C +// Allow for keymap or userspace rules.mk to specify an alternate location for the keymap array +#ifdef INTROSPECTION_KEYMAP_C +# include INTROSPECTION_KEYMAP_C +#endif // INTROSPECTION_KEYMAP_C + #include "keymap_introspection.h" #define NUM_KEYMAP_LAYERS ((uint8_t)(sizeof(keymaps) / ((MATRIX_ROWS) * (MATRIX_COLS) * sizeof(uint16_t)))) diff --git a/users/manna-harbour_miryoku/post_rules.mk b/users/manna-harbour_miryoku/post_rules.mk index c5b4b7d28e..8fece85e66 100644 --- a/users/manna-harbour_miryoku/post_rules.mk +++ b/users/manna-harbour_miryoku/post_rules.mk @@ -1,8 +1,6 @@ # Copyright 2019 Manna Harbour # https://github.com/manna-harbour/miryoku -SRC += manna-harbour_miryoku.c # keymaps - # alternative layouts: # alphas diff --git a/users/manna-harbour_miryoku/rules.mk b/users/manna-harbour_miryoku/rules.mk index 879c7fc43e..ea226c4a3d 100644 --- a/users/manna-harbour_miryoku/rules.mk +++ b/users/manna-harbour_miryoku/rules.mk @@ -5,7 +5,7 @@ MOUSEKEY_ENABLE = yes # Mouse keys EXTRAKEY_ENABLE = yes # Audio control and System control AUTO_SHIFT_ENABLE = yes # Auto Shift -SRC += manna-harbour_miryoku.c # keymaps +INTROSPECTION_KEYMAP_C = manna-harbour_miryoku.c # keymaps include users/manna-harbour_miryoku/custom_rules.mk -- cgit v1.2.3 From d9bb189e25f14578ca74d6a3aa9f9a467f6f6595 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 7 Jul 2022 09:27:50 +0200 Subject: [Core] Update mpaland/printf to eyalroz/printf fork (#16163) mpaland printf implementation was abandoned in ~2019 and the fork by eyalroz is now regarded to be the goto replacement of it. So this commit incoporates the changes needed to use this fork in QMK. Note that pointer ptrdiff_t is always supported since commit 51c90f93a97fdaef895783ecbe24569be0db7cb8 --- builddefs/build_test.mk | 6 ++-- lib/printf | 2 +- platforms/arm_atsam/platform.mk | 1 + platforms/avr/platform.mk | 1 + platforms/chibios/platform.mk | 3 +- quantum/logging/print.c | 2 +- quantum/logging/print.h | 68 +++++++++++++++++++++++++---------------- quantum/logging/print.mk | 17 ++++++----- 8 files changed, 61 insertions(+), 39 deletions(-) (limited to 'quantum') diff --git a/builddefs/build_test.mk b/builddefs/build_test.mk index bd9b372c33..64db99fed9 100644 --- a/builddefs/build_test.mk +++ b/builddefs/build_test.mk @@ -38,11 +38,11 @@ CREATE_MAP := no VPATH += \ $(LIB_PATH)/googletest \ $(LIB_PATH)/googlemock \ - $(LIB_PATH)/printf + $(COMMON_VPATH) \ + $(TEST_PATH) all: elf -VPATH += $(TEST_PATH) $(COMMON_VPATH) PLATFORM:=TEST PLATFORM_KEY:=test BOOTLOADER_TYPE:=none @@ -64,6 +64,7 @@ include $(QUANTUM_PATH)/debounce/tests/rules.mk include $(QUANTUM_PATH)/encoder/tests/rules.mk include $(QUANTUM_PATH)/sequencer/tests/rules.mk include $(QUANTUM_PATH)/wear_leveling/tests/rules.mk +include $(QUANTUM_PATH)/logging/print.mk include $(PLATFORM_PATH)/test/rules.mk ifneq ($(filter $(FULL_TESTS),$(TEST)),) include $(BUILDDEFS_PATH)/build_full_test.mk @@ -71,7 +72,6 @@ endif $(TEST)_SRC += \ tests/test_common/main.c \ - $(LIB_PATH)/printf/printf.c \ $(QUANTUM_PATH)/logging/print.c $(TEST_OBJ)/$(TEST)_SRC := $($(TEST)_SRC) diff --git a/lib/printf b/lib/printf index d3b984684b..c2e3b4e10d 160000 --- a/lib/printf +++ b/lib/printf @@ -1 +1 @@ -Subproject commit d3b984684bb8a8bdc48cc7a1abecb93ce59bbe3e +Subproject commit c2e3b4e10d281e7f0f694d3ecbd9f320977288cc diff --git a/platforms/arm_atsam/platform.mk b/platforms/arm_atsam/platform.mk index 9618838dc3..9462f517ae 100644 --- a/platforms/arm_atsam/platform.mk +++ b/platforms/arm_atsam/platform.mk @@ -24,6 +24,7 @@ COMPILEFLAGS += -fno-strict-aliasing COMPILEFLAGS += -mfloat-abi=hard COMPILEFLAGS += -mfpu=fpv4-sp-d16 COMPILEFLAGS += -mthumb +COMPILEFLAGS += -fno-builtin-printf #ALLOW_WARNINGS = yes diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk index b51a94c93a..39a11b28e4 100644 --- a/platforms/avr/platform.mk +++ b/platforms/avr/platform.mk @@ -24,6 +24,7 @@ COMPILEFLAGS += -fdata-sections COMPILEFLAGS += -fpack-struct COMPILEFLAGS += -fshort-enums COMPILEFLAGS += -mcall-prologues +COMPILEFLAGS += -fno-builtin-printf # Linker relaxation is only possible if # link time optimizations are not enabled. diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 63cc1a4b33..b2a8ec89e1 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -349,7 +349,8 @@ SHARED_CFLAGS = -fomit-frame-pointer \ -ffunction-sections \ -fdata-sections \ -fno-common \ - -fshort-wchar + -fshort-wchar \ + -fno-builtin-printf LDSCRIPT_PATH := $(shell dirname "$(LDSCRIPT)") diff --git a/quantum/logging/print.c b/quantum/logging/print.c index 50a6b826ee..17e6737ac4 100644 --- a/quantum/logging/print.c +++ b/quantum/logging/print.c @@ -28,6 +28,6 @@ void print_set_sendchar(sendchar_func_t send) { func = send; } -void _putchar(char character) { +void putchar_(char character) { func(character); } diff --git a/quantum/logging/print.h b/quantum/logging/print.h index aa72fc7074..5fbf189505 100644 --- a/quantum/logging/print.h +++ b/quantum/logging/print.h @@ -32,6 +32,22 @@ void print_set_sendchar(sendchar_func_t func); +/** + * @brief This macro suppress format warnings for the function that is passed + * in. The main use-case is that `b` format specifier for printing binary + * numbers is not in the official C standard. Inclusion is planned for the + * upcoming C2X C standard, but until then GCC will always output a warning for + * a unknown format specifier. + */ +#define IGNORE_FORMAT_WARNING(func) \ + do { \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wformat\""); \ + _Pragma("GCC diagnostic ignored \"-Wformat-extra-args\""); \ + func; \ + _Pragma("GCC diagnostic pop"); \ + } while (0) + #ifndef NO_PRINT # if __has_include_next("_print.h") # include_next "_print.h" /* Include the platforms print.h */ @@ -78,25 +94,25 @@ void print_set_sendchar(sendchar_func_t func); #define print_hex16(i) xprintf("%04X", i) #define print_hex32(i) xprintf("%08lX", i) /* binary */ -#define print_bin4(i) xprintf("%04b", i) -#define print_bin8(i) xprintf("%08b", i) -#define print_bin16(i) xprintf("%016b", i) -#define print_bin32(i) xprintf("%032lb", i) -#define print_bin_reverse8(i) xprintf("%08b", bitrev(i)) -#define print_bin_reverse16(i) xprintf("%016b", bitrev16(i)) -#define print_bin_reverse32(i) xprintf("%032lb", bitrev32(i)) +#define print_bin4(i) IGNORE_FORMAT_WARNING(xprintf("%04b", i)) +#define print_bin8(i) IGNORE_FORMAT_WARNING(xprintf("%08b", i)) +#define print_bin16(i) IGNORE_FORMAT_WARNING(xprintf("%016b", i)) +#define print_bin32(i) IGNORE_FORMAT_WARNING(xprintf("%032lb", i)) +#define print_bin_reverse8(i) IGNORE_FORMAT_WARNING(xprintf("%08b", bitrev(i))) +#define print_bin_reverse16(i) IGNORE_FORMAT_WARNING(xprintf("%016b", bitrev16(i))) +#define print_bin_reverse32(i) IGNORE_FORMAT_WARNINGxprintf("%032lb", bitrev32(i))) /* print value utility */ #define print_val_dec(v) xprintf(#v ": %u\n", v) #define print_val_decs(v) xprintf(#v ": %d\n", v) #define print_val_hex8(v) xprintf(#v ": %X\n", v) #define print_val_hex16(v) xprintf(#v ": %02X\n", v) #define print_val_hex32(v) xprintf(#v ": %04lX\n", v) -#define print_val_bin8(v) xprintf(#v ": %08b\n", v) -#define print_val_bin16(v) xprintf(#v ": %016b\n", v) -#define print_val_bin32(v) xprintf(#v ": %032lb\n", v) -#define print_val_bin_reverse8(v) xprintf(#v ": %08b\n", bitrev(v)) -#define print_val_bin_reverse16(v) xprintf(#v ": %016b\n", bitrev16(v)) -#define print_val_bin_reverse32(v) xprintf(#v ": %032lb\n", bitrev32(v)) +#define print_val_bin8(v) IGNORE_FORMAT_WARNING(xprintf(#v ": %08b\n", v)) +#define print_val_bin16(v) IGNORE_FORMAT_WARNING(xprintf(#v ": %016b\n", v)) +#define print_val_bin32(v) IGNORE_FORMAT_WARNING(xprintf(#v ": %032lb\n", v)) +#define print_val_bin_reverse8(v) IGNORE_FORMAT_WARNING(xprintf(#v ": %08b\n", bitrev(v))) +#define print_val_bin_reverse16(v) IGNORE_FORMAT_WARNING(xprintf(#v ": %016b\n", bitrev16(v))) +#define print_val_bin_reverse32(v) IGNORE_FORMAT_WARNING(xprintf(#v ": %032lb\n", bitrev32(v))) // User print disables the normal print messages in the body of QMK/TMK code and // is meant as a lightweight alternative to NOPRINT. Use it when you only want to do @@ -114,22 +130,22 @@ void print_set_sendchar(sendchar_func_t func); #define uprint_hex16(i) uprintf("%04X", i) #define uprint_hex32(i) uprintf("%08lX", i) /* binary */ -#define uprint_bin4(i) uprintf("%04b", i) -#define uprint_bin8(i) uprintf("%08b", i) -#define uprint_bin16(i) uprintf("%016b", i) -#define uprint_bin32(i) uprintf("%032lb", i) -#define uprint_bin_reverse8(i) uprintf("%08b", bitrev(i)) -#define uprint_bin_reverse16(i) uprintf("%016b", bitrev16(i)) -#define uprint_bin_reverse32(i) uprintf("%032lb", bitrev32(i)) +#define uprint_bin4(i) IGNORE_FORMAT_WARNING(uprintf("%04b", i)) +#define uprint_bin8(i) IGNORE_FORMAT_WARNING(uprintf("%08b", i)) +#define uprint_bin16(i) IGNORE_FORMAT_WARNING(uprintf("%016b", i)) +#define uprint_bin32(i) IGNORE_FORMAT_WARNING(uprintf("%032lb", i)) +#define uprint_bin_reverse8(i) IGNORE_FORMAT_WARNING(uprintf("%08b", bitrev(i))) +#define uprint_bin_reverse16(i) IGNORE_FORMAT_WARNING(uprintf("%016b", bitrev16(i))) +#define uprint_bin_reverse32(i) IGNORE_FORMAT_WARNING(uprintf("%032lb", bitrev32(i))) /* print value utility */ #define uprint_val_dec(v) uprintf(#v ": %u\n", v) #define uprint_val_decs(v) uprintf(#v ": %d\n", v) #define uprint_val_hex8(v) uprintf(#v ": %X\n", v) #define uprint_val_hex16(v) uprintf(#v ": %02X\n", v) #define uprint_val_hex32(v) uprintf(#v ": %04lX\n", v) -#define uprint_val_bin8(v) uprintf(#v ": %08b\n", v) -#define uprint_val_bin16(v) uprintf(#v ": %016b\n", v) -#define uprint_val_bin32(v) uprintf(#v ": %032lb\n", v) -#define uprint_val_bin_reverse8(v) uprintf(#v ": %08b\n", bitrev(v)) -#define uprint_val_bin_reverse16(v) uprintf(#v ": %016b\n", bitrev16(v)) -#define uprint_val_bin_reverse32(v) uprintf(#v ": %032lb\n", bitrev32(v)) +#define uprint_val_bin8(v) IGNORE_FORMAT_WARNING(uprintf(#v ": %08b\n", v)) +#define uprint_val_bin16(v) IGNORE_FORMAT_WARNING(uprintf(#v ": %016b\n", v)) +#define uprint_val_bin32(v) IGNORE_FORMAT_WARNING(uprintf(#v ": %032lb\n", v)) +#define uprint_val_bin_reverse8(v) IGNORE_FORMAT_WARNING(uprintf(#v ": %08b\n", bitrev(v))) +#define uprint_val_bin_reverse16(v) IGNORE_FORMAT_WARNING(uprintf(#v ": %016b\n", bitrev16(v))) +#define uprint_val_bin_reverse32(v) IGNORE_FORMAT_WARNING(uprintf(#v ": %032lb\n", bitrev32(v))) diff --git a/quantum/logging/print.mk b/quantum/logging/print.mk index 67c004192d..658c533dad 100644 --- a/quantum/logging/print.mk +++ b/quantum/logging/print.mk @@ -1,9 +1,12 @@ -PRINTF_PATH = $(LIB_PATH)/printf +PRINTF_PATH = $(LIB_PATH)/printf/src -VPATH += $(PRINTF_PATH) -SRC += $(PRINTF_PATH)/printf.c +VPATH += $(PRINTF_PATH) $(PRINTF_PATH)/printf +SRC += printf.c QUANTUM_SRC +=$(QUANTUM_DIR)/logging/print.c -OPT_DEFS += -DPRINTF_DISABLE_SUPPORT_FLOAT -OPT_DEFS += -DPRINTF_DISABLE_SUPPORT_EXPONENTIAL -OPT_DEFS += -DPRINTF_DISABLE_SUPPORT_LONG_LONG -OPT_DEFS += -DPRINTF_DISABLE_SUPPORT_PTRDIFF_T + +OPT_DEFS += -DPRINTF_SUPPORT_DECIMAL_SPECIFIERS=0 +OPT_DEFS += -DPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS=0 +OPT_DEFS += -DPRINTF_SUPPORT_LONG_LONG=0 +OPT_DEFS += -DPRINTF_SUPPORT_WRITEBACK_SPECIFIER=0 +OPT_DEFS += -DSUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS=0 +OPT_DEFS += -DPRINTF_ALIAS_STANDARD_FUNCTION_NAMES=1 -- cgit v1.2.3 From 8224f62806b66f0825b68fd8c00436ee57a28e9a Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 7 Jul 2022 10:00:40 +0200 Subject: Make debounce() signal changes in the cooked matrix as return value (#17554) --- docs/custom_matrix.md | 6 +++--- docs/ja/custom_matrix.md | 6 +++--- quantum/debounce.h | 16 +++++++++++----- quantum/debounce/asym_eager_defer_pk.c | 11 +++++++++-- quantum/debounce/none.c | 11 +++++++---- quantum/debounce/sym_defer_g.c | 12 +++++++++--- quantum/debounce/sym_defer_pk.c | 12 +++++++++--- quantum/debounce/sym_defer_pr.c | 14 +++++++++----- quantum/debounce/sym_eager_pk.c | 7 ++++++- quantum/debounce/sym_eager_pr.c | 11 ++++++++--- quantum/debounce/tests/debounce_test_common.cpp | 6 +++++- quantum/matrix.c | 5 ++--- quantum/matrix_common.c | 5 ++--- 13 files changed, 83 insertions(+), 39 deletions(-) (limited to 'quantum') diff --git a/docs/custom_matrix.md b/docs/custom_matrix.md index 8f6878f94a..6d6ae5e972 100644 --- a/docs/custom_matrix.md +++ b/docs/custom_matrix.md @@ -81,17 +81,17 @@ void matrix_init(void) { } uint8_t matrix_scan(void) { - bool matrix_has_changed = false; + bool changed = false; // TODO: add matrix scanning routine here // Unless hardware debouncing - use the configured debounce routine - debounce(raw_matrix, matrix, MATRIX_ROWS, changed); + changed = debounce(raw_matrix, matrix, MATRIX_ROWS, changed); // This *must* be called for correct keyboard behavior matrix_scan_quantum(); - return matrix_has_changed; + return changed; } ``` diff --git a/docs/ja/custom_matrix.md b/docs/ja/custom_matrix.md index 277fc658d3..2c697bb148 100644 --- a/docs/ja/custom_matrix.md +++ b/docs/ja/custom_matrix.md @@ -87,17 +87,17 @@ void matrix_init(void) { } uint8_t matrix_scan(void) { - bool matrix_has_changed = false; + bool changed = false; // TODO: ここにマトリックススキャンルーチンを追加します // ハードウェアによるデバウンスがない場合 - 設定されているデバウンスルーチンを使用します - debounce(raw_matrix, matrix, MATRIX_ROWS, changed); + changed = debounce(raw_matrix, matrix, MATRIX_ROWS, changed); // 正しいキーボード動作のためにこれを呼び出す*必要があります* matrix_scan_quantum(); - return matrix_has_changed; + return changed; } ``` diff --git a/quantum/debounce.h b/quantum/debounce.h index 3532d9cd7b..a8629654c2 100644 --- a/quantum/debounce.h +++ b/quantum/debounce.h @@ -1,10 +1,16 @@ #pragma once -// raw is the current key state -// on entry cooked is the previous debounced state -// on exit cooked is the current debounced state -// changed is true if raw has changed since the last call -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed); +/** + * @brief Debounce raw matrix events according to the choosen debounce algorithm. + * + * @param raw The current key state + * @param cooked The debounced key state + * @param num_rows Number of rows to debounce + * @param changed True if raw has changed since the last call + * @return true Cooked has new keychanges after debouncing + * @return false Cooked is the same as before + */ +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed); void debounce_init(uint8_t num_rows); diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c index b1eb4a2b7b..4745c6f465 100644 --- a/quantum/debounce/asym_eager_defer_pk.c +++ b/quantum/debounce/asym_eager_defer_pk.c @@ -55,6 +55,7 @@ static debounce_counter_t *debounce_counters; static fast_timer_t last_time; static bool counters_need_update; static bool matrix_need_update; +static bool cooked_changed; # define DEBOUNCE_ELAPSED 0 @@ -77,8 +78,9 @@ void debounce_free(void) { debounce_counters = NULL; } -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { bool updated_last = false; + cooked_changed = false; if (counters_need_update) { fast_timer_t now = timer_read_fast(); @@ -102,6 +104,8 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool transfer_matrix_values(raw, cooked, num_rows); } + + return cooked_changed; } static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) { @@ -123,7 +127,9 @@ static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_need_update = true; } else { // key-up: defer - cooked[row] = (cooked[row] & ~col_mask) | (raw[row] & col_mask); + matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask); + cooked_changed |= cooked_next ^ cooked[row]; + cooked[row] = cooked_next; } } else { debounce_pointer->time -= elapsed_time; @@ -152,6 +158,7 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui if (debounce_pointer->pressed) { // key-down: eager cooked[row] ^= col_mask; + cooked_changed = true; } } } else if (debounce_pointer->time != DEBOUNCE_ELAPSED) { diff --git a/quantum/debounce/none.c b/quantum/debounce/none.c index 8a85cc04a8..4cff5e05e2 100644 --- a/quantum/debounce/none.c +++ b/quantum/debounce/none.c @@ -17,13 +17,16 @@ #include "matrix.h" #include "quantum.h" #include +#include void debounce_init(uint8_t num_rows) {} -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - for (int i = 0; i < num_rows; i++) { - cooked[i] = raw[i]; - } +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { + bool cooked_changed = memcmp(raw, cooked, sizeof(matrix_row_t) * num_rows) != 0; + + memcpy(cooked, raw, sizeof(matrix_row_t) * num_rows); + + return cooked_changed; } void debounce_free(void) {} diff --git a/quantum/debounce/sym_defer_g.c b/quantum/debounce/sym_defer_g.c index 47450992a4..d04310a761 100644 --- a/quantum/debounce/sym_defer_g.c +++ b/quantum/debounce/sym_defer_g.c @@ -20,6 +20,7 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state. #include "matrix.h" #include "timer.h" #include "quantum.h" +#include #ifndef DEBOUNCE # define DEBOUNCE 5 #endif @@ -30,18 +31,23 @@ static fast_timer_t debouncing_time; void debounce_init(uint8_t num_rows) {} -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { + bool cooked_changed = false; + if (changed) { debouncing = true; debouncing_time = timer_read_fast(); } if (debouncing && timer_elapsed_fast(debouncing_time) >= DEBOUNCE) { - for (int i = 0; i < num_rows; i++) { - cooked[i] = raw[i]; + if (memcmp(cooked, raw, sizeof(matrix_row_t) * num_rows) != 0) { + memcpy(cooked, raw, sizeof(matrix_row_t) * num_rows); + cooked_changed = true; } debouncing = false; } + + return cooked_changed; } void debounce_free(void) {} diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c index 9dee29e28e..7b59b5e100 100644 --- a/quantum/debounce/sym_defer_pk.c +++ b/quantum/debounce/sym_defer_pk.c @@ -48,6 +48,7 @@ typedef uint8_t debounce_counter_t; static debounce_counter_t *debounce_counters; static fast_timer_t last_time; static bool counters_need_update; +static bool cooked_changed; # define DEBOUNCE_ELAPSED 0 @@ -70,8 +71,9 @@ void debounce_free(void) { debounce_counters = NULL; } -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { bool updated_last = false; + cooked_changed = false; if (counters_need_update) { fast_timer_t now = timer_read_fast(); @@ -95,6 +97,8 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool start_debounce_counters(raw, cooked, num_rows); } + + return cooked_changed; } static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) { @@ -104,8 +108,10 @@ static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], for (uint8_t col = 0; col < MATRIX_COLS; col++) { if (*debounce_pointer != DEBOUNCE_ELAPSED) { if (*debounce_pointer <= elapsed_time) { - *debounce_pointer = DEBOUNCE_ELAPSED; - cooked[row] = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col)); + *debounce_pointer = DEBOUNCE_ELAPSED; + matrix_row_t cooked_next = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col)); + cooked_changed |= cooked[row] ^ cooked_next; + cooked[row] = cooked_next; } else { *debounce_pointer -= elapsed_time; counters_need_update = true; diff --git a/quantum/debounce/sym_defer_pr.c b/quantum/debounce/sym_defer_pr.c index ce24f0922f..452c4599d0 100644 --- a/quantum/debounce/sym_defer_pr.c +++ b/quantum/debounce/sym_defer_pr.c @@ -46,11 +46,12 @@ void debounce_free(void) { last_raw = NULL; } -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - uint16_t now = timer_read(); - uint16_t elapsed16 = TIMER_DIFF_16(now, last_time); - last_time = now; - uint8_t elapsed = (elapsed16 > 255) ? 255 : elapsed16; +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { + uint16_t now = timer_read(); + uint16_t elapsed16 = TIMER_DIFF_16(now, last_time); + last_time = now; + uint8_t elapsed = (elapsed16 > 255) ? 255 : elapsed16; + bool cooked_changed = false; uint8_t* countdown = countdowns; @@ -63,10 +64,13 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool } else if (*countdown > elapsed) { *countdown -= elapsed; } else if (*countdown) { + cooked_changed |= cooked[row] ^ raw_row; cooked[row] = raw_row; *countdown = 0; } } + + return cooked_changed; } bool debounce_active(void) { diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c index fe3e88bb06..f736d1645c 100644 --- a/quantum/debounce/sym_eager_pk.c +++ b/quantum/debounce/sym_eager_pk.c @@ -49,6 +49,7 @@ static debounce_counter_t *debounce_counters; static fast_timer_t last_time; static bool counters_need_update; static bool matrix_need_update; +static bool cooked_changed; # define DEBOUNCE_ELAPSED 0 @@ -71,8 +72,9 @@ void debounce_free(void) { debounce_counters = NULL; } -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { bool updated_last = false; + cooked_changed = false; if (counters_need_update) { fast_timer_t now = timer_read_fast(); @@ -96,6 +98,8 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool transfer_matrix_values(raw, cooked, num_rows); } + + return cooked_changed; } // If the current time is > debounce counter, set the counter to enable input. @@ -132,6 +136,7 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui *debounce_pointer = DEBOUNCE; counters_need_update = true; existing_row ^= col_mask; // flip the bit. + cooked_changed = true; } } debounce_pointer++; diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c index 29b0cabefb..aad5ca351b 100644 --- a/quantum/debounce/sym_eager_pr.c +++ b/quantum/debounce/sym_eager_pr.c @@ -48,6 +48,7 @@ static bool matrix_need_update; static debounce_counter_t *debounce_counters; static fast_timer_t last_time; static bool counters_need_update; +static bool cooked_changed; # define DEBOUNCE_ELAPSED 0 @@ -67,8 +68,9 @@ void debounce_free(void) { debounce_counters = NULL; } -void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { +bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { bool updated_last = false; + cooked_changed = false; if (counters_need_update) { fast_timer_t now = timer_read_fast(); @@ -92,6 +94,8 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool transfer_matrix_values(raw, cooked, num_rows); } + + return cooked_changed; } // If the current time is > debounce counter, set the counter to enable input. @@ -123,8 +127,9 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui // determine new value basd on debounce pointer + raw value if (existing_row != raw_row) { if (*debounce_pointer == DEBOUNCE_ELAPSED) { - *debounce_pointer = DEBOUNCE; - cooked[row] = raw_row; + *debounce_pointer = DEBOUNCE; + cooked[row] = raw_row; + cooked_changed |= cooked[row] ^ raw[row]; counters_need_update = true; } } diff --git a/quantum/debounce/tests/debounce_test_common.cpp b/quantum/debounce/tests/debounce_test_common.cpp index 0d5a7bb766..bd98e32955 100644 --- a/quantum/debounce/tests/debounce_test_common.cpp +++ b/quantum/debounce/tests/debounce_test_common.cpp @@ -125,11 +125,15 @@ void DebounceTest::runDebounce(bool changed) { std::copy(std::begin(input_matrix_), std::end(input_matrix_), std::begin(raw_matrix_)); std::copy(std::begin(output_matrix_), std::end(output_matrix_), std::begin(cooked_matrix_)); - debounce(raw_matrix_, cooked_matrix_, MATRIX_ROWS, changed); + bool cooked_changed = debounce(raw_matrix_, cooked_matrix_, MATRIX_ROWS, changed); if (!std::equal(std::begin(input_matrix_), std::end(input_matrix_), std::begin(raw_matrix_))) { FAIL() << "Fatal error: debounce() modified raw matrix at " << strTime() << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_) << "\nraw_matrix:\n" << strMatrix(raw_matrix_); } + + if (std::equal(std::begin(output_matrix_), std::end(output_matrix_), std::begin(cooked_matrix_)) && cooked_changed) { + FAIL() << "Fatal error: debounce() did detect a wrong cooked matrix change at " << strTime() << "\noutput_matrix: cooked_changed=" << cooked_changed << "\n" << strMatrix(output_matrix_) << "\ncooked_matrix:\n" << strMatrix(cooked_matrix_); + } } void DebounceTest::checkCookedMatrix(bool changed, const std::string &error_message) { diff --git a/quantum/matrix.c b/quantum/matrix.c index db59b73754..db683104ed 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c @@ -337,10 +337,9 @@ uint8_t matrix_scan(void) { if (changed) memcpy(raw_matrix, curr_matrix, sizeof(curr_matrix)); #ifdef SPLIT_KEYBOARD - debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed); - changed = (changed || matrix_post_scan()); + changed = debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed) | matrix_post_scan(); #else - debounce(raw_matrix, matrix, ROWS_PER_HAND, changed); + changed = debounce(raw_matrix, matrix, ROWS_PER_HAND, changed); matrix_scan_quantum(); #endif return (uint8_t)changed; diff --git a/quantum/matrix_common.c b/quantum/matrix_common.c index 2cf8484347..68f0e38297 100644 --- a/quantum/matrix_common.c +++ b/quantum/matrix_common.c @@ -169,10 +169,9 @@ __attribute__((weak)) uint8_t matrix_scan(void) { bool changed = matrix_scan_custom(raw_matrix); #ifdef SPLIT_KEYBOARD - debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed); - changed = (changed || matrix_post_scan()); + changed = debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed) | matrix_post_scan(); #else - debounce(raw_matrix, matrix, ROWS_PER_HAND, changed); + changed = debounce(raw_matrix, matrix, ROWS_PER_HAND, changed); matrix_scan_quantum(); #endif -- cgit v1.2.3 From 643f6367a19649a0f5af6d43f2ed7f0e93b21f70 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 7 Jul 2022 14:14:09 +0200 Subject: [Fix] Patches after printf library update (#17584) * Add missing '(' to print_bin_reverse32 declaration * Fix insufficient character buffers on satisfaction75 * Remove \0 character in format string and use corrected offset math instead on rocketboard 16 * Replace snprintf_ with snprintf for djinn * Explicitly ignore format checks for tracktyl manuform that uses %b specifier * Print properly escaped version string in command.c, as PRODUCT or other defines can contain constructs like 'Vendor keyboard 66%' which will be interpreted as a format specifier --- .../cannonkeys/satisfaction75/satisfaction_oled.c | 4 ++-- .../handwired/tractyl_manuform/tractyl_manuform.c | 22 +++++++++++----------- keyboards/rocketboard_16/keymaps/default/keymap.c | 4 ++-- keyboards/rocketboard_16/keymaps/via/keymap.c | 4 ++-- .../tzarc/djinn/graphics/theme_djinn_default.c | 10 +++++----- quantum/command.c | 2 +- quantum/logging/print.h | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) (limited to 'quantum') diff --git a/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c b/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c index fff8b65bd7..1e8465387c 100644 --- a/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c +++ b/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c @@ -145,7 +145,7 @@ static char* get_time(void) { hour = 12; } - static char time_str[8] = ""; + static char time_str[11] = ""; sprintf(time_str, "%02d:%02d%s", hour, minute, is_pm ? "pm" : "am"); return time_str; @@ -162,7 +162,7 @@ static char* get_date(void) { day = day_config; } - static char date_str[11] = ""; + static char date_str[15] = ""; sprintf(date_str, "%04d-%02d-%02d", year, month, day); return date_str; diff --git a/keyboards/handwired/tractyl_manuform/tractyl_manuform.c b/keyboards/handwired/tractyl_manuform/tractyl_manuform.c index c68234d8d8..d3e2e02975 100644 --- a/keyboards/handwired/tractyl_manuform/tractyl_manuform.c +++ b/keyboards/handwired/tractyl_manuform/tractyl_manuform.c @@ -247,17 +247,17 @@ static bool has_shift_mod(void) { */ __attribute__((unused)) static void debug_charybdis_config_to_console(charybdis_config_t* config) { # ifdef CONSOLE_ENABLE - dprintf("(charybdis) process_record_kb: config = {\n" - "\traw = 0x%04X,\n" - "\t{\n" - "\t\tis_dragscroll_enabled=%b\n" - "\t\tis_sniping_enabled=%b\n" - "\t\tdefault_dpi=0x%02X (%ld)\n" - "\t\tsniping_dpi=0x%01X (%ld)\n" - "\t}\n" - "}\n", - config->raw, config->is_dragscroll_enabled, config->is_sniping_enabled, config->pointer_default_dpi, get_pointer_default_dpi(config), config->pointer_sniping_dpi, get_pointer_sniping_dpi(config)); -# endif // CONSOLE_ENABLE + IGNORE_FORMAT_WARNING(dprintf("(charybdis) process_record_kb: config = {\n" + "\traw = 0x%04X,\n" + "\t{\n" + "\t\tis_dragscroll_enabled=%b\n" + "\t\tis_sniping_enabled=%b\n" + "\t\tdefault_dpi=0x%02X (%ld)\n" + "\t\tsniping_dpi=0x%01X (%ld)\n" + "\t}\n" + "}\n", + config->raw, config->is_dragscroll_enabled, config->is_sniping_enabled, config->pointer_default_dpi, get_pointer_default_dpi(config), config->pointer_sniping_dpi, get_pointer_sniping_dpi(config))); +# endif // CONSOLE_ENABLE } bool process_record_kb(uint16_t keycode, keyrecord_t* record) { diff --git a/keyboards/rocketboard_16/keymaps/default/keymap.c b/keyboards/rocketboard_16/keymaps/default/keymap.c index ce26a834d0..dc83cbd62b 100644 --- a/keyboards/rocketboard_16/keymaps/default/keymap.c +++ b/keyboards/rocketboard_16/keymaps/default/keymap.c @@ -107,10 +107,10 @@ static void oled_write_ln_centered(const char * data, bool inverted) char line_buf[21]; // Amount to offset string from left side - uint8_t offset = (21 - strlen(data))/2; + uint8_t offset = (22 - strlen(data)) / 2; // Formatted string centering... look, it works, don't ask how... - snprintf(line_buf, 21, "%*s%s%*s\0", offset, "", data, offset, ""); // Centers data within 21 character buffer with null termination + snprintf(line_buf, 21, "%*s%s%*s", offset, "", data, offset, ""); // Centers data within 21 character buffer oled_write_ln(line_buf, inverted); } diff --git a/keyboards/rocketboard_16/keymaps/via/keymap.c b/keyboards/rocketboard_16/keymaps/via/keymap.c index ce26a834d0..08b8e65b4f 100644 --- a/keyboards/rocketboard_16/keymaps/via/keymap.c +++ b/keyboards/rocketboard_16/keymaps/via/keymap.c @@ -107,10 +107,10 @@ static void oled_write_ln_centered(const char * data, bool inverted) char line_buf[21]; // Amount to offset string from left side - uint8_t offset = (21 - strlen(data))/2; + uint8_t offset = (22 - strlen(data))/2; // Formatted string centering... look, it works, don't ask how... - snprintf(line_buf, 21, "%*s%s%*s\0", offset, "", data, offset, ""); // Centers data within 21 character buffer with null termination + snprintf(line_buf, 21, "%*s%s%*s", offset, "", data, offset, ""); // Centers data within 21 character buffer oled_write_ln(line_buf, inverted); } diff --git a/keyboards/tzarc/djinn/graphics/theme_djinn_default.c b/keyboards/tzarc/djinn/graphics/theme_djinn_default.c index 616a3c2430..a4e87bd341 100644 --- a/keyboards/tzarc/djinn/graphics/theme_djinn_default.c +++ b/keyboards/tzarc/djinn/graphics/theme_djinn_default.c @@ -158,7 +158,7 @@ void draw_ui_user(void) { if (hue_redraw || rgb_effect_redraw) { static int max_rgb_xpos = 0; xpos = 16; - snprintf_(buf, sizeof(buf), "rgb: %s", rgb_matrix_name(curr_effect)); + snprintf(buf, sizeof(buf), "rgb: %s", rgb_matrix_name(curr_effect)); for (int i = 5; i < sizeof(buf); ++i) { if (buf[i] == 0) @@ -187,7 +187,7 @@ void draw_ui_user(void) { static int max_layer_xpos = 0; xpos = 16; - snprintf_(buf, sizeof(buf), "layer: %s", layer_name); + snprintf(buf, sizeof(buf), "layer: %s", layer_name); xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0); if (max_layer_xpos < xpos) { max_layer_xpos = xpos; @@ -200,7 +200,7 @@ void draw_ui_user(void) { if (hue_redraw || power_state_redraw) { static int max_power_xpos = 0; xpos = 16; - snprintf_(buf, sizeof(buf), "power: %s", usbpd_str(kb_state.current_setting)); + snprintf(buf, sizeof(buf), "power: %s", usbpd_str(kb_state.current_setting)); xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0); if (max_power_xpos < xpos) { max_power_xpos = xpos; @@ -213,7 +213,7 @@ void draw_ui_user(void) { if (hue_redraw || scan_redraw) { static int max_scans_xpos = 0; xpos = 16; - snprintf_(buf, sizeof(buf), "scans: %d", (int)theme_state.scan_rate); + snprintf(buf, sizeof(buf), "scans: %d", (int)theme_state.scan_rate); xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0); if (max_scans_xpos < xpos) { max_scans_xpos = xpos; @@ -226,7 +226,7 @@ void draw_ui_user(void) { if (hue_redraw || wpm_redraw) { static int max_wpm_xpos = 0; xpos = 16; - snprintf_(buf, sizeof(buf), "wpm: %d", (int)get_current_wpm()); + snprintf(buf, sizeof(buf), "wpm: %d", (int)get_current_wpm()); xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0); if (max_wpm_xpos < xpos) { max_wpm_xpos = xpos; diff --git a/quantum/command.c b/quantum/command.c index 2e94cb44b8..84757b9b01 100644 --- a/quantum/command.c +++ b/quantum/command.c @@ -161,7 +161,7 @@ static void command_common_help(void) { } static void print_version(void) { - print(/* clang-format off */ + xprintf("%s", /* clang-format off */ "\n\t- Version -\n" "VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") " "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") " diff --git a/quantum/logging/print.h b/quantum/logging/print.h index 5fbf189505..4c4195de50 100644 --- a/quantum/logging/print.h +++ b/quantum/logging/print.h @@ -100,7 +100,7 @@ void print_set_sendchar(sendchar_func_t func); #define print_bin32(i) IGNORE_FORMAT_WARNING(xprintf("%032lb", i)) #define print_bin_reverse8(i) IGNORE_FORMAT_WARNING(xprintf("%08b", bitrev(i))) #define print_bin_reverse16(i) IGNORE_FORMAT_WARNING(xprintf("%016b", bitrev16(i))) -#define print_bin_reverse32(i) IGNORE_FORMAT_WARNINGxprintf("%032lb", bitrev32(i))) +#define print_bin_reverse32(i) IGNORE_FORMAT_WARNING(xprintf("%032lb", bitrev32(i))) /* print value utility */ #define print_val_dec(v) xprintf(#v ": %u\n", v) #define print_val_decs(v) xprintf(#v ": %d\n", v) -- cgit v1.2.3 From 61df87ae2ccaafc8387c4349187f0ab7e9e7bfbc Mon Sep 17 00:00:00 2001 From: "FREEWING.JP" Date: Tue, 12 Jul 2022 04:59:16 +0900 Subject: Added Delay time dynamic keymap's macro feature (#16810) Co-authored-by: Joel Challis Co-authored-by: Ryan --- quantum/dynamic_keymap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index fc1c55784d..cbe9f13940 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c @@ -93,6 +93,10 @@ _Static_assert((DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) - (DYNAMIC_KEYMAP_MACRO_EEPROM_A # define DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + 1) #endif +#ifndef DYNAMIC_KEYMAP_MACRO_DELAY +# define DYNAMIC_KEYMAP_MACRO_DELAY TAP_CODE_DELAY +#endif + uint8_t dynamic_keymap_get_layer_count(void) { return DYNAMIC_KEYMAP_LAYER_COUNT; } @@ -300,6 +304,6 @@ void dynamic_keymap_macro_send(uint8_t id) { break; } } - send_string(data); + send_string_with_delay(data, DYNAMIC_KEYMAP_MACRO_DELAY); } } -- cgit v1.2.3 From 5db705d054e54a901f8968e3380e13c791991ab3 Mon Sep 17 00:00:00 2001 From: Daniel Kao Date: Tue, 12 Jul 2022 21:17:40 -0700 Subject: Cirque trackpad features: circular scroll, inertial cursor (#17482) --- builddefs/common_features.mk | 4 + docs/feature_pointing_device.md | 31 ++- drivers/sensors/cirque_pinnacle.c | 191 +++++++------- drivers/sensors/cirque_pinnacle.h | 14 +- drivers/sensors/cirque_pinnacle_gestures.c | 226 ++++++++++++++++ drivers/sensors/cirque_pinnacle_gestures.h | 107 ++++++++ drivers/sensors/cirque_pinnacle_regdefs.h | 405 +++++++++++++++++++++++++++++ quantum/pointing_device.h | 2 + quantum/pointing_device_drivers.c | 101 ++++--- quantum/pointing_device_gestures.c | 133 ++++++++++ quantum/pointing_device_gestures.h | 58 +++++ 11 files changed, 1123 insertions(+), 149 deletions(-) create mode 100644 drivers/sensors/cirque_pinnacle_gestures.c create mode 100644 drivers/sensors/cirque_pinnacle_gestures.h create mode 100644 drivers/sensors/cirque_pinnacle_regdefs.h create mode 100644 quantum/pointing_device_gestures.c create mode 100644 quantum/pointing_device_gestures.h (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 5cc4508307..01dbdc3330 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -149,10 +149,14 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), cirque_pinnacle_i2c) OPT_DEFS += -DSTM32_I2C -DHAL_USE_I2C=TRUE SRC += drivers/sensors/cirque_pinnacle.c + SRC += drivers/sensors/cirque_pinnacle_gestures.c + SRC += $(QUANTUM_DIR)/pointing_device_gestures.c QUANTUM_LIB_SRC += i2c_master.c else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), cirque_pinnacle_spi) OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE SRC += drivers/sensors/cirque_pinnacle.c + SRC += drivers/sensors/cirque_pinnacle_gestures.c + SRC += $(QUANTUM_DIR)/pointing_device_gestures.c QUANTUM_LIB_SRC += spi_master.c else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball) OPT_DEFS += -DSTM32_SPI -DHAL_USE_I2C=TRUE diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md index 264362ea77..70129dfc9a 100644 --- a/docs/feature_pointing_device.md +++ b/docs/feature_pointing_device.md @@ -89,15 +89,15 @@ POINTING_DEVICE_DRIVER = cirque_pinnacle_spi This supports the Cirque Pinnacle 1CA027 Touch Controller, which is used in the TM040040, TM035035 and the TM023023 trackpads. These are I2C or SPI compatible, and both configurations are supported. -| Setting | Description | Default | -|-------------------------------- |-----------------------------------------------------------------------|--------------------- | -|`CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` | -|`CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` | -|`CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` | -|`CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` | -|`CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `ADC_ATTENUATE_4X` | -|`CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | -|`CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | +| Setting | Description | Default | +|-------------------------------- |------------------------------------------------------------|--------------------| +|`CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` | +|`CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` | +|`CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` | +|`CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` | +|`CIRQUE_PINNACLE_DIAMETER_MM` | (Optional) Diameter of the trackpad sensor in millimeters. | `40` | +|`CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `ADC_ATTENUATE_4X` | +|`CIRQUE_PINNACLE_CURVED_OVERLAY` | (Optional) Applies settings tuned for curved overlay. | _not defined_ | **`CIRQUE_PINNACLE_ATTENUATION`** is a measure of how much data is suppressed in regards to sensitivity. The higher the attenuation, the less sensitive the touchpad will be. @@ -120,10 +120,21 @@ Default attenuation is set to 4X, although if you are using a thicker overlay (s |`CIRQUE_PINNACLE_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ | |`CIRQUE_PINNACLE_SPI_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ | -Default Scaling/CPI is 1024. +Default Scaling is 1024. Actual CPI depends on trackpad diameter. Also see the `POINTING_DEVICE_TASK_THROTTLE_MS`, which defaults to 10ms when using Cirque Pinnacle, which matches the internal update rate of the position registers (in standard configuration). Advanced configuration for pen/stylus usage might require lower values. +#### Cirque Trackpad gestures + +| Gesture Setting | Description | Default | +|-----------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------| +|`POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` | (Optional) Enable inertial cursor. Cursor continues moving after a flick gesture and slows down by kinetic friction | _not defined_ | +|`CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE` | (Optional) Enable circular scroll. Touch originating in outer ring can trigger scroll by moving along the perimeter. Near side triggers vertical scroll and far side triggers horizontal scroll. | _not defined_ | +|`CIRQUE_PINNACLE_TAP_ENABLE` | (Optional) Enable tap to click. This currently only works on the master side. | _not defined_ | +|`CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | +|`CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | + +**`POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE`** is not specific to Cirque trackpad; any pointing device with a lift/contact status can integrate this gesture into its driver. e.g. PMW3360 can use Lift_Stat from Motion register. Note that `POINTING_DEVICE_MOTION_PIN` cannot be used with this feature; continuous polling of `pointing_device_get_report()` is needed to generate glide reports. ### Pimoroni Trackball diff --git a/drivers/sensors/cirque_pinnacle.c b/drivers/sensors/cirque_pinnacle.c index 1d1e4ccfc6..c50d5a2525 100644 --- a/drivers/sensors/cirque_pinnacle.c +++ b/drivers/sensors/cirque_pinnacle.c @@ -9,47 +9,16 @@ #include "wait.h" #include "timer.h" -// Registers for RAP -// clang-format off -#define FIRMWARE_ID 0x00 -#define FIRMWARE_VERSION_C 0x01 -#define STATUS_1 0x02 -#define SYSCONFIG_1 0x03 -#define FEEDCONFIG_1 0x04 -#define FEEDCONFIG_2 0x05 -#define CALIBRATION_CONFIG_1 0x07 -#define PS2_AU_CONTROL 0x08 -#define SAMPLE_RATE 0x09 -#define Z_IDLE_COUNT 0x0A -#define Z_SCALER 0x0B -#define SLEEP_INTERVAL 0x0C -#define SLEEP_TIMER 0x0D -#define PACKET_BYTE_0 0x12 -#define PACKET_BYTE_1 0x13 -#define PACKET_BYTE_2 0x14 -#define PACKET_BYTE_3 0x15 -#define PACKET_BYTE_4 0x16 -#define PACKET_BYTE_5 0x17 - -#define ERA_VALUE 0x1B -#define ERA_HIGH_BYTE 0x1C -#define ERA_LOW_BYTE 0x1D -#define ERA_CONTROL 0x1E - -// ADC-attenuation settings (held in BIT_7 and BIT_6) -// 1X = most sensitive, 4X = least sensitive -#define ADC_ATTENUATE_1X 0x00 -#define ADC_ATTENUATE_2X 0x40 -#define ADC_ATTENUATE_3X 0x80 -#define ADC_ATTENUATE_4X 0xC0 - #ifndef CIRQUE_PINNACLE_ATTENUATION -# define CIRQUE_PINNACLE_ATTENUATION ADC_ATTENUATE_4X +# ifdef CIRQUE_PINNACLE_CURVED_OVERLAY +# define CIRQUE_PINNACLE_ATTENUATION EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_2X +# else +# define CIRQUE_PINNACLE_ATTENUATION EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_4X +# endif #endif -// clang-format on bool touchpad_init; -uint16_t scale_data = 1024; +uint16_t scale_data = CIRQUE_PINNACLE_DEFAULT_SCALE; void cirque_pinnacle_clear_flags(void); void cirque_pinnacle_enable_feed(bool feedEnable); @@ -106,43 +75,45 @@ void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResoluti // Clears Status1 register flags (SW_CC and SW_DR) void cirque_pinnacle_clear_flags() { - RAP_Write(STATUS_1, 0x00); + RAP_Write(HOSTREG__STATUS1, HOSTREG__STATUS1_DEFVAL & ~(HOSTREG__STATUS1__COMMAND_COMPLETE | HOSTREG__STATUS1__DATA_READY)); wait_us(50); } // Enables/Disables the feed void cirque_pinnacle_enable_feed(bool feedEnable) { - uint8_t temp; - RAP_ReadBytes(FEEDCONFIG_1, &temp, 1); // Store contents of FeedConfig1 register + uint8_t feedconfig1; + RAP_ReadBytes(HOSTREG__FEEDCONFIG1, &feedconfig1, 1); if (feedEnable) { - temp |= 0x01; // Set Feed Enable bit + feedconfig1 |= HOSTREG__FEEDCONFIG1__FEED_ENABLE; } else { - temp &= ~0x01; // Clear Feed Enable bit + feedconfig1 &= ~HOSTREG__FEEDCONFIG1__FEED_ENABLE; } - RAP_Write(FEEDCONFIG_1, temp); + RAP_Write(HOSTREG__FEEDCONFIG1, feedconfig1); } /* ERA (Extended Register Access) Functions */ // Reads bytes from an extended register at
(16-bit address), // stores values in <*data> void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) { - uint8_t ERAControlValue = 0xFF; + uint8_t ERAControlValue = 0xFF; + uint16_t timeout_timer; cirque_pinnacle_enable_feed(false); // Disable feed - RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Send upper byte of ERA address - RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address + RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_HIGH, (uint8_t)(address >> 8)); // Send upper byte of ERA address + RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_LOW, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address for (uint16_t i = 0; i < count; i++) { - RAP_Write(ERA_CONTROL, 0x05); // Signal ERA-read (auto-increment) to Pinnacle + RAP_Write(HOSTREG__EXT_REG_AXS_CTRL, HOSTREG__EREG_AXS__INC_ADDR_READ | HOSTREG__EREG_AXS__READ); // Signal ERA-read (auto-increment) to Pinnacle // Wait for status register 0x1E to clear + timeout_timer = timer_read(); do { - RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1); - } while (ERAControlValue != 0x00); + RAP_ReadBytes(HOSTREG__EXT_REG_AXS_CTRL, &ERAControlValue, 1); + } while ((ERAControlValue != 0x00) && (timer_elapsed(timeout_timer) <= CIRQUE_PINNACLE_TIMEOUT)); - RAP_ReadBytes(ERA_VALUE, data + i, 1); + RAP_ReadBytes(HOSTREG__EXT_REG_AXS_VALUE, data + i, 1); cirque_pinnacle_clear_flags(); } @@ -150,46 +121,80 @@ void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) { // Writes a byte, , to an extended register at
(16-bit address) void ERA_WriteByte(uint16_t address, uint8_t data) { - uint8_t ERAControlValue = 0xFF; + uint8_t ERAControlValue = 0xFF; + uint16_t timeout_timer; cirque_pinnacle_enable_feed(false); // Disable feed - RAP_Write(ERA_VALUE, data); // Send data byte to be written + RAP_Write(HOSTREG__EXT_REG_AXS_VALUE, data); // Send data byte to be written - RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Upper byte of ERA address - RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address + RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_HIGH, (uint8_t)(address >> 8)); // Upper byte of ERA address + RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_LOW, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address - RAP_Write(ERA_CONTROL, 0x02); // Signal an ERA-write to Pinnacle + RAP_Write(HOSTREG__EXT_REG_AXS_CTRL, HOSTREG__EREG_AXS__WRITE); // Signal an ERA-write to Pinnacle // Wait for status register 0x1E to clear + timeout_timer = timer_read(); do { - RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1); - } while (ERAControlValue != 0x00); + RAP_ReadBytes(HOSTREG__EXT_REG_AXS_CTRL, &ERAControlValue, 1); + } while ((ERAControlValue != 0x00) && (timer_elapsed(timeout_timer) <= CIRQUE_PINNACLE_TIMEOUT)); cirque_pinnacle_clear_flags(); } void cirque_pinnacle_set_adc_attenuation(uint8_t adcGain) { - uint8_t temp = 0x00; + uint8_t adcconfig = 0x00; - ERA_ReadBytes(0x0187, &temp, 1); - temp &= 0x3F; // clear top two bits - temp |= adcGain; - ERA_WriteByte(0x0187, temp); - ERA_ReadBytes(0x0187, &temp, 1); + ERA_ReadBytes(EXTREG__TRACK_ADCCONFIG, &adcconfig, 1); + adcconfig &= EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK; + adcconfig |= adcGain; + ERA_WriteByte(EXTREG__TRACK_ADCCONFIG, adcconfig); + ERA_ReadBytes(EXTREG__TRACK_ADCCONFIG, &adcconfig, 1); } // Changes thresholds to improve detection of fingers +// Not needed for flat overlay? void cirque_pinnacle_tune_edge_sensitivity(void) { - uint8_t temp = 0x00; + uint8_t widezmin = 0x00; - ERA_ReadBytes(0x0149, &temp, 1); - ERA_WriteByte(0x0149, 0x04); - ERA_ReadBytes(0x0149, &temp, 1); + ERA_ReadBytes(EXTREG__XAXIS_WIDEZMIN, &widezmin, 1); + ERA_WriteByte(EXTREG__XAXIS_WIDEZMIN, 0x04); // magic number from Cirque sample code + ERA_ReadBytes(EXTREG__XAXIS_WIDEZMIN, &widezmin, 1); - ERA_ReadBytes(0x0168, &temp, 1); - ERA_WriteByte(0x0168, 0x03); - ERA_ReadBytes(0x0168, &temp, 1); + ERA_ReadBytes(EXTREG__YAXIS_WIDEZMIN, &widezmin, 1); + ERA_WriteByte(EXTREG__YAXIS_WIDEZMIN, 0x03); // magic number from Cirque sample code + ERA_ReadBytes(EXTREG__YAXIS_WIDEZMIN, &widezmin, 1); +} + +// Perform calibration +void cirque_pinnacle_calibrate(void) { + uint8_t calconfig; + uint16_t timeout_timer; + + RAP_ReadBytes(HOSTREG__CALCONFIG1, &calconfig, 1); + calconfig |= HOSTREG__CALCONFIG1__CALIBRATE; + RAP_Write(HOSTREG__CALCONFIG1, calconfig); + + // Calibration takes ~100ms according to GT-AN-090624, doubling the timeout just to be safe + timeout_timer = timer_read(); + do { + RAP_ReadBytes(HOSTREG__CALCONFIG1, &calconfig, 1); + } while ((calconfig & HOSTREG__CALCONFIG1__CALIBRATE) && (timer_elapsed(timeout_timer) <= 200)); + + cirque_pinnacle_clear_flags(); +} + +// Enable/disable cursor smoothing, smoothing is enabled by default +void cirque_pinnacle_cursor_smoothing(bool enable) { + uint8_t feedconfig3; + + RAP_ReadBytes(HOSTREG__FEEDCONFIG3, &feedconfig3, 1); + if (enable) { + feedconfig3 &= ~HOSTREG__FEEDCONFIG3__DISABLE_CROSS_RATE_SMOOTHING; + } else { + feedconfig3 |= HOSTREG__FEEDCONFIG3__DISABLE_CROSS_RATE_SMOOTHING; + } + RAP_Write(HOSTREG__FEEDCONFIG3, feedconfig3); } /* Pinnacle-based TM040040/TM035035/TM023023 Functions */ @@ -205,44 +210,28 @@ void cirque_pinnacle_init(void) { // Host clears SW_CC flag cirque_pinnacle_clear_flags(); - // SysConfig1 (Low Power Mode) - // Bit 0: Reset, 1=Reset - // Bit 1: Shutdown, 1=Shutdown, 0=Active - // Bit 2: Sleep Enable, 1=low power mode, 0=normal mode // send a RESET command now, in case QMK had a soft-reset without a power cycle - RAP_Write(SYSCONFIG_1, 0x01); + RAP_Write(HOSTREG__SYSCONFIG1, HOSTREG__SYSCONFIG1__RESET); wait_ms(30); // Pinnacle needs 10-15ms to boot, so wait long enough before configuring - RAP_Write(SYSCONFIG_1, 0x00); + RAP_Write(HOSTREG__SYSCONFIG1, HOSTREG__SYSCONFIG1_DEFVAL); wait_us(50); // FeedConfig2 (Feature flags for Relative Mode Only) - // Bit 0: IntelliMouse Enable, 1=enable, 0=disable - // Bit 1: All Taps Disable, 1=disable, 0=enable - // Bit 2: Secondary Tap Disable, 1=disable, 0=enable - // Bit 3: Scroll Disable, 1=disable, 0=enable - // Bit 4: GlideExtend® Disable, 1=disable, 0=enable - // Bit 5: reserved - // Bit 6: reserved - // Bit 7: Swap X & Y, 1=90° rotation, 0=0° rotation - RAP_Write(FEEDCONFIG_2, 0x00); + RAP_Write(HOSTREG__FEEDCONFIG2, HOSTREG__FEEDCONFIG2_DEFVAL); // FeedConfig1 (Data Output Flags) - // Bit 0: Feed enable, 1=feed, 0=no feed - // Bit 1: Data mode, 1=absolute, 0=relative - // Bit 2: Filter disable, 1=no filter, 0=filter - // Bit 3: X disable, 1=no X data, 0=X data - // Bit 4: Y disable, 1=no Y data, 0=Y data - // Bit 5: reserved - // Bit 6: X data Invert, 1=X max to 0, 0=0 to Y max - // Bit 7: Y data Invert, 1=Y max to 0, 0=0 to Y max - RAP_Write(FEEDCONFIG_1, CIRQUE_PINNACLE_POSITION_MODE << 1); - - // Host sets z-idle packet count to 5 (default is 0x1F/30) - RAP_Write(Z_IDLE_COUNT, 5); + RAP_Write(HOSTREG__FEEDCONFIG1, CIRQUE_PINNACLE_POSITION_MODE ? HOSTREG__FEEDCONFIG1__DATA_TYPE__REL0_ABS1 : HOSTREG__FEEDCONFIG1_DEFVAL); - cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION); + // Host sets z-idle packet count to 5 (default is 0x1E/30) + RAP_Write(HOSTREG__ZIDLE, 5); + cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION); +#ifdef CIRQUE_PINNACLE_CURVED_OVERLAY cirque_pinnacle_tune_edge_sensitivity(); +#endif + // Force a calibration after setting ADC attenuation + cirque_pinnacle_calibrate(); + cirque_pinnacle_enable_feed(true); } @@ -252,15 +241,15 @@ pinnacle_data_t cirque_pinnacle_read_data(void) { pinnacle_data_t result = {0}; // Check if there is valid data available - RAP_ReadBytes(STATUS_1, &data_ready, 1); // bit2 is Software Data Ready, bit3 is Command Complete, bit0 and bit1 are reserved/unused - if ((data_ready & 0x04) == 0) { + RAP_ReadBytes(HOSTREG__STATUS1, &data_ready, 1); + if ((data_ready & HOSTREG__STATUS1__DATA_READY) == 0) { // no data available yet result.valid = false; // be explicit return result; } // Read all data bytes - RAP_ReadBytes(PACKET_BYTE_0, data, 6); + RAP_ReadBytes(HOSTREG__PACKETBYTE_0, data, 6); // Get ready for the next data sample cirque_pinnacle_clear_flags(); diff --git a/drivers/sensors/cirque_pinnacle.h b/drivers/sensors/cirque_pinnacle.h index d65bdb41b6..1c9bf06fd3 100644 --- a/drivers/sensors/cirque_pinnacle.h +++ b/drivers/sensors/cirque_pinnacle.h @@ -2,6 +2,7 @@ #pragma once +#include "cirque_pinnacle_regdefs.h" #include #include @@ -15,6 +16,11 @@ # define CIRQUE_PINNACLE_POSITION_MODE CIRQUE_PINNACLE_ABSOLUTE_MODE #endif +#define CIRQUE_PINNACLE_DEFAULT_SCALE 1024 +#ifndef CIRQUE_PINNACLE_DIAMETER_MM +# define CIRQUE_PINNACLE_DIAMETER_MM 40 +#endif + // Coordinate scaling values #ifndef CIRQUE_PINNACLE_X_LOWER # define CIRQUE_PINNACLE_X_LOWER 127 // min "reachable" X value @@ -41,7 +47,7 @@ # include "i2c_master.h" // Cirque's 7-bit I2C Slave Address # ifndef CIRQUE_PINNACLE_ADDR -# define CIRQUE_PINNACLE_ADDR 0x2A +# define CIRQUE_PINNACLE_ADDR I2C_ADDRESS_DEFAULT # endif #elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) # include "spi_master.h" @@ -66,6 +72,10 @@ # endif #endif +#define DIVIDE_UNSIGNED_ROUND(numerator, denominator) (((numerator) + ((denominator) / 2)) / (denominator)) +#define CIRQUE_PINNACLE_INCH_TO_PX(inch) (DIVIDE_UNSIGNED_ROUND((inch) * (uint32_t)CIRQUE_PINNACLE_DIAMETER_MM * 10, 254)) +#define CIRQUE_PINNACLE_PX_TO_INCH(px) (DIVIDE_UNSIGNED_ROUND((px) * (uint32_t)254, CIRQUE_PINNACLE_DIAMETER_MM * 10)) + // Convenient way to store and access measurements typedef struct { bool valid; // true if valid data was read, false if no data was ready @@ -84,6 +94,8 @@ typedef struct { } pinnacle_data_t; void cirque_pinnacle_init(void); +void cirque_pinnacle_calibrate(void); +void cirque_pinnacle_cursor_smoothing(bool enable); pinnacle_data_t cirque_pinnacle_read_data(void); void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution); uint16_t cirque_pinnacle_get_scale(void); diff --git a/drivers/sensors/cirque_pinnacle_gestures.c b/drivers/sensors/cirque_pinnacle_gestures.c new file mode 100644 index 0000000000..f6f9177e08 --- /dev/null +++ b/drivers/sensors/cirque_pinnacle_gestures.c @@ -0,0 +1,226 @@ +/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) + * Copyright 2022 Daniel Kao + * + * 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 . + */ +#include +#include +#include "cirque_pinnacle_gestures.h" +#include "pointing_device.h" +#include "timer.h" + +#if defined(CIRQUE_PINNACLE_TAP_ENABLE) || defined(CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE) +static cirque_pinnacle_features_t features = {.tap_enable = true, .circular_scroll_enable = true}; +#endif + +#ifdef CIRQUE_PINNACLE_TAP_ENABLE +static trackpad_tap_context_t tap; + +static report_mouse_t trackpad_tap(report_mouse_t mouse_report, pinnacle_data_t touchData) { + if (touchData.touchDown != tap.touchDown) { + tap.touchDown = touchData.touchDown; + if (!touchData.zValue) { + if (timer_elapsed(tap.timer) < CIRQUE_PINNACLE_TAPPING_TERM && tap.timer != 0) { + mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); + pointing_device_set_report(mouse_report); + pointing_device_send(); +# if TAP_CODE_DELAY > 0 + wait_ms(TAP_CODE_DELAY); +# endif + mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1); + pointing_device_set_report(mouse_report); + pointing_device_send(); + } + } + tap.timer = timer_read(); + } + if (timer_elapsed(tap.timer) > (CIRQUE_PINNACLE_TOUCH_DEBOUNCE)) { + tap.timer = 0; + } + + return mouse_report; +} + +void cirque_pinnacle_enable_tap(bool enable) { + features.tap_enable = enable; +} +#endif + +#ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE +/* To set a trackpad exclusively as scroll wheel: outer_ring_pct = 100, trigger_px = 0, trigger_ang = 0 */ +static circular_scroll_context_t scroll = {.config = {.outer_ring_pct = 33, + .trigger_px = 16, + .trigger_ang = 9102, /* 50 degrees */ + .wheel_clicks = 18}}; + +static inline uint16_t atan2_16(int32_t dy, int32_t dx) { + if (dy == 0) { + if (dx >= 0) { + return 0; + } else { + return 32768; + } + } + + int32_t abs_y = dy > 0 ? dy : -dy; + int16_t a; + + if (dx >= 0) { + a = 8192 - (8192 * (dx - abs_y) / (dx + abs_y)); + } else { + a = 24576 - (8192 * (dx + abs_y) / (abs_y - dx)); + } + + if (dy < 0) { + return -a; // negate if in quad III or IV + } + return a; +} + +static circular_scroll_t circular_scroll(pinnacle_data_t touchData) { + circular_scroll_t report = {0, 0, false}; + int8_t x, y, wheel_clicks; + uint8_t center = 256 / 2, mag; + int16_t ang, dot, det, opposite_side, adjacent_side; + uint16_t scale = cirque_pinnacle_get_scale(); + + if (touchData.zValue) { + /* + * Place origin at center of trackpad, treat coordinates as vectors. + * Scale to fixed int8_t size; angles are independent of resolution. + */ + if (scale) { + x = (int8_t)((int32_t)touchData.xValue * 256 / scale - center); + y = (int8_t)((int32_t)touchData.yValue * 256 / scale - center); + } else { + x = 0; + y = 0; + } + + /* Check if first touch */ + if (!scroll.z) { + report.suppress_touch = false; + /* Check if touch falls within outer ring */ + mag = sqrt16(x * x + y * y); + if (mag * 100 / center >= 100 - scroll.config.outer_ring_pct) { + scroll.state = SCROLL_DETECTING; + scroll.x = x; + scroll.y = y; + scroll.mag = mag; + /* + * Decide scroll axis: + * Vertical if started from righ half + * Horizontal if started from left half + * Flipped for left-handed + */ +# if defined(POINTING_DEVICE_ROTATION_90) + scroll.axis = y < 0; +# elif defined(POINTING_DEVICE_ROTATION_180) + scroll.axis = x > 0; +# elif defined(POINTING_DEVICE_ROTATION_270) + scroll.axis = y > 0; +# else + scroll.axis = x < 0; +# endif + } + } else if (scroll.state == SCROLL_DETECTING) { + report.suppress_touch = true; + /* Already detecting scroll, check movement from touchdown location */ + mag = sqrt16((x - scroll.x) * (x - scroll.x) + (y - scroll.y) * (y - scroll.y)); + if (mag >= scroll.config.trigger_px) { + /* + * Find angle of movement. + * 0 degrees here means movement towards center of circle + */ + dot = scroll.x * x + scroll.y * y; + det = scroll.x * y - scroll.y * x; + opposite_side = abs(det); /* Based on scalar rejection */ + adjacent_side = abs(scroll.mag * scroll.mag - abs(dot)); /* Based on scalar projection */ + ang = (int16_t)atan2_16(opposite_side, adjacent_side); + if (ang < scroll.config.trigger_ang) { + /* Not a scroll, release coordinates */ + report.suppress_touch = false; + scroll.state = NOT_SCROLL; + } else { + /* Scroll detected */ + scroll.state = SCROLL_VALID; + } + } + } + if (scroll.state == SCROLL_VALID) { + report.suppress_touch = true; + dot = scroll.x * x + scroll.y * y; + det = scroll.x * y - scroll.y * x; + ang = (int16_t)atan2_16(det, dot); + wheel_clicks = ((int32_t)ang * scroll.config.wheel_clicks) / 65536; + if (wheel_clicks >= 1 || wheel_clicks <= -1) { + if (scroll.config.left_handed) { + if (scroll.axis == 0) { + report.h = -wheel_clicks; + } else { + report.v = wheel_clicks; + } + } else { + if (scroll.axis == 0) { + report.v = -wheel_clicks; + } else { + report.h = wheel_clicks; + } + } + scroll.x = x; + scroll.y = y; + } + } + } + + scroll.z = touchData.zValue; + if (!scroll.z) scroll.state = SCROLL_UNINITIALIZED; + + return report; +} + +void cirque_pinnacle_enable_circular_scroll(bool enable) { + features.circular_scroll_enable = enable; +} + +void cirque_pinnacle_configure_circular_scroll(uint8_t outer_ring_pct, uint8_t trigger_px, uint16_t trigger_ang, uint8_t wheel_clicks, bool left_handed) { + scroll.config.outer_ring_pct = outer_ring_pct; + scroll.config.trigger_px = trigger_px; + scroll.config.trigger_ang = trigger_ang; + scroll.config.wheel_clicks = wheel_clicks; + scroll.config.left_handed = left_handed; +} +#endif + +bool cirque_pinnacle_gestures(report_mouse_t* mouse_report, pinnacle_data_t touchData) { + bool suppress_mouse_update = false; + +#ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE + circular_scroll_t scroll_report; + if (features.circular_scroll_enable) { + scroll_report = circular_scroll(touchData); + mouse_report->v = scroll_report.v; + mouse_report->h = scroll_report.h; + suppress_mouse_update = scroll_report.suppress_touch; + } +#endif + +#ifdef CIRQUE_PINNACLE_TAP_ENABLE + if (features.tap_enable) { + *mouse_report = trackpad_tap(*mouse_report, touchData); + } +#endif + + return suppress_mouse_update; +} diff --git a/drivers/sensors/cirque_pinnacle_gestures.h b/drivers/sensors/cirque_pinnacle_gestures.h new file mode 100644 index 0000000000..f39782b467 --- /dev/null +++ b/drivers/sensors/cirque_pinnacle_gestures.h @@ -0,0 +1,107 @@ +/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) + * Copyright 2022 Daniel Kao + * + * 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 . + */ +#pragma once + +#include "cirque_pinnacle.h" +#include "report.h" + +typedef struct { + bool tap_enable; + bool circular_scroll_enable; +} cirque_pinnacle_features_t; + +#ifdef CIRQUE_PINNACLE_TAP_ENABLE +# ifndef CIRQUE_PINNACLE_TAPPING_TERM +# include "action.h" +# include "action_tapping.h" +# define CIRQUE_PINNACLE_TAPPING_TERM GET_TAPPING_TERM(KC_BTN1, &(keyrecord_t){}) +# endif +# ifndef CIRQUE_PINNACLE_TOUCH_DEBOUNCE +# define CIRQUE_PINNACLE_TOUCH_DEBOUNCE (CIRQUE_PINNACLE_TAPPING_TERM * 8) +# endif + +typedef struct { + uint16_t timer; + bool touchDown; +} trackpad_tap_context_t; + +/* Enable/disable tap gesture */ +void cirque_pinnacle_enable_tap(bool enable); +#endif + +#ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE +typedef enum { + SCROLL_UNINITIALIZED, + SCROLL_DETECTING, + SCROLL_VALID, + NOT_SCROLL, +} circular_scroll_status_t; + +typedef struct { + int8_t v; + int8_t h; + bool suppress_touch; +} circular_scroll_t; + +typedef struct { + uint8_t outer_ring_pct; /* Width of outer ring, given as a percentage of the radius */ + uint8_t trigger_px; /* Amount of movement before triggering scroll validation, in pixels 0~127 */ + uint16_t trigger_ang; /* Angle required to validate scroll, in radians where pi = 32768 */ + uint8_t wheel_clicks; /* How many clicks to report in a circle */ + bool left_handed; /* Whether scrolling should be flipped for left handed use */ +} circular_scroll_config_t; + +typedef struct { + circular_scroll_config_t config; + circular_scroll_status_t state; + uint8_t mag; + int8_t x; + int8_t y; + uint16_t z; + bool axis; +} circular_scroll_context_t; + +/* Enable/disable circular scroll gesture */ +void cirque_pinnacle_enable_circular_scroll(bool enable); + +/* + * Configure circular scroll gesture. + * Trackpad can be configured to act exclusively as a scroll wheel with outer_ring_pct = 0, trigger_px = 0, trigger_ang = 0. + * @param outer_ring_pct Width of outer ring from which to begin scroll validation, given as a percentage of the radius. + * @param trigger_px Amount of movement before triggering scroll validation. Expressed in pixels, trackpad coordinates are scaled to radius of 128 pixels for circular scroll. + * @param triger_ang Angle required to validate scroll, angle smaller than this will invalidate scroll. In radians where pi = 32768, 0 means movement towards center of trackpad, 16384 means movement perpendicular to center. + * @param wheel_clicks Number of scroll wheel clicks to report in a full rotation. + * @param left_handed Whether scrolling should be flipped for left-handed use. + */ +void cirque_pinnacle_configure_circular_scroll(uint8_t outer_ring_pct, uint8_t trigger_px, uint16_t trigger_ang, uint8_t wheel_clicks, bool left_handed); +#endif + +#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +/* Implementation in pointing_device_drivers.c */ + +/* Enable/disable inertial cursor */ +void cirque_pinnacle_enable_cursor_glide(bool enable); + +/* + * Configure inertial cursor. + * @param trigger_px Movement required to trigger cursor glide, set this to non-zero if you have some amount of hover. + */ +void cirque_pinnacle_configure_cursor_glide(float trigger_px); +#endif + +/* Process available gestures */ +bool cirque_pinnacle_gestures(report_mouse_t* mouse_report, pinnacle_data_t touchData); diff --git a/drivers/sensors/cirque_pinnacle_regdefs.h b/drivers/sensors/cirque_pinnacle_regdefs.h new file mode 100644 index 0000000000..993da1e757 --- /dev/null +++ b/drivers/sensors/cirque_pinnacle_regdefs.h @@ -0,0 +1,405 @@ +// Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license +// based on https://github.com/cirque-corp/Cirque_Pinnacle_1CA027/tree/master/Additional_Examples +// with modifications and changes for QMK +// refer to documentation: Gen2 and Gen3 (Pinnacle ASIC) at https://www.cirque.com/gen2gen3-asic-details + +#pragma once + +// clang-format off + +#define HostReg__0 (0x00) +#define HostReg__1 (0x01) +#define HostReg__2 (0x02) +#define HostReg__3 (0x03) +#define HostReg__4 (0x04) +#define HostReg__5 (0x05) +#define HostReg__6 (0x06) +#define HostReg__7 (0x07) +#define HostReg__8 (0x08) +#define HostReg__9 (0x09) +#define HostReg__10 (0x0A) +#define HostReg__11 (0x0B) +#define HostReg__12 (0x0C) +#define HostReg__13 (0x0D) +#define HostReg__14 (0x0E) +#define HostReg__15 (0x0F) +#define HostReg__16 (0x10) +#define HostReg__17 (0x11) +#define HostReg__18 (0x12) +#define HostReg__19 (0x13) +#define HostReg__20 (0x14) +#define HostReg__21 (0x15) +#define HostReg__22 (0x16) +#define HostReg__23 (0x17) +#define HostReg__24 (0x18) +#define HostReg__25 (0x19) +#define HostReg__26 (0x1A) +#define HostReg__27 (0x1B) +#define HostReg__28 (0x1C) +#define HostReg__29 (0x1D) +#define HostReg__30 (0x1E) +#define HostReg__31 (0x1F) + +// ---------------- Register Assignments ------------------------------------- + +/*--------------------------------------------------------------------------*\ + Chip ID / Version +\*--------------------------------------------------------------------------*/ +// Chip ID Register +#define HOSTREG__CHIPID HostReg__0 + +// Chip Version Register +#define HOSTREG__VERSION HostReg__1 + +/*--------------------------------------------------------------------------*\ + Status Register +\*--------------------------------------------------------------------------*/ +// Status 1 Register -- MUST BE HOSTREG__2 +#define HOSTREG__STATUS1 HostReg__2 +# define HOSTREG__STATUS1__DATA_READY 0x04 +# define HOSTREG__STATUS1__COMMAND_COMPLETE 0x08 +#define HOSTREG__STATUS1_DEFVAL 0x00 + +/*--------------------------------------------------------------------------*\ + System Config Register +\*--------------------------------------------------------------------------*/ +#define HOSTREG__SYSCONFIG1 HostReg__3 +# define HOSTREG__SYSCONFIG1__RESET 0x01 +# define HOSTREG__SYSCONFIG1__STANDBY 0x02 +# define HOSTREG__SYSCONFIG1__AUTO_SLEEP 0x04 +# define HOSTREG__SYSCONFIG1__TRACK_DISABLE 0x08 +# define HOSTREG__SYSCONFIG1__ANYMEAS_ENABLE 0x10 +# define HOSTREG__SYSCONFIG1__GPIO_CTRL_ENABLE 0x20 +# define HOSTREG__SYSCONFIG1__WAKEUP_TOGGLE 0x40 +# define HOSTREG__SYSCONFIG1__FORCE_WAKEUP 0x80 +#define HOSTREG__SYSCONFIG1_DEFVAL 0x00 + +/*--------------------------------------------------------------------------*\ + Feed Config Registers +\*--------------------------------------------------------------------------*/ +// Feed Config Register1 +#define HOSTREG__FEEDCONFIG1 HostReg__4 +# define HOSTREG__FEEDCONFIG1__FEED_ENABLE 0x01 +# define HOSTREG__FEEDCONFIG1__DATA_TYPE__REL0_ABS1 0x02 +# define HOSTREG__FEEDCONFIG1__FILTER_DISABLE 0x04 +# define HOSTREG__FEEDCONFIG1__X_AXIS_DISABLE 0x08 +# define HOSTREG__FEEDCONFIG1__Y_AXIS_DISABLE 0x10 +# define HOSTREG__FEEDCONFIG1__AXIS_FOR_Z__Y0_X1 0x20 +# define HOSTREG__FEEDCONFIG1__X_DATA_INVERT 0x40 +# define HOSTREG__FEEDCONFIG1__Y_DATA_INVERT 0x80 +#define HOSTREG__FEEDCONFIG1_DEFVAL 0x00 + +// Feed Config Register2 +#define HOSTREG__FEEDCONFIG2 HostReg__5 +# define HOSTREG__FEEDCONFIG2__INTELLIMOUSE_MODE 0x01 +# define HOSTREG__FEEDCONFIG2__ALL_TAP_DISABLE 0x02 +# define HOSTREG__FEEDCONFIG2__SECONDARY_TAP_DISABLE 0x04 +# define HOSTREG__FEEDCONFIG2__SCROLL_DISABLE 0x08 +# define HOSTREG__FEEDCONFIG2__GLIDE_EXTEND_DISABLE 0x10 +# define HOSTREG__FEEDCONFIG2__PALM_BEFORE_Z_ENABLE 0x20 +# define HOSTREG__FEEDCONFIG2__BUTNS_46_SCROLL_5_MIDDLE 0x40 +# define HOSTREG__FEEDCONFIG2__SWAP_XY_RELATIVE 0x80 +#define HOSTREG__FEEDCONFIG2_DEFVAL 0x00 + +// Feed Config Register3 +#define HOSTREG__FEEDCONFIG3 HostReg__6 +# define HOSTREG__FEEDCONFIG3__BTNS_456_TO_123_IN_REL 0x01 +# define HOSTREG__FEEDCONFIG3__DISABLE_CROSS_RATE_SMOOTHING 0x02 +# define HOSTREG__FEEDCONFIG3__DISABLE_PALM_NERD_MEAS 0x04 +# define HOSTREG__FEEDCONFIG3__DISABLE_NOISE_AVOIDANCE 0x08 +# define HOSTREG__FEEDCONFIG3__DISABLE_WRAP_LOCKOUT 0x10 +# define HOSTREG__FEEDCONFIG3__DISABLE_DYNAMIC_EMI_ADJUST 0x20 +# define HOSTREG__FEEDCONFIG3__DISABLE_HW_EMI_DETECT 0x40 +# define HOSTREG__FEEDCONFIG3__DISABLE_SW_EMI_DETECT 0x80 +#define HOSTREG__FEEDCONFIG3_DEFVAL 0x00 + +/*--------------------------------------------------------------------------*\ + Calibration Config +\*--------------------------------------------------------------------------*/ +#define HOSTREG__CALCONFIG1 HostReg__7 +# define HOSTREG__CALCONFIG1__CALIBRATE 0x01 +# define HOSTREG__CALCONFIG1__BACKGROUND_COMP_ENABLE 0x02 +# define HOSTREG__CALCONFIG1__NERD_COMP_ENABLE 0x04 +# define HOSTREG__CALCONFIG1__TRACK_ERROR_COMP_ENABLE 0x08 +# define HOSTREG__CALCONFIG1__TAP_COMP_ENABLE 0x10 +# define HOSTREG__CALCONFIG1__PALM_ERROR_COMP_ENABLE 0x20 +# define HOSTREG__CALCONFIG1__CALIBRATION_MATRIX_DISABLE 0x40 +# define HOSTREG__CALCONFIG1__FORCE_PRECALIBRATION_NOISE_CHECK 0x80 +#define HOSTREG__CALCONFIG1_DEFVAL (HOSTREG__CALCONFIG1__BACKGROUND_COMP_ENABLE | HOSTREG__CALCONFIG1__NERD_COMP_ENABLE | HOSTREG__CALCONFIG1__TRACK_ERROR_COMP_ENABLE | HOSTREG__CALCONFIG1__TAP_COMP_ENABLE | HOSTREG__CALCONFIG1__PALM_ERROR_COMP_ENABLE) + +/*--------------------------------------------------------------------------*\ + PS2 Aux Control Register +\*--------------------------------------------------------------------------*/ +#define HOSTREG__PS2AUX_CTRL HostReg__8 +# define HOSTREG__PS2AUX_CTRL__CMD_PASSTHRU_ENABLE 0x01 +# define HOSTREG__PS2AUX_CTRL__SP_EXTENDED_MODE 0x02 +# define HOSTREG__PS2AUX_CTRL__GS_DISABLE 0x04 +# define HOSTREG__PS2AUX_CTRL__SP_DISABLE 0x08 +# define HOSTREG__PS2AUX_CTRL__GS_COORDINATE_DISABLE 0x10 +# define HOSTREG__PS2AUX_CTRL__SP_COORDINATE_DISABLE 0x20 +# define HOSTREG__PS2AUX_CTRL__DISABLE_AA00_DETECT 0x40 +# define HOSTREG__PS2AUX_CTRL__AUX_PRESENT 0x80 +#define HOSTREG__PR2AUX_CTRL_DEFVAL 0x00 + +/*--------------------------------------------------------------------------*\ + Sample Rate Value +\*--------------------------------------------------------------------------*/ +#define HOSTREG__SAMPLERATE HostReg__9 +# define HOSTREG__SAMPLERATE__10_SPS 0x0A +# define HOSTREG__SAMPLERATE__20_SPS 0x14 +# define HOSTREG__SAMPLERATE__40_SPS 0x28 +# define HOSTREG__SAMPLERATE__60_SPS 0x3C +# define HOSTREG__SAMPLERATE__80_SPS 0x50 +# define HOSTREG__SAMPLERATE__100_SPS 0x64 +# define HOSTREG__SAMPLERATE__200_SPS 0xC8 // 200sps not supported + // only for ps2 compatibility + // rate set to 100sps +#define HOSTREG__SAMPLERATE_DEFVAL HOSTREG__SAMPLERATE__100_SPS + +/*--------------------------------------------------------------------------*\ + Z Idle Value +\*--------------------------------------------------------------------------*/ +#define HOSTREG__ZIDLE HostReg__10 +#define HOSTREG__ZIDLE_DEFVAL 30 // 0x1E + +/*--------------------------------------------------------------------------*\ + Z Scaler Value +\*--------------------------------------------------------------------------*/ +#define HOSTREG__ZSCALER HostReg__11 +#define HOSTREG__ZSCALER_DEFVAL 8 // 0x08 + +/*--------------------------------------------------------------------------*\ + Sleep Interval Value +\*--------------------------------------------------------------------------*/ +#define HOSTREG__SLEEP_INTERVAL HostReg__12 +#define HOSTREG__SLEEP_INTERVAL_DEFVAL 73 // 0x49 + +/*--------------------------------------------------------------------------*\ + Sleep Delay Value +\*--------------------------------------------------------------------------*/ +#define HOSTREG__SLEEP_DELAY HostReg__13 +#define HOSTREG__SLEEP_DELAY_DEFVAL 39 // 0x27 + +/*--------------------------------------------------------------------------*\ + Dynamic EMI Bad Channel Count Thresholds +\*--------------------------------------------------------------------------*/ +#define HOSTREG__DYNAMIC_EMI_ADJUST_THRESHOLD HostReg__14 +#define HOSTREG__DYNAMIC_EMI_ADJUST_THRESHOLD_DEFVAL 66 // 0x42 + +/*--------------------------------------------------------------------------*\ + Packet Registers +\*--------------------------------------------------------------------------*/ +#define HOSTREG__PACKETBYTE_0 HostReg__18 +#define HOSTREG__PACKETBYTE_1 HostReg__19 +#define HOSTREG__PACKETBYTE_2 HostReg__20 +#define HOSTREG__PACKETBYTE_3 HostReg__21 +#define HOSTREG__PACKETBYTE_4 HostReg__22 +#define HOSTREG__PACKETBYTE_5 HostReg__23 + +/*--------------------------------------------------------------------------*\ + Port A GPIO Control +\*--------------------------------------------------------------------------*/ +#define HOSTREG__PORTA_GPIO_CTRL HostReg__24 +#define HOSTREG__PORTA_GPIO_CTRL_DEFVAL 0xFF + +/*--------------------------------------------------------------------------*\ + Port A GPIO Data +\*--------------------------------------------------------------------------*/ +#define HOSTREG__PORTA_GPIO_DATA HostReg__25 +#define HOSTREG__PORTA_GPIO_DATA_DEFVAL 0x00 + +/*--------------------------------------------------------------------------*\ + Port B GPIO Control And Data +\*--------------------------------------------------------------------------*/ + +#define HOSTREG__PORTB_GPIO_CTRL_DATA HostReg__26 +# define HOSTREG__PORTB_GPIO_DATA__PB0 0x01 +# define HOSTREG__PORTB_GPIO_DATA__PB1 0x02 +# define HOSTREG__PORTB_GPIO_DATA__PB2 0x04 +# define HOSTREG__PORTB_GPIO_CTRL__PB0 0x08 +# define HOSTREG__PORTB_GPIO_CTRL__PB1 0x10 +# define HOSTREG__PORTB_GPIO_CTRL__PB2 0x20 +# define HOSTREG__PORTB_GPIO_RSVD_0 0x40 +# define HOSTREG__PORTB_GPIO_READ1_WRITE0 0x80 +#define HOSTREG__PORTB_GPIO_CTRL_DATA_DEFVAL (HOSTREG__PORTB_GPIO_CTRL__PB0 | HOSTREG__PORTB_GPIO_CTRL__PB1 | HOSTREG__PORTB_GPIO_CTRL__PB2) + +/*--------------------------------------------------------------------------*\ + Extended Register Access +\*--------------------------------------------------------------------------*/ +#define HOSTREG__EXT_REG_AXS_VALUE HostReg__27 + +#define HOSTREG__EXT_REG_AXS_ADDR_HIGH HostReg__28 +#define HOSTREG__EXT_REG_AXS_ADDR_LOW HostReg__29 + +#define HOSTREG__EXT_REG_AXS_CTRL HostReg__30 +# define HOSTREG__EREG_AXS__READ 0x01 +# define HOSTREG__EREG_AXS__WRITE 0x02 +# define HOSTREG__EREG_AXS__INC_ADDR_READ 0x04 +# define HOSTREG__EREG_AXS__INC_ADDR_WRITE 0x08 +# define HOSTREG__EREG_AXS__RSVD_3 0x10 +# define HOSTREG__EREG_AXS__RSVD_2 0x20 +# define HOSTREG__EREG_AXS__RSVD_1 0x40 +# define HOSTREG__EREG_AXS__RSVD_0 0x80 + +#define HOSTREG__EXT_REG_AXS_VALUE_DEFVAL 0x00 +#define HOSTREG__EXT_REG_AXS_ADDR_HIGH_DEFVAL 0x00 +#define HOSTREG__EXT_REG_AXS_ADDR_LOW_DEFVAL 0x00 +#define HOSTREG__EXT_REG_AXS_CTRL_DEFVAL 0x00 + +/*--------------------------------------------------------------------------*\ + Product ID +\*--------------------------------------------------------------------------*/ +#define HOSTREG__PRODUCT_ID HostReg__31 + + + +//Some useful values +#define I2C_ADDRESS_DEFAULT 0x2A +#define FIRMWARE_ID 0x07 +#define FIRMWARE_VERSION 0x9D + +//Anymeas config options +//First setting is HostReg 5. This sets toggle frequency (EF) and gain. +//Gain is upper two bits (0xC0), frequency is lower 6 bits (0x3F) +#define AnyMeas_AccumBits_ElecFreq HostReg__5 +# define ADCCNFG_ELEC_FREQ 0x3F /* Bit 4, 3, 2, 1, 0 */ +# define ADCCNFG_EF_0 0x02 // 500,000Hz +# define ADCCNFG_EF_1 0x03 // 444,444Hz +# define ADCCNFG_EF_2 0x04 // 400,000Hz +# define ADCCNFG_EF_3 0x05 // 363,636Hz +# define ADCCNFG_EF_4 0x06 // 333,333Hz +# define ADCCNFG_EF_5 0x07 // 307,692Hz +# define ADCCNFG_EF_6 0x09 // 267,000Hz +# define ADCCNFG_EF_7 0x0B // 235,000Hz +# define ADCCNFG_ACCUMBITSSELECT 0xC0 /* Bit 7, 6 */ +# define ADCCNFG_ACCBITS_17_14_0 0x00 //This is about 2x gain +# define ADCCNFG_ACCBITS_17_15_1 0x40 //This is about 1.6x gain +# define ADCCNFG_ACCBITS_17_2__80 0x80 //This is about 1.3x gain +# define ADCCNFG_ACCBITS_17_2__C0 0xC0 //This is lowest gain +//Note, all frequencies above are based on default 500ns aperture. If aperture is shorter the frequencies will be faster and if aperture is longer the frequencies will be slower. + +//Next is HostReg 6. This sets the sample length. There are four possible settings to bit length. All other settings are not normally used and should be a 0. +#define AnyMeas_BitLength HostReg__6 +# define ADCCTRL_BIT_LENGTH 0x03 /* Bit 1, 0 */ +# define ADCCTRL_SAMPLES_32 0x00 //Note: this does not work. +# define ADCCTRL_SAMPLES_128 0x01 +# define ADCCTRL_SAMPLES_256 0x02 +# define ADCCTRL_SAMPLES_512 0x03 +# define ADCCTRL_ENABLE 0x20 /* Bit 5 */ +# define ADCCTRL_INT_FLAG 0x40 /* Bit 6 */ +# define ADCCTRL_START_BUSY 0x80 /* Bit 7 */ +//The smaller the sample length the faster the measurement but the lower the SNR. For high SNR requirements 512 sample length is recommended. Alternatively, multiple 128 or 256 length measurements could be averaged. + +//Next is HostReg 7. This sets the sense mux. Pinnacle has 2 sense lines, Sense N and Sense P1. There is also a Sense P2 but it is not bonded out, it is only internal. +//Signal on Sense N will be inverted from signal on Sense P1. Other than sign inversion, signal strength should be the same. +#define AnyMeas_ADC_MuxControl HostReg__7 +# define ADCMUXCTRL_SENSEP1GATE 0x01 //Enables Sense P1. Can be combined with Sense N input or exclusivly Sense P1 alone. +# define ADCMUXCTRL_SENSEP2GATE 0x02 //Not used. +# define ADCMUXCTRL_SENSENGATE 0x04 //Enables Sense N. Can be combined with Sense P inputs or exclusivly Sense N alone. +# define ADCMUXCTRL_REF0GATE 0x08 //This enables the RefCap0. This is a capacitor inside the chip that is roughly 0.25pF. It is also controlled with the toggle and polarity bits so those bits must be set properly as well in order to use it. +# define ADCMUXCTRL_REF1GATE 0x10 //This enables the RefCap1. This is a capacitor inside the chip that is roughly 0.5pF. It is also controlled with the toggle and polarity bits so those bits must be set properly as well in order to use it. +# define ADCMUXCTRL_OSCMEASEN 0x80 //this is a test mode for measuring the internal oscillator. It is for IC test only. + +//Next is HostReg 8. This contains various ADC config settings that are not likely to be used. +#define AnyMeas_ADC_Config2 HostReg__8 +# define ADCCNFG2_ADC_CLK_SELECT 0x01 /* Bit 0 */ //If 0 use the standard 8Mhz clock. If 1 use a divide by 2, 4Mhz clock. Only used if extra slow toggle frequencies are required. +# define ADCCNFG2_EMI_FLAG 0x02 /* Bit 1 */ //EMI flag threshold only used with internal FW. Not valid in anymeas mode. +# define ADCCNFG2_EMI_FLAG_THRESHOLD_0 0x04 /* Bit 2 */ //EMI flag threshold only used with internal FW. Not valid in anymeas mode. +# define ADCCNFG2_EMI_FLAG_THRESHOLD_1 0x08 /* Bit 3 */ //EMI flag threshold only used with internal FW. Not valid in anymeas mode. +# define ADCCNFG2_DSX2_EXTEND 0x10 /* Bit 4 */ //extend one signal on the receive. Could also be helpful in situations where sensor cap is extremely high. +# define ADCCNFG2_ETOGGLE_DELAY 0x20 /* Bit 5 */ //delay a bit before toggling electrodes. Could be helpful in situations where sensor cap is extremely high. + +//Next is HostReg 9. This sets the aperture length. Bottom 4 bits set the aperture width +#define AnyMeas_ADC_AWidth HostReg__9 +# define ADCAWIDTH_AWIDTHMASK 0x0F +# define ADCAWIDTH_APERTURE_OPEN 0x00 //does not work +# define ADCAWIDTH_APERTURE_125NS 0x01 //does not work +# define ADCAWIDTH_APERTURE_250NS 0x02 +# define ADCAWIDTH_APERTURE_375NS 0x03 +# define ADCAWIDTH_APERTURE_500NS 0x04 +# define ADCAWIDTH_APERTURE_625NS 0x05 +# define ADCAWIDTH_APERTURE_750NS 0x06 +# define ADCAWIDTH_APERTURE_875NS 0x07 +# define ADCAWIDTH_APERTURE_1000NS 0x08 +# define ADCAWIDTH_APERTURE_1125NS 0x09 +# define ADCAWIDTH_APERTURE_1250NS 0x0A +# define ADCAWIDTH_APERTURE_1375NS 0x0B +# define ADCAWIDTH_APERTURE_1500NS 0x0C +# define ADCAWIDTH_APERTURE_1625NS 0x0D +# define ADCAWIDTH_APERTURE_1750NS 0x0E +# define ADCAWIDTH_APERTURE_1875NS 0x0F +# define ADCAWIDTH_AWIDTHPLUSHALF 0x10 +# define ADCAWIDTH_AOPEN 0x20 +# define ADCAWIDTH_W2WAIT 0x40 + +//next two registers give the high and low bytes to the 16 bit address where Pinnacle will pull the measurement data. Normally these addresses are within the base 32 registers. +#define AnyMeas_pADCMeasInfoStart_High_Byte HostReg__10 +#define AnyMeas_pADCMeasInfoStart_Low_Byte HostReg__11 + +//Next is the measurement index, this sets the measurement state machine to the start and should be a 0 at start. +#define AnyMeas_MeasIndex HostReg__12 +# define ANYMEASSTATE_RESET_START 0x00 +# define ANYMEASSTATE_START_MEASUREMENT 0x01 +# define ANYMEASSTATE_WAIT_FOR_MEASUREMENT_AND_HOST 0x02 + +//next is the state itself of the measurement, should always be 0. +#define AnyMeas_State HostReg__13 + +//next is the number of measurements. Use 0x80 to repeat the single measurement or repeat a number of measurements. +//0x40 will turn the ADC off after measurements. This will result in longer startup time for a subsequent measurement, but lower idle power draw. +#define AnyMeas_Control_NumMeas HostReg__14 +# define ANYMEAS_CONTROL__NUM_MEAS_MASK 0x3F +# define ANYMEAS_CONTROL__ADC_POST_MEAS_PWR 0x40 +# define ANYMEAS_CONTROL__REPEAT 0x80 + +//These are not used +#define AnyMeas_pADCMeasInfo_High_Byte HostReg__15 +#define AnyMeas_pADCMeasInfo_Low_Byte HostReg__16 + +//16 bit result of measurement will be found in these two registers. +#define AnyMeas_Result_High_Byte HostReg__17 +#define AnyMeas_Result_Low_Byte HostReg__18 + +// ---------------- Extended Register Assignments ---------------------------- +/*--------------------------------------------------------------------------*\ + ADC Mux Control +\*--------------------------------------------------------------------------*/ +#define EXTREG__ADCMUX_CTRL 0x00EB +# define EXTREG__ADCMUX_CTRL__SNSP_ENABLE 0x01 +# define EXTREG__ADCMUX_CTRL__SNSN_ENABLE 0x04 + +/*--------------------------------------------------------------------------*\ + Timer Reload Registers +\*--------------------------------------------------------------------------*/ +#define EXTREG__PACKET_TIMER_RELOAD 0x019F +#define EXTREG__TRACK_TIMER_RELOAD 0x019E +// These two registers should have matching content. +# define EXTREG__TIMER_RELOAD__300_SPS 0x06 +# define EXTREG__TIMER_RELOAD__200_SPS 0x09 +# define EXTREG__TIMER_RELOAD__100_SPS 0x13 + +/*--------------------------------------------------------------------------*\ + Track ADC Config +\*--------------------------------------------------------------------------*/ +#define EXTREG__TRACK_ADCCONFIG 0x0187 +// ADC-attenuation settings (held in BIT_7 and BIT_6) +// 1X = most sensitive, 4X = least sensitive +# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK 0x3F +# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_1X 0x00 +# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_2X 0x40 +# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_3X 0x80 +# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_4X 0xC0 +#define EXTREG__TRACK_ADCCONFIG_DEFVAL 0x4E + + +/*--------------------------------------------------------------------------*\ + Tune Edge Sensitivity +\*--------------------------------------------------------------------------*/ +// These registers are not detailed in any publically available documentation +// Names inferred from debug prints in https://github.com/cirque-corp/Cirque_Pinnacle_1CA027/blob/master/Circular_Trackpad +#define EXTREG__XAXIS_WIDEZMIN 0x0149 +#define EXTREG__YAXIS_WIDEZMIN 0x0168 +#define EXTREG__XAXIS_WIDEZMIN_DEFVAL 0x06 +#define EXTREG__YAXIS_WIDEZMIN_DEFVAL 0x05 + +// clang-format on diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h index 1e5ef9590c..8225e55aa2 100644 --- a/quantum/pointing_device.h +++ b/quantum/pointing_device.h @@ -31,6 +31,8 @@ along with this program. If not, see . # include "drivers/sensors/analog_joystick.h" #elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) # include "drivers/sensors/cirque_pinnacle.h" +# include "drivers/sensors/cirque_pinnacle_gestures.h" +# include "pointing_device_gestures.h" #elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) # include "i2c_master.h" # include "drivers/sensors/pimoroni_trackball.h" diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c index 435fcabf7c..8f510b3a98 100644 --- a/quantum/pointing_device_drivers.c +++ b/quantum/pointing_device_drivers.c @@ -97,27 +97,48 @@ const pointing_device_driver_t pointing_device_driver = { // clang-format on #elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) -# ifndef CIRQUE_PINNACLE_TAPPING_TERM -# include "action.h" -# include "action_tapping.h" -# define CIRQUE_PINNACLE_TAPPING_TERM GET_TAPPING_TERM(KC_BTN1, &(keyrecord_t){}) -# endif -# ifndef CIRQUE_PINNACLE_TOUCH_DEBOUNCE -# define CIRQUE_PINNACLE_TOUCH_DEBOUNCE (CIRQUE_PINNACLE_TAPPING_TERM * 8) +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +static bool cursor_glide_enable = true; + +static cursor_glide_context_t glide = {.config = { + .coef = 102, /* Good default friction coef */ + .interval = 10, /* 100sps */ + .trigger_px = 10, /* Default threshold in case of hover, set to 0 if you'd like */ + }}; + +void cirque_pinnacle_enable_cursor_glide(bool enable) { + cursor_glide_enable = enable; +} + +void cirque_pinnacle_configure_cursor_glide(float trigger_px) { + glide.config.trigger_px = trigger_px; +} # endif report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { pinnacle_data_t touchData = cirque_pinnacle_read_data(); mouse_xy_report_t report_x = 0, report_y = 0; static mouse_xy_report_t x = 0, y = 0; - static uint16_t mouse_timer = 0; - static bool is_z_down = false; +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE + cursor_glide_t glide_report = {0}; + + if (cursor_glide_enable) { + glide_report = cursor_glide_check(&glide); + } +# endif # if !CIRQUE_PINNACLE_POSITION_MODE # error Cirque Pinnacle with relative mode not implemented yet. # endif if (!touchData.valid) { +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE + if (cursor_glide_enable && glide_report.valid) { + report_x = glide_report.dx; + report_y = glide_report.dy; + goto mouse_report_update; + } +# endif return mouse_report; } @@ -130,45 +151,51 @@ report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { // Scale coordinates to arbitrary X, Y resolution cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); - if (x && y && touchData.xValue && touchData.yValue) { - report_x = (mouse_xy_report_t)(touchData.xValue - x); - report_y = (mouse_xy_report_t)(touchData.yValue - y); - } - x = touchData.xValue; - y = touchData.yValue; - mouse_report.x = report_x; - mouse_report.y = report_y; - - if (touchData.touchDown != is_z_down) { - is_z_down = touchData.touchDown; - if (!touchData.zValue) { - if (timer_elapsed(mouse_timer) < CIRQUE_PINNACLE_TAPPING_TERM && mouse_timer != 0) { - mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); - pointing_device_set_report(mouse_report); - pointing_device_send(); -# if TAP_CODE_DELAY > 0 - wait_ms(TAP_CODE_DELAY); -# endif - mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1); - pointing_device_set_report(mouse_report); - pointing_device_send(); + if (!cirque_pinnacle_gestures(&mouse_report, touchData)) { + if (x && y && touchData.xValue && touchData.yValue) { + report_x = (mouse_xy_report_t)(touchData.xValue - x); + report_y = (mouse_xy_report_t)(touchData.yValue - y); + } + x = touchData.xValue; + y = touchData.yValue; + +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE + if (cursor_glide_enable) { + if (touchData.touchDown) { + cursor_glide_update(&glide, report_x, report_y, touchData.zValue); + } else if (!glide_report.valid) { + glide_report = cursor_glide_start(&glide); + if (glide_report.valid) { + report_x = glide_report.dx; + report_y = glide_report.dy; + } } } - mouse_timer = timer_read(); - } - if (timer_elapsed(mouse_timer) > (CIRQUE_PINNACLE_TOUCH_DEBOUNCE)) { - mouse_timer = 0; +# endif } +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +mouse_report_update: +# endif + mouse_report.x = report_x; + mouse_report.y = report_y; + return mouse_report; } +uint16_t cirque_pinnacle_get_cpi(void) { + return CIRQUE_PINNACLE_PX_TO_INCH(cirque_pinnacle_get_scale()); +} +void cirque_pinnacle_set_cpi(uint16_t cpi) { + cirque_pinnacle_set_scale(CIRQUE_PINNACLE_INCH_TO_PX(cpi)); +} + // clang-format off const pointing_device_driver_t pointing_device_driver = { .init = cirque_pinnacle_init, .get_report = cirque_pinnacle_get_report, - .set_cpi = cirque_pinnacle_set_scale, - .get_cpi = cirque_pinnacle_get_scale + .set_cpi = cirque_pinnacle_set_cpi, + .get_cpi = cirque_pinnacle_get_cpi }; // clang-format on diff --git a/quantum/pointing_device_gestures.c b/quantum/pointing_device_gestures.c new file mode 100644 index 0000000000..02b11ebe3f --- /dev/null +++ b/quantum/pointing_device_gestures.c @@ -0,0 +1,133 @@ +/* Copyright 2022 Daniel Kao + * + * 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 . + */ +#include +#include "pointing_device_gestures.h" +#include "timer.h" + +#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +# ifdef POINTING_DEVICE_MOTION_PIN +# error POINTING_DEVICE_MOTION_PIN not supported when using inertial cursor. Need repeated calls to get_report() to generate glide events. +# endif + +static void cursor_glide_stop(cursor_glide_context_t* glide) { + memset(&glide->status, 0, sizeof(glide->status)); +} + +static cursor_glide_t cursor_glide(cursor_glide_context_t* glide) { + cursor_glide_status_t* status = &glide->status; + cursor_glide_t report; + int32_t p; + int32_t x, y; + + if (status->v0 == 0) { + report.dx = 0; + report.dy = 0; + report.valid = false; + cursor_glide_stop(glide); + goto exit; + } + + status->counter++; + /* Calculate current 1D position */ + p = status->v0 * status->counter - (int32_t)glide->config.coef * status->counter * status->counter / 2; + /* + * Translate to x & y axes + * Done this way instead of applying friction to each axis separately, so we don't end up with the shorter axis stuck at 0 towards the end of diagonal movements. + */ + x = (int32_t)(p * status->dx0 / status->v0); + y = (int32_t)(p * status->dy0 / status->v0); + report.dx = (mouse_xy_report_t)(x - status->x); + report.dy = (mouse_xy_report_t)(y - status->y); + report.valid = true; + if (report.dx <= 1 && report.dx >= -1 && report.dy <= 1 && report.dy >= -1) { + /* Stop gliding once speed is low enough */ + cursor_glide_stop(glide); + goto exit; + } + status->x = x; + status->y = y; + status->timer = timer_read(); + +exit: + return report; +} + +cursor_glide_t cursor_glide_check(cursor_glide_context_t* glide) { + cursor_glide_t invalid_report = {0, 0, false}; + cursor_glide_status_t* status = &glide->status; + + if (status->z || (status->dx0 == 0 && status->dy0 == 0) || timer_elapsed(status->timer) < glide->config.interval) { + return invalid_report; + } else { + return cursor_glide(glide); + } +} + +static inline uint16_t sqrt32(uint32_t x) { + uint32_t l, m, h; + + if (x == 0) { + return 0; + } else if (x > (UINT16_MAX >> 2)) { + /* Safe upper bound to avoid integer overflow with m * m */ + h = UINT16_MAX; + } else { + /* Upper bound based on closest log2 */ + h = (1 << (((__builtin_clzl(1) - __builtin_clzl(x) + 1) + 1) >> 1)); + } + /* Lower bound based on closest log2 */ + l = (1 << ((__builtin_clzl(1) - __builtin_clzl(x)) >> 1)); + + /* Binary search to find integer square root */ + while (l != h - 1) { + m = (l + h) / 2; + if (m * m <= x) { + l = m; + } else { + h = m; + } + } + return l; +} + +cursor_glide_t cursor_glide_start(cursor_glide_context_t* glide) { + cursor_glide_t invalid_report = {0, 0, false}; + cursor_glide_status_t* status = &glide->status; + + status->timer = timer_read(); + status->counter = 0; + status->v0 = (status->dx0 == 0 && status->dy0 == 0) ? 0.0 : sqrt32(((int32_t)status->dx0 * 256 * status->dx0 * 256) + ((int32_t)status->dy0 * 256 * status->dy0 * 256)); // skip trigonometry if not needed, calculate distance in Q8 + status->x = 0; + status->y = 0; + status->z = 0; + + if (status->v0 < ((uint32_t)glide->config.trigger_px * 256)) { /* Q8 comparison */ + /* Not enough velocity to be worth gliding, abort */ + cursor_glide_stop(glide); + return invalid_report; + } + + return cursor_glide(glide); +} + +void cursor_glide_update(cursor_glide_context_t* glide, mouse_xy_report_t dx, mouse_xy_report_t dy, uint16_t z) { + cursor_glide_status_t* status = &glide->status; + + status->dx0 = dx; + status->dy0 = dy; + status->z = z; +} +#endif diff --git a/quantum/pointing_device_gestures.h b/quantum/pointing_device_gestures.h new file mode 100644 index 0000000000..d2ea44971b --- /dev/null +++ b/quantum/pointing_device_gestures.h @@ -0,0 +1,58 @@ +/* Copyright 2022 Daniel Kao + * + * 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 . + */ +#pragma once + +#include +#include "report.h" + +#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +typedef struct { + mouse_xy_report_t dx; + mouse_xy_report_t dy; + bool valid; +} cursor_glide_t; + +typedef struct { + uint16_t trigger_px; /* Pixels of movement needed to trigger cursor glide */ + uint16_t coef; /* Coefficient of friction */ + uint16_t interval; /* Glide report interval, in milliseconds */ +} cursor_glide_config_t; + +typedef struct { + int32_t v0; + int32_t x; + int32_t y; + uint16_t z; + uint16_t timer; + uint16_t counter; + mouse_xy_report_t dx0; + mouse_xy_report_t dy0; +} cursor_glide_status_t; + +typedef struct { + cursor_glide_config_t config; + cursor_glide_status_t status; +} cursor_glide_context_t; + +/* Check glide report conditions, calculates glide coordinates */ +cursor_glide_t cursor_glide_check(cursor_glide_context_t* glide); + +/* Start glide reporting, gives first set of glide coordinates */ +cursor_glide_t cursor_glide_start(cursor_glide_context_t* glide); + +/* Update glide engine on the latest cursor movement, cursor glide is based on the final movement */ +void cursor_glide_update(cursor_glide_context_t* glide, mouse_xy_report_t dx, mouse_xy_report_t dy, uint16_t z); +#endif -- cgit v1.2.3 From 1dfe2bb49ab9cae1450697bf95d7a4c7bfc18bab Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Tue, 12 Jul 2022 22:18:02 -0700 Subject: Update LED/RGB Matrix flag function behavior (#17651) --- quantum/led_matrix/led_matrix.c | 14 ++++++++++++-- quantum/led_matrix/led_matrix.h | 1 + quantum/rgb_matrix/rgb_matrix.c | 12 +++++++++++- quantum/rgb_matrix/rgb_matrix.h | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) (limited to 'quantum') diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c index 38ed79bed0..75a0aba5a0 100644 --- a/quantum/led_matrix/led_matrix.c +++ b/quantum/led_matrix/led_matrix.c @@ -618,10 +618,20 @@ void led_matrix_decrease_speed(void) { led_matrix_decrease_speed_helper(true); } +void led_matrix_set_flags_eeprom_helper(led_flags_t flags, bool write_to_eeprom) { + led_matrix_config.flags = flags; + eeconfig_flag_led_matrix(write_to_eeprom); + dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_config.flags); +} + led_flags_t led_matrix_get_flags(void) { - return led_matrix_eeconfig.flags; + return led_matrix_config.flags; } void led_matrix_set_flags(led_flags_t flags) { - led_matrix_eeconfig.flags = flags; + led_matrix_set_flags_eeprom_helper(flags, true); +} + +void led_matrix_set_flags_noeeprom(led_flags_t flags) { + led_matrix_set_flags_eeprom_helper(flags, false); } diff --git a/quantum/led_matrix/led_matrix.h b/quantum/led_matrix/led_matrix.h index d21f36e295..b2abec7eb1 100644 --- a/quantum/led_matrix/led_matrix.h +++ b/quantum/led_matrix/led_matrix.h @@ -158,6 +158,7 @@ void led_matrix_decrease_speed(void); void led_matrix_decrease_speed_noeeprom(void); 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. */ diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c index a51e379025..2730686839 100644 --- a/quantum/rgb_matrix/rgb_matrix.c +++ b/quantum/rgb_matrix/rgb_matrix.c @@ -731,10 +731,20 @@ void rgb_matrix_decrease_speed(void) { rgb_matrix_decrease_speed_helper(true); } +void rgb_matrix_set_flags_eeprom_helper(led_flags_t flags, bool write_to_eeprom) { + rgb_matrix_config.flags = flags; + eeconfig_flag_rgb_matrix(write_to_eeprom); + dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.flags); +} + led_flags_t rgb_matrix_get_flags(void) { return rgb_matrix_config.flags; } void rgb_matrix_set_flags(led_flags_t flags) { - rgb_matrix_config.flags = flags; + rgb_matrix_set_flags_eeprom_helper(flags, true); +} + +void rgb_matrix_set_flags_noeeprom(led_flags_t flags) { + rgb_matrix_set_flags_eeprom_helper(flags, false); } diff --git a/quantum/rgb_matrix/rgb_matrix.h b/quantum/rgb_matrix/rgb_matrix.h index 359d507a4d..fc9fc3e020 100644 --- a/quantum/rgb_matrix/rgb_matrix.h +++ b/quantum/rgb_matrix/rgb_matrix.h @@ -182,6 +182,7 @@ void rgb_matrix_increase_speed_noeeprom(void); void rgb_matrix_decrease_speed(void); void rgb_matrix_decrease_speed_noeeprom(void); led_flags_t rgb_matrix_get_flags(void); +led_flags_t rgb_matrix_get_flags_noeeprom(void); void rgb_matrix_set_flags(led_flags_t flags); #ifndef RGBLIGHT_ENABLE -- cgit v1.2.3 From 09e4001bba6510afd0b34df154b75c17c32e2076 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Wed, 13 Jul 2022 01:10:51 -0700 Subject: [Bug] Fix compile issue with LED Matrix (#17658) --- quantum/led_matrix/led_matrix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'quantum') diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c index 75a0aba5a0..14dd0dd48a 100644 --- a/quantum/led_matrix/led_matrix.c +++ b/quantum/led_matrix/led_matrix.c @@ -619,13 +619,13 @@ void led_matrix_decrease_speed(void) { } void led_matrix_set_flags_eeprom_helper(led_flags_t flags, bool write_to_eeprom) { - led_matrix_config.flags = flags; + led_matrix_eeconfig.flags = flags; eeconfig_flag_led_matrix(write_to_eeprom); - dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_config.flags); + dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.flags); } led_flags_t led_matrix_get_flags(void) { - return led_matrix_config.flags; + return led_matrix_eeconfig.flags; } void led_matrix_set_flags(led_flags_t flags) { -- cgit v1.2.3 From 3c58f989295e17d03b66db9a154e02cde7336ece Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 14 Jul 2022 11:50:00 +0200 Subject: [Core] PMW33XX drivers overhaul (#17613) * PMW33XX drivers overhaul This combines the PMW3389 and PM3360 drivers as they only differ in the firmware blobs and CPI get and set functions. The following changes have been made: * PMW3389 now gets the same multi-sensor feature that is already available on the PMW3360. * Introduced a shared pmw33xx_report_t struct is now directly readable via SPI transactions instead of individual byte-sized reads, saving multiple copies and bitshift operations. * pmw33(89/60)_get_report functions had unreachable branches in their motion detection logic these have been simplied as much as possible. * The fast firmware upload option has been removed as this becomes obsolete by the newly introduced polled waiting functions for ChibiOS polled waiting * PMW33(60/89)_SPI_LSBFIRST and PMW33(60/89)_SPI_MODE config options have been removed as they don't need to be configurable. * All PMW3389 and PMW3360 defines have been unified to a PMW33XX prefix to reduce code duplication and make the defines interchangeable * Adjust keyboards to PMW33XX naming scheme --- builddefs/common_features.mk | 6 +- docs/feature_pointing_device.md | 81 ++- drivers/sensors/pmw3360.c | 567 ++++++++++---------- drivers/sensors/pmw3360.h | 134 +++-- drivers/sensors/pmw3360_firmware.h | 288 ---------- drivers/sensors/pmw3389.c | 580 +++++++++++---------- drivers/sensors/pmw3389.h | 135 ++--- drivers/sensors/pmw3389_firmware.h | 307 ----------- drivers/sensors/pmw33xx_common.c | 218 ++++++++ drivers/sensors/pmw33xx_common.h | 145 ++++++ keyboards/bastardkb/charybdis/3x5/config.h | 4 +- .../charybdis/3x5/keymaps/drashna/config.h | 6 +- keyboards/bastardkb/charybdis/4x6/config.h | 4 +- .../charybdis/4x6/keymaps/drashna/config.h | 8 +- keyboards/bbrfkr/dynamis/config.h | 2 +- .../handwired/tractyl_manuform/4x6_right/config.h | 4 +- .../handwired/tractyl_manuform/4x6_right/info.json | 2 +- .../tractyl_manuform/5x6_right/elite_c/config.h | 4 +- .../tractyl_manuform/5x6_right/f303/config.h | 5 +- .../tractyl_manuform/5x6_right/f411/config.h | 5 +- .../tractyl_manuform/5x6_right/teensy2pp/config.h | 4 +- keyboards/oddball/config.h | 2 +- keyboards/ploopyco/mouse/config.h | 4 +- keyboards/ploopyco/trackball/config.h | 4 +- quantum/pointing_device.h | 7 +- quantum/pointing_device_drivers.c | 87 +--- 26 files changed, 1168 insertions(+), 1445 deletions(-) delete mode 100644 drivers/sensors/pmw3360_firmware.h delete mode 100644 drivers/sensors/pmw3389_firmware.h create mode 100644 drivers/sensors/pmw33xx_common.c create mode 100644 drivers/sensors/pmw33xx_common.h (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 01dbdc3330..d7a00ba944 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -161,11 +161,9 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball) OPT_DEFS += -DSTM32_SPI -DHAL_USE_I2C=TRUE QUANTUM_LIB_SRC += i2c_master.c - else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pmw3360) - OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE - QUANTUM_LIB_SRC += spi_master.c - else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pmw3389) + else ifneq ($(filter $(strip $(POINTING_DEVICE_DRIVER)),pmw3360 pmw3389),) OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE + SRC += drivers/sensors/pmw33xx_common.c QUANTUM_LIB_SRC += spi_master.c endif endif diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md index 70129dfc9a..607c74c562 100644 --- a/docs/feature_pointing_device.md +++ b/docs/feature_pointing_device.md @@ -154,54 +154,61 @@ The Pimoroni Trackball module is a I2C based breakout board with an RGB enable t |`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` | |`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` | -### PMW 3360 Sensor +### PMW 3360 and PMW 3389 Sensor -This drivers supports multiple sensors _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards). -To use the PMW 3360 sensor, add this to your `rules.mk` +This drivers supports both the PMW 3360 and PMW 3389 sensor as well as multiple sensors of the same type _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards). + +To use the **PMW 3360** sensor, add this to your `rules.mk` ```make POINTING_DEVICE_DRIVER = pmw3360 ``` -The PMW 3360 is an SPI driven optical sensor, that uses a built in IR LED for surface tracking. +The CPI range is 100-12000, in increments of 100. Defaults to 1600 CPI. -| Setting | Description | Default | -|-----------------------------|--------------------------------------------------------------------------------------------|---------------| -|`PMW3360_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ | -|`PMW3360_CS_PINS` | (Alternative) Sets the Cable Select pins connected to multiple sensors. | _not defined_ | -|`PMW3360_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` | -|`PMW3360_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` | -|`PMW3360_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` | -|`PMW3360_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ | -|`PMW3360_LIFTOFF_DISTANCE` | (Optional) Sets the lift off distance at run time | `0x02` | -|`ROTATIONAL_TRANSFORM_ANGLE` | (Optional) Allows for the sensor data to be rotated +/- 127 degrees directly in the sensor.| `0` | -|`PMW3360_FIRMWARE_UPLOAD_FAST` | (Optional) Skips the 15us wait between firmware blocks. | _not defined_ | +To use the **PMW 3389** sensor, add this to your `rules.mk` -The CPI range is 100-12000, in increments of 100. Defaults to 1600 CPI. +```make +POINTING_DEVICE_DRIVER = pmw3389 +``` -To use multiple sensors, instead of setting `PMW3360_CS_PIN` you need to set `PMW3360_CS_PINS` and also handle and merge the read from this sensor in user code. +The CPI range is 50-16000, in increments of 50. Defaults to 2000 CPI. + +Both PMW 3360 and PMW 3389 are SPI driven optical sensors, that use a built in IR LED for surface tracking. + +| Setting | Description | Default | +| ---------------------------- | ------------------------------------------------------------------------------------------- | ------------- | +| `PMW33XX_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ | +| `PMW33XX_CS_PINS` | (Alternative) Sets the Cable Select pins connected to multiple sensors. | _not defined_ | +| `PMW33XX_CPI` | (Optional) Sets counts per inch sensitivity of the sensor. | _varies_ | +| `PMW33XX_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` | +| `PMW33XX_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ | +| `PMW33XX_LIFTOFF_DISTANCE` | (Optional) Sets the lift off distance at run time | `0x02` | +| `ROTATIONAL_TRANSFORM_ANGLE` | (Optional) Allows for the sensor data to be rotated +/- 127 degrees directly in the sensor. | `0` | + +To use multiple sensors, instead of setting `PMW33XX_CS_PIN` you need to set `PMW33XX_CS_PINS` and also handle and merge the read from this sensor in user code. Note that different (per sensor) values of CPI, speed liftoff, rotational angle or flipping of X/Y is not currently supported. ```c // in config.h: -#define PMW3360_CS_PINS { B5, B6 } - +#define PMW33XX_CS_PINS { B5, B6 } // in keyboard.c: #ifdef POINTING_DEVICE_ENABLE void pointing_device_init_kb(void) { - pmw3360_init(1); // index 1 is the second device. - pointing_device_set_cpi(800); // applies to both sensors + pmw33xx_init(1); // index 1 is the second device. + pmw33xx_set_cpi(0, 800); // applies to first sensor + pmw33xx_set_cpi(1, 800); // applies to second sensor pointing_device_init_user(); } // Contains report from sensor #0 already, need to merge in from sensor #1 report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { - report_pmw3360_t data = pmw3360_read_burst(1); - if (data.isOnSurface && data.isMotion) { + pmw33xx_report_t report = pmw33xx_read_burst(1); + if (!report.motion.b.is_lifted && report.motion.b.is_motion) { // From quantum/pointing_device_drivers.c #define constrain_hid(amt) ((amt) < -127 ? -127 : ((amt) > 127 ? 127 : (amt))) - mouse_report.x = constrain_hid(mouse_report.x + data.dx); - mouse_report.y = constrain_hid(mouse_report.y + data.dy); + mouse_report.x = constrain_hid(mouse_report.x + report.delta_x); + mouse_report.y = constrain_hid(mouse_report.y + report.delta_y); } return pointing_device_task_user(mouse_report); } @@ -209,30 +216,6 @@ report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { ``` -### PMW 3389 Sensor - -To use the PMW 3389 sensor, add this to your `rules.mk` - -```make -POINTING_DEVICE_DRIVER = pmw3389 -``` - -The PMW 3389 is an SPI driven optical sensor, that uses a built in IR LED for surface tracking. - -| Setting | Description | Default | -|---------------------------------|--------------------------------------------------------------------------------------------|---------------| -|`PMW3389_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ | -|`PMW3389_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` | -|`PMW3389_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` | -|`PMW3389_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` | -|`PMW3389_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ | -|`PMW3389_LIFTOFF_DISTANCE` | (Optional) Sets the lift off distance at run time | `0x02` | -|`ROTATIONAL_TRANSFORM_ANGLE` | (Optional) Allows for the sensor data to be rotated +/- 30 degrees directly in the sensor. | `0` | -|`PMW3389_FIRMWARE_UPLOAD_FAST` | (Optional) Skips the 15us wait between firmware blocks. | _not defined_ | - -The CPI range is 50-16000, in increments of 50. Defaults to 2000 CPI. - - ### Custom Driver If you have a sensor type that isn't supported above, a custom option is available by adding the following to your `rules.mk` diff --git a/drivers/sensors/pmw3360.c b/drivers/sensors/pmw3360.c index 5f4d17a3f0..2c6d91d588 100644 --- a/drivers/sensors/pmw3360.c +++ b/drivers/sensors/pmw3360.c @@ -1,291 +1,294 @@ -/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2019 Sunjun Kim - * Copyright 2020 Ploopy Corporation - * Copyright 2022 Ulrich Spörlein - * - * 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 . - */ - -#include "spi_master.h" -#include "pmw3360.h" -#include "wait.h" -#include "debug.h" -#include "print.h" -#include "pmw3360_firmware.h" - -// Registers -// clang-format off -#define REG_Product_ID 0x00 -#define REG_Revision_ID 0x01 -#define REG_Motion 0x02 -#define REG_Delta_X_L 0x03 -#define REG_Delta_X_H 0x04 -#define REG_Delta_Y_L 0x05 -#define REG_Delta_Y_H 0x06 -#define REG_SQUAL 0x07 -#define REG_Raw_Data_Sum 0x08 -#define REG_Maximum_Raw_data 0x09 -#define REG_Minimum_Raw_data 0x0a -#define REG_Shutter_Lower 0x0b -#define REG_Shutter_Upper 0x0c -#define REG_Control 0x0d -#define REG_Config1 0x0f -#define REG_Config2 0x10 -#define REG_Angle_Tune 0x11 -#define REG_Frame_Capture 0x12 -#define REG_SROM_Enable 0x13 -#define REG_Run_Downshift 0x14 -#define REG_Rest1_Rate_Lower 0x15 -#define REG_Rest1_Rate_Upper 0x16 -#define REG_Rest1_Downshift 0x17 -#define REG_Rest2_Rate_Lower 0x18 -#define REG_Rest2_Rate_Upper 0x19 -#define REG_Rest2_Downshift 0x1a -#define REG_Rest3_Rate_Lower 0x1b -#define REG_Rest3_Rate_Upper 0x1c -#define REG_Observation 0x24 -#define REG_Data_Out_Lower 0x25 -#define REG_Data_Out_Upper 0x26 -#define REG_Raw_Data_Dump 0x29 -#define REG_SROM_ID 0x2a -#define REG_Min_SQ_Run 0x2b -#define REG_Raw_Data_Threshold 0x2c -#define REG_Config5 0x2f -#define REG_Power_Up_Reset 0x3a -#define REG_Shutdown 0x3b -#define REG_Inverse_Product_ID 0x3f -#define REG_LiftCutoff_Tune3 0x41 -#define REG_Angle_Snap 0x42 -#define REG_LiftCutoff_Tune1 0x4a -#define REG_Motion_Burst 0x50 -#define REG_LiftCutoff_Tune_Timeout 0x58 -#define REG_LiftCutoff_Tune_Min_Length 0x5a -#define REG_SROM_Load_Burst 0x62 -#define REG_Lift_Config 0x63 -#define REG_Raw_Data_Burst 0x64 -#define REG_LiftCutoff_Tune2 0x65 - -#define CPI_STEP 100 -// clang-format on - -// limits to 0--119, resulting in a CPI range of 100 -- 12000 (as only steps of 100 are possible). -#ifndef MAX_CPI -# define MAX_CPI 0x77 -#endif - -static const pin_t pins[] = PMW3360_CS_PINS; -#define NUMBER_OF_SENSORS (sizeof(pins) / sizeof(pin_t)) - -// per-sensor driver state -static bool _inBurst[NUMBER_OF_SENSORS] = {0}; - -#ifdef CONSOLE_ENABLE -void print_byte(uint8_t byte) { - dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); -} -#endif -#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) - -bool pmw3360_spi_start(int8_t index) { - bool status = spi_start(pins[index], PMW3360_SPI_LSBFIRST, PMW3360_SPI_MODE, PMW3360_SPI_DIVISOR); - // tNCS-SCLK, 120ns - wait_us(1); - return status; -} - -spi_status_t pmw3360_write(int8_t index, uint8_t reg_addr, uint8_t data) { - pmw3360_spi_start(index); - - if (reg_addr != REG_Motion_Burst) { - _inBurst[index] = false; - } - - // send address of the register, with MSBit = 1 to indicate it's a write - spi_status_t status = spi_write(reg_addr | 0x80); - status = spi_write(data); - - // tSCLK-NCS for write operation is 35us - wait_us(35); - spi_stop(); - - // tSWW/tSWR (=180us) minus tSCLK-NCS. Could be shortened, but it looks like a safe lower bound - wait_us(145); - return status; -} - -uint8_t pmw3360_read(int8_t index, uint8_t reg_addr) { - pmw3360_spi_start(index); - // send adress of the register, with MSBit = 0 to indicate it's a read - spi_write(reg_addr & 0x7f); - // tSRAD (=160us) - wait_us(160); - uint8_t data = spi_read(); - - // tSCLK-NCS for read operation is 120ns - wait_us(1); - spi_stop(); - - // tSRW/tSRR (=20us) minus tSCLK-NCS - wait_us(19); - return data; -} - -bool pmw3360_check_signature(int8_t index) { - uint8_t pid = pmw3360_read(index, REG_Product_ID); - uint8_t iv_pid = pmw3360_read(index, REG_Inverse_Product_ID); - uint8_t SROM_ver = pmw3360_read(index, REG_SROM_ID); - return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04 -} - -void pmw3360_upload_firmware(int8_t index) { - // Datasheet claims we need to disable REST mode first, but during startup - // it's already disabled and we're not turning it on ... - // pmw3360_write(index, REG_Config2, 0x00); // disable REST mode - pmw3360_write(index, REG_SROM_Enable, 0x1d); - - wait_ms(10); - - pmw3360_write(index, REG_SROM_Enable, 0x18); - - pmw3360_spi_start(index); - spi_write(REG_SROM_Load_Burst | 0x80); - wait_us(15); - - for (uint16_t i = 0; i < FIRMWARE_LENGTH; i++) { - spi_write(pgm_read_byte(firmware_data + i)); -#ifndef PMW3360_FIRMWARE_UPLOAD_FAST - wait_us(15); -#endif +// Copyright 2022 Stefan Kerkmann (KarlK90) +// Copyright 2022 Ulrich Spörlein (@uqs) +// Copyright 2021 Alabastard (@Alabastard-64) +// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) +// Copyright 2019 Sunjun Kim +// Copyright 2020 Ploopy Corporation +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "pmw33xx_common.h" +#include "progmem.h" + +extern const size_t pmw33xx_number_of_sensors; + +uint16_t pmw33xx_get_cpi(uint8_t sensor) { + if (sensor >= pmw33xx_number_of_sensors) { + return 0; } - wait_us(200); - pmw3360_read(index, REG_SROM_ID); - pmw3360_write(index, REG_Config2, 0x00); + uint8_t cpival = pmw33xx_read(sensor, REG_Config1); + return (uint16_t)((cpival + 1) & 0xFF) * PMW33XX_CPI_STEP; } -bool pmw3360_init(int8_t index) { - if (index >= NUMBER_OF_SENSORS) { - return false; +void pmw33xx_set_cpi(uint8_t sensor, uint16_t cpi) { + if (sensor >= pmw33xx_number_of_sensors) { + return; } - spi_init(); - // power up, need to first drive NCS high then low. - // the datasheet does not say for how long, 40us works well in practice. - pmw3360_spi_start(index); - wait_us(40); - spi_stop(); - wait_us(40); - pmw3360_write(index, REG_Power_Up_Reset, 0x5a); - wait_ms(50); - - // read registers and discard - pmw3360_read(index, REG_Motion); - pmw3360_read(index, REG_Delta_X_L); - pmw3360_read(index, REG_Delta_X_H); - pmw3360_read(index, REG_Delta_Y_L); - pmw3360_read(index, REG_Delta_Y_H); - - pmw3360_upload_firmware(index); - - spi_stop(); - - wait_ms(10); - pmw3360_set_cpi(PMW3360_CPI); - - wait_ms(1); - - pmw3360_write(index, REG_Config2, 0x00); - - pmw3360_write(index, REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -127, 127)); - - pmw3360_write(index, REG_Lift_Config, PMW3360_LIFTOFF_DISTANCE); - - bool init_success = pmw3360_check_signature(index); -#ifdef CONSOLE_ENABLE - if (init_success) { - dprintf("pmw3360 signature verified"); - } else { - dprintf("pmw3360 signature verification failed!"); - } -#endif - - return init_success; + uint8_t cpival = CONSTRAIN((cpi / PMW33XX_CPI_STEP) - 1, 0, (PMW33XX_CPI_MAX / PMW33XX_CPI_STEP) - 1U); + pmw33xx_write(sensor, REG_Config1, cpival); } -// Only support reading the value from sensor #0, no one is using this anyway. -uint16_t pmw3360_get_cpi(void) { - uint8_t cpival = pmw3360_read(0, REG_Config1); - return (uint16_t)((cpival + 1) & 0xFF) * CPI_STEP; -} - -// Write same CPI to all sensors. -void pmw3360_set_cpi(uint16_t cpi) { - uint8_t cpival = constrain((cpi / CPI_STEP) - 1, 0, MAX_CPI); - for (size_t i = 0; i < NUMBER_OF_SENSORS; i++) { - pmw3360_write(i, REG_Config1, cpival); - } -} +// PID, Inverse PID, SROM version +const uint8_t pmw33xx_firmware_signature[3] PROGMEM = {0x42, 0xBD, 0x04}; -report_pmw3360_t pmw3360_read_burst(int8_t index) { - report_pmw3360_t report = {0}; - if (index >= NUMBER_OF_SENSORS) { - return report; - } - - if (!_inBurst[index]) { -#ifdef CONSOLE_ENABLE - dprintf("burst on for index %d", index); -#endif - pmw3360_write(index, REG_Motion_Burst, 0x00); - _inBurst[index] = true; - } - - pmw3360_spi_start(index); - spi_write(REG_Motion_Burst); - wait_us(35); // waits for tSRAD_MOTBR - - report.motion = spi_read(); - spi_read(); // skip Observation - // delta registers - report.dx = spi_read(); - report.mdx = spi_read(); - report.dy = spi_read(); - report.mdy = spi_read(); - - if (report.motion & 0b111) { // panic recovery, sometimes burst mode works weird. - _inBurst[index] = false; - } - - spi_stop(); - -#ifdef CONSOLE_ENABLE - if (debug_mouse) { - print_byte(report.motion); - print_byte(report.dx); - print_byte(report.mdx); - print_byte(report.dy); - print_byte(report.mdy); - dprintf("\n"); - } -#endif - - report.isMotion = (report.motion & 0x80) != 0; - report.isOnSurface = (report.motion & 0x08) == 0; - report.dx |= (report.mdx << 8); - report.dx = report.dx * -1; - report.dy |= (report.mdy << 8); - report.dy = report.dy * -1; - - return report; -} +// Firmware Blob for PMW3360 +// clang-format off +const uint8_t pmw33xx_firmware_data[PMW33XX_FIRMWARE_LENGTH] PROGMEM = { + 0x01, 0x04, 0x8E, 0x96, 0x6E, 0x77, 0x3E, 0xFE, 0x7E, 0x5F, 0x1D, 0xB8, 0xF2, 0x66, 0x4E, 0xFF, + 0x5D, 0x19, 0xB0, 0xC2, 0x04, 0x69, 0x54, 0x2A, 0xD6, 0x2E, 0xBF, 0xDD, 0x19, 0xB0, 0xC3, 0xE5, + 0x29, 0xB1, 0xE0, 0x23, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x79, + 0x51, 0x20, 0xC7, 0x06, 0x8E, 0x7C, 0x7C, 0x7A, 0x76, 0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0x0E, + 0x9E, 0xBE, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xA5, 0xA1, 0xA9, 0xD0, 0x22, 0xC6, 0xEF, 0x5C, 0x1B, + 0x95, 0x89, 0x90, 0xA2, 0xA7, 0xCC, 0xFB, 0x55, 0x28, 0xB3, 0xE4, 0x4A, 0xF7, 0x6C, 0x3B, 0xF4, + 0x6A, 0x56, 0x2E, 0xDE, 0x1F, 0x9D, 0xB8, 0xD3, 0x05, 0x88, 0x92, 0xA6, 0xCE, 0x1E, 0xBE, 0xDF, + 0x1D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x5C, 0x07, 0x11, 0x5D, 0x98, 0x0B, 0x9D, 0x94, 0x97, 0xEE, + 0x4E, 0x45, 0x33, 0x6B, 0x44, 0xC7, 0x29, 0x56, 0x27, 0x30, 0xC6, 0xA7, 0xD5, 0xF2, 0x56, 0xDF, + 0xB4, 0x38, 0x62, 0xCB, 0xA0, 0xB6, 0xE3, 0x0F, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6F, 0x76, 0x89, + 0xB5, 0x77, 0x41, 0x27, 0x82, 0x66, 0x65, 0x82, 0xCC, 0xD5, 0xE6, 0x20, 0xD5, 0x27, 0x17, 0xC5, + 0xF8, 0x03, 0x23, 0x7C, 0x5F, 0x64, 0xA5, 0x1D, 0xC1, 0xD6, 0x36, 0xCB, 0x4C, 0xD4, 0xDB, 0x66, + 0xD7, 0x8B, 0xB1, 0x99, 0x7E, 0x6F, 0x4C, 0x36, 0x40, 0x06, 0xD6, 0xEB, 0xD7, 0xA2, 0xE4, 0xF4, + 0x95, 0x51, 0x5A, 0x54, 0x96, 0xD5, 0x53, 0x44, 0xD7, 0x8C, 0xE0, 0xB9, 0x40, 0x68, 0xD2, 0x18, + 0xE9, 0xDD, 0x9A, 0x23, 0x92, 0x48, 0xEE, 0x7F, 0x43, 0xAF, 0xEA, 0x77, 0x38, 0x84, 0x8C, 0x0A, + 0x72, 0xAF, 0x69, 0xF8, 0xDD, 0xF1, 0x24, 0x83, 0xA3, 0xF8, 0x4A, 0xBF, 0xF5, 0x94, 0x13, 0xDB, + 0xBB, 0xD8, 0xB4, 0xB3, 0xA0, 0xFB, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71, 0xA2, 0xD3, + 0x13, 0xE7, 0xFA, 0xE7, 0xCE, 0x0F, 0x63, 0x15, 0x0B, 0x6B, 0x94, 0xBB, 0x37, 0x83, 0x26, 0x05, + 0x9D, 0xFB, 0x46, 0x92, 0xFC, 0x0A, 0x15, 0xD1, 0x0D, 0x73, 0x92, 0xD6, 0x8C, 0x1B, 0x8C, 0xB8, + 0x55, 0x8A, 0xCE, 0xBD, 0xFE, 0x8E, 0xFC, 0xED, 0x09, 0x12, 0x83, 0x91, 0x82, 0x51, 0x31, 0x23, + 0xFB, 0xB4, 0x0C, 0x76, 0xAD, 0x7C, 0xD9, 0xB4, 0x4B, 0xB2, 0x67, 0x14, 0x09, 0x9C, 0x7F, 0x0C, + 0x18, 0xBA, 0x3B, 0xD6, 0x8E, 0x14, 0x2A, 0xE4, 0x1B, 0x52, 0x9F, 0x2B, 0x7D, 0xE1, 0xFB, 0x6A, + 0x33, 0x02, 0xFA, 0xAC, 0x5A, 0xF2, 0x3E, 0x88, 0x7E, 0xAE, 0xD1, 0xF3, 0x78, 0xE8, 0x05, 0xD1, + 0xE3, 0xDC, 0x21, 0xF6, 0xE1, 0x9A, 0xBD, 0x17, 0x0E, 0xD9, 0x46, 0x9B, 0x88, 0x03, 0xEA, 0xF6, + 0x66, 0xBE, 0x0E, 0x1B, 0x50, 0x49, 0x96, 0x40, 0x97, 0xF1, 0xF1, 0xE4, 0x80, 0xA6, 0x6E, 0xE8, + 0x77, 0x34, 0xBF, 0x29, 0x40, 0x44, 0xC2, 0xFF, 0x4E, 0x98, 0xD3, 0x9C, 0xA3, 0x32, 0x2B, 0x76, + 0x51, 0x04, 0x09, 0xE7, 0xA9, 0xD1, 0xA6, 0x32, 0xB1, 0x23, 0x53, 0xE2, 0x47, 0xAB, 0xD6, 0xF5, + 0x69, 0x5C, 0x3E, 0x5F, 0xFA, 0xAE, 0x45, 0x20, 0xE5, 0xD2, 0x44, 0xFF, 0x39, 0x32, 0x6D, 0xFD, + 0x27, 0x57, 0x5C, 0xFD, 0xF0, 0xDE, 0xC1, 0xB5, 0x99, 0xE5, 0xF5, 0x1C, 0x77, 0x01, 0x75, 0xC5, + 0x6D, 0x58, 0x92, 0xF2, 0xB2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7A, 0x30, 0xFF, 0xB7, 0xF0, 0xEF, + 0x77, 0xC1, 0x8A, 0x5D, 0xDC, 0xC0, 0xD1, 0x29, 0x30, 0x1E, 0x77, 0x38, 0x7A, 0x94, 0xF1, 0xB8, + 0x7A, 0x7E, 0xEF, 0xA4, 0xD1, 0xAC, 0x31, 0x4A, 0xF2, 0x5D, 0x64, 0x3D, 0xB2, 0xE2, 0xF0, 0x08, + 0x99, 0xFC, 0x70, 0xEE, 0x24, 0xA7, 0x7E, 0xEE, 0x1E, 0x20, 0x69, 0x7D, 0x44, 0xBF, 0x87, 0x42, + 0xDF, 0x88, 0x3B, 0x0C, 0xDA, 0x42, 0xC9, 0x04, 0xF9, 0x45, 0x50, 0xFC, 0x83, 0x8F, 0x11, 0x6A, + 0x72, 0xBC, 0x99, 0x95, 0xF0, 0xAC, 0x3D, 0xA7, 0x3B, 0xCD, 0x1C, 0xE2, 0x88, 0x79, 0x37, 0x11, + 0x5F, 0x39, 0x89, 0x95, 0x0A, 0x16, 0x84, 0x7A, 0xF6, 0x8A, 0xA4, 0x28, 0xE4, 0xED, 0x83, 0x80, + 0x3B, 0xB1, 0x23, 0xA5, 0x03, 0x10, 0xF4, 0x66, 0xEA, 0xBB, 0x0C, 0x0F, 0xC5, 0xEC, 0x6C, 0x69, + 0xC5, 0xD3, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0x99, 0x88, 0x76, 0x08, 0xA0, 0xA8, 0x95, 0x7C, 0xD8, + 0x38, 0x6D, 0xCD, 0x59, 0x02, 0x51, 0x4B, 0xF1, 0xB5, 0x2B, 0x50, 0xE3, 0xB6, 0xBD, 0xD0, 0x72, + 0xCF, 0x9E, 0xFD, 0x6E, 0xBB, 0x44, 0xC8, 0x24, 0x8A, 0x77, 0x18, 0x8A, 0x13, 0x06, 0xEF, 0x97, + 0x7D, 0xFA, 0x81, 0xF0, 0x31, 0xE6, 0xFA, 0x77, 0xED, 0x31, 0x06, 0x31, 0x5B, 0x54, 0x8A, 0x9F, + 0x30, 0x68, 0xDB, 0xE2, 0x40, 0xF8, 0x4E, 0x73, 0xFA, 0xAB, 0x74, 0x8B, 0x10, 0x58, 0x13, 0xDC, + 0xD2, 0xE6, 0x78, 0xD1, 0x32, 0x2E, 0x8A, 0x9F, 0x2C, 0x58, 0x06, 0x48, 0x27, 0xC5, 0xA9, 0x5E, + 0x81, 0x47, 0x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xA4, 0x3E, 0x88, 0x9C, 0xDA, 0x33, 0x0A, 0xCE, + 0xBC, 0x8B, 0x8E, 0xCF, 0x9F, 0xD3, 0x71, 0x80, 0x43, 0xCF, 0x6B, 0xA9, 0x51, 0x83, 0x76, 0x30, + 0x82, 0xC5, 0x6A, 0x85, 0x39, 0x11, 0x50, 0x1A, 0x82, 0xDC, 0x1E, 0x1C, 0xD5, 0x7D, 0xA9, 0x71, + 0x99, 0x33, 0x47, 0x19, 0x97, 0xB3, 0x5A, 0xB1, 0xDF, 0xED, 0xA4, 0xF2, 0xE6, 0x26, 0x84, 0xA2, + 0x28, 0x9A, 0x9E, 0xDF, 0xA6, 0x6A, 0xF4, 0xD6, 0xFC, 0x2E, 0x5B, 0x9D, 0x1A, 0x2A, 0x27, 0x68, + 0xFB, 0xC1, 0x83, 0x21, 0x4B, 0x90, 0xE0, 0x36, 0xDD, 0x5B, 0x31, 0x42, 0x55, 0xA0, 0x13, 0xF7, + 0xD0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xC5, 0xF3, 0x21, 0xF8, 0x37, 0x2F, 0x40, 0xF3, + 0xD4, 0xAF, 0x16, 0x08, 0x36, 0x02, 0xFC, 0x77, 0xC5, 0x8B, 0x04, 0x90, 0x56, 0xB9, 0xC9, 0x67, + 0x9A, 0x99, 0xE8, 0x00, 0xD3, 0x86, 0xFF, 0x97, 0x2D, 0x08, 0xE9, 0xB7, 0xB3, 0x91, 0xBC, 0xDF, + 0x45, 0xC6, 0xED, 0x0F, 0x8C, 0x4C, 0x1E, 0xE6, 0x5B, 0x6E, 0x38, 0x30, 0xE4, 0xAA, 0xE3, 0x95, + 0xDE, 0xB9, 0xE4, 0x9A, 0xF5, 0xB2, 0x55, 0x9A, 0x87, 0x9B, 0xF6, 0x6A, 0xB2, 0xF2, 0x77, 0x9A, + 0x31, 0xF4, 0x7A, 0x31, 0xD1, 0x1D, 0x04, 0xC0, 0x7C, 0x32, 0xA2, 0x9E, 0x9A, 0xF5, 0x62, 0xF8, + 0x27, 0x8D, 0xBF, 0x51, 0xFF, 0xD3, 0xDF, 0x64, 0x37, 0x3F, 0x2A, 0x6F, 0x76, 0x3A, 0x7D, 0x77, + 0x06, 0x9E, 0x77, 0x7F, 0x5E, 0xEB, 0x32, 0x51, 0xF9, 0x16, 0x66, 0x9A, 0x09, 0xF3, 0xB0, 0x08, + 0xA4, 0x70, 0x96, 0x46, 0x30, 0xFF, 0xDA, 0x4F, 0xE9, 0x1B, 0xED, 0x8D, 0xF8, 0x74, 0x1F, 0x31, + 0x92, 0xB3, 0x73, 0x17, 0x36, 0xDB, 0x91, 0x30, 0xD6, 0x88, 0x55, 0x6B, 0x34, 0x77, 0x87, 0x7A, + 0xE7, 0xEE, 0x06, 0xC6, 0x1C, 0x8C, 0x19, 0x0C, 0x48, 0x46, 0x23, 0x5E, 0x9C, 0x07, 0x5C, 0xBF, + 0xB4, 0x7E, 0xD6, 0x4F, 0x74, 0x9C, 0xE2, 0xC5, 0x50, 0x8B, 0xC5, 0x8B, 0x15, 0x90, 0x60, 0x62, + 0x57, 0x29, 0xD0, 0x13, 0x43, 0xA1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xC7, 0x4D, 0x19, 0x86, 0xCC, + 0x2F, 0x2A, 0x75, 0x5A, 0xFC, 0xEB, 0x97, 0x2A, 0x70, 0xE3, 0x78, 0xD8, 0x91, 0xB0, 0x4F, 0x99, + 0x07, 0xA3, 0x95, 0xEA, 0x24, 0x21, 0xD5, 0xDE, 0x51, 0x20, 0x93, 0x27, 0x0A, 0x30, 0x73, 0xA8, + 0xFF, 0x8A, 0x97, 0xE9, 0xA7, 0x6A, 0x8E, 0x0D, 0xE8, 0xF0, 0xDF, 0xEC, 0xEA, 0xB4, 0x6C, 0x1D, + 0x39, 0x2A, 0x62, 0x2D, 0x3D, 0x5A, 0x8B, 0x65, 0xF8, 0x90, 0x05, 0x2E, 0x7E, 0x91, 0x2C, 0x78, + 0xEF, 0x8E, 0x7A, 0xC1, 0x2F, 0xAC, 0x78, 0xEE, 0xAF, 0x28, 0x45, 0x06, 0x4C, 0x26, 0xAF, 0x3B, + 0xA2, 0xDB, 0xA3, 0x93, 0x06, 0xB5, 0x3C, 0xA5, 0xD8, 0xEE, 0x8F, 0xAF, 0x25, 0xCC, 0x3F, 0x85, + 0x68, 0x48, 0xA9, 0x62, 0xCC, 0x97, 0x8F, 0x7F, 0x2A, 0xEA, 0xE0, 0x15, 0x0A, 0xAD, 0x62, 0x07, + 0xBD, 0x45, 0xF8, 0x41, 0xD8, 0x36, 0xCB, 0x4C, 0xDB, 0x6E, 0xE6, 0x3A, 0xE7, 0xDA, 0x15, 0xE9, + 0x29, 0x1E, 0x12, 0x10, 0xA0, 0x14, 0x2C, 0x0E, 0x3D, 0xF4, 0xBF, 0x39, 0x41, 0x92, 0x75, 0x0B, + 0x25, 0x7B, 0xA3, 0xCE, 0x39, 0x9C, 0x15, 0x64, 0xC8, 0xFA, 0x3D, 0xEF, 0x73, 0x27, 0xFE, 0x26, + 0x2E, 0xCE, 0xDA, 0x6E, 0xFD, 0x71, 0x8E, 0xDD, 0xFE, 0x76, 0xEE, 0xDC, 0x12, 0x5C, 0x02, 0xC5, + 0x3A, 0x4E, 0x4E, 0x4F, 0xBF, 0xCA, 0x40, 0x15, 0xC7, 0x6E, 0x8D, 0x41, 0xF1, 0x10, 0xE0, 0x4F, + 0x7E, 0x97, 0x7F, 0x1C, 0xAE, 0x47, 0x8E, 0x6B, 0xB1, 0x25, 0x31, 0xB0, 0x73, 0xC7, 0x1B, 0x97, + 0x79, 0xF9, 0x80, 0xD3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1E, 0xE4, 0xD0, 0x80, 0x21, 0xD6, 0xEE, + 0x6B, 0x6C, 0x4F, 0xBF, 0xF5, 0xB7, 0xD9, 0x09, 0x87, 0x2F, 0xA9, 0x14, 0xBE, 0x27, 0xD9, 0x72, + 0x50, 0x01, 0xD4, 0x13, 0x73, 0xA6, 0xA7, 0x51, 0x02, 0x75, 0x25, 0xE1, 0xB3, 0x45, 0x34, 0x7D, + 0xA8, 0x8E, 0xEB, 0xF3, 0x16, 0x49, 0xCB, 0x4F, 0x8C, 0xA1, 0xB9, 0x36, 0x85, 0x39, 0x75, 0x5D, + 0x08, 0x00, 0xAE, 0xEB, 0xF6, 0xEA, 0xD7, 0x13, 0x3A, 0x21, 0x5A, 0x5F, 0x30, 0x84, 0x52, 0x26, + 0x95, 0xC9, 0x14, 0xF2, 0x57, 0x55, 0x6B, 0xB1, 0x10, 0xC2, 0xE1, 0xBD, 0x3B, 0x51, 0xC0, 0xB7, + 0x55, 0x4C, 0x71, 0x12, 0x26, 0xC7, 0x0D, 0xF9, 0x51, 0xA4, 0x38, 0x02, 0x05, 0x7F, 0xB8, 0xF1, + 0x72, 0x4B, 0xBF, 0x71, 0x89, 0x14, 0xF3, 0x77, 0x38, 0xD9, 0x71, 0x24, 0xF3, 0x00, 0x11, 0xA1, + 0xD8, 0xD4, 0x69, 0x27, 0x08, 0x37, 0x35, 0xC9, 0x11, 0x9D, 0x90, 0x1C, 0x0E, 0xE7, 0x1C, 0xFF, + 0x2D, 0x1E, 0xE8, 0x92, 0xE1, 0x18, 0x10, 0x95, 0x7C, 0xE0, 0x80, 0xF4, 0x96, 0x43, 0x21, 0xF9, + 0x75, 0x21, 0x64, 0x38, 0xDD, 0x9F, 0x1E, 0x95, 0x16, 0xDA, 0x56, 0x1D, 0x4F, 0x9A, 0x53, 0xB2, + 0xE2, 0xE4, 0x18, 0xCB, 0x6B, 0x1A, 0x65, 0xEB, 0x56, 0xC6, 0x3B, 0xE5, 0xFE, 0xD8, 0x26, 0x3F, + 0x3A, 0x84, 0x59, 0x72, 0x66, 0xA2, 0xF3, 0x75, 0xFF, 0xFB, 0x60, 0xB3, 0x22, 0xAD, 0x3F, 0x2D, + 0x6B, 0xF9, 0xEB, 0xEA, 0x05, 0x7C, 0xD8, 0x8F, 0x6D, 0x2C, 0x98, 0x9E, 0x2B, 0x93, 0xF1, 0x5E, + 0x46, 0xF0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xD7, 0x7F, 0xF9, 0xF0, 0xE5, 0x7D, 0xDB, 0x1D, 0x75, + 0x19, 0xF3, 0xC4, 0x58, 0x9B, 0x17, 0x88, 0xA8, 0x92, 0xE0, 0xBE, 0xBD, 0x8B, 0x1D, 0x8D, 0x9F, + 0x56, 0x76, 0xAD, 0xAF, 0x29, 0xE2, 0xD9, 0xD5, 0x52, 0xF6, 0xB5, 0x56, 0x35, 0x57, 0x3A, 0xC8, + 0xE1, 0x56, 0x43, 0x19, 0x94, 0xD3, 0x04, 0x9B, 0x6D, 0x35, 0xD8, 0x0B, 0x5F, 0x4D, 0x19, 0x8E, + 0xEC, 0xFA, 0x64, 0x91, 0x0A, 0x72, 0x20, 0x2B, 0xBC, 0x1A, 0x4A, 0xFE, 0x8B, 0xFD, 0xBB, 0xED, + 0x1B, 0x23, 0xEA, 0xAD, 0x72, 0x82, 0xA1, 0x29, 0x99, 0x71, 0xBD, 0xF0, 0x95, 0xC1, 0x03, 0xDD, + 0x7B, 0xC2, 0xB2, 0x3C, 0x28, 0x54, 0xD3, 0x68, 0xA4, 0x72, 0xC8, 0x66, 0x96, 0xE0, 0xD1, 0xD8, + 0x7F, 0xF8, 0xD1, 0x26, 0x2B, 0xF7, 0xAD, 0xBA, 0x55, 0xCA, 0x15, 0xB9, 0x32, 0xC3, 0xE5, 0x88, + 0x97, 0x8E, 0x5C, 0xFB, 0x92, 0x25, 0x8B, 0xBF, 0xA2, 0x45, 0x55, 0x7A, 0xA7, 0x6F, 0x8B, 0x57, + 0x5B, 0xCF, 0x0E, 0xCB, 0x1D, 0xFB, 0x20, 0x82, 0x77, 0xA8, 0x8C, 0xCC, 0x16, 0xCE, 0x1D, 0xFA, + 0xDE, 0xCC, 0x0B, 0x62, 0xFE, 0xCC, 0xE1, 0xB7, 0xF0, 0xC3, 0x81, 0x64, 0x73, 0x40, 0xA0, 0xC2, + 0x4D, 0x89, 0x11, 0x75, 0x33, 0x55, 0x33, 0x8D, 0xE8, 0x4A, 0xFD, 0xEA, 0x6E, 0x30, 0x0B, 0xD7, + 0x31, 0x2C, 0xDE, 0x47, 0xE3, 0xBF, 0xF8, 0x55, 0x42, 0xE2, 0x7F, 0x59, 0xE5, 0x17, 0xEF, 0x99, + 0x34, 0x69, 0x91, 0xB1, 0x23, 0x8E, 0x20, 0x87, 0x2D, 0xA8, 0xFE, 0xD5, 0x8A, 0xF3, 0x84, 0x3A, + 0xF0, 0x37, 0xE4, 0x09, 0x00, 0x54, 0xEE, 0x67, 0x49, 0x93, 0xE4, 0x81, 0x70, 0xE3, 0x90, 0x4D, + 0xEF, 0xFE, 0x41, 0xB7, 0x99, 0x7B, 0xC1, 0x83, 0xBA, 0x62, 0x12, 0x6F, 0x7D, 0xDE, 0x6B, 0xAF, + 0xDA, 0x16, 0xF9, 0x55, 0x51, 0xEE, 0xA6, 0x0C, 0x2B, 0x02, 0xA3, 0xFD, 0x8D, 0xFB, 0x30, 0x17, + 0xE4, 0x6F, 0xDF, 0x36, 0x71, 0xC4, 0xCA, 0x87, 0x25, 0x48, 0xB0, 0x47, 0xEC, 0xEA, 0xB4, 0xBF, + 0xA5, 0x4D, 0x9B, 0x9F, 0x02, 0x93, 0xC4, 0xE3, 0xE4, 0xE8, 0x42, 0x2D, 0x68, 0x81, 0x15, 0x0A, + 0xEB, 0x84, 0x5B, 0xD6, 0xA8, 0x74, 0xFB, 0x7D, 0x1D, 0xCB, 0x2C, 0xDA, 0x46, 0x2A, 0x76, 0x62, + 0xCE, 0xBC, 0x5C, 0x9E, 0x8B, 0xE7, 0xCF, 0xBE, 0x78, 0xF5, 0x7C, 0xEB, 0xB3, 0x3A, 0x9C, 0xAA, + 0x6F, 0xCC, 0x72, 0xD1, 0x59, 0xF2, 0x11, 0x23, 0xD6, 0x3F, 0x48, 0xD1, 0xB7, 0xCE, 0xB0, 0xBF, + 0xCB, 0xEA, 0x80, 0xDE, 0x57, 0xD4, 0x5E, 0x97, 0x2F, 0x75, 0xD1, 0x50, 0x8E, 0x80, 0x2C, 0x66, + 0x79, 0xBF, 0x72, 0x4B, 0xBD, 0x8A, 0x81, 0x6C, 0xD3, 0xE1, 0x01, 0xDC, 0xD2, 0x15, 0x26, 0xC5, + 0x36, 0xDA, 0x2C, 0x1A, 0xC0, 0x27, 0x94, 0xED, 0xB7, 0x9B, 0x85, 0x0B, 0x5E, 0x80, 0x97, 0xC5, + 0xEC, 0x4F, 0xEC, 0x88, 0x5D, 0x50, 0x07, 0x35, 0x47, 0xDC, 0x0B, 0x3B, 0x3D, 0xDD, 0x60, 0xAF, + 0xA8, 0x5D, 0x81, 0x38, 0x24, 0x25, 0x5D, 0x5C, 0x15, 0xD1, 0xDE, 0xB3, 0xAB, 0xEC, 0x05, 0x69, + 0xEF, 0x83, 0xED, 0x57, 0x54, 0xB8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xDA, 0x9F, 0x2D, 0x7F, + 0x36, 0xBB, 0x44, 0x5A, 0x34, 0xE8, 0x7F, 0xBF, 0x03, 0xEB, 0x00, 0x7F, 0x59, 0x68, 0x22, 0x79, + 0xCF, 0x73, 0x6C, 0x2C, 0x29, 0xA7, 0xA1, 0x5F, 0x38, 0xA1, 0x1D, 0xF0, 0x20, 0x53, 0xE0, 0x1A, + 0x63, 0x14, 0x58, 0x71, 0x10, 0xAA, 0x08, 0x0C, 0x3E, 0x16, 0x1A, 0x60, 0x22, 0x82, 0x7F, 0xBA, + 0xA4, 0x43, 0xA0, 0xD0, 0xAC, 0x1B, 0xD5, 0x6B, 0x64, 0xB5, 0x14, 0x93, 0x31, 0x9E, 0x53, 0x50, + 0xD0, 0x57, 0x66, 0xEE, 0x5A, 0x4F, 0xFB, 0x03, 0x2A, 0x69, 0x58, 0x76, 0xF1, 0x83, 0xF7, 0x4E, + 0xBA, 0x8C, 0x42, 0x06, 0x60, 0x5D, 0x6D, 0xCE, 0x60, 0x88, 0xAE, 0xA4, 0xC3, 0xF1, 0x03, 0xA5, + 0x4B, 0x98, 0xA1, 0xFF, 0x67, 0xE1, 0xAC, 0xA2, 0xB8, 0x62, 0xD7, 0x6F, 0xA0, 0x31, 0xB4, 0xD2, + 0x77, 0xAF, 0x21, 0x10, 0x06, 0xC6, 0x9A, 0xFF, 0x1D, 0x09, 0x17, 0x0E, 0x5F, 0xF1, 0xAA, 0x54, + 0x34, 0x4B, 0x45, 0x8A, 0x87, 0x63, 0xA6, 0xDC, 0xF9, 0x24, 0x30, 0x67, 0xC6, 0xB2, 0xD6, 0x61, + 0x33, 0x69, 0xEE, 0x50, 0x61, 0x57, 0x28, 0xE7, 0x7E, 0xEE, 0xEC, 0x3A, 0x5A, 0x73, 0x4E, 0xA8, + 0x8D, 0xE4, 0x18, 0xEA, 0xEC, 0x41, 0x64, 0xC8, 0xE2, 0xE8, 0x66, 0xB6, 0x2D, 0xB6, 0xFB, 0x6A, + 0x6C, 0x16, 0xB3, 0xDD, 0x46, 0x43, 0xB9, 0x73, 0x00, 0x6A, 0x71, 0xED, 0x4E, 0x9D, 0x25, 0x1A, + 0xC3, 0x3C, 0x4A, 0x95, 0x15, 0x99, 0x35, 0x81, 0x14, 0x02, 0xD6, 0x98, 0x9B, 0xEC, 0xD8, 0x23, + 0x3B, 0x84, 0x29, 0xAF, 0x0C, 0x99, 0x83, 0xA6, 0x9A, 0x34, 0x4F, 0xFA, 0xE8, 0xD0, 0x3C, 0x4B, + 0xD0, 0xFB, 0xB6, 0x68, 0xB8, 0x9E, 0x8F, 0xCD, 0xF7, 0x60, 0x2D, 0x7A, 0x22, 0xE5, 0x7D, 0xAB, + 0x65, 0x1B, 0x95, 0xA7, 0xA8, 0x7F, 0xB6, 0x77, 0x47, 0x7B, 0x5F, 0x8B, 0x12, 0x72, 0xD0, 0xD4, + 0x91, 0xEF, 0xDE, 0x19, 0x50, 0x3C, 0xA7, 0x8B, 0xC4, 0xA9, 0xB3, 0x23, 0xCB, 0x76, 0xE6, 0x81, + 0xF0, 0xC1, 0x04, 0x8F, 0xA3, 0xB8, 0x54, 0x5B, 0x97, 0xAC, 0x19, 0xFF, 0x3F, 0x55, 0x27, 0x2F, + 0xE0, 0x1D, 0x42, 0x9B, 0x57, 0xFC, 0x4B, 0x4E, 0x0F, 0xCE, 0x98, 0xA9, 0x43, 0x57, 0x03, 0xBD, + 0xE7, 0xC8, 0x94, 0xDF, 0x6E, 0x36, 0x73, 0x32, 0xB4, 0xEF, 0x2E, 0x85, 0x7A, 0x6E, 0xFC, 0x6C, + 0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xF3, 0xE4, 0x9F, 0x3E, 0xDC, 0x68, 0xF3, 0xB5, 0xF3, 0x19, + 0x80, 0x92, 0x06, 0x99, 0xA2, 0xE8, 0x6F, 0xFF, 0x2E, 0x7F, 0xAE, 0x42, 0xA4, 0x5F, 0xFB, 0xD4, + 0x0E, 0x81, 0x2B, 0xC3, 0x04, 0xFF, 0x2B, 0xB3, 0x74, 0x4E, 0x36, 0x5B, 0x9C, 0x15, 0x00, 0xC6, + 0x47, 0x2B, 0xE8, 0x8B, 0x3D, 0xF1, 0x9C, 0x03, 0x9A, 0x58, 0x7F, 0x9B, 0x9C, 0xBF, 0x85, 0x49, + 0x79, 0x35, 0x2E, 0x56, 0x7B, 0x41, 0x14, 0x39, 0x47, 0x83, 0x26, 0xAA, 0x07, 0x89, 0x98, 0x11, + 0x1B, 0x86, 0xE7, 0x73, 0x7A, 0xD8, 0x7D, 0x78, 0x61, 0x53, 0xE9, 0x79, 0xF5, 0x36, 0x8D, 0x44, + 0x92, 0x84, 0xF9, 0x13, 0x50, 0x58, 0x3B, 0xA4, 0x6A, 0x36, 0x65, 0x49, 0x8E, 0x3C, 0x0E, 0xF1, + 0x6F, 0xD2, 0x84, 0xC4, 0x7E, 0x8E, 0x3F, 0x39, 0xAE, 0x7C, 0x84, 0xF1, 0x63, 0x37, 0x8E, 0x3C, + 0xCC, 0x3E, 0x44, 0x81, 0x45, 0xF1, 0x4B, 0xB9, 0xED, 0x6B, 0x36, 0x5D, 0xBB, 0x20, 0x60, 0x1A, + 0x0F, 0xA3, 0xAA, 0x55, 0x77, 0x3A, 0xA9, 0xAE, 0x37, 0x4D, 0xBA, 0xB8, 0x86, 0x6B, 0xBC, 0x08, + 0x50, 0xF6, 0xCC, 0xA4, 0xBD, 0x1D, 0x40, 0x72, 0xA5, 0x86, 0xFA, 0xE2, 0x10, 0xAE, 0x3D, 0x58, + 0x4B, 0x97, 0xF3, 0x43, 0x74, 0xA9, 0x9E, 0xEB, 0x21, 0xB7, 0x01, 0xA4, 0x86, 0x93, 0x97, 0xEE, + 0x2F, 0x4F, 0x3B, 0x86, 0xA1, 0x41, 0x6F, 0x41, 0x26, 0x90, 0x78, 0x5C, 0x7F, 0x30, 0x38, 0x4B, + 0x3F, 0xAA, 0xEC, 0xED, 0x5C, 0x6F, 0x0E, 0xAD, 0x43, 0x87, 0xFD, 0x93, 0x35, 0xE6, 0x01, 0xEF, + 0x41, 0x26, 0x90, 0x99, 0x9E, 0xFB, 0x19, 0x5B, 0xAD, 0xD2, 0x91, 0x8A, 0xE0, 0x46, 0xAF, 0x65, + 0xFA, 0x4F, 0x84, 0xC1, 0xA1, 0x2D, 0xCF, 0x45, 0x8B, 0xD3, 0x85, 0x50, 0x55, 0x7C, 0xF9, 0x67, + 0x88, 0xD4, 0x4E, 0xE9, 0xD7, 0x6B, 0x61, 0x54, 0xA1, 0xA4, 0xA6, 0xA2, 0xC2, 0xBF, 0x30, 0x9C, + 0x40, 0x9F, 0x5F, 0xD7, 0x69, 0x2B, 0x24, 0x82, 0x5E, 0xD9, 0xD6, 0xA7, 0x12, 0x54, 0x1A, 0xF7, + 0x55, 0x9F, 0x76, 0x50, 0xA9, 0x95, 0x84, 0xE6, 0x6B, 0x6D, 0xB5, 0x96, 0x54, 0xD6, 0xCD, 0xB3, + 0xA1, 0x9B, 0x46, 0xA7, 0x94, 0x4D, 0xC4, 0x94, 0xB4, 0x98, 0xE3, 0xE1, 0xE2, 0x34, 0xD5, 0x33, + 0x16, 0x07, 0x54, 0xCD, 0xB7, 0x77, 0x53, 0xDB, 0x4F, 0x4D, 0x46, 0x9D, 0xE9, 0xD4, 0x9C, 0x8A, + 0x36, 0xB6, 0xB8, 0x38, 0x26, 0x6C, 0x0E, 0xFF, 0x9C, 0x1B, 0x43, 0x8B, 0x80, 0xCC, 0xB9, 0x3D, + 0xDA, 0xC7, 0xF1, 0x8A, 0xF2, 0x6D, 0xB8, 0xD7, 0x74, 0x2F, 0x7E, 0x1E, 0xB7, 0xD3, 0x4A, 0xB4, + 0xAC, 0xFC, 0x79, 0x48, 0x6C, 0xBC, 0x96, 0xB6, 0x94, 0x46, 0x57, 0x2D, 0xB0, 0xA3, 0xFC, 0x1E, + 0xB9, 0x52, 0x60, 0x85, 0x2D, 0x41, 0xD0, 0x43, 0x01, 0x1E, 0x1C, 0xD5, 0x7D, 0xFC, 0xF3, 0x96, + 0x0D, 0xC7, 0xCB, 0x2A, 0x29, 0x9A, 0x93, 0xDD, 0x88, 0x2D, 0x37, 0x5D, 0xAA, 0xFB, 0x49, 0x68, + 0xA0, 0x9C, 0x50, 0x86, 0x7F, 0x68, 0x56, 0x57, 0xF9, 0x79, 0x18, 0x39, 0xD4, 0xE0, 0x01, 0x84, + 0x33, 0x61, 0xCA, 0xA5, 0xD2, 0xD6, 0xE4, 0xC9, 0x8A, 0x4A, 0x23, 0x44, 0x4E, 0xBC, 0xF0, 0xDC, + 0x24, 0xA1, 0xA0, 0xC4, 0xE2, 0x07, 0x3C, 0x10, 0xC4, 0xB5, 0x25, 0x4B, 0x65, 0x63, 0xF4, 0x80, + 0xE7, 0xCF, 0x61, 0xB1, 0x71, 0x82, 0x21, 0x87, 0x2C, 0xF5, 0x91, 0x00, 0x32, 0x0C, 0xEC, 0xA9, + 0xB5, 0x9A, 0x74, 0x85, 0xE3, 0x36, 0x8F, 0x76, 0x4F, 0x9C, 0x6D, 0xCE, 0xBC, 0xAD, 0x0A, 0x4B, + 0xED, 0x76, 0x04, 0xCB, 0xC3, 0xB9, 0x33, 0x9E, 0x01, 0x93, 0x96, 0x69, 0x7D, 0xC5, 0xA2, 0x45, + 0x79, 0x9B, 0x04, 0x5C, 0x84, 0x09, 0xED, 0x88, 0x43, 0xC7, 0xAB, 0x93, 0x14, 0x26, 0xA1, 0x40, + 0xB5, 0xCE, 0x4E, 0xBF, 0x2A, 0x42, 0x85, 0x3E, 0x2C, 0x3B, 0x54, 0xE8, 0x12, 0x1F, 0x0E, 0x97, + 0x59, 0xB2, 0x27, 0x89, 0xFA, 0xF2, 0xDF, 0x8E, 0x68, 0x59, 0xDC, 0x06, 0xBC, 0xB6, 0x85, 0x0D, + 0x06, 0x22, 0xEC, 0xB1, 0xCB, 0xE5, 0x04, 0xE6, 0x3D, 0xB3, 0xB0, 0x41, 0x73, 0x08, 0x3F, 0x3C, + 0x58, 0x86, 0x63, 0xEB, 0x50, 0xEE, 0x1D, 0x2C, 0x37, 0x74, 0xA9, 0xD3, 0x18, 0xA3, 0x47, 0x6E, + 0x93, 0x54, 0xAD, 0x0A, 0x5D, 0xB8, 0x2A, 0x55, 0x5D, 0x78, 0xF6, 0xEE, 0xBE, 0x8E, 0x3C, 0x76, + 0x69, 0xB9, 0x40, 0xC2, 0x34, 0xEC, 0x2A, 0xB9, 0xED, 0x7E, 0x20, 0xE4, 0x8D, 0x00, 0x38, 0xC7, + 0xE6, 0x8F, 0x44, 0xA8, 0x86, 0xCE, 0xEB, 0x2A, 0xE9, 0x90, 0xF1, 0x4C, 0xDF, 0x32, 0xFB, 0x73, + 0x1B, 0x6D, 0x92, 0x1E, 0x95, 0xFE, 0xB4, 0xDB, 0x65, 0xDF, 0x4D, 0x23, 0x54, 0x89, 0x48, 0xBF, + 0x4A, 0x2E, 0x70, 0xD6, 0xD7, 0x62, 0xB4, 0x33, 0x29, 0xB1, 0x3A, 0x33, 0x4C, 0x23, 0x6D, 0xA6, + 0x76, 0xA5, 0x21, 0x63, 0x48, 0xE6, 0x90, 0x5D, 0xED, 0x90, 0x95, 0x0B, 0x7A, 0x84, 0xBE, 0xB8, + 0x0D, 0x5E, 0x63, 0x0C, 0x62, 0x26, 0x4C, 0x14, 0x5A, 0xB3, 0xAC, 0x23, 0xA4, 0x74, 0xA7, 0x6F, + 0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xA0, 0x28, 0xB7, 0xEE, 0x19, 0x38, 0xF1, 0x64, 0x80, 0x82, + 0x43, 0xE1, 0x41, 0x27, 0x1F, 0x1F, 0x90, 0x54, 0x7A, 0xD5, 0x23, 0x2E, 0xD1, 0x3D, 0xCB, 0x28, + 0xBA, 0x58, 0x7F, 0xDC, 0x7C, 0x91, 0x24, 0xE9, 0x28, 0x51, 0x83, 0x6E, 0xC5, 0x56, 0x21, 0x42, + 0xED, 0xA0, 0x56, 0x22, 0xA1, 0x40, 0x80, 0x6B, 0xA8, 0xF7, 0x94, 0xCA, 0x13, 0x6B, 0x0C, 0x39, + 0xD9, 0xFD, 0xE9, 0xF3, 0x6F, 0xA6, 0x9E, 0xFC, 0x70, 0x8A, 0xB3, 0xBC, 0x59, 0x3C, 0x1E, 0x1D, + 0x6C, 0xF9, 0x7C, 0xAF, 0xF9, 0x88, 0x71, 0x95, 0xEB, 0x57, 0x00, 0xBD, 0x9F, 0x8C, 0x4F, 0xE1, + 0x24, 0x83, 0xC5, 0x22, 0xEA, 0xFD, 0xD3, 0x0C, 0xE2, 0x17, 0x18, 0x7C, 0x6A, 0x4C, 0xDE, 0x77, + 0xB4, 0x53, 0x9B, 0x4C, 0x81, 0xCD, 0x23, 0x60, 0xAA, 0x0E, 0x25, 0x73, 0x9C, 0x02, 0x79, 0x32, + 0x30, 0xDF, 0x74, 0xDF, 0x75, 0x19, 0xF4, 0xA5, 0x14, 0x5C, 0xF7, 0x7A, 0xA8, 0xA5, 0x91, 0x84, + 0x7C, 0x60, 0x03, 0x06, 0x3B, 0xCD, 0x50, 0xB6, 0x27, 0x9C, 0xFE, 0xB1, 0xDD, 0xCC, 0xD3, 0xB0, + 0x59, 0x24, 0xB2, 0xCA, 0xE2, 0x1C, 0x81, 0x22, 0x9D, 0x07, 0x8F, 0x8E, 0xB9, 0xBE, 0x4E, 0xFA, + 0xFC, 0x39, 0x65, 0xBA, 0xBF, 0x9D, 0x12, 0x37, 0x5E, 0x97, 0x7E, 0xF3, 0x89, 0xF5, 0x5D, 0xF5, + 0xE3, 0x09, 0x8C, 0x62, 0xB5, 0x20, 0x9D, 0x0C, 0x53, 0x8A, 0x68, 0x1B, 0xD2, 0x8F, 0x75, 0x17, + 0x5D, 0xD4, 0xE5, 0xDA, 0x75, 0x62, 0x19, 0x14, 0x6A, 0x26, 0x2D, 0xEB, 0xF8, 0xAF, 0x37, 0xF0, + 0x6C, 0xA4, 0x55, 0xB1, 0xBC, 0xE2, 0x33, 0xC0, 0x9A, 0xCA, 0xB0, 0x11, 0x49, 0x4F, 0x68, 0x9B, + 0x3B, 0x6B, 0x3C, 0xCC, 0x13, 0xF6, 0xC7, 0x85, 0x61, 0x68, 0x42, 0xAE, 0xBB, 0xDD, 0xCD, 0x45, + 0x16, 0x29, 0x1D, 0xEA, 0xDB, 0xC8, 0x03, 0x94, 0x3C, 0xEE, 0x4F, 0x82, 0x11, 0xC3, 0xEC, 0x28, + 0xBD, 0x97, 0x05, 0x99, 0xDE, 0xD7, 0xBB, 0x5E, 0x22, 0x1F, 0xD4, 0xEB, 0x64, 0xD9, 0x92, 0xD9, + 0x85, 0xB7, 0x6A, 0x05, 0x6A, 0xE4, 0x24, 0x41, 0xF1, 0xCD, 0xF0, 0xD8, 0x3F, 0xF8, 0x9E, 0x0E, + 0xCD, 0x0B, 0x7A, 0x70, 0x6B, 0x5A, 0x75, 0x0A, 0x6A, 0x33, 0x88, 0xEC, 0x17, 0x75, 0x08, 0x70, + 0x10, 0x2F, 0x24, 0xCF, 0xC4, 0xE9, 0x42, 0x00, 0x61, 0x94, 0xCA, 0x1F, 0x3A, 0x76, 0x06, 0xFA, + 0xD2, 0x48, 0x81, 0xF0, 0x77, 0x60, 0x03, 0x45, 0xD9, 0x61, 0xF4, 0xA4, 0x6F, 0x3D, 0xD9, 0x30, + 0xC3, 0x04, 0x6B, 0x54, 0x2A, 0xB7, 0xEC, 0x3B, 0xF4, 0x4B, 0xF5, 0x68, 0x52, 0x26, 0xCE, 0xFF, + 0x5D, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x23, 0xC4, 0x0A, 0x77, 0x4D, 0xF9, 0x51, + 0x20, 0xA3, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x19, 0x91, 0xA0, 0xA3, + 0xC4, 0xEB, 0x54, 0x0B, 0x75, 0x68, 0x52, 0x07, 0x8C, 0x9A, 0x97, 0x8D, 0x79, 0x70, 0x62, 0x46, + 0xEF, 0x5C, 0x1B, 0x95, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x67, 0x4C, + 0x1A, 0xB6, 0xCF, 0xFD, 0x78, 0x53, 0x24, 0xAB, 0xB5, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0x12, + 0x87, 0x6D, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6D, 0x58, 0x32, 0xC7, 0x0C, 0x9A, 0x97, 0xAC, + 0xDA, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x1D, 0xB8, 0xF2, 0x66, 0x2F, 0xBD, 0xF8, 0x72, 0x47, 0xED, + 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8C, 0x7B, 0x55, 0x09, 0x90, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8, + 0x53, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0xEC, 0x5A, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x3C, 0xFA, 0x76, + 0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x53, 0x05, 0x69, 0x31, 0xC1, 0x00, 0x82, + 0x86, 0x8E, 0x7F, 0x5D, 0x19, 0xB0, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0x8B, 0x94, 0x8B, + 0x75, 0x68, 0x33, 0xC5, 0x08, 0x92, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0x1C, 0xBA, 0xD7, 0x0D, 0x98, + 0xB2, 0xE6, 0x2F, 0xDC, 0x1B, 0x95, 0x89, 0x71, 0x60, 0x23, 0xC4, 0x0A, 0x96, 0x8F, 0x9C, 0xBA, + 0xF6, 0x6E, 0x3F, 0xFC, 0x5B, 0x15, 0xA8, 0xD2, 0x26, 0xAF, 0xBD, 0xF8, 0x72, 0x66, 0x2F, 0xDC, + 0x1B, 0xB4, 0xCB, 0x14, 0x8B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6F, + 0x3D, 0xD9, 0x30, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x70, 0x43, + 0x04, 0x6B, 0x35, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x58, + 0x32, 0xE6, 0x2F, 0xBD, 0xF8, 0x72, 0x66, 0x4E, 0x1E, 0xBE, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x1D, + 0x99, 0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x77, 0x4D, 0x18, 0x93, 0xA4, 0xAB, 0xD4, 0x0B, 0x75, 0x49, + 0x10, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8, 0x53, 0x24, 0xAB, 0xB5, 0xE8, 0x33, 0xE4, 0x4A, 0x16, 0xAE, + 0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xB3, 0xC5, 0x08, 0x73, 0x45, 0xE9, 0x31, 0xC1, 0xE1, 0x21, + 0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x86, 0x6F, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0xA4, 0xCA, 0x16, + 0xAE, 0xDE, 0x1F, 0x9D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x72, 0x47, 0x0C, 0x9A, 0xB6, + 0xCF, 0xFD, 0x59, 0x11, 0xA0, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x39, 0xF0, + 0x43, 0x04, 0x8A, 0x96, 0xAE, 0xDE, 0x3E, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xC2, 0x06, 0x6F, 0x3D, + 0xF8, 0x72, 0x47, 0x0C, 0x9A, 0x97, 0x8D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x45, 0xE9, 0x31, 0xE0, + 0x23, 0xA5, 0xA9, 0xD0, 0x03, 0x84, 0x8A, 0x96, 0xAE, 0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xD2, + 0x26, 0xCE, 0xFF, 0x5D, 0x19, 0x91, 0x81, 0x80, 0x82, 0x67, 0x2D, 0xD8, 0x13, 0xA4, 0xAB, 0xD4, + 0x0B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0xE9, 0x50, 0x22, + 0xC6, 0xEF, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x64, 0x4A, 0xF7, 0x4D, 0xF9, + 0x51, 0x20, 0xA3, 0xC4, 0x0A, 0x96, 0xAE, 0xDE, 0x3E, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x3C, 0xFA, + 0x76, 0x4F, 0xFD, 0x78, 0x72, 0x66, 0x2F, 0xBD, 0xD9, 0x30, 0xC3, 0xE5, 0x48, 0x12, 0x87, 0x8C, + 0x7B, 0x55, 0x28, 0xD2, 0x07, 0x8C, 0x9A, 0x97, 0xAC, 0xDA, 0x17, 0x8D, 0x79, 0x51, 0x20, 0xA3, + 0xC4, 0xEB, 0x54, 0x0B, 0x94, 0x8B, 0x94, 0xAA, 0xD6, 0x2E, 0xBF, 0xFC, 0x5B, 0x15, 0xA8, 0xD2, + 0x26, 0xAF, 0xDC, 0x1B, 0xB4, 0xEA, 0x37, 0xEC, 0x3B, 0xF4, 0x6A, 0x37, 0xCD, 0x18, 0x93, 0x85, + 0x69, 0x31, 0xC1, 0xE1, 0x40, 0xE3, 0x25, 0xC8, 0x12, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0xFD, 0x59, + 0x11, 0xA0, 0xC2, 0x06, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x37, 0xEC, + 0x5A, 0x36, 0xEE, 0x3F, 0xFC, 0x7A, 0x76, 0x4F, 0x1C, 0x9B, 0x95, 0x89, 0x71, 0x41, 0x00, 0x63, + 0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x0F, 0x9C, 0xBA, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x69, 0x31, 0xC1, + 0x00, 0x82, 0x86, 0x8E, 0x9E, 0xBE, 0xDF, 0x3C, 0xFA, 0x57, 0x2C, 0xDA, 0x36, 0xEE, 0x3F, 0xFC, + 0x5B, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0xED, 0x58, + 0x13, 0xA4, 0xCA, 0xF7, 0x4D, 0xF9, 0x51, 0x01, 0x80, 0x63, 0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x2E, + 0xBF, 0xDD, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x42, 0x06, 0x8E, 0x7F, 0x5D, 0x19, + 0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x96, 0x8F, 0x7D, 0x78, 0x72, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x56, + 0x2E, 0xDE, 0x1F, 0xBC, 0xFA, 0x57, 0x0D, 0x79, 0x51, 0x01, 0x61, 0x21, 0xA1, 0xC0, 0xE3, 0x25, + 0xA9, 0xB1, 0xC1, 0xE1, 0x40, 0x02, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0x93, 0xA4, 0xAB, 0xD4, + 0x2A, 0xD6, 0x0F, 0x9C, 0x9B, 0xB4, 0xCB, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xC4, + 0xEB, 0x35, 0xC9, 0xF1, 0x60, 0x42, 0x06, 0x8E, 0x7F, 0x7C, 0x7A, 0x76, 0x6E, 0x3F, 0xFC, 0x7A, + 0x76, 0x6E, 0x5E, 0x3E, 0xFE, 0x7E, 0x5F, 0x3C, 0xDB, 0x15, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xC0, + 0xE3, 0x44, 0xEB, 0x54, 0x2A, 0xB7, 0xCD, 0xF9, 0x70, 0x62, 0x27, 0xAD, 0xD8, 0x32, 0xC7, 0x0C, + 0x7B, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xEC, 0x3B, 0xD5, 0x28, 0xD2, 0x07, 0x6D, 0x39, 0xD1, 0x20, + 0xC2, 0xE7, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0xB2, 0xC7, 0x0C, 0x59, 0x28, 0xF3, 0x9B +}; diff --git a/drivers/sensors/pmw3360.h b/drivers/sensors/pmw3360.h index 3aa8ed0ed8..8aa70bd427 100644 --- a/drivers/sensors/pmw3360.h +++ b/drivers/sensors/pmw3360.h @@ -1,79 +1,73 @@ -/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2019 Sunjun Kim - * Copyright 2020 Ploopy Corporation - * - * 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 . - */ +// Copyright 2022 Stefan Kerkmann (KarlK90) +// Copyright 2022 Ulrich Spörlein (@uqs) +// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) +// Copyright 2019 Sunjun Kim +// Copyright 2020 Ploopy Corporation +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include -#ifndef PMW3360_CPI -# define PMW3360_CPI 1600 +#if !defined(PMW33XX_CPI) +# define PMW33XX_CPI 1600U #endif -#ifndef PMW3360_CLOCK_SPEED -# define PMW3360_CLOCK_SPEED 2000000 -#endif - -#ifndef PMW3360_SPI_LSBFIRST -# define PMW3360_SPI_LSBFIRST false -#endif - -#ifndef PMW3360_SPI_MODE -# define PMW3360_SPI_MODE 3 -#endif - -#ifndef PMW3360_SPI_DIVISOR -# ifdef __AVR__ -# define PMW3360_SPI_DIVISOR (F_CPU / PMW3360_CLOCK_SPEED) -# else -# define PMW3360_SPI_DIVISOR 64 -# endif -#endif - -#ifndef PMW3360_LIFTOFF_DISTANCE -# define PMW3360_LIFTOFF_DISTANCE 0x02 -#endif - -#ifndef ROTATIONAL_TRANSFORM_ANGLE -# define ROTATIONAL_TRANSFORM_ANGLE 0x00 -#endif - -// Support single and plural spellings -#ifndef PMW3360_CS_PINS -# ifndef PMW3360_CS_PIN -# error "No chip select pin defined -- missing PMW3360_CS_PIN or PMW3360_CS_PINS" -# else -# define PMW3360_CS_PINS \ - { PMW3360_CS_PIN } -# endif -#endif +#define PMW33XX_CPI_STEP 100 +#define PMW33XX_CPI_MIN 100 +#define PMW33XX_CPI_MAX 12000 -typedef struct { - int8_t motion; - bool isMotion; // True if a motion is detected. - bool isOnSurface; // True when a chip is on a surface - int16_t dx; // displacement on x directions. Unit: Count. (CPI * Count = Inch value) - int8_t mdx; - int16_t dy; // displacement on y directions. - int8_t mdy; -} report_pmw3360_t; +#define PMW33XX_FIRMWARE_LENGTH 4094 -bool pmw3360_init(int8_t index); -uint16_t pmw3360_get_cpi(void); -void pmw3360_set_cpi(uint16_t cpi); -/* Reads and clears the current delta values on the sensor */ -report_pmw3360_t pmw3360_read_burst(int8_t index); +// PMW3360 register addresses +// clang-format off +#define REG_Product_ID 0x00 +#define REG_Revision_ID 0x01 +#define REG_Motion 0x02 +#define REG_Delta_X_L 0x03 +#define REG_Delta_X_H 0x04 +#define REG_Delta_Y_L 0x05 +#define REG_Delta_Y_H 0x06 +#define REG_SQUAL 0x07 +#define REG_Raw_Data_Sum 0x08 +#define REG_Maximum_Raw_data 0x09 +#define REG_Minimum_Raw_data 0x0a +#define REG_Shutter_Lower 0x0b +#define REG_Shutter_Upper 0x0c +#define REG_Control 0x0d +#define REG_Config1 0x0f +#define REG_Config2 0x10 +#define REG_Angle_Tune 0x11 +#define REG_Frame_Capture 0x12 +#define REG_SROM_Enable 0x13 +#define REG_Run_Downshift 0x14 +#define REG_Rest1_Rate_Lower 0x15 +#define REG_Rest1_Rate_Upper 0x16 +#define REG_Rest1_Downshift 0x17 +#define REG_Rest2_Rate_Lower 0x18 +#define REG_Rest2_Rate_Upper 0x19 +#define REG_Rest2_Downshift 0x1a +#define REG_Rest3_Rate_Lower 0x1b +#define REG_Rest3_Rate_Upper 0x1c +#define REG_Observation 0x24 +#define REG_Data_Out_Lower 0x25 +#define REG_Data_Out_Upper 0x26 +#define REG_Raw_Data_Dump 0x29 +#define REG_SROM_ID 0x2a +#define REG_Min_SQ_Run 0x2b +#define REG_Raw_Data_Threshold 0x2c +#define REG_Config5 0x2f +#define REG_Power_Up_Reset 0x3a +#define REG_Shutdown 0x3b +#define REG_Inverse_Product_ID 0x3f +#define REG_LiftCutoff_Tune3 0x41 +#define REG_Angle_Snap 0x42 +#define REG_LiftCutoff_Tune1 0x4a +#define REG_Motion_Burst 0x50 +#define REG_LiftCutoff_Tune_Timeout 0x58 +#define REG_LiftCutoff_Tune_Min_Length 0x5a +#define REG_SROM_Load_Burst 0x62 +#define REG_Lift_Config 0x63 +#define REG_Raw_Data_Burst 0x64 +#define REG_LiftCutoff_Tune2 0x65 +// clang-format on diff --git a/drivers/sensors/pmw3360_firmware.h b/drivers/sensors/pmw3360_firmware.h deleted file mode 100644 index ed9fda5a75..0000000000 --- a/drivers/sensors/pmw3360_firmware.h +++ /dev/null @@ -1,288 +0,0 @@ -/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2019 Sunjun Kim - * Copyright 2020 Ploopy Corporation - * - * 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 . - */ - -#pragma once - -#include "progmem.h" - -// PID, Inverse PID, SROM version -const uint8_t firmware_signature[] PROGMEM = {0x42, 0xBD, 0x04}; - -#define FIRMWARE_LENGTH 4094 - -// Firmware Blob foor PMW3360 - -// clang-format off -const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = { - 0x01, 0x04, 0x8E, 0x96, 0x6E, 0x77, 0x3E, 0xFE, 0x7E, 0x5F, 0x1D, 0xB8, 0xF2, 0x66, 0x4E, 0xFF, - 0x5D, 0x19, 0xB0, 0xC2, 0x04, 0x69, 0x54, 0x2A, 0xD6, 0x2E, 0xBF, 0xDD, 0x19, 0xB0, 0xC3, 0xE5, - 0x29, 0xB1, 0xE0, 0x23, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x79, - 0x51, 0x20, 0xC7, 0x06, 0x8E, 0x7C, 0x7C, 0x7A, 0x76, 0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0x0E, - 0x9E, 0xBE, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xA5, 0xA1, 0xA9, 0xD0, 0x22, 0xC6, 0xEF, 0x5C, 0x1B, - 0x95, 0x89, 0x90, 0xA2, 0xA7, 0xCC, 0xFB, 0x55, 0x28, 0xB3, 0xE4, 0x4A, 0xF7, 0x6C, 0x3B, 0xF4, - 0x6A, 0x56, 0x2E, 0xDE, 0x1F, 0x9D, 0xB8, 0xD3, 0x05, 0x88, 0x92, 0xA6, 0xCE, 0x1E, 0xBE, 0xDF, - 0x1D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x5C, 0x07, 0x11, 0x5D, 0x98, 0x0B, 0x9D, 0x94, 0x97, 0xEE, - 0x4E, 0x45, 0x33, 0x6B, 0x44, 0xC7, 0x29, 0x56, 0x27, 0x30, 0xC6, 0xA7, 0xD5, 0xF2, 0x56, 0xDF, - 0xB4, 0x38, 0x62, 0xCB, 0xA0, 0xB6, 0xE3, 0x0F, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6F, 0x76, 0x89, - 0xB5, 0x77, 0x41, 0x27, 0x82, 0x66, 0x65, 0x82, 0xCC, 0xD5, 0xE6, 0x20, 0xD5, 0x27, 0x17, 0xC5, - 0xF8, 0x03, 0x23, 0x7C, 0x5F, 0x64, 0xA5, 0x1D, 0xC1, 0xD6, 0x36, 0xCB, 0x4C, 0xD4, 0xDB, 0x66, - 0xD7, 0x8B, 0xB1, 0x99, 0x7E, 0x6F, 0x4C, 0x36, 0x40, 0x06, 0xD6, 0xEB, 0xD7, 0xA2, 0xE4, 0xF4, - 0x95, 0x51, 0x5A, 0x54, 0x96, 0xD5, 0x53, 0x44, 0xD7, 0x8C, 0xE0, 0xB9, 0x40, 0x68, 0xD2, 0x18, - 0xE9, 0xDD, 0x9A, 0x23, 0x92, 0x48, 0xEE, 0x7F, 0x43, 0xAF, 0xEA, 0x77, 0x38, 0x84, 0x8C, 0x0A, - 0x72, 0xAF, 0x69, 0xF8, 0xDD, 0xF1, 0x24, 0x83, 0xA3, 0xF8, 0x4A, 0xBF, 0xF5, 0x94, 0x13, 0xDB, - 0xBB, 0xD8, 0xB4, 0xB3, 0xA0, 0xFB, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71, 0xA2, 0xD3, - 0x13, 0xE7, 0xFA, 0xE7, 0xCE, 0x0F, 0x63, 0x15, 0x0B, 0x6B, 0x94, 0xBB, 0x37, 0x83, 0x26, 0x05, - 0x9D, 0xFB, 0x46, 0x92, 0xFC, 0x0A, 0x15, 0xD1, 0x0D, 0x73, 0x92, 0xD6, 0x8C, 0x1B, 0x8C, 0xB8, - 0x55, 0x8A, 0xCE, 0xBD, 0xFE, 0x8E, 0xFC, 0xED, 0x09, 0x12, 0x83, 0x91, 0x82, 0x51, 0x31, 0x23, - 0xFB, 0xB4, 0x0C, 0x76, 0xAD, 0x7C, 0xD9, 0xB4, 0x4B, 0xB2, 0x67, 0x14, 0x09, 0x9C, 0x7F, 0x0C, - 0x18, 0xBA, 0x3B, 0xD6, 0x8E, 0x14, 0x2A, 0xE4, 0x1B, 0x52, 0x9F, 0x2B, 0x7D, 0xE1, 0xFB, 0x6A, - 0x33, 0x02, 0xFA, 0xAC, 0x5A, 0xF2, 0x3E, 0x88, 0x7E, 0xAE, 0xD1, 0xF3, 0x78, 0xE8, 0x05, 0xD1, - 0xE3, 0xDC, 0x21, 0xF6, 0xE1, 0x9A, 0xBD, 0x17, 0x0E, 0xD9, 0x46, 0x9B, 0x88, 0x03, 0xEA, 0xF6, - 0x66, 0xBE, 0x0E, 0x1B, 0x50, 0x49, 0x96, 0x40, 0x97, 0xF1, 0xF1, 0xE4, 0x80, 0xA6, 0x6E, 0xE8, - 0x77, 0x34, 0xBF, 0x29, 0x40, 0x44, 0xC2, 0xFF, 0x4E, 0x98, 0xD3, 0x9C, 0xA3, 0x32, 0x2B, 0x76, - 0x51, 0x04, 0x09, 0xE7, 0xA9, 0xD1, 0xA6, 0x32, 0xB1, 0x23, 0x53, 0xE2, 0x47, 0xAB, 0xD6, 0xF5, - 0x69, 0x5C, 0x3E, 0x5F, 0xFA, 0xAE, 0x45, 0x20, 0xE5, 0xD2, 0x44, 0xFF, 0x39, 0x32, 0x6D, 0xFD, - 0x27, 0x57, 0x5C, 0xFD, 0xF0, 0xDE, 0xC1, 0xB5, 0x99, 0xE5, 0xF5, 0x1C, 0x77, 0x01, 0x75, 0xC5, - 0x6D, 0x58, 0x92, 0xF2, 0xB2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7A, 0x30, 0xFF, 0xB7, 0xF0, 0xEF, - 0x77, 0xC1, 0x8A, 0x5D, 0xDC, 0xC0, 0xD1, 0x29, 0x30, 0x1E, 0x77, 0x38, 0x7A, 0x94, 0xF1, 0xB8, - 0x7A, 0x7E, 0xEF, 0xA4, 0xD1, 0xAC, 0x31, 0x4A, 0xF2, 0x5D, 0x64, 0x3D, 0xB2, 0xE2, 0xF0, 0x08, - 0x99, 0xFC, 0x70, 0xEE, 0x24, 0xA7, 0x7E, 0xEE, 0x1E, 0x20, 0x69, 0x7D, 0x44, 0xBF, 0x87, 0x42, - 0xDF, 0x88, 0x3B, 0x0C, 0xDA, 0x42, 0xC9, 0x04, 0xF9, 0x45, 0x50, 0xFC, 0x83, 0x8F, 0x11, 0x6A, - 0x72, 0xBC, 0x99, 0x95, 0xF0, 0xAC, 0x3D, 0xA7, 0x3B, 0xCD, 0x1C, 0xE2, 0x88, 0x79, 0x37, 0x11, - 0x5F, 0x39, 0x89, 0x95, 0x0A, 0x16, 0x84, 0x7A, 0xF6, 0x8A, 0xA4, 0x28, 0xE4, 0xED, 0x83, 0x80, - 0x3B, 0xB1, 0x23, 0xA5, 0x03, 0x10, 0xF4, 0x66, 0xEA, 0xBB, 0x0C, 0x0F, 0xC5, 0xEC, 0x6C, 0x69, - 0xC5, 0xD3, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0x99, 0x88, 0x76, 0x08, 0xA0, 0xA8, 0x95, 0x7C, 0xD8, - 0x38, 0x6D, 0xCD, 0x59, 0x02, 0x51, 0x4B, 0xF1, 0xB5, 0x2B, 0x50, 0xE3, 0xB6, 0xBD, 0xD0, 0x72, - 0xCF, 0x9E, 0xFD, 0x6E, 0xBB, 0x44, 0xC8, 0x24, 0x8A, 0x77, 0x18, 0x8A, 0x13, 0x06, 0xEF, 0x97, - 0x7D, 0xFA, 0x81, 0xF0, 0x31, 0xE6, 0xFA, 0x77, 0xED, 0x31, 0x06, 0x31, 0x5B, 0x54, 0x8A, 0x9F, - 0x30, 0x68, 0xDB, 0xE2, 0x40, 0xF8, 0x4E, 0x73, 0xFA, 0xAB, 0x74, 0x8B, 0x10, 0x58, 0x13, 0xDC, - 0xD2, 0xE6, 0x78, 0xD1, 0x32, 0x2E, 0x8A, 0x9F, 0x2C, 0x58, 0x06, 0x48, 0x27, 0xC5, 0xA9, 0x5E, - 0x81, 0x47, 0x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xA4, 0x3E, 0x88, 0x9C, 0xDA, 0x33, 0x0A, 0xCE, - 0xBC, 0x8B, 0x8E, 0xCF, 0x9F, 0xD3, 0x71, 0x80, 0x43, 0xCF, 0x6B, 0xA9, 0x51, 0x83, 0x76, 0x30, - 0x82, 0xC5, 0x6A, 0x85, 0x39, 0x11, 0x50, 0x1A, 0x82, 0xDC, 0x1E, 0x1C, 0xD5, 0x7D, 0xA9, 0x71, - 0x99, 0x33, 0x47, 0x19, 0x97, 0xB3, 0x5A, 0xB1, 0xDF, 0xED, 0xA4, 0xF2, 0xE6, 0x26, 0x84, 0xA2, - 0x28, 0x9A, 0x9E, 0xDF, 0xA6, 0x6A, 0xF4, 0xD6, 0xFC, 0x2E, 0x5B, 0x9D, 0x1A, 0x2A, 0x27, 0x68, - 0xFB, 0xC1, 0x83, 0x21, 0x4B, 0x90, 0xE0, 0x36, 0xDD, 0x5B, 0x31, 0x42, 0x55, 0xA0, 0x13, 0xF7, - 0xD0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xC5, 0xF3, 0x21, 0xF8, 0x37, 0x2F, 0x40, 0xF3, - 0xD4, 0xAF, 0x16, 0x08, 0x36, 0x02, 0xFC, 0x77, 0xC5, 0x8B, 0x04, 0x90, 0x56, 0xB9, 0xC9, 0x67, - 0x9A, 0x99, 0xE8, 0x00, 0xD3, 0x86, 0xFF, 0x97, 0x2D, 0x08, 0xE9, 0xB7, 0xB3, 0x91, 0xBC, 0xDF, - 0x45, 0xC6, 0xED, 0x0F, 0x8C, 0x4C, 0x1E, 0xE6, 0x5B, 0x6E, 0x38, 0x30, 0xE4, 0xAA, 0xE3, 0x95, - 0xDE, 0xB9, 0xE4, 0x9A, 0xF5, 0xB2, 0x55, 0x9A, 0x87, 0x9B, 0xF6, 0x6A, 0xB2, 0xF2, 0x77, 0x9A, - 0x31, 0xF4, 0x7A, 0x31, 0xD1, 0x1D, 0x04, 0xC0, 0x7C, 0x32, 0xA2, 0x9E, 0x9A, 0xF5, 0x62, 0xF8, - 0x27, 0x8D, 0xBF, 0x51, 0xFF, 0xD3, 0xDF, 0x64, 0x37, 0x3F, 0x2A, 0x6F, 0x76, 0x3A, 0x7D, 0x77, - 0x06, 0x9E, 0x77, 0x7F, 0x5E, 0xEB, 0x32, 0x51, 0xF9, 0x16, 0x66, 0x9A, 0x09, 0xF3, 0xB0, 0x08, - 0xA4, 0x70, 0x96, 0x46, 0x30, 0xFF, 0xDA, 0x4F, 0xE9, 0x1B, 0xED, 0x8D, 0xF8, 0x74, 0x1F, 0x31, - 0x92, 0xB3, 0x73, 0x17, 0x36, 0xDB, 0x91, 0x30, 0xD6, 0x88, 0x55, 0x6B, 0x34, 0x77, 0x87, 0x7A, - 0xE7, 0xEE, 0x06, 0xC6, 0x1C, 0x8C, 0x19, 0x0C, 0x48, 0x46, 0x23, 0x5E, 0x9C, 0x07, 0x5C, 0xBF, - 0xB4, 0x7E, 0xD6, 0x4F, 0x74, 0x9C, 0xE2, 0xC5, 0x50, 0x8B, 0xC5, 0x8B, 0x15, 0x90, 0x60, 0x62, - 0x57, 0x29, 0xD0, 0x13, 0x43, 0xA1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xC7, 0x4D, 0x19, 0x86, 0xCC, - 0x2F, 0x2A, 0x75, 0x5A, 0xFC, 0xEB, 0x97, 0x2A, 0x70, 0xE3, 0x78, 0xD8, 0x91, 0xB0, 0x4F, 0x99, - 0x07, 0xA3, 0x95, 0xEA, 0x24, 0x21, 0xD5, 0xDE, 0x51, 0x20, 0x93, 0x27, 0x0A, 0x30, 0x73, 0xA8, - 0xFF, 0x8A, 0x97, 0xE9, 0xA7, 0x6A, 0x8E, 0x0D, 0xE8, 0xF0, 0xDF, 0xEC, 0xEA, 0xB4, 0x6C, 0x1D, - 0x39, 0x2A, 0x62, 0x2D, 0x3D, 0x5A, 0x8B, 0x65, 0xF8, 0x90, 0x05, 0x2E, 0x7E, 0x91, 0x2C, 0x78, - 0xEF, 0x8E, 0x7A, 0xC1, 0x2F, 0xAC, 0x78, 0xEE, 0xAF, 0x28, 0x45, 0x06, 0x4C, 0x26, 0xAF, 0x3B, - 0xA2, 0xDB, 0xA3, 0x93, 0x06, 0xB5, 0x3C, 0xA5, 0xD8, 0xEE, 0x8F, 0xAF, 0x25, 0xCC, 0x3F, 0x85, - 0x68, 0x48, 0xA9, 0x62, 0xCC, 0x97, 0x8F, 0x7F, 0x2A, 0xEA, 0xE0, 0x15, 0x0A, 0xAD, 0x62, 0x07, - 0xBD, 0x45, 0xF8, 0x41, 0xD8, 0x36, 0xCB, 0x4C, 0xDB, 0x6E, 0xE6, 0x3A, 0xE7, 0xDA, 0x15, 0xE9, - 0x29, 0x1E, 0x12, 0x10, 0xA0, 0x14, 0x2C, 0x0E, 0x3D, 0xF4, 0xBF, 0x39, 0x41, 0x92, 0x75, 0x0B, - 0x25, 0x7B, 0xA3, 0xCE, 0x39, 0x9C, 0x15, 0x64, 0xC8, 0xFA, 0x3D, 0xEF, 0x73, 0x27, 0xFE, 0x26, - 0x2E, 0xCE, 0xDA, 0x6E, 0xFD, 0x71, 0x8E, 0xDD, 0xFE, 0x76, 0xEE, 0xDC, 0x12, 0x5C, 0x02, 0xC5, - 0x3A, 0x4E, 0x4E, 0x4F, 0xBF, 0xCA, 0x40, 0x15, 0xC7, 0x6E, 0x8D, 0x41, 0xF1, 0x10, 0xE0, 0x4F, - 0x7E, 0x97, 0x7F, 0x1C, 0xAE, 0x47, 0x8E, 0x6B, 0xB1, 0x25, 0x31, 0xB0, 0x73, 0xC7, 0x1B, 0x97, - 0x79, 0xF9, 0x80, 0xD3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1E, 0xE4, 0xD0, 0x80, 0x21, 0xD6, 0xEE, - 0x6B, 0x6C, 0x4F, 0xBF, 0xF5, 0xB7, 0xD9, 0x09, 0x87, 0x2F, 0xA9, 0x14, 0xBE, 0x27, 0xD9, 0x72, - 0x50, 0x01, 0xD4, 0x13, 0x73, 0xA6, 0xA7, 0x51, 0x02, 0x75, 0x25, 0xE1, 0xB3, 0x45, 0x34, 0x7D, - 0xA8, 0x8E, 0xEB, 0xF3, 0x16, 0x49, 0xCB, 0x4F, 0x8C, 0xA1, 0xB9, 0x36, 0x85, 0x39, 0x75, 0x5D, - 0x08, 0x00, 0xAE, 0xEB, 0xF6, 0xEA, 0xD7, 0x13, 0x3A, 0x21, 0x5A, 0x5F, 0x30, 0x84, 0x52, 0x26, - 0x95, 0xC9, 0x14, 0xF2, 0x57, 0x55, 0x6B, 0xB1, 0x10, 0xC2, 0xE1, 0xBD, 0x3B, 0x51, 0xC0, 0xB7, - 0x55, 0x4C, 0x71, 0x12, 0x26, 0xC7, 0x0D, 0xF9, 0x51, 0xA4, 0x38, 0x02, 0x05, 0x7F, 0xB8, 0xF1, - 0x72, 0x4B, 0xBF, 0x71, 0x89, 0x14, 0xF3, 0x77, 0x38, 0xD9, 0x71, 0x24, 0xF3, 0x00, 0x11, 0xA1, - 0xD8, 0xD4, 0x69, 0x27, 0x08, 0x37, 0x35, 0xC9, 0x11, 0x9D, 0x90, 0x1C, 0x0E, 0xE7, 0x1C, 0xFF, - 0x2D, 0x1E, 0xE8, 0x92, 0xE1, 0x18, 0x10, 0x95, 0x7C, 0xE0, 0x80, 0xF4, 0x96, 0x43, 0x21, 0xF9, - 0x75, 0x21, 0x64, 0x38, 0xDD, 0x9F, 0x1E, 0x95, 0x16, 0xDA, 0x56, 0x1D, 0x4F, 0x9A, 0x53, 0xB2, - 0xE2, 0xE4, 0x18, 0xCB, 0x6B, 0x1A, 0x65, 0xEB, 0x56, 0xC6, 0x3B, 0xE5, 0xFE, 0xD8, 0x26, 0x3F, - 0x3A, 0x84, 0x59, 0x72, 0x66, 0xA2, 0xF3, 0x75, 0xFF, 0xFB, 0x60, 0xB3, 0x22, 0xAD, 0x3F, 0x2D, - 0x6B, 0xF9, 0xEB, 0xEA, 0x05, 0x7C, 0xD8, 0x8F, 0x6D, 0x2C, 0x98, 0x9E, 0x2B, 0x93, 0xF1, 0x5E, - 0x46, 0xF0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xD7, 0x7F, 0xF9, 0xF0, 0xE5, 0x7D, 0xDB, 0x1D, 0x75, - 0x19, 0xF3, 0xC4, 0x58, 0x9B, 0x17, 0x88, 0xA8, 0x92, 0xE0, 0xBE, 0xBD, 0x8B, 0x1D, 0x8D, 0x9F, - 0x56, 0x76, 0xAD, 0xAF, 0x29, 0xE2, 0xD9, 0xD5, 0x52, 0xF6, 0xB5, 0x56, 0x35, 0x57, 0x3A, 0xC8, - 0xE1, 0x56, 0x43, 0x19, 0x94, 0xD3, 0x04, 0x9B, 0x6D, 0x35, 0xD8, 0x0B, 0x5F, 0x4D, 0x19, 0x8E, - 0xEC, 0xFA, 0x64, 0x91, 0x0A, 0x72, 0x20, 0x2B, 0xBC, 0x1A, 0x4A, 0xFE, 0x8B, 0xFD, 0xBB, 0xED, - 0x1B, 0x23, 0xEA, 0xAD, 0x72, 0x82, 0xA1, 0x29, 0x99, 0x71, 0xBD, 0xF0, 0x95, 0xC1, 0x03, 0xDD, - 0x7B, 0xC2, 0xB2, 0x3C, 0x28, 0x54, 0xD3, 0x68, 0xA4, 0x72, 0xC8, 0x66, 0x96, 0xE0, 0xD1, 0xD8, - 0x7F, 0xF8, 0xD1, 0x26, 0x2B, 0xF7, 0xAD, 0xBA, 0x55, 0xCA, 0x15, 0xB9, 0x32, 0xC3, 0xE5, 0x88, - 0x97, 0x8E, 0x5C, 0xFB, 0x92, 0x25, 0x8B, 0xBF, 0xA2, 0x45, 0x55, 0x7A, 0xA7, 0x6F, 0x8B, 0x57, - 0x5B, 0xCF, 0x0E, 0xCB, 0x1D, 0xFB, 0x20, 0x82, 0x77, 0xA8, 0x8C, 0xCC, 0x16, 0xCE, 0x1D, 0xFA, - 0xDE, 0xCC, 0x0B, 0x62, 0xFE, 0xCC, 0xE1, 0xB7, 0xF0, 0xC3, 0x81, 0x64, 0x73, 0x40, 0xA0, 0xC2, - 0x4D, 0x89, 0x11, 0x75, 0x33, 0x55, 0x33, 0x8D, 0xE8, 0x4A, 0xFD, 0xEA, 0x6E, 0x30, 0x0B, 0xD7, - 0x31, 0x2C, 0xDE, 0x47, 0xE3, 0xBF, 0xF8, 0x55, 0x42, 0xE2, 0x7F, 0x59, 0xE5, 0x17, 0xEF, 0x99, - 0x34, 0x69, 0x91, 0xB1, 0x23, 0x8E, 0x20, 0x87, 0x2D, 0xA8, 0xFE, 0xD5, 0x8A, 0xF3, 0x84, 0x3A, - 0xF0, 0x37, 0xE4, 0x09, 0x00, 0x54, 0xEE, 0x67, 0x49, 0x93, 0xE4, 0x81, 0x70, 0xE3, 0x90, 0x4D, - 0xEF, 0xFE, 0x41, 0xB7, 0x99, 0x7B, 0xC1, 0x83, 0xBA, 0x62, 0x12, 0x6F, 0x7D, 0xDE, 0x6B, 0xAF, - 0xDA, 0x16, 0xF9, 0x55, 0x51, 0xEE, 0xA6, 0x0C, 0x2B, 0x02, 0xA3, 0xFD, 0x8D, 0xFB, 0x30, 0x17, - 0xE4, 0x6F, 0xDF, 0x36, 0x71, 0xC4, 0xCA, 0x87, 0x25, 0x48, 0xB0, 0x47, 0xEC, 0xEA, 0xB4, 0xBF, - 0xA5, 0x4D, 0x9B, 0x9F, 0x02, 0x93, 0xC4, 0xE3, 0xE4, 0xE8, 0x42, 0x2D, 0x68, 0x81, 0x15, 0x0A, - 0xEB, 0x84, 0x5B, 0xD6, 0xA8, 0x74, 0xFB, 0x7D, 0x1D, 0xCB, 0x2C, 0xDA, 0x46, 0x2A, 0x76, 0x62, - 0xCE, 0xBC, 0x5C, 0x9E, 0x8B, 0xE7, 0xCF, 0xBE, 0x78, 0xF5, 0x7C, 0xEB, 0xB3, 0x3A, 0x9C, 0xAA, - 0x6F, 0xCC, 0x72, 0xD1, 0x59, 0xF2, 0x11, 0x23, 0xD6, 0x3F, 0x48, 0xD1, 0xB7, 0xCE, 0xB0, 0xBF, - 0xCB, 0xEA, 0x80, 0xDE, 0x57, 0xD4, 0x5E, 0x97, 0x2F, 0x75, 0xD1, 0x50, 0x8E, 0x80, 0x2C, 0x66, - 0x79, 0xBF, 0x72, 0x4B, 0xBD, 0x8A, 0x81, 0x6C, 0xD3, 0xE1, 0x01, 0xDC, 0xD2, 0x15, 0x26, 0xC5, - 0x36, 0xDA, 0x2C, 0x1A, 0xC0, 0x27, 0x94, 0xED, 0xB7, 0x9B, 0x85, 0x0B, 0x5E, 0x80, 0x97, 0xC5, - 0xEC, 0x4F, 0xEC, 0x88, 0x5D, 0x50, 0x07, 0x35, 0x47, 0xDC, 0x0B, 0x3B, 0x3D, 0xDD, 0x60, 0xAF, - 0xA8, 0x5D, 0x81, 0x38, 0x24, 0x25, 0x5D, 0x5C, 0x15, 0xD1, 0xDE, 0xB3, 0xAB, 0xEC, 0x05, 0x69, - 0xEF, 0x83, 0xED, 0x57, 0x54, 0xB8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xDA, 0x9F, 0x2D, 0x7F, - 0x36, 0xBB, 0x44, 0x5A, 0x34, 0xE8, 0x7F, 0xBF, 0x03, 0xEB, 0x00, 0x7F, 0x59, 0x68, 0x22, 0x79, - 0xCF, 0x73, 0x6C, 0x2C, 0x29, 0xA7, 0xA1, 0x5F, 0x38, 0xA1, 0x1D, 0xF0, 0x20, 0x53, 0xE0, 0x1A, - 0x63, 0x14, 0x58, 0x71, 0x10, 0xAA, 0x08, 0x0C, 0x3E, 0x16, 0x1A, 0x60, 0x22, 0x82, 0x7F, 0xBA, - 0xA4, 0x43, 0xA0, 0xD0, 0xAC, 0x1B, 0xD5, 0x6B, 0x64, 0xB5, 0x14, 0x93, 0x31, 0x9E, 0x53, 0x50, - 0xD0, 0x57, 0x66, 0xEE, 0x5A, 0x4F, 0xFB, 0x03, 0x2A, 0x69, 0x58, 0x76, 0xF1, 0x83, 0xF7, 0x4E, - 0xBA, 0x8C, 0x42, 0x06, 0x60, 0x5D, 0x6D, 0xCE, 0x60, 0x88, 0xAE, 0xA4, 0xC3, 0xF1, 0x03, 0xA5, - 0x4B, 0x98, 0xA1, 0xFF, 0x67, 0xE1, 0xAC, 0xA2, 0xB8, 0x62, 0xD7, 0x6F, 0xA0, 0x31, 0xB4, 0xD2, - 0x77, 0xAF, 0x21, 0x10, 0x06, 0xC6, 0x9A, 0xFF, 0x1D, 0x09, 0x17, 0x0E, 0x5F, 0xF1, 0xAA, 0x54, - 0x34, 0x4B, 0x45, 0x8A, 0x87, 0x63, 0xA6, 0xDC, 0xF9, 0x24, 0x30, 0x67, 0xC6, 0xB2, 0xD6, 0x61, - 0x33, 0x69, 0xEE, 0x50, 0x61, 0x57, 0x28, 0xE7, 0x7E, 0xEE, 0xEC, 0x3A, 0x5A, 0x73, 0x4E, 0xA8, - 0x8D, 0xE4, 0x18, 0xEA, 0xEC, 0x41, 0x64, 0xC8, 0xE2, 0xE8, 0x66, 0xB6, 0x2D, 0xB6, 0xFB, 0x6A, - 0x6C, 0x16, 0xB3, 0xDD, 0x46, 0x43, 0xB9, 0x73, 0x00, 0x6A, 0x71, 0xED, 0x4E, 0x9D, 0x25, 0x1A, - 0xC3, 0x3C, 0x4A, 0x95, 0x15, 0x99, 0x35, 0x81, 0x14, 0x02, 0xD6, 0x98, 0x9B, 0xEC, 0xD8, 0x23, - 0x3B, 0x84, 0x29, 0xAF, 0x0C, 0x99, 0x83, 0xA6, 0x9A, 0x34, 0x4F, 0xFA, 0xE8, 0xD0, 0x3C, 0x4B, - 0xD0, 0xFB, 0xB6, 0x68, 0xB8, 0x9E, 0x8F, 0xCD, 0xF7, 0x60, 0x2D, 0x7A, 0x22, 0xE5, 0x7D, 0xAB, - 0x65, 0x1B, 0x95, 0xA7, 0xA8, 0x7F, 0xB6, 0x77, 0x47, 0x7B, 0x5F, 0x8B, 0x12, 0x72, 0xD0, 0xD4, - 0x91, 0xEF, 0xDE, 0x19, 0x50, 0x3C, 0xA7, 0x8B, 0xC4, 0xA9, 0xB3, 0x23, 0xCB, 0x76, 0xE6, 0x81, - 0xF0, 0xC1, 0x04, 0x8F, 0xA3, 0xB8, 0x54, 0x5B, 0x97, 0xAC, 0x19, 0xFF, 0x3F, 0x55, 0x27, 0x2F, - 0xE0, 0x1D, 0x42, 0x9B, 0x57, 0xFC, 0x4B, 0x4E, 0x0F, 0xCE, 0x98, 0xA9, 0x43, 0x57, 0x03, 0xBD, - 0xE7, 0xC8, 0x94, 0xDF, 0x6E, 0x36, 0x73, 0x32, 0xB4, 0xEF, 0x2E, 0x85, 0x7A, 0x6E, 0xFC, 0x6C, - 0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xF3, 0xE4, 0x9F, 0x3E, 0xDC, 0x68, 0xF3, 0xB5, 0xF3, 0x19, - 0x80, 0x92, 0x06, 0x99, 0xA2, 0xE8, 0x6F, 0xFF, 0x2E, 0x7F, 0xAE, 0x42, 0xA4, 0x5F, 0xFB, 0xD4, - 0x0E, 0x81, 0x2B, 0xC3, 0x04, 0xFF, 0x2B, 0xB3, 0x74, 0x4E, 0x36, 0x5B, 0x9C, 0x15, 0x00, 0xC6, - 0x47, 0x2B, 0xE8, 0x8B, 0x3D, 0xF1, 0x9C, 0x03, 0x9A, 0x58, 0x7F, 0x9B, 0x9C, 0xBF, 0x85, 0x49, - 0x79, 0x35, 0x2E, 0x56, 0x7B, 0x41, 0x14, 0x39, 0x47, 0x83, 0x26, 0xAA, 0x07, 0x89, 0x98, 0x11, - 0x1B, 0x86, 0xE7, 0x73, 0x7A, 0xD8, 0x7D, 0x78, 0x61, 0x53, 0xE9, 0x79, 0xF5, 0x36, 0x8D, 0x44, - 0x92, 0x84, 0xF9, 0x13, 0x50, 0x58, 0x3B, 0xA4, 0x6A, 0x36, 0x65, 0x49, 0x8E, 0x3C, 0x0E, 0xF1, - 0x6F, 0xD2, 0x84, 0xC4, 0x7E, 0x8E, 0x3F, 0x39, 0xAE, 0x7C, 0x84, 0xF1, 0x63, 0x37, 0x8E, 0x3C, - 0xCC, 0x3E, 0x44, 0x81, 0x45, 0xF1, 0x4B, 0xB9, 0xED, 0x6B, 0x36, 0x5D, 0xBB, 0x20, 0x60, 0x1A, - 0x0F, 0xA3, 0xAA, 0x55, 0x77, 0x3A, 0xA9, 0xAE, 0x37, 0x4D, 0xBA, 0xB8, 0x86, 0x6B, 0xBC, 0x08, - 0x50, 0xF6, 0xCC, 0xA4, 0xBD, 0x1D, 0x40, 0x72, 0xA5, 0x86, 0xFA, 0xE2, 0x10, 0xAE, 0x3D, 0x58, - 0x4B, 0x97, 0xF3, 0x43, 0x74, 0xA9, 0x9E, 0xEB, 0x21, 0xB7, 0x01, 0xA4, 0x86, 0x93, 0x97, 0xEE, - 0x2F, 0x4F, 0x3B, 0x86, 0xA1, 0x41, 0x6F, 0x41, 0x26, 0x90, 0x78, 0x5C, 0x7F, 0x30, 0x38, 0x4B, - 0x3F, 0xAA, 0xEC, 0xED, 0x5C, 0x6F, 0x0E, 0xAD, 0x43, 0x87, 0xFD, 0x93, 0x35, 0xE6, 0x01, 0xEF, - 0x41, 0x26, 0x90, 0x99, 0x9E, 0xFB, 0x19, 0x5B, 0xAD, 0xD2, 0x91, 0x8A, 0xE0, 0x46, 0xAF, 0x65, - 0xFA, 0x4F, 0x84, 0xC1, 0xA1, 0x2D, 0xCF, 0x45, 0x8B, 0xD3, 0x85, 0x50, 0x55, 0x7C, 0xF9, 0x67, - 0x88, 0xD4, 0x4E, 0xE9, 0xD7, 0x6B, 0x61, 0x54, 0xA1, 0xA4, 0xA6, 0xA2, 0xC2, 0xBF, 0x30, 0x9C, - 0x40, 0x9F, 0x5F, 0xD7, 0x69, 0x2B, 0x24, 0x82, 0x5E, 0xD9, 0xD6, 0xA7, 0x12, 0x54, 0x1A, 0xF7, - 0x55, 0x9F, 0x76, 0x50, 0xA9, 0x95, 0x84, 0xE6, 0x6B, 0x6D, 0xB5, 0x96, 0x54, 0xD6, 0xCD, 0xB3, - 0xA1, 0x9B, 0x46, 0xA7, 0x94, 0x4D, 0xC4, 0x94, 0xB4, 0x98, 0xE3, 0xE1, 0xE2, 0x34, 0xD5, 0x33, - 0x16, 0x07, 0x54, 0xCD, 0xB7, 0x77, 0x53, 0xDB, 0x4F, 0x4D, 0x46, 0x9D, 0xE9, 0xD4, 0x9C, 0x8A, - 0x36, 0xB6, 0xB8, 0x38, 0x26, 0x6C, 0x0E, 0xFF, 0x9C, 0x1B, 0x43, 0x8B, 0x80, 0xCC, 0xB9, 0x3D, - 0xDA, 0xC7, 0xF1, 0x8A, 0xF2, 0x6D, 0xB8, 0xD7, 0x74, 0x2F, 0x7E, 0x1E, 0xB7, 0xD3, 0x4A, 0xB4, - 0xAC, 0xFC, 0x79, 0x48, 0x6C, 0xBC, 0x96, 0xB6, 0x94, 0x46, 0x57, 0x2D, 0xB0, 0xA3, 0xFC, 0x1E, - 0xB9, 0x52, 0x60, 0x85, 0x2D, 0x41, 0xD0, 0x43, 0x01, 0x1E, 0x1C, 0xD5, 0x7D, 0xFC, 0xF3, 0x96, - 0x0D, 0xC7, 0xCB, 0x2A, 0x29, 0x9A, 0x93, 0xDD, 0x88, 0x2D, 0x37, 0x5D, 0xAA, 0xFB, 0x49, 0x68, - 0xA0, 0x9C, 0x50, 0x86, 0x7F, 0x68, 0x56, 0x57, 0xF9, 0x79, 0x18, 0x39, 0xD4, 0xE0, 0x01, 0x84, - 0x33, 0x61, 0xCA, 0xA5, 0xD2, 0xD6, 0xE4, 0xC9, 0x8A, 0x4A, 0x23, 0x44, 0x4E, 0xBC, 0xF0, 0xDC, - 0x24, 0xA1, 0xA0, 0xC4, 0xE2, 0x07, 0x3C, 0x10, 0xC4, 0xB5, 0x25, 0x4B, 0x65, 0x63, 0xF4, 0x80, - 0xE7, 0xCF, 0x61, 0xB1, 0x71, 0x82, 0x21, 0x87, 0x2C, 0xF5, 0x91, 0x00, 0x32, 0x0C, 0xEC, 0xA9, - 0xB5, 0x9A, 0x74, 0x85, 0xE3, 0x36, 0x8F, 0x76, 0x4F, 0x9C, 0x6D, 0xCE, 0xBC, 0xAD, 0x0A, 0x4B, - 0xED, 0x76, 0x04, 0xCB, 0xC3, 0xB9, 0x33, 0x9E, 0x01, 0x93, 0x96, 0x69, 0x7D, 0xC5, 0xA2, 0x45, - 0x79, 0x9B, 0x04, 0x5C, 0x84, 0x09, 0xED, 0x88, 0x43, 0xC7, 0xAB, 0x93, 0x14, 0x26, 0xA1, 0x40, - 0xB5, 0xCE, 0x4E, 0xBF, 0x2A, 0x42, 0x85, 0x3E, 0x2C, 0x3B, 0x54, 0xE8, 0x12, 0x1F, 0x0E, 0x97, - 0x59, 0xB2, 0x27, 0x89, 0xFA, 0xF2, 0xDF, 0x8E, 0x68, 0x59, 0xDC, 0x06, 0xBC, 0xB6, 0x85, 0x0D, - 0x06, 0x22, 0xEC, 0xB1, 0xCB, 0xE5, 0x04, 0xE6, 0x3D, 0xB3, 0xB0, 0x41, 0x73, 0x08, 0x3F, 0x3C, - 0x58, 0x86, 0x63, 0xEB, 0x50, 0xEE, 0x1D, 0x2C, 0x37, 0x74, 0xA9, 0xD3, 0x18, 0xA3, 0x47, 0x6E, - 0x93, 0x54, 0xAD, 0x0A, 0x5D, 0xB8, 0x2A, 0x55, 0x5D, 0x78, 0xF6, 0xEE, 0xBE, 0x8E, 0x3C, 0x76, - 0x69, 0xB9, 0x40, 0xC2, 0x34, 0xEC, 0x2A, 0xB9, 0xED, 0x7E, 0x20, 0xE4, 0x8D, 0x00, 0x38, 0xC7, - 0xE6, 0x8F, 0x44, 0xA8, 0x86, 0xCE, 0xEB, 0x2A, 0xE9, 0x90, 0xF1, 0x4C, 0xDF, 0x32, 0xFB, 0x73, - 0x1B, 0x6D, 0x92, 0x1E, 0x95, 0xFE, 0xB4, 0xDB, 0x65, 0xDF, 0x4D, 0x23, 0x54, 0x89, 0x48, 0xBF, - 0x4A, 0x2E, 0x70, 0xD6, 0xD7, 0x62, 0xB4, 0x33, 0x29, 0xB1, 0x3A, 0x33, 0x4C, 0x23, 0x6D, 0xA6, - 0x76, 0xA5, 0x21, 0x63, 0x48, 0xE6, 0x90, 0x5D, 0xED, 0x90, 0x95, 0x0B, 0x7A, 0x84, 0xBE, 0xB8, - 0x0D, 0x5E, 0x63, 0x0C, 0x62, 0x26, 0x4C, 0x14, 0x5A, 0xB3, 0xAC, 0x23, 0xA4, 0x74, 0xA7, 0x6F, - 0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xA0, 0x28, 0xB7, 0xEE, 0x19, 0x38, 0xF1, 0x64, 0x80, 0x82, - 0x43, 0xE1, 0x41, 0x27, 0x1F, 0x1F, 0x90, 0x54, 0x7A, 0xD5, 0x23, 0x2E, 0xD1, 0x3D, 0xCB, 0x28, - 0xBA, 0x58, 0x7F, 0xDC, 0x7C, 0x91, 0x24, 0xE9, 0x28, 0x51, 0x83, 0x6E, 0xC5, 0x56, 0x21, 0x42, - 0xED, 0xA0, 0x56, 0x22, 0xA1, 0x40, 0x80, 0x6B, 0xA8, 0xF7, 0x94, 0xCA, 0x13, 0x6B, 0x0C, 0x39, - 0xD9, 0xFD, 0xE9, 0xF3, 0x6F, 0xA6, 0x9E, 0xFC, 0x70, 0x8A, 0xB3, 0xBC, 0x59, 0x3C, 0x1E, 0x1D, - 0x6C, 0xF9, 0x7C, 0xAF, 0xF9, 0x88, 0x71, 0x95, 0xEB, 0x57, 0x00, 0xBD, 0x9F, 0x8C, 0x4F, 0xE1, - 0x24, 0x83, 0xC5, 0x22, 0xEA, 0xFD, 0xD3, 0x0C, 0xE2, 0x17, 0x18, 0x7C, 0x6A, 0x4C, 0xDE, 0x77, - 0xB4, 0x53, 0x9B, 0x4C, 0x81, 0xCD, 0x23, 0x60, 0xAA, 0x0E, 0x25, 0x73, 0x9C, 0x02, 0x79, 0x32, - 0x30, 0xDF, 0x74, 0xDF, 0x75, 0x19, 0xF4, 0xA5, 0x14, 0x5C, 0xF7, 0x7A, 0xA8, 0xA5, 0x91, 0x84, - 0x7C, 0x60, 0x03, 0x06, 0x3B, 0xCD, 0x50, 0xB6, 0x27, 0x9C, 0xFE, 0xB1, 0xDD, 0xCC, 0xD3, 0xB0, - 0x59, 0x24, 0xB2, 0xCA, 0xE2, 0x1C, 0x81, 0x22, 0x9D, 0x07, 0x8F, 0x8E, 0xB9, 0xBE, 0x4E, 0xFA, - 0xFC, 0x39, 0x65, 0xBA, 0xBF, 0x9D, 0x12, 0x37, 0x5E, 0x97, 0x7E, 0xF3, 0x89, 0xF5, 0x5D, 0xF5, - 0xE3, 0x09, 0x8C, 0x62, 0xB5, 0x20, 0x9D, 0x0C, 0x53, 0x8A, 0x68, 0x1B, 0xD2, 0x8F, 0x75, 0x17, - 0x5D, 0xD4, 0xE5, 0xDA, 0x75, 0x62, 0x19, 0x14, 0x6A, 0x26, 0x2D, 0xEB, 0xF8, 0xAF, 0x37, 0xF0, - 0x6C, 0xA4, 0x55, 0xB1, 0xBC, 0xE2, 0x33, 0xC0, 0x9A, 0xCA, 0xB0, 0x11, 0x49, 0x4F, 0x68, 0x9B, - 0x3B, 0x6B, 0x3C, 0xCC, 0x13, 0xF6, 0xC7, 0x85, 0x61, 0x68, 0x42, 0xAE, 0xBB, 0xDD, 0xCD, 0x45, - 0x16, 0x29, 0x1D, 0xEA, 0xDB, 0xC8, 0x03, 0x94, 0x3C, 0xEE, 0x4F, 0x82, 0x11, 0xC3, 0xEC, 0x28, - 0xBD, 0x97, 0x05, 0x99, 0xDE, 0xD7, 0xBB, 0x5E, 0x22, 0x1F, 0xD4, 0xEB, 0x64, 0xD9, 0x92, 0xD9, - 0x85, 0xB7, 0x6A, 0x05, 0x6A, 0xE4, 0x24, 0x41, 0xF1, 0xCD, 0xF0, 0xD8, 0x3F, 0xF8, 0x9E, 0x0E, - 0xCD, 0x0B, 0x7A, 0x70, 0x6B, 0x5A, 0x75, 0x0A, 0x6A, 0x33, 0x88, 0xEC, 0x17, 0x75, 0x08, 0x70, - 0x10, 0x2F, 0x24, 0xCF, 0xC4, 0xE9, 0x42, 0x00, 0x61, 0x94, 0xCA, 0x1F, 0x3A, 0x76, 0x06, 0xFA, - 0xD2, 0x48, 0x81, 0xF0, 0x77, 0x60, 0x03, 0x45, 0xD9, 0x61, 0xF4, 0xA4, 0x6F, 0x3D, 0xD9, 0x30, - 0xC3, 0x04, 0x6B, 0x54, 0x2A, 0xB7, 0xEC, 0x3B, 0xF4, 0x4B, 0xF5, 0x68, 0x52, 0x26, 0xCE, 0xFF, - 0x5D, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x23, 0xC4, 0x0A, 0x77, 0x4D, 0xF9, 0x51, - 0x20, 0xA3, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x19, 0x91, 0xA0, 0xA3, - 0xC4, 0xEB, 0x54, 0x0B, 0x75, 0x68, 0x52, 0x07, 0x8C, 0x9A, 0x97, 0x8D, 0x79, 0x70, 0x62, 0x46, - 0xEF, 0x5C, 0x1B, 0x95, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x67, 0x4C, - 0x1A, 0xB6, 0xCF, 0xFD, 0x78, 0x53, 0x24, 0xAB, 0xB5, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0x12, - 0x87, 0x6D, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6D, 0x58, 0x32, 0xC7, 0x0C, 0x9A, 0x97, 0xAC, - 0xDA, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x1D, 0xB8, 0xF2, 0x66, 0x2F, 0xBD, 0xF8, 0x72, 0x47, 0xED, - 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8C, 0x7B, 0x55, 0x09, 0x90, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8, - 0x53, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0xEC, 0x5A, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x3C, 0xFA, 0x76, - 0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x53, 0x05, 0x69, 0x31, 0xC1, 0x00, 0x82, - 0x86, 0x8E, 0x7F, 0x5D, 0x19, 0xB0, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0x8B, 0x94, 0x8B, - 0x75, 0x68, 0x33, 0xC5, 0x08, 0x92, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0x1C, 0xBA, 0xD7, 0x0D, 0x98, - 0xB2, 0xE6, 0x2F, 0xDC, 0x1B, 0x95, 0x89, 0x71, 0x60, 0x23, 0xC4, 0x0A, 0x96, 0x8F, 0x9C, 0xBA, - 0xF6, 0x6E, 0x3F, 0xFC, 0x5B, 0x15, 0xA8, 0xD2, 0x26, 0xAF, 0xBD, 0xF8, 0x72, 0x66, 0x2F, 0xDC, - 0x1B, 0xB4, 0xCB, 0x14, 0x8B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6F, - 0x3D, 0xD9, 0x30, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x70, 0x43, - 0x04, 0x6B, 0x35, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x58, - 0x32, 0xE6, 0x2F, 0xBD, 0xF8, 0x72, 0x66, 0x4E, 0x1E, 0xBE, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x1D, - 0x99, 0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x77, 0x4D, 0x18, 0x93, 0xA4, 0xAB, 0xD4, 0x0B, 0x75, 0x49, - 0x10, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8, 0x53, 0x24, 0xAB, 0xB5, 0xE8, 0x33, 0xE4, 0x4A, 0x16, 0xAE, - 0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xB3, 0xC5, 0x08, 0x73, 0x45, 0xE9, 0x31, 0xC1, 0xE1, 0x21, - 0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x86, 0x6F, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0xA4, 0xCA, 0x16, - 0xAE, 0xDE, 0x1F, 0x9D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x72, 0x47, 0x0C, 0x9A, 0xB6, - 0xCF, 0xFD, 0x59, 0x11, 0xA0, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x39, 0xF0, - 0x43, 0x04, 0x8A, 0x96, 0xAE, 0xDE, 0x3E, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xC2, 0x06, 0x6F, 0x3D, - 0xF8, 0x72, 0x47, 0x0C, 0x9A, 0x97, 0x8D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x45, 0xE9, 0x31, 0xE0, - 0x23, 0xA5, 0xA9, 0xD0, 0x03, 0x84, 0x8A, 0x96, 0xAE, 0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xD2, - 0x26, 0xCE, 0xFF, 0x5D, 0x19, 0x91, 0x81, 0x80, 0x82, 0x67, 0x2D, 0xD8, 0x13, 0xA4, 0xAB, 0xD4, - 0x0B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0xE9, 0x50, 0x22, - 0xC6, 0xEF, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x64, 0x4A, 0xF7, 0x4D, 0xF9, - 0x51, 0x20, 0xA3, 0xC4, 0x0A, 0x96, 0xAE, 0xDE, 0x3E, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x3C, 0xFA, - 0x76, 0x4F, 0xFD, 0x78, 0x72, 0x66, 0x2F, 0xBD, 0xD9, 0x30, 0xC3, 0xE5, 0x48, 0x12, 0x87, 0x8C, - 0x7B, 0x55, 0x28, 0xD2, 0x07, 0x8C, 0x9A, 0x97, 0xAC, 0xDA, 0x17, 0x8D, 0x79, 0x51, 0x20, 0xA3, - 0xC4, 0xEB, 0x54, 0x0B, 0x94, 0x8B, 0x94, 0xAA, 0xD6, 0x2E, 0xBF, 0xFC, 0x5B, 0x15, 0xA8, 0xD2, - 0x26, 0xAF, 0xDC, 0x1B, 0xB4, 0xEA, 0x37, 0xEC, 0x3B, 0xF4, 0x6A, 0x37, 0xCD, 0x18, 0x93, 0x85, - 0x69, 0x31, 0xC1, 0xE1, 0x40, 0xE3, 0x25, 0xC8, 0x12, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0xFD, 0x59, - 0x11, 0xA0, 0xC2, 0x06, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x37, 0xEC, - 0x5A, 0x36, 0xEE, 0x3F, 0xFC, 0x7A, 0x76, 0x4F, 0x1C, 0x9B, 0x95, 0x89, 0x71, 0x41, 0x00, 0x63, - 0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x0F, 0x9C, 0xBA, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x69, 0x31, 0xC1, - 0x00, 0x82, 0x86, 0x8E, 0x9E, 0xBE, 0xDF, 0x3C, 0xFA, 0x57, 0x2C, 0xDA, 0x36, 0xEE, 0x3F, 0xFC, - 0x5B, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0xED, 0x58, - 0x13, 0xA4, 0xCA, 0xF7, 0x4D, 0xF9, 0x51, 0x01, 0x80, 0x63, 0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x2E, - 0xBF, 0xDD, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x42, 0x06, 0x8E, 0x7F, 0x5D, 0x19, - 0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x96, 0x8F, 0x7D, 0x78, 0x72, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x56, - 0x2E, 0xDE, 0x1F, 0xBC, 0xFA, 0x57, 0x0D, 0x79, 0x51, 0x01, 0x61, 0x21, 0xA1, 0xC0, 0xE3, 0x25, - 0xA9, 0xB1, 0xC1, 0xE1, 0x40, 0x02, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0x93, 0xA4, 0xAB, 0xD4, - 0x2A, 0xD6, 0x0F, 0x9C, 0x9B, 0xB4, 0xCB, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xC4, - 0xEB, 0x35, 0xC9, 0xF1, 0x60, 0x42, 0x06, 0x8E, 0x7F, 0x7C, 0x7A, 0x76, 0x6E, 0x3F, 0xFC, 0x7A, - 0x76, 0x6E, 0x5E, 0x3E, 0xFE, 0x7E, 0x5F, 0x3C, 0xDB, 0x15, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xC0, - 0xE3, 0x44, 0xEB, 0x54, 0x2A, 0xB7, 0xCD, 0xF9, 0x70, 0x62, 0x27, 0xAD, 0xD8, 0x32, 0xC7, 0x0C, - 0x7B, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xEC, 0x3B, 0xD5, 0x28, 0xD2, 0x07, 0x6D, 0x39, 0xD1, 0x20, - 0xC2, 0xE7, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0xB2, 0xC7, 0x0C, 0x59, 0x28, 0xF3, 0x9B -}; diff --git a/drivers/sensors/pmw3389.c b/drivers/sensors/pmw3389.c index 828dafa134..cba94d6c65 100644 --- a/drivers/sensors/pmw3389.c +++ b/drivers/sensors/pmw3389.c @@ -1,294 +1,314 @@ -/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2019 Sunjun Kim - * Copyright 2020 Ploopy Corporation - * - * 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 . - */ +// Copyright 2022 Stefan Kerkmann (KarlK90) +// Copyright 2021 Alabastard (@Alabastard-64) +// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) +// Copyright 2019 Sunjun Kim +// Copyright 2020 Ploopy Corporation +// SPDX-License-Identifier: GPL-2.0-or-later -#include "spi_master.h" -#include "pmw3389.h" -#include "wait.h" -#include "debug.h" -#include "print.h" -#include "pmw3389_firmware.h" +#include "pmw33xx_common.h" +#include "progmem.h" -// Registers -// clang-format off -#define REG_Product_ID 0x00 -#define REG_Revision_ID 0x01 -#define REG_Motion 0x02 -#define REG_Delta_X_L 0x03 -#define REG_Delta_X_H 0x04 -#define REG_Delta_Y_L 0x05 -#define REG_Delta_Y_H 0x06 -#define REG_SQUAL 0x07 -#define REG_RawData_Sum 0x08 -#define REG_Maximum_RawData 0x09 -#define REG_Minimum_RawData 0x0a -#define REG_Shutter_Lower 0x0b -#define REG_Shutter_Upper 0x0c -#define REG_Ripple_Control 0x0d -#define REG_Resolution_L 0x0e -#define REG_Resolution_H 0x0f -#define REG_Config2 0x10 -#define REG_Angle_Tune 0x11 -#define REG_Frame_Capture 0x12 -#define REG_SROM_Enable 0x13 -#define REG_Run_Downshift 0x14 -#define REG_Rest1_Rate_Lower 0x15 -#define REG_Rest1_Rate_Upper 0x16 -#define REG_Rest1_Downshift 0x17 -#define REG_Rest2_Rate_Lower 0x18 -#define REG_Rest2_Rate_Upper 0x19 -#define REG_Rest2_Downshift 0x1a -#define REG_Rest3_Rate_Lower 0x1b -#define REG_Rest3_Rate_Upper 0x1c -#define REG_Observation 0x24 -#define REG_Data_Out_Lower 0x25 -#define REG_Data_Out_Upper 0x26 -#define REG_SROM_ID 0x2a -#define REG_Min_SQ_Run 0x2b -#define REG_RawData_Threshold 0x2c -#define REG_Control2 0x2d -#define REG_Config5_L 0x2e -#define REG_Config5_H 0x2f -#define REG_Power_Up_Reset 0X3a -#define REG_Shutdown 0x3b -#define REG_Inverse_Product_ID 0x3f -#define REG_LiftCutoff_Cal3 0x41 -#define REG_Angle_Snap 0x42 -#define REG_LiftCutoff_Cal1 0x4a -#define REG_Motion_Burst 0x50 -#define REG_SROM_Load_Burst 0x62 -#define REG_Lift_Config 0x63 -#define REG_RawData_Burst 0x64 -#define REG_LiftCutoff_Cal2 0x65 -#define REG_LiftCutoff_Cal_Timeout 0x71 -#define REG_LiftCutoff_Cal_Min_Length 0x72 -#define REG_PWM_Period_Cnt 0x73 -#define REG_PWM_Width_Cnt 0x74 - -#define CPI_STEP 50 -// clang-format on - -// limits to 0--319, resulting in a CPI range of 50 -- 16000 (as only steps of 50 are possible). -#ifndef MAX_CPI -# define MAX_CPI 0x013f -#endif - -bool _inBurst = false; - -#ifdef CONSOLE_ENABLE -void print_byte(uint8_t byte) { - dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); -} -#endif -#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) - -bool pmw3389_spi_start(void) { - bool status = spi_start(PMW3389_CS_PIN, PMW3389_SPI_LSBFIRST, PMW3389_SPI_MODE, PMW3389_SPI_DIVISOR); - // tNCS-SCLK, 120ns - wait_us(1); - return status; -} - -spi_status_t pmw3389_write(uint8_t reg_addr, uint8_t data) { - pmw3389_spi_start(); - - if (reg_addr != REG_Motion_Burst) { - _inBurst = false; - } - - // send address of the register, with MSBit = 1 to indicate it's a write - spi_status_t status = spi_write(reg_addr | 0x80); - status = spi_write(data); - - // tSCLK-NCS for write operation is 35 us - wait_us(35); - spi_stop(); - - // tSWW/tSWR (=180us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound - wait_us(145); - return status; -} - -uint8_t pmw3389_read(uint8_t reg_addr) { - pmw3389_spi_start(); - // send adress of the register, with MSBit = 0 to indicate it's a read - spi_write(reg_addr & 0x7f); - // tSRAD (=160us) - wait_us(160); - uint8_t data = spi_read(); - - // tSCLK-NCS, 120ns - wait_us(1); - spi_stop(); - - // tSRW/tSRR (=20us) minus tSCLK-NCS - wait_us(19); - return data; -} - -bool pmw3389_init(void) { - setPinOutput(PMW3389_CS_PIN); - - spi_init(); - _inBurst = false; - - spi_stop(); - pmw3389_spi_start(); - spi_stop(); - - pmw3389_write(REG_Shutdown, 0xb6); // Shutdown first - wait_ms(300); - - pmw3389_spi_start(); - wait_us(40); - spi_stop(); - wait_us(40); - - // power up, need to first drive NCS high then low, see above. - pmw3389_write(REG_Power_Up_Reset, 0x5a); - wait_ms(50); - - // read registers and discard - pmw3389_read(REG_Motion); - pmw3389_read(REG_Delta_X_L); - pmw3389_read(REG_Delta_X_H); - pmw3389_read(REG_Delta_Y_L); - pmw3389_read(REG_Delta_Y_H); - - pmw3389_upload_firmware(); - - spi_stop(); +extern const size_t pmw33xx_number_of_sensors; - wait_ms(10); - pmw3389_set_cpi(PMW3389_CPI); - - wait_ms(1); - - pmw3389_write(REG_Config2, 0x00); - - pmw3389_write(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -127, 127)); - - pmw3389_write(REG_Lift_Config, PMW3389_LIFTOFF_DISTANCE); - - bool init_success = pmw3389_check_signature(); -#ifdef CONSOLE_ENABLE - if (init_success) { - dprintf("pmw3389 signature verified"); - } else { - dprintf("pmw3389 signature verification failed!"); +uint16_t pmw33xx_get_cpi(uint8_t sensor) { + if (sensor >= pmw33xx_number_of_sensors) { + return 0; } -#endif - - writePinLow(PMW3389_CS_PIN); - return init_success; + uint16_t cpival = (pmw33xx_read(sensor, REG_Resolution_H) << 8) | pmw33xx_read(sensor, REG_Resolution_L); + return (uint16_t)((cpival + 1) & 0xFFFF) * PMW33XX_CPI_STEP; } -void pmw3389_upload_firmware(void) { - // Datasheet claims we need to disable REST mode first, but during startup - // it's already disabled and we're not turning it on ... - // pmw3389_write(REG_Config2, 0x00); // disable REST mode - pmw3389_write(REG_SROM_Enable, 0x1d); - - wait_ms(10); - - pmw3389_write(REG_SROM_Enable, 0x18); - - pmw3389_spi_start(); - spi_write(REG_SROM_Load_Burst | 0x80); - wait_us(15); - - for (uint16_t i = 0; i < FIRMWARE_LENGTH; i++) { - spi_write(pgm_read_byte(firmware_data + i)); -#ifndef PMW3389_FIRMWARE_UPLOAD_FAST - wait_us(15); -#endif +void pmw33xx_set_cpi(uint8_t sensor, uint16_t cpi) { + if (sensor >= pmw33xx_number_of_sensors) { + return; } - wait_us(200); - - pmw3389_read(REG_SROM_ID); - pmw3389_write(REG_Config2, 0x00); -} - -bool pmw3389_check_signature(void) { - uint8_t pid = pmw3389_read(REG_Product_ID); - uint8_t iv_pid = pmw3389_read(REG_Inverse_Product_ID); - uint8_t SROM_ver = pmw3389_read(REG_SROM_ID); - return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04 -} -uint16_t pmw3389_get_cpi(void) { - uint16_t cpival = (pmw3389_read(REG_Resolution_H) << 8) | pmw3389_read(REG_Resolution_L); - return (uint16_t)((cpival + 1) & 0xffff) * CPI_STEP; -} - -void pmw3389_set_cpi(uint16_t cpi) { - uint16_t cpival = constrain((cpi / CPI_STEP) - 1, 0, MAX_CPI); + uint16_t cpival = CONSTRAIN((cpi / PMW33XX_CPI_STEP) - 1, 0, (PMW33XX_CPI_MAX / PMW33XX_CPI_STEP) - 1U); // Sets upper byte first for more consistent setting of cpi - pmw3389_write(REG_Resolution_H, (cpival >> 8) & 0xff); - pmw3389_write(REG_Resolution_L, cpival & 0xff); + pmw33xx_write(sensor, REG_Resolution_H, (cpival >> 8) & 0xFF); + pmw33xx_write(sensor, REG_Resolution_L, cpival & 0xFF); } -report_pmw3389_t pmw3389_read_burst(void) { - report_pmw3389_t report = {0}; - - if (!_inBurst) { -#ifdef CONSOLE_ENABLE - dprintf("burst on"); -#endif - pmw3389_write(REG_Motion_Burst, 0x00); - _inBurst = true; - } - - pmw3389_spi_start(); - spi_write(REG_Motion_Burst); - wait_us(35); // waits for tSRAD_MOTBR - - report.motion = spi_read(); - spi_read(); // skip Observation - // delta registers - report.dx = spi_read(); - report.mdx = spi_read(); - report.dy = spi_read(); - report.mdy = spi_read(); - - if (report.motion & 0b111) { // panic recovery, sometimes burst mode works weird. - _inBurst = false; - } - - spi_stop(); - -#ifdef CONSOLE_ENABLE - if (debug_mouse) { - print_byte(report.motion); - print_byte(report.dx); - print_byte(report.mdx); - print_byte(report.dy); - print_byte(report.mdy); - dprintf("\n"); - } -#endif +// PID, Inverse PID, SROM version +const uint8_t pmw33xx_firmware_signature[3] PROGMEM = {0x42, 0xBD, 0x04}; - report.isMotion = (report.motion & 0x80) != 0; - report.isOnSurface = (report.motion & 0x08) == 0; - report.dx |= (report.mdx << 8); - report.dx = report.dx * -1; - report.dy |= (report.mdy << 8); - report.dy = report.dy * -1; +// Firmware Blob for PMW3389 +// clang-format off +const uint8_t pmw33xx_firmware_data[PMW33XX_FIRMWARE_LENGTH] PROGMEM = { + 0x01, 0xe8, 0xba, 0x26, 0x0b, 0xb2, 0xbe, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0xa8, 0xb3, + 0xe4, 0x2b, 0xb5, 0xe8, 0x53, 0x07, 0x6d, 0x3b, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, 0xd9, + 0x11, 0xa0, 0xc2, 0xe7, 0x2d, 0xb9, 0xd1, 0x20, 0xa3, 0xa5, 0xc8, 0xf3, 0x64, 0x4a, 0xf7, + 0x4d, 0x18, 0x93, 0xa4, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xfe, 0x7e, 0x7e, + 0x5f, 0x1d, 0x99, 0xb0, 0xc3, 0xe5, 0x29, 0xd3, 0x03, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x58, + 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xf2, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xc0, 0x02, + 0x86, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xb3, 0xe4, 0x4a, 0x16, + 0xab, 0xbf, 0xdd, 0x38, 0xf2, 0x66, 0x4e, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xc8, + 0x12, 0xa6, 0xaf, 0xdc, 0x3a, 0xd1, 0x41, 0x60, 0x75, 0x58, 0x24, 0x92, 0xd4, 0x72, 0x6c, + 0xe0, 0x2f, 0xfd, 0x23, 0x8d, 0x1c, 0x5b, 0xb2, 0x97, 0x36, 0x3d, 0x0b, 0xa2, 0x49, 0xb1, + 0x58, 0xf2, 0x1f, 0xc0, 0xcb, 0xf8, 0x41, 0x4f, 0xcd, 0x1e, 0x6b, 0x39, 0xa7, 0x2b, 0xe9, + 0x30, 0x16, 0x83, 0xd2, 0x0e, 0x47, 0x8f, 0xe3, 0xb1, 0xdf, 0xa2, 0x15, 0xdb, 0x5d, 0x30, + 0xc5, 0x1a, 0xab, 0x31, 0x99, 0xf3, 0xfa, 0xb2, 0x86, 0x69, 0xad, 0x7a, 0xe8, 0xa7, 0x18, + 0x6a, 0xcc, 0xc8, 0x65, 0x23, 0x87, 0xa8, 0x5f, 0xf5, 0x21, 0x59, 0x75, 0x09, 0x71, 0x45, + 0x55, 0x25, 0x4b, 0xda, 0xa1, 0xc3, 0xf7, 0x41, 0xab, 0x59, 0xd9, 0x74, 0x12, 0x55, 0x5f, + 0xbc, 0xaf, 0xd9, 0xfd, 0xb0, 0x1e, 0xa3, 0x0f, 0xff, 0xde, 0x11, 0x16, 0x6a, 0xae, 0x0e, + 0xe1, 0x5d, 0x3c, 0x10, 0x43, 0x9a, 0xa1, 0x0b, 0x24, 0x8f, 0x0d, 0x7f, 0x0b, 0x5e, 0x4c, + 0x42, 0xa4, 0x84, 0x2c, 0x40, 0xd0, 0x55, 0x39, 0xe6, 0x4b, 0xf8, 0x9b, 0x2f, 0xdc, 0x28, + 0xff, 0xfa, 0xb5, 0x85, 0x19, 0xe5, 0x28, 0xa1, 0x77, 0xaa, 0x73, 0xf3, 0x03, 0xc7, 0x62, + 0xa6, 0x91, 0x18, 0xc9, 0xb0, 0xcd, 0x05, 0xdc, 0xca, 0x81, 0x26, 0x1a, 0x47, 0x40, 0xda, + 0x36, 0x7d, 0x6a, 0x53, 0xc8, 0x5a, 0x77, 0x5d, 0x19, 0xa4, 0x1b, 0x23, 0x83, 0xd0, 0xb2, + 0xaa, 0x0e, 0xbf, 0x77, 0x4e, 0x3a, 0x3b, 0x59, 0x00, 0x31, 0x0d, 0x02, 0x1b, 0x88, 0x7a, + 0xd4, 0xbd, 0x9d, 0xcc, 0x58, 0x04, 0x69, 0xf6, 0x3b, 0xca, 0x42, 0xe2, 0xfd, 0xc3, 0x3d, + 0x39, 0xc5, 0xd0, 0x71, 0xe4, 0xc8, 0xb7, 0x3e, 0x3f, 0xc8, 0xe9, 0xca, 0xc9, 0x3f, 0x04, + 0x4e, 0x1b, 0x79, 0xca, 0xa5, 0x61, 0xc2, 0xed, 0x1d, 0xa6, 0xda, 0x5a, 0xe9, 0x7f, 0x65, + 0x8c, 0xbe, 0x12, 0x6e, 0xa4, 0x5b, 0x33, 0x2f, 0x84, 0x28, 0x9c, 0x1c, 0x88, 0x2d, 0xff, + 0x07, 0xbf, 0xa6, 0xd7, 0x5a, 0x88, 0x86, 0xb0, 0x3f, 0xf6, 0x31, 0x5b, 0x11, 0x6d, 0xf5, + 0x58, 0xeb, 0x58, 0x02, 0x9e, 0xb5, 0x9a, 0xb1, 0xff, 0x25, 0x9d, 0x8b, 0x4f, 0xb6, 0x0a, + 0xf9, 0xea, 0x3e, 0x3f, 0x21, 0x09, 0x65, 0x21, 0x22, 0xfe, 0x3d, 0x4e, 0x11, 0x5b, 0x9e, + 0x5a, 0x59, 0x8b, 0xdd, 0xd8, 0xce, 0xd6, 0xd9, 0x59, 0xd2, 0x1e, 0xfd, 0xef, 0x0d, 0x1b, + 0xd9, 0x61, 0x7f, 0xd7, 0x2d, 0xad, 0x62, 0x09, 0xe5, 0x22, 0x63, 0xea, 0xc7, 0x31, 0xd9, + 0xa1, 0x38, 0x80, 0x5c, 0xa7, 0x32, 0x82, 0xec, 0x1b, 0xa2, 0x49, 0x5a, 0x06, 0xd2, 0x7c, + 0xc9, 0x96, 0x57, 0xbb, 0x17, 0x75, 0xfc, 0x7a, 0x8f, 0x0d, 0x77, 0xb5, 0x7a, 0x8e, 0x3e, + 0xf4, 0xba, 0x2f, 0x69, 0x13, 0x26, 0xd6, 0xd9, 0x21, 0x60, 0x2f, 0x21, 0x3e, 0x87, 0xee, + 0xfd, 0x87, 0x16, 0x0d, 0xc8, 0x08, 0x00, 0x25, 0x71, 0xac, 0x2c, 0x03, 0x2a, 0x37, 0x2d, + 0xb3, 0x34, 0x09, 0x91, 0xe3, 0x06, 0x2c, 0x38, 0x37, 0x95, 0x3b, 0x17, 0x7a, 0xaf, 0xac, + 0x99, 0x55, 0xab, 0x41, 0x39, 0x5f, 0x8e, 0xa6, 0x43, 0x80, 0x03, 0x88, 0x6f, 0x7d, 0xbd, + 0x5a, 0xb4, 0x2b, 0x32, 0x23, 0x5a, 0xa9, 0x31, 0x32, 0x39, 0x4c, 0x5b, 0xf4, 0x6b, 0xaf, + 0x66, 0x6f, 0x3c, 0x8e, 0x2d, 0x82, 0x97, 0x9f, 0x4a, 0x01, 0xdc, 0x99, 0x98, 0x00, 0xec, + 0x38, 0x7a, 0x79, 0x70, 0xa6, 0x85, 0xd6, 0x21, 0x63, 0x0d, 0x45, 0x9a, 0x2e, 0x5e, 0xa7, + 0xb1, 0xea, 0x66, 0x6a, 0xbc, 0x62, 0x2d, 0x7b, 0x7d, 0x85, 0xea, 0x95, 0x2f, 0xc0, 0xe8, + 0x6f, 0x35, 0xa0, 0x3a, 0x02, 0x25, 0xbc, 0xb2, 0x5f, 0x5c, 0x43, 0x96, 0xcc, 0x26, 0xd2, + 0x16, 0xb4, 0x96, 0x73, 0xd7, 0x13, 0xc7, 0xae, 0x53, 0x15, 0x31, 0x89, 0x68, 0x66, 0x6d, + 0x2c, 0x92, 0x1f, 0xcc, 0x5b, 0xa7, 0x8f, 0x5d, 0xbb, 0xc9, 0xdb, 0xe8, 0x3b, 0x9d, 0x61, + 0x74, 0x8b, 0x05, 0xa1, 0x58, 0x52, 0x68, 0xee, 0x3d, 0x39, 0x79, 0xa0, 0x9b, 0xdd, 0xe1, + 0x55, 0xc9, 0x60, 0xeb, 0xad, 0xb8, 0x5b, 0xc2, 0x5a, 0xb5, 0x2c, 0x18, 0x55, 0xa9, 0x50, + 0xc3, 0xf6, 0x72, 0x5f, 0xcc, 0xe2, 0xf4, 0x55, 0xb5, 0xd6, 0xb5, 0x4a, 0x99, 0xa5, 0x28, + 0x74, 0x97, 0x18, 0xe8, 0xc0, 0x84, 0x89, 0x50, 0x03, 0x86, 0x4d, 0x1a, 0xb7, 0x09, 0x90, + 0xa2, 0x01, 0x04, 0xbb, 0x73, 0x62, 0xcb, 0x97, 0x22, 0x70, 0x5d, 0x52, 0x41, 0x8e, 0xd9, + 0x90, 0x15, 0xaa, 0xab, 0x0a, 0x31, 0x65, 0xb4, 0xda, 0xd0, 0xee, 0x24, 0xc9, 0x41, 0x91, + 0x1e, 0xbc, 0x46, 0x70, 0x40, 0x9d, 0xda, 0x0e, 0x2a, 0xe4, 0xb2, 0x4c, 0x9f, 0xf2, 0xfc, + 0xf3, 0x84, 0x17, 0x44, 0x1e, 0xd7, 0xca, 0x23, 0x1f, 0x3f, 0x5a, 0x22, 0x3d, 0xaf, 0x9b, + 0x2d, 0xfc, 0x41, 0xad, 0x26, 0xb4, 0x45, 0x67, 0x0b, 0x80, 0x0e, 0xf9, 0x61, 0x37, 0xec, + 0x3b, 0xf4, 0x4b, 0x14, 0xdf, 0x5a, 0x0c, 0x3a, 0x50, 0x0b, 0x14, 0x0c, 0x72, 0xae, 0xc6, + 0xc5, 0xec, 0x35, 0x53, 0x2d, 0x59, 0xed, 0x91, 0x74, 0xe2, 0xc4, 0xc8, 0xf2, 0x25, 0x6b, + 0x97, 0x6f, 0xc9, 0x76, 0xce, 0xa9, 0xb1, 0x99, 0x8f, 0x5a, 0x92, 0x3b, 0xc4, 0x8d, 0x54, + 0x50, 0x40, 0x72, 0xd6, 0x90, 0x83, 0xfc, 0xe5, 0x49, 0x8b, 0x17, 0xf5, 0xfd, 0x6b, 0x8d, + 0x32, 0x02, 0xe9, 0x0a, 0xfe, 0xbf, 0x00, 0x6b, 0xa3, 0xad, 0x5f, 0x09, 0x4b, 0x97, 0x2b, + 0x00, 0x58, 0x65, 0x2e, 0x07, 0x49, 0x0a, 0x3b, 0x6b, 0x2e, 0x50, 0x6c, 0x1d, 0xac, 0xb7, + 0x6a, 0x26, 0xd8, 0x13, 0xa4, 0xca, 0x16, 0xae, 0xab, 0x93, 0xb9, 0x1c, 0x1c, 0xb4, 0x47, + 0x6a, 0x38, 0x36, 0x17, 0x27, 0xc9, 0x7f, 0xc7, 0x64, 0xcb, 0x89, 0x58, 0xc5, 0x61, 0xc2, + 0xc6, 0xea, 0x15, 0x0b, 0x34, 0x0c, 0x5d, 0x61, 0x76, 0x6e, 0x2b, 0x62, 0x40, 0x92, 0xa3, + 0x6c, 0xef, 0xf4, 0xe4, 0xc3, 0xa1, 0xa8, 0xf5, 0x94, 0x79, 0x0d, 0xd1, 0x3d, 0xcb, 0x3d, + 0x40, 0xb6, 0xd0, 0xf0, 0x10, 0x54, 0xd8, 0x47, 0x25, 0x51, 0xc5, 0x41, 0x79, 0x00, 0xe5, + 0xa0, 0x72, 0xde, 0xbb, 0x3b, 0x62, 0x17, 0xf6, 0xbc, 0x5d, 0x00, 0x76, 0x2e, 0xa7, 0x3b, + 0xb6, 0xf1, 0x98, 0x72, 0x59, 0x2a, 0x73, 0xb0, 0x21, 0xd6, 0x49, 0xe0, 0xc0, 0xd5, 0xeb, + 0x02, 0x7d, 0x4b, 0x41, 0x28, 0x70, 0x2d, 0xec, 0x2b, 0x71, 0x1f, 0x0b, 0xb9, 0x71, 0x63, + 0x06, 0xe6, 0xbc, 0x60, 0xbb, 0xf4, 0x9a, 0x62, 0x43, 0x09, 0x18, 0x4e, 0x93, 0x06, 0x4d, + 0x76, 0xfa, 0x7f, 0xbd, 0x02, 0xe4, 0x50, 0x91, 0x12, 0xe5, 0x86, 0xff, 0x64, 0x1e, 0xaf, + 0x7e, 0xb3, 0xb2, 0xde, 0x89, 0xc1, 0xa2, 0x6f, 0x40, 0x7b, 0x41, 0x51, 0x63, 0xea, 0x25, + 0xd1, 0x97, 0x57, 0x92, 0xa8, 0x45, 0xa1, 0xa5, 0x45, 0x21, 0x43, 0x7f, 0x83, 0x15, 0x29, + 0xd0, 0x30, 0x53, 0x32, 0xb4, 0x5a, 0x17, 0x96, 0xbc, 0xc2, 0x68, 0xa9, 0xb7, 0xaf, 0xac, + 0xdf, 0xf1, 0xe3, 0x89, 0xba, 0x24, 0x79, 0x54, 0xc6, 0x14, 0x07, 0x1c, 0x1e, 0x0d, 0x3a, + 0x6b, 0xe5, 0x3d, 0x4e, 0x10, 0x60, 0x96, 0xec, 0x6c, 0xda, 0x47, 0xae, 0x03, 0x25, 0x39, + 0x1d, 0x74, 0xc8, 0xac, 0x6a, 0xf2, 0x6b, 0x05, 0x2a, 0x9a, 0xe7, 0xe8, 0x92, 0xd6, 0xc2, + 0x6d, 0xfa, 0xe8, 0xa7, 0x9d, 0x5f, 0x48, 0xc9, 0x75, 0xf1, 0x66, 0x6a, 0xdb, 0x5d, 0x9a, + 0xcd, 0x27, 0xdd, 0xb9, 0x24, 0x04, 0x9c, 0x18, 0xc2, 0x6d, 0x0c, 0x91, 0x34, 0x48, 0x42, + 0x6f, 0xe9, 0x59, 0x70, 0xc4, 0x7e, 0x81, 0x0e, 0x32, 0x0a, 0x93, 0x48, 0xb0, 0xc0, 0x15, + 0x9e, 0x05, 0xac, 0x36, 0x16, 0xcb, 0x59, 0x65, 0xa0, 0x83, 0xdf, 0x3e, 0xda, 0xfb, 0x1d, + 0x1a, 0xdb, 0x65, 0xec, 0x9a, 0xc6, 0xc3, 0x8e, 0x3c, 0x45, 0xfd, 0xc8, 0xf5, 0x1c, 0x6a, + 0x67, 0x0d, 0x8f, 0x99, 0x7d, 0x30, 0x21, 0x8c, 0xea, 0x22, 0x87, 0x65, 0xc9, 0xb2, 0x4c, + 0xe4, 0x1b, 0x46, 0xba, 0x54, 0xbd, 0x7c, 0xca, 0xd5, 0x8f, 0x5b, 0xa5, 0x01, 0x04, 0xd8, + 0x0a, 0x16, 0xbf, 0xb9, 0x50, 0x2e, 0x37, 0x2f, 0x64, 0xf3, 0x70, 0x11, 0x02, 0x05, 0x31, + 0x9b, 0xa0, 0xb2, 0x01, 0x5e, 0x4f, 0x19, 0xc9, 0xd4, 0xea, 0xa1, 0x79, 0x54, 0x53, 0xa7, + 0xde, 0x2f, 0x49, 0xd3, 0xd1, 0x63, 0xb5, 0x03, 0x15, 0x4e, 0xbf, 0x04, 0xb3, 0x26, 0x8b, + 0x20, 0xb2, 0x45, 0xcf, 0xcd, 0x5b, 0x82, 0x32, 0x88, 0x61, 0xa7, 0xa8, 0xb2, 0xa0, 0x72, + 0x96, 0xc0, 0xdb, 0x2b, 0xe2, 0x5f, 0xba, 0xe3, 0xf5, 0x8a, 0xde, 0xf1, 0x18, 0x01, 0x16, + 0x40, 0xd9, 0x86, 0x12, 0x09, 0x18, 0x1b, 0x05, 0x0c, 0xb1, 0xb5, 0x47, 0xe2, 0x43, 0xab, + 0xfe, 0x92, 0x63, 0x7e, 0x95, 0x2b, 0xf0, 0xaf, 0xe1, 0xf1, 0xc3, 0x4a, 0xff, 0x2b, 0x09, + 0xbb, 0x4a, 0x0e, 0x9a, 0xc4, 0xd8, 0x64, 0x7d, 0x83, 0xa0, 0x4f, 0x44, 0xdb, 0xc4, 0xa8, + 0x58, 0xef, 0xfc, 0x9e, 0x77, 0xf9, 0xa6, 0x8f, 0x58, 0x8b, 0x12, 0xf4, 0xe9, 0x81, 0x12, + 0x47, 0x51, 0x41, 0x83, 0xef, 0xf6, 0x73, 0xbc, 0x8e, 0x0f, 0x4c, 0x8f, 0x4e, 0x69, 0x90, + 0x77, 0x29, 0x5d, 0x92, 0xb0, 0x6d, 0x06, 0x67, 0x29, 0x60, 0xbd, 0x4b, 0x17, 0xc8, 0x89, + 0x69, 0x28, 0x29, 0xd6, 0x78, 0xcb, 0x11, 0x4c, 0xba, 0x8b, 0x68, 0xae, 0x7e, 0x9f, 0xef, + 0x95, 0xda, 0xe2, 0x9e, 0x7f, 0xe9, 0x55, 0xe5, 0xe1, 0xe2, 0xb7, 0xe6, 0x5f, 0xbb, 0x2c, + 0xa2, 0xe6, 0xee, 0xc7, 0x0a, 0x60, 0xa9, 0xd1, 0x80, 0xdf, 0x7f, 0xd6, 0x97, 0xab, 0x1d, + 0x22, 0x25, 0xfc, 0x79, 0x23, 0xe0, 0xae, 0xc5, 0xef, 0x16, 0xa4, 0xa1, 0x0f, 0x92, 0xa9, + 0xc7, 0xe3, 0x3a, 0x55, 0xdf, 0x62, 0x49, 0xd9, 0xf5, 0x84, 0x49, 0xc5, 0x90, 0x34, 0xd3, + 0xe1, 0xac, 0x99, 0x21, 0xb1, 0x02, 0x76, 0x4a, 0xfa, 0xd4, 0xbb, 0xa4, 0x9c, 0xa2, 0xe2, + 0xcb, 0x3d, 0x3b, 0x14, 0x75, 0x60, 0xd1, 0x02, 0xb4, 0xa3, 0xb4, 0x72, 0x06, 0xf9, 0x19, + 0x9c, 0xe2, 0xe4, 0xa7, 0x0f, 0x25, 0x88, 0xc6, 0x86, 0xd6, 0x8c, 0x74, 0x4e, 0x6e, 0xfc, + 0xa8, 0x48, 0x9e, 0xa7, 0x9d, 0x1a, 0x4b, 0x37, 0x09, 0xc8, 0xb0, 0x10, 0xbe, 0x6f, 0xfe, + 0xa3, 0xc4, 0x7a, 0xb5, 0x3d, 0xe8, 0x30, 0xf1, 0x0d, 0xa0, 0xb2, 0x44, 0xfc, 0x9b, 0x8c, + 0xf8, 0x61, 0xed, 0x81, 0xd1, 0x62, 0x11, 0xb4, 0xe1, 0xd5, 0x39, 0x52, 0x89, 0xd3, 0xa8, + 0x49, 0x31, 0xdf, 0xb6, 0xf9, 0x91, 0xf4, 0x1c, 0x9d, 0x09, 0x95, 0x40, 0x56, 0xe7, 0xe3, + 0xcd, 0x5c, 0x92, 0xc1, 0x1d, 0x6b, 0xe9, 0x78, 0x6f, 0x8e, 0x94, 0x42, 0x66, 0xa2, 0xaa, + 0xd3, 0xc8, 0x2e, 0xe3, 0xf6, 0x07, 0x72, 0x0b, 0x6b, 0x1e, 0x7b, 0xb9, 0x7c, 0xe0, 0xa0, + 0xbc, 0xd9, 0x25, 0xdf, 0x87, 0xa8, 0x5f, 0x9c, 0xcc, 0xf0, 0xdb, 0x42, 0x8e, 0x07, 0x31, + 0x13, 0x01, 0x66, 0x32, 0xd1, 0xb8, 0xd6, 0xe3, 0x5e, 0x12, 0x76, 0x61, 0xd3, 0x38, 0x89, + 0xe6, 0x17, 0x6f, 0xa5, 0xf2, 0x71, 0x0e, 0xa5, 0xe2, 0x88, 0x30, 0xbb, 0xbe, 0x8a, 0xea, + 0xc7, 0x62, 0xc4, 0xcf, 0xb8, 0xcd, 0x33, 0x8d, 0x3d, 0x3e, 0xb5, 0x60, 0x3a, 0x03, 0x92, + 0xe4, 0x6d, 0x1b, 0xe0, 0xb4, 0x84, 0x08, 0x55, 0x88, 0xa7, 0x3a, 0xb9, 0x3d, 0x43, 0xc3, + 0xc0, 0xfa, 0x07, 0x6a, 0xca, 0x94, 0xad, 0x99, 0x55, 0xf1, 0xf1, 0xc0, 0x23, 0x87, 0x1d, + 0x3d, 0x1c, 0xd1, 0x66, 0xa0, 0x57, 0x10, 0x52, 0xa2, 0x7f, 0xbe, 0xf9, 0x88, 0xb6, 0x02, + 0xbf, 0x08, 0x23, 0xa9, 0x0c, 0x63, 0x17, 0x2a, 0xae, 0xf5, 0xf7, 0xb7, 0x21, 0x83, 0x92, + 0x31, 0x23, 0x0d, 0x20, 0xc3, 0xc2, 0x05, 0x21, 0x62, 0x8e, 0x45, 0xe8, 0x14, 0xc1, 0xda, + 0x75, 0xb8, 0xf8, 0x92, 0x01, 0xd0, 0x5d, 0x18, 0x9f, 0x99, 0x11, 0x19, 0xf5, 0x35, 0xe8, + 0x7f, 0x20, 0x88, 0x8c, 0x05, 0x75, 0xf5, 0xd7, 0x40, 0x17, 0xbb, 0x1e, 0x36, 0x52, 0xd9, + 0xa4, 0x9c, 0xc2, 0x9d, 0x42, 0x81, 0xd8, 0xc7, 0x8a, 0xe7, 0x4c, 0x81, 0xe0, 0xb7, 0x57, + 0xed, 0x48, 0x8b, 0xf0, 0x97, 0x15, 0x61, 0xd9, 0x2c, 0x7c, 0x45, 0xaf, 0xc2, 0xcd, 0xfc, + 0xaa, 0x13, 0xad, 0x59, 0xcc, 0xb2, 0xb2, 0x6e, 0xdd, 0x63, 0x9c, 0x32, 0x0f, 0xec, 0x83, + 0xbe, 0x78, 0xac, 0x91, 0x44, 0x1a, 0x1f, 0xea, 0xfd, 0x5d, 0x8e, 0xb4, 0xc0, 0x84, 0xd4, + 0xac, 0xb4, 0x87, 0x5f, 0xac, 0xef, 0xdf, 0xcd, 0x12, 0x56, 0xc8, 0xcd, 0xfe, 0xc5, 0xda, + 0xd3, 0xc1, 0x69, 0xf3, 0x61, 0x05, 0xea, 0x25, 0xe2, 0x12, 0x05, 0x8f, 0x39, 0x08, 0x08, + 0x7c, 0x37, 0xb6, 0x7e, 0x5b, 0xd8, 0xb1, 0x0e, 0xf2, 0xdb, 0x4b, 0xf1, 0xad, 0x90, 0x01, + 0x57, 0xcd, 0xa0, 0xb4, 0x52, 0xe8, 0xf3, 0xd7, 0x8a, 0xbd, 0x4f, 0x9f, 0x21, 0x40, 0x72, + 0xa4, 0xfc, 0x0b, 0x01, 0x2b, 0x2f, 0xb6, 0x4c, 0x95, 0x2d, 0x35, 0x33, 0x41, 0x6b, 0xa0, + 0x93, 0xe7, 0x2c, 0xf2, 0xd3, 0x72, 0x8b, 0xf4, 0x4f, 0x15, 0x3c, 0xaf, 0xd6, 0x12, 0xde, + 0x3f, 0x83, 0x3f, 0xff, 0xf8, 0x7f, 0xf6, 0xcc, 0xa6, 0x7f, 0xc9, 0x9a, 0x6e, 0x1f, 0xc1, + 0x0c, 0xfb, 0xee, 0x9c, 0xe7, 0xaf, 0xc9, 0x26, 0x54, 0xef, 0xb0, 0x39, 0xef, 0xb2, 0xe9, + 0x23, 0xc4, 0xef, 0xd1, 0xa1, 0xa4, 0x25, 0x24, 0x6f, 0x8d, 0x6a, 0xe5, 0x8a, 0x32, 0x3a, + 0xaf, 0xfc, 0xda, 0xce, 0x18, 0x25, 0x42, 0x07, 0x4d, 0x45, 0x8b, 0xdf, 0x85, 0xcf, 0x55, + 0xb2, 0x24, 0xfe, 0x9c, 0x69, 0x74, 0xa7, 0x6e, 0xa0, 0xce, 0xc0, 0x39, 0xf4, 0x86, 0xc6, + 0x8d, 0xae, 0xb9, 0x48, 0x64, 0x13, 0x0b, 0x40, 0x81, 0xa2, 0xc9, 0xa8, 0x85, 0x51, 0xee, + 0x9f, 0xcf, 0xa2, 0x8c, 0x19, 0x52, 0x48, 0xe2, 0xc1, 0xa8, 0x58, 0xb4, 0x10, 0x24, 0x06, + 0x58, 0x51, 0xfc, 0xb9, 0x12, 0xec, 0xfd, 0x73, 0xb4, 0x6d, 0x84, 0xfa, 0x06, 0x8b, 0x05, + 0x0b, 0x2d, 0xd6, 0xd6, 0x1f, 0x29, 0x82, 0x9f, 0x19, 0x12, 0x1e, 0xb2, 0x04, 0x8f, 0x7f, + 0x4d, 0xbd, 0x30, 0x2e, 0xe3, 0xe0, 0x88, 0x29, 0xc5, 0x93, 0xd6, 0x6c, 0x1f, 0x29, 0x45, + 0x91, 0xa7, 0x58, 0xcd, 0x05, 0x17, 0xd6, 0x6d, 0xb3, 0xca, 0x66, 0xcc, 0x3c, 0x4a, 0x74, + 0xfd, 0x08, 0x10, 0xa6, 0x99, 0x92, 0x10, 0xd2, 0x85, 0xab, 0x6e, 0x1d, 0x0e, 0x8b, 0x26, + 0x46, 0xd1, 0x6c, 0x84, 0xc0, 0x26, 0x43, 0x59, 0x68, 0xf0, 0x13, 0x1d, 0xfb, 0xe3, 0xd1, + 0xd2, 0xb4, 0x71, 0x9e, 0xf2, 0x59, 0x6a, 0x33, 0x29, 0x79, 0xd2, 0xd7, 0x26, 0xf1, 0xae, + 0x78, 0x9e, 0x1f, 0x0f, 0x3f, 0xe3, 0xe8, 0xd0, 0x27, 0x78, 0x77, 0xf6, 0xac, 0x9c, 0x56, + 0x39, 0x73, 0x8a, 0x6b, 0x2f, 0x34, 0x78, 0xb1, 0x11, 0xdb, 0xa4, 0x5c, 0x80, 0x01, 0x71, + 0x6a, 0xc2, 0xd1, 0x2e, 0x5e, 0x76, 0x28, 0x70, 0x93, 0xae, 0x3e, 0x78, 0xb0, 0x1f, 0x0f, + 0xda, 0xbf, 0xfb, 0x8a, 0x67, 0x65, 0x4f, 0x91, 0xed, 0x49, 0x75, 0x78, 0x62, 0xa2, 0x93, + 0xb5, 0x70, 0x7f, 0x4d, 0x08, 0x4e, 0x79, 0x61, 0xa8, 0x5f, 0x7f, 0xb4, 0x65, 0x9f, 0x91, + 0x54, 0x3a, 0xe8, 0x50, 0x33, 0xd3, 0xd5, 0x8a, 0x7c, 0xf3, 0x9e, 0x8b, 0x77, 0x7b, 0xc6, + 0xc6, 0x0c, 0x45, 0x95, 0x1f, 0xb0, 0xd0, 0x0b, 0x27, 0x4a, 0xfd, 0xc7, 0xf7, 0x0d, 0x5a, + 0x43, 0xc9, 0x7d, 0x35, 0xb0, 0x7d, 0xc4, 0x9c, 0x57, 0x1e, 0x76, 0x0d, 0xf1, 0x95, 0x30, + 0x71, 0xcc, 0xb3, 0x66, 0x3b, 0x63, 0xa8, 0x6c, 0xa3, 0x43, 0xa0, 0x24, 0xcc, 0xb7, 0x53, + 0xfe, 0xfe, 0xbc, 0x6e, 0x60, 0x89, 0xaf, 0x16, 0x21, 0xc8, 0x91, 0x6a, 0x89, 0xce, 0x80, + 0x2c, 0xf1, 0x59, 0xce, 0xc3, 0x60, 0x61, 0x3b, 0x0b, 0x19, 0xfe, 0x99, 0xac, 0x65, 0x90, + 0x15, 0x12, 0x05, 0xac, 0x7e, 0xff, 0x98, 0x7b, 0x66, 0x64, 0x0e, 0x4b, 0x5b, 0xaa, 0x8d, + 0x3b, 0xd2, 0x56, 0xcf, 0x99, 0x39, 0xee, 0x22, 0x81, 0xd0, 0x60, 0x06, 0x66, 0x20, 0x81, + 0x48, 0x3c, 0x6f, 0x3a, 0x77, 0xba, 0xcb, 0x52, 0xac, 0x79, 0x56, 0xaf, 0xe9, 0x16, 0x17, + 0x0a, 0xa3, 0x82, 0x08, 0xd5, 0x3c, 0x97, 0xcb, 0x09, 0xff, 0x7f, 0xf9, 0x4f, 0x60, 0x05, + 0xb9, 0x53, 0x26, 0xaa, 0xb8, 0x50, 0xaa, 0x19, 0x25, 0xae, 0x5f, 0xea, 0x8a, 0xd0, 0x89, + 0x12, 0x80, 0x43, 0x50, 0x24, 0x12, 0x21, 0x14, 0xcd, 0x77, 0xeb, 0x21, 0xcc, 0x5c, 0x09, + 0x64, 0xf3, 0xc7, 0xcb, 0xc5, 0x4b, 0xc3, 0xe7, 0xed, 0xe7, 0x86, 0x2c, 0x1d, 0x8e, 0x19, + 0x52, 0x9b, 0x2a, 0x0c, 0x18, 0x72, 0x0b, 0x1e, 0x1b, 0xb0, 0x0f, 0x42, 0x99, 0x04, 0xae, + 0xd5, 0xb7, 0x89, 0x1a, 0xb9, 0x4f, 0xd6, 0xaf, 0xf3, 0xc9, 0x93, 0x6f, 0xb0, 0x60, 0x83, + 0x6e, 0x6b, 0xd1, 0x5f, 0x3f, 0x1a, 0x83, 0x1e, 0x24, 0x00, 0x87, 0xb5, 0x3e, 0xdb, 0xf9, + 0x4d, 0xa7, 0x16, 0x2e, 0x19, 0x5b, 0x8f, 0x1b, 0x0d, 0x47, 0x72, 0x42, 0xe9, 0x0a, 0x11, + 0x08, 0x2d, 0x88, 0x1c, 0xbc, 0xc7, 0xb4, 0xbe, 0x29, 0x4d, 0x03, 0x5e, 0xec, 0xdf, 0xf3, + 0x3d, 0x2f, 0xe8, 0x1d, 0x9a, 0xd2, 0xd1, 0xab, 0x41, 0x3d, 0x87, 0x11, 0x45, 0xb0, 0x0d, + 0x46, 0xf5, 0xe8, 0x95, 0x62, 0x1c, 0x68, 0xf7, 0xa6, 0x5b, 0x39, 0x4e, 0xbf, 0x47, 0xba, + 0x5d, 0x7f, 0xb7, 0x6a, 0xf4, 0xba, 0x1d, 0x69, 0xf6, 0xa4, 0xe7, 0xe4, 0x6b, 0x3b, 0x0d, + 0x23, 0x16, 0x4a, 0xb2, 0x68, 0xf0, 0xb2, 0x0d, 0x09, 0x17, 0x6a, 0x63, 0x8c, 0x83, 0xd3, + 0xbd, 0x05, 0xc9, 0xf6, 0xf0, 0xa1, 0x31, 0x0b, 0x2c, 0xac, 0x83, 0xac, 0x80, 0x34, 0x32, + 0xb4, 0xec, 0xd0, 0xbc, 0x54, 0x82, 0x9a, 0xc8, 0xf6, 0xa0, 0x7d, 0xc6, 0x79, 0x73, 0xf4, + 0x20, 0x99, 0xf3, 0xb4, 0x01, 0xde, 0x91, 0x27, 0xf2, 0xc0, 0xdc, 0x81, 0x00, 0x4e, 0x7e, + 0x07, 0x99, 0xc8, 0x3a, 0x51, 0xbc, 0x38, 0xd6, 0x8a, 0xa2, 0xde, 0x3b, 0x6a, 0x8c, 0x1a, + 0x7c, 0x81, 0x0f, 0x3a, 0x1f, 0xe4, 0x05, 0x7b, 0x20, 0x35, 0x6b, 0xa5, 0x6a, 0xa7, 0xe7, + 0xbc, 0x9c, 0x20, 0xec, 0x00, 0x15, 0xe2, 0x51, 0xaf, 0x77, 0xeb, 0x29, 0x3c, 0x7d, 0x2e, + 0x00, 0x5c, 0x81, 0x21, 0xfa, 0x35, 0x6f, 0x40, 0xef, 0xfb, 0xd1, 0x3f, 0xcc, 0x9d, 0x55, + 0x53, 0xfb, 0x5a, 0xa5, 0x56, 0x89, 0x0b, 0x52, 0xeb, 0x57, 0x73, 0x4f, 0x1b, 0x67, 0x24, + 0xcb, 0xb8, 0x6a, 0x10, 0x69, 0xd6, 0xfb, 0x52, 0x40, 0xff, 0x20, 0xa5, 0xf3, 0x72, 0xe1, + 0x3d, 0xa4, 0x8c, 0x81, 0x66, 0x16, 0x0d, 0x5d, 0xad, 0xa8, 0x50, 0x25, 0x78, 0x31, 0x77, + 0x0c, 0x57, 0xe4, 0xe9, 0x15, 0x2d, 0xdb, 0x07, 0x87, 0xc8, 0xb0, 0x43, 0xde, 0xfc, 0xfe, + 0xa9, 0xeb, 0xf5, 0xb0, 0xd3, 0x7b, 0xe9, 0x1f, 0x6e, 0xca, 0xe4, 0x03, 0x95, 0xc5, 0xd1, + 0x59, 0x72, 0x63, 0xf0, 0x86, 0x54, 0xe8, 0x16, 0x62, 0x0b, 0x35, 0x29, 0xc2, 0x68, 0xd0, + 0xd6, 0x3e, 0x90, 0x60, 0x57, 0x1d, 0xc9, 0xed, 0x3f, 0xed, 0xb0, 0x2f, 0x7e, 0x97, 0x02, + 0x51, 0xec, 0xee, 0x6f, 0x82, 0x74, 0x76, 0x7f, 0xfb, 0xd6, 0xc4, 0xc3, 0xdd, 0xe8, 0xb1, + 0x60, 0xfc, 0xc6, 0xb9, 0x0d, 0x6a, 0x33, 0x78, 0xc6, 0xc1, 0xbf, 0x86, 0x2c, 0x50, 0xcc, + 0x9a, 0x70, 0x8e, 0x7b, 0xec, 0xab, 0x95, 0xac, 0x53, 0xa0, 0x4b, 0x07, 0x88, 0xaf, 0x42, + 0xed, 0x19, 0x8d, 0xf6, 0x32, 0x17, 0x48, 0x47, 0x1d, 0x41, 0x6f, 0xfe, 0x2e, 0xa7, 0x8f, + 0x4b, 0xa0, 0x51, 0xf3, 0xbf, 0x02, 0x0a, 0x48, 0x58, 0xf7, 0xa1, 0x6d, 0xea, 0xa5, 0x13, + 0x5a, 0x5b, 0xea, 0x0c, 0x9e, 0x52, 0x4f, 0x9e, 0xb9, 0x71, 0x7f, 0x23, 0x83, 0xda, 0x1b, + 0x86, 0x9a, 0x41, 0x29, 0xda, 0x70, 0xe7, 0x64, 0xa1, 0x7b, 0xd5, 0x0a, 0x22, 0x0d, 0x5c, + 0x40, 0xc4, 0x81, 0x07, 0x25, 0x35, 0x4a, 0x1c, 0x10, 0xdb, 0x45, 0x0a, 0xff, 0x36, 0xd4, + 0xe0, 0xeb, 0x5f, 0x68, 0xd6, 0x67, 0xc6, 0xd0, 0x8b, 0x76, 0x1a, 0x7d, 0x59, 0x42, 0xa1, + 0xcb, 0x96, 0x4d, 0x84, 0x09, 0x9a, 0x3d, 0xe0, 0x52, 0x85, 0x6e, 0x48, 0x90, 0x85, 0x2a, + 0x63, 0xb2, 0x69, 0xd2, 0x00, 0x43, 0x31, 0x37, 0xb3, 0x52, 0xaf, 0x62, 0xfa, 0xc1, 0xe0, + 0x03, 0xfb, 0x62, 0xaa, 0x88, 0xc9, 0xb2, 0x2c, 0xd5, 0xa8, 0xf5, 0xa5, 0x4c, 0x12, 0x59, + 0x4e, 0x06, 0x5e, 0x9b, 0x15, 0x66, 0x11, 0xb2, 0x27, 0x92, 0xdc, 0x98, 0x59, 0xde, 0xdf, + 0xfa, 0x9a, 0x32, 0x2e, 0xc0, 0x5d, 0x3c, 0x33, 0x41, 0x6d, 0xaf, 0xb2, 0x25, 0x23, 0x14, + 0xa5, 0x7b, 0xc7, 0x9b, 0x68, 0xf3, 0xda, 0xeb, 0xe3, 0xa9, 0xe2, 0x6f, 0x0e, 0x1d, 0x1c, + 0xba, 0x55, 0xb6, 0x34, 0x6a, 0x93, 0x1f, 0x1f, 0xb8, 0x34, 0xc8, 0x84, 0x08, 0xb1, 0x6b, + 0x6a, 0x28, 0x74, 0x74, 0xe5, 0xeb, 0x75, 0xe9, 0x7c, 0xd8, 0xba, 0xd8, 0x42, 0xa5, 0xee, + 0x1f, 0x80, 0xd9, 0x96, 0xb2, 0x2e, 0xe7, 0xbf, 0xba, 0xeb, 0xd1, 0x69, 0xbb, 0x8f, 0xfd, + 0x5a, 0x63, 0x8f, 0x39, 0x7f, 0xdf, 0x1d, 0x37, 0xd2, 0x18, 0x35, 0x9d, 0xb6, 0xcc, 0xe4, + 0x27, 0x81, 0x89, 0x38, 0x38, 0x68, 0x33, 0xe7, 0x78, 0xd8, 0x76, 0xf5, 0xee, 0xd0, 0x4a, + 0x07, 0x69, 0x19, 0x7a, 0xad, 0x18, 0xb1, 0x94, 0x61, 0x45, 0x53, 0xa2, 0x48, 0xda, 0x96, + 0x4a, 0xf9, 0xee, 0x94, 0x2a, 0x1f, 0x6e, 0x18, 0x3c, 0x92, 0x46, 0xd1, 0x1a, 0x28, 0x18, + 0x32, 0x1f, 0x3a, 0x45, 0xbe, 0x04, 0x35, 0x92, 0xe5, 0xa3, 0xcb, 0xb5, 0x2e, 0x32, 0x43, + 0xac, 0x65, 0x17, 0x89, 0x99, 0x15, 0x03, 0x9e, 0xb1, 0x23, 0x2f, 0xed, 0x76, 0x4d, 0xd8, + 0xac, 0x21, 0x40, 0xc4, 0x99, 0x4e, 0x65, 0x71, 0x2c, 0xb3, 0x45, 0xab, 0xfb, 0xe7, 0x72, + 0x39, 0x56, 0x30, 0x6d, 0xfb, 0x74, 0xeb, 0x99, 0xf3, 0xcd, 0x57, 0x5c, 0x78, 0x75, 0xe9, + 0x8d, 0xc3, 0xa2, 0xfb, 0x5d, 0xe0, 0x90, 0xc5, 0x55, 0xad, 0x91, 0x53, 0x4e, 0x9e, 0xbd, + 0x8c, 0x49, 0xa4, 0xa4, 0x69, 0x10, 0x0c, 0xc5, 0x76, 0xe9, 0x25, 0x86, 0x8d, 0x66, 0x23, + 0xa8, 0xdb, 0x5c, 0xe8, 0xd9, 0x30, 0xe1, 0x15, 0x7b, 0xc0, 0x99, 0x0f, 0x03, 0xec, 0xaa, + 0x12, 0xef, 0xce, 0xd4, 0xea, 0x55, 0x5c, 0x08, 0x86, 0xf4, 0xf4, 0xb0, 0x83, 0x42, 0x95, + 0x37, 0xb6, 0x38, 0xe0, 0x2b, 0x54, 0x89, 0xbd, 0x4e, 0x20, 0x9d, 0x3f, 0xc3, 0x4b, 0xb7, + 0xec, 0xfa, 0x5a, 0x14, 0x03, 0xcb, 0x64, 0xc8, 0x34, 0x4a, 0x4b, 0x6e, 0xf8, 0x6e, 0x56, + 0xf6, 0xdd, 0x5f, 0xa1, 0x24, 0xe2, 0xd4, 0xd0, 0x82, 0x64, 0x1f, 0x8e, 0x9b, 0xfa, 0xb4, + 0xcb, 0xdb, 0x0a, 0xe8, 0x15, 0xfc, 0x15, 0xab, 0x4b, 0x18, 0xbf, 0xd4, 0x42, 0x14, 0x48, + 0x82, 0x85, 0xdd, 0xeb, 0x49, 0x1b, 0x0b, 0x0b, 0x05, 0xe9, 0xb4, 0xa1, 0x33, 0x0a, 0x5d, + 0x0e, 0x6c, 0x4b, 0xc0, 0xd6, 0x6c, 0x7c, 0xfb, 0x69, 0x0b, 0x53, 0x19, 0xe4, 0xf3, 0x35, + 0xfc, 0xbe, 0xa1, 0x34, 0x02, 0x09, 0x4f, 0x74, 0x86, 0x92, 0xcd, 0x5d, 0x1a, 0xc1, 0x27, + 0x0c, 0xf2, 0xc5, 0xcf, 0xdd, 0x23, 0x93, 0x02, 0xbd, 0x41, 0x5e, 0x42, 0xf0, 0xa0, 0x9d, + 0x0c, 0x72, 0xc8, 0xec, 0x32, 0x0a, 0x8a, 0xfd, 0x3d, 0x5a, 0x41, 0x27, 0x0c, 0x88, 0x59, + 0xad, 0x94, 0x2e, 0xef, 0x5d, 0x8f, 0xc7, 0xdf, 0x66, 0xe4, 0xdd, 0x56, 0x6c, 0x7b, 0xca, + 0x55, 0x81, 0xae, 0xae, 0x5c, 0x1b, 0x1a, 0xab, 0xae, 0x99, 0x8d, 0xcc, 0x42, 0x97, 0x59, + 0xf4, 0x14, 0x3f, 0x75, 0xc6, 0xd1, 0x88, 0xba, 0xaa, 0x84, 0x4a, 0xd0, 0x34, 0x08, 0x3b, + 0x7d, 0xdb, 0x15, 0x06, 0xb0, 0x5c, 0xbd, 0x40, 0xf5, 0xa8, 0xec, 0xae, 0x36, 0x40, 0xdd, + 0x90, 0x1c, 0x3e, 0x0d, 0x7e, 0x73, 0xc7, 0xc2, 0xc5, 0x6a, 0xff, 0x52, 0x05, 0x7f, 0xbe, + 0xd0, 0x92, 0xfd, 0xb3, 0x6f, 0xff, 0x5d, 0xb7, 0x97, 0x64, 0x73, 0x7b, 0xca, 0xd1, 0x98, + 0x24, 0x6b, 0x0b, 0x01, 0x68, 0xdd, 0x27, 0x85, 0x85, 0xb5, 0x83, 0xc1, 0xe0, 0x50, 0x64, + 0xc7, 0xaf, 0xf1, 0xc6, 0x4d, 0xb1, 0xef, 0xc9, 0xb4, 0x0a, 0x6d, 0x65, 0xf3, 0x47, 0xcc, + 0xa3, 0x02, 0x21, 0x0c, 0xbe, 0x22, 0x29, 0x05, 0xcf, 0x5f, 0xe8, 0x94, 0x6c, 0xe5, 0xdc, + 0xc4, 0xdf, 0xbe, 0x3e, 0xa8, 0xb4, 0x18, 0xb0, 0x99, 0xb8, 0x6f, 0xff, 0x5d, 0xb9, 0xfd, + 0x3b, 0x5d, 0x16, 0xbf, 0x3e, 0xd8, 0xb3, 0xd8, 0x08, 0x34, 0xf6, 0x47, 0x35, 0x5b, 0x72, + 0x1a, 0x33, 0xad, 0x52, 0x5d, 0xb8, 0xd0, 0x77, 0xc6, 0xab, 0xba, 0x55, 0x09, 0x5f, 0x02, + 0xf8, 0xd4, 0x5f, 0x53, 0x06, 0x91, 0xcd, 0x74, 0x42, 0xae, 0x54, 0x91, 0x81, 0x62, 0x13, + 0x6f, 0xd8, 0xa9, 0x77, 0xc3, 0x6c, 0xcb, 0xf1, 0x29, 0x5a, 0xcc, 0xda, 0x35, 0xbd, 0x52, + 0x23, 0xbe, 0x59, 0xeb, 0x12, 0x6d, 0xb7, 0x53, 0xee, 0xfc, 0xb4, 0x1b, 0x13, 0x5e, 0xba, + 0x16, 0x7c, 0xc5, 0xf3, 0xe3, 0x6d, 0x07, 0x78, 0xf5, 0x2b, 0x21, 0x05, 0x88, 0x4c, 0xc0, + 0xa1, 0xe3, 0x36, 0x10, 0xf8, 0x1b, 0xd8, 0x17, 0xfb, 0x6a, 0x4e, 0xd8, 0xb3, 0x47, 0x2d, + 0x99, 0xbd, 0xbb, 0x5d, 0x37, 0x7d, 0xba, 0xf1, 0xe1, 0x7c, 0xc0, 0xc5, 0x54, 0x62, 0x7f, + 0xcf, 0x5a, 0x4a, 0x93, 0xcc, 0xf1, 0x1b, 0x34, 0xc8, 0xa6, 0x05, 0x4c, 0x55, 0x8b, 0x54, + 0x84, 0xd5, 0x77, 0xeb, 0xc0, 0x6d, 0x3a, 0x29, 0xbd, 0x75, 0x61, 0x09, 0x9a, 0x2c, 0xbb, + 0xf7, 0x18, 0x79, 0x34, 0x90, 0x24, 0xa5, 0x81, 0x70, 0x87, 0xc5, 0x02, 0x7c, 0xba, 0xd4, + 0x5e, 0x14, 0x8e, 0xe4, 0xed, 0xa2, 0x61, 0x6a, 0xb9, 0x6e, 0xb5, 0x4a, 0xb9, 0x01, 0x46, + 0xf4, 0xcf, 0xbc, 0x09, 0x2f, 0x27, 0x4b, 0xbd, 0x86, 0x7a, 0x10, 0xe1, 0xd4, 0xc8, 0xd9, + 0x20, 0x8d, 0x8a, 0x63, 0x00, 0x63, 0x44, 0xeb, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7, + 0xad, 0xb9, 0xd1, 0x01, 0x80, 0x63, 0x25, 0xc8, 0x12, 0xa6, 0xce, 0x1e, 0xbe, 0xfe, 0x7e, + 0x5f, 0x3c, 0xdb, 0x34, 0xea, 0x37, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x8c, 0x9a, 0xb6, + 0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x1b, 0xb4, 0xea, 0x56, + 0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xd6, 0x2e, 0xde, 0x1f, 0x9d, + 0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x66, 0x4e, 0x1e, 0x9f, 0x9d, 0xb8, 0xf2, 0x47, + 0x0c, 0x9a, 0xb6, 0xee, 0x3f, 0xfc, 0x7a, 0x57, 0x0d, 0x79, 0x70, 0x62, 0x27, 0xad, 0xb9, + 0xd1, 0x01, 0x61, 0x40, 0x02, 0x67, 0x2d, 0xd8, 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xd7, 0x2c, + 0xbb, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x01, + 0x80, 0x63, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a, + 0x37, 0xcd, 0x18, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0xa8, 0xd2, 0x07, 0x6d, 0x58, 0x32, + 0xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x57, 0x0d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x6f, 0x5c, + 0x1b, 0x95, 0xa8, 0xb3, 0xc5, 0xe9, 0x31, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93, + 0x85, 0x69, 0x31, 0xc1, 0xe1, 0x21, 0xc0, 0xe3, 0x44, 0x0a, 0x77, 0x6c, 0x5a, 0x17, 0x8d, + 0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xf4, 0x4b, 0x14, + 0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xb3, 0xc5, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c, + 0xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xd9, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xa1, 0xc0, + 0x02, 0x86, 0x6f, 0x5c, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xdd, + 0x19, 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x7c, 0x5b, 0x15, 0x89, 0x90, 0x83, 0x84, 0x6b, 0x54, + 0x0b, 0x75, 0x68, 0x52, 0x07, 0x6d, 0x58, 0x32, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed, 0x58, + 0x32, 0xe6, 0x4e, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x38, 0xd3, 0x05, 0x88, 0x92, + 0xa6, 0xaf, 0xdc, 0x1b, 0xb4, 0xcb, 0xf5, 0x68, 0x52, 0x07, 0x8c, 0x7b, 0x55, 0x09, 0x90, + 0x83, 0x84, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x3b, 0xd5, 0x09, 0x90, 0xa2, 0xc6, 0x0e, 0x7f, + 0x7c, 0x7a, 0x57, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0x0c, 0x7b, 0x74, 0x4b, + 0x14, 0x8b, 0x94, 0xaa, 0xb7, 0xcd, 0x18, 0x93, 0xa4, 0xca, 0x16, 0xae, 0xbf, 0xdd, 0x19, + 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0xeb, 0x35, 0xc9, + 0x10, 0x83, 0x65, 0x48, 0x12, 0xa6, 0xce, 0x1e, 0x9f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60, + 0x23, 0xc4, 0xeb, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xcf, 0x81, 0x10, 0xac, 0x74 +}; - return report; -} +// clang-format off diff --git a/drivers/sensors/pmw3389.h b/drivers/sensors/pmw3389.h index db4a763fe3..fafd1e2046 100644 --- a/drivers/sensors/pmw3389.h +++ b/drivers/sensors/pmw3389.h @@ -1,76 +1,77 @@ -/* Copyright 2021 Alabastard (@Alabastard-64) - * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2019 Sunjun Kim - * Copyright 2020 Ploopy Corporation - * - * 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 . - */ +// Copyright 2022 Stefan Kerkmann (KarlK90) +// Copyright 2021 Alabastard (@Alabastard-64) +// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) +// Copyright 2019 Sunjun Kim +// Copyright 2020 Ploopy Corporation +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include -#ifndef PMW3389_CPI -# define PMW3389_CPI 2000 +#if !defined(PMW33XX_CPI) +# define PMW33XX_CPI 2000 #endif -#ifndef PMW3389_CLOCK_SPEED -# define PMW3389_CLOCK_SPEED 2000000 -#endif - -#ifndef PMW3389_SPI_LSBFIRST -# define PMW3389_SPI_LSBFIRST false -#endif - -#ifndef PMW3389_SPI_MODE -# define PMW3389_SPI_MODE 3 -#endif - -#ifndef PMW3389_SPI_DIVISOR -# ifdef __AVR__ -# define PMW3389_SPI_DIVISOR (F_CPU / PMW3389_CLOCK_SPEED) -# else -# define PMW3389_SPI_DIVISOR 64 -# endif -#endif - -#ifndef PMW3389_LIFTOFF_DISTANCE -# define PMW3389_LIFTOFF_DISTANCE 0x02 -#endif - -#ifndef ROTATIONAL_TRANSFORM_ANGLE -# define ROTATIONAL_TRANSFORM_ANGLE 0x00 -#endif - -#ifndef PMW3389_CS_PIN -# error "No chip select pin defined -- missing PMW3389_CS_PIN" -#endif +#define PMW33XX_CPI_STEP 50 +#define PMW33XX_CPI_MIN 50 +#define PMW33XX_CPI_MAX 16000 -typedef struct { - int8_t motion; - bool isMotion; // True if a motion is detected. - bool isOnSurface; // True when a chip is on a surface - int16_t dx; // displacement on x directions. Unit: Count. (CPI * Count = Inch value) - int8_t mdx; - int16_t dy; // displacement on y directions. - int8_t mdy; -} report_pmw3389_t; +#define PMW33XX_FIRMWARE_LENGTH 4094 -bool pmw3389_init(void); -void pmw3389_upload_firmware(void); -bool pmw3389_check_signature(void); -uint16_t pmw3389_get_cpi(void); -void pmw3389_set_cpi(uint16_t cpi); -/* Reads and clears the current delta values on the sensor */ -report_pmw3389_t pmw3389_read_burst(void); +// PMW3389 register addresses +// clang-format off +#define REG_Product_ID 0x00 +#define REG_Revision_ID 0x01 +#define REG_Motion 0x02 +#define REG_Delta_X_L 0x03 +#define REG_Delta_X_H 0x04 +#define REG_Delta_Y_L 0x05 +#define REG_Delta_Y_H 0x06 +#define REG_SQUAL 0x07 +#define REG_RawData_Sum 0x08 +#define REG_Maximum_RawData 0x09 +#define REG_Minimum_RawData 0x0a +#define REG_Shutter_Lower 0x0b +#define REG_Shutter_Upper 0x0c +#define REG_Ripple_Control 0x0d +#define REG_Resolution_L 0x0e +#define REG_Resolution_H 0x0f +#define REG_Config2 0x10 +#define REG_Angle_Tune 0x11 +#define REG_Frame_Capture 0x12 +#define REG_SROM_Enable 0x13 +#define REG_Run_Downshift 0x14 +#define REG_Rest1_Rate_Lower 0x15 +#define REG_Rest1_Rate_Upper 0x16 +#define REG_Rest1_Downshift 0x17 +#define REG_Rest2_Rate_Lower 0x18 +#define REG_Rest2_Rate_Upper 0x19 +#define REG_Rest2_Downshift 0x1a +#define REG_Rest3_Rate_Lower 0x1b +#define REG_Rest3_Rate_Upper 0x1c +#define REG_Observation 0x24 +#define REG_Data_Out_Lower 0x25 +#define REG_Data_Out_Upper 0x26 +#define REG_SROM_ID 0x2a +#define REG_Min_SQ_Run 0x2b +#define REG_RawData_Threshold 0x2c +#define REG_Control2 0x2d +#define REG_Config5_L 0x2e +#define REG_Config5_H 0x2f +#define REG_Power_Up_Reset 0X3a +#define REG_Shutdown 0x3b +#define REG_Inverse_Product_ID 0x3f +#define REG_LiftCutoff_Cal3 0x41 +#define REG_Angle_Snap 0x42 +#define REG_LiftCutoff_Cal1 0x4a +#define REG_Motion_Burst 0x50 +#define REG_SROM_Load_Burst 0x62 +#define REG_Lift_Config 0x63 +#define REG_RawData_Burst 0x64 +#define REG_LiftCutoff_Cal2 0x65 +#define REG_LiftCutoff_Cal_Timeout 0x71 +#define REG_LiftCutoff_Cal_Min_Length 0x72 +#define REG_PWM_Period_Cnt 0x73 +#define REG_PWM_Width_Cnt 0x74 +// clang-format on diff --git a/drivers/sensors/pmw3389_firmware.h b/drivers/sensors/pmw3389_firmware.h deleted file mode 100644 index cd9638b605..0000000000 --- a/drivers/sensors/pmw3389_firmware.h +++ /dev/null @@ -1,307 +0,0 @@ -/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2019 Sunjun Kim - * Copyright 2020 Ploopy Corporation - * - * 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 . - */ - -#pragma once - -#include "progmem.h" - -// PID, Inverse PID, SROM version -const uint8_t firmware_signature[] PROGMEM = {0x42, 0xBD, 0x04}; - -#define FIRMWARE_LENGTH 4094 - -// Firmware Blob for PMW3389 - -// clang-format off -const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = { - 0x01, 0xe8, 0xba, 0x26, 0x0b, 0xb2, 0xbe, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0xa8, 0xb3, - 0xe4, 0x2b, 0xb5, 0xe8, 0x53, 0x07, 0x6d, 0x3b, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, 0xd9, - 0x11, 0xa0, 0xc2, 0xe7, 0x2d, 0xb9, 0xd1, 0x20, 0xa3, 0xa5, 0xc8, 0xf3, 0x64, 0x4a, 0xf7, - 0x4d, 0x18, 0x93, 0xa4, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xfe, 0x7e, 0x7e, - 0x5f, 0x1d, 0x99, 0xb0, 0xc3, 0xe5, 0x29, 0xd3, 0x03, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x58, - 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xf2, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xc0, 0x02, - 0x86, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xb3, 0xe4, 0x4a, 0x16, - 0xab, 0xbf, 0xdd, 0x38, 0xf2, 0x66, 0x4e, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xc8, - 0x12, 0xa6, 0xaf, 0xdc, 0x3a, 0xd1, 0x41, 0x60, 0x75, 0x58, 0x24, 0x92, 0xd4, 0x72, 0x6c, - 0xe0, 0x2f, 0xfd, 0x23, 0x8d, 0x1c, 0x5b, 0xb2, 0x97, 0x36, 0x3d, 0x0b, 0xa2, 0x49, 0xb1, - 0x58, 0xf2, 0x1f, 0xc0, 0xcb, 0xf8, 0x41, 0x4f, 0xcd, 0x1e, 0x6b, 0x39, 0xa7, 0x2b, 0xe9, - 0x30, 0x16, 0x83, 0xd2, 0x0e, 0x47, 0x8f, 0xe3, 0xb1, 0xdf, 0xa2, 0x15, 0xdb, 0x5d, 0x30, - 0xc5, 0x1a, 0xab, 0x31, 0x99, 0xf3, 0xfa, 0xb2, 0x86, 0x69, 0xad, 0x7a, 0xe8, 0xa7, 0x18, - 0x6a, 0xcc, 0xc8, 0x65, 0x23, 0x87, 0xa8, 0x5f, 0xf5, 0x21, 0x59, 0x75, 0x09, 0x71, 0x45, - 0x55, 0x25, 0x4b, 0xda, 0xa1, 0xc3, 0xf7, 0x41, 0xab, 0x59, 0xd9, 0x74, 0x12, 0x55, 0x5f, - 0xbc, 0xaf, 0xd9, 0xfd, 0xb0, 0x1e, 0xa3, 0x0f, 0xff, 0xde, 0x11, 0x16, 0x6a, 0xae, 0x0e, - 0xe1, 0x5d, 0x3c, 0x10, 0x43, 0x9a, 0xa1, 0x0b, 0x24, 0x8f, 0x0d, 0x7f, 0x0b, 0x5e, 0x4c, - 0x42, 0xa4, 0x84, 0x2c, 0x40, 0xd0, 0x55, 0x39, 0xe6, 0x4b, 0xf8, 0x9b, 0x2f, 0xdc, 0x28, - 0xff, 0xfa, 0xb5, 0x85, 0x19, 0xe5, 0x28, 0xa1, 0x77, 0xaa, 0x73, 0xf3, 0x03, 0xc7, 0x62, - 0xa6, 0x91, 0x18, 0xc9, 0xb0, 0xcd, 0x05, 0xdc, 0xca, 0x81, 0x26, 0x1a, 0x47, 0x40, 0xda, - 0x36, 0x7d, 0x6a, 0x53, 0xc8, 0x5a, 0x77, 0x5d, 0x19, 0xa4, 0x1b, 0x23, 0x83, 0xd0, 0xb2, - 0xaa, 0x0e, 0xbf, 0x77, 0x4e, 0x3a, 0x3b, 0x59, 0x00, 0x31, 0x0d, 0x02, 0x1b, 0x88, 0x7a, - 0xd4, 0xbd, 0x9d, 0xcc, 0x58, 0x04, 0x69, 0xf6, 0x3b, 0xca, 0x42, 0xe2, 0xfd, 0xc3, 0x3d, - 0x39, 0xc5, 0xd0, 0x71, 0xe4, 0xc8, 0xb7, 0x3e, 0x3f, 0xc8, 0xe9, 0xca, 0xc9, 0x3f, 0x04, - 0x4e, 0x1b, 0x79, 0xca, 0xa5, 0x61, 0xc2, 0xed, 0x1d, 0xa6, 0xda, 0x5a, 0xe9, 0x7f, 0x65, - 0x8c, 0xbe, 0x12, 0x6e, 0xa4, 0x5b, 0x33, 0x2f, 0x84, 0x28, 0x9c, 0x1c, 0x88, 0x2d, 0xff, - 0x07, 0xbf, 0xa6, 0xd7, 0x5a, 0x88, 0x86, 0xb0, 0x3f, 0xf6, 0x31, 0x5b, 0x11, 0x6d, 0xf5, - 0x58, 0xeb, 0x58, 0x02, 0x9e, 0xb5, 0x9a, 0xb1, 0xff, 0x25, 0x9d, 0x8b, 0x4f, 0xb6, 0x0a, - 0xf9, 0xea, 0x3e, 0x3f, 0x21, 0x09, 0x65, 0x21, 0x22, 0xfe, 0x3d, 0x4e, 0x11, 0x5b, 0x9e, - 0x5a, 0x59, 0x8b, 0xdd, 0xd8, 0xce, 0xd6, 0xd9, 0x59, 0xd2, 0x1e, 0xfd, 0xef, 0x0d, 0x1b, - 0xd9, 0x61, 0x7f, 0xd7, 0x2d, 0xad, 0x62, 0x09, 0xe5, 0x22, 0x63, 0xea, 0xc7, 0x31, 0xd9, - 0xa1, 0x38, 0x80, 0x5c, 0xa7, 0x32, 0x82, 0xec, 0x1b, 0xa2, 0x49, 0x5a, 0x06, 0xd2, 0x7c, - 0xc9, 0x96, 0x57, 0xbb, 0x17, 0x75, 0xfc, 0x7a, 0x8f, 0x0d, 0x77, 0xb5, 0x7a, 0x8e, 0x3e, - 0xf4, 0xba, 0x2f, 0x69, 0x13, 0x26, 0xd6, 0xd9, 0x21, 0x60, 0x2f, 0x21, 0x3e, 0x87, 0xee, - 0xfd, 0x87, 0x16, 0x0d, 0xc8, 0x08, 0x00, 0x25, 0x71, 0xac, 0x2c, 0x03, 0x2a, 0x37, 0x2d, - 0xb3, 0x34, 0x09, 0x91, 0xe3, 0x06, 0x2c, 0x38, 0x37, 0x95, 0x3b, 0x17, 0x7a, 0xaf, 0xac, - 0x99, 0x55, 0xab, 0x41, 0x39, 0x5f, 0x8e, 0xa6, 0x43, 0x80, 0x03, 0x88, 0x6f, 0x7d, 0xbd, - 0x5a, 0xb4, 0x2b, 0x32, 0x23, 0x5a, 0xa9, 0x31, 0x32, 0x39, 0x4c, 0x5b, 0xf4, 0x6b, 0xaf, - 0x66, 0x6f, 0x3c, 0x8e, 0x2d, 0x82, 0x97, 0x9f, 0x4a, 0x01, 0xdc, 0x99, 0x98, 0x00, 0xec, - 0x38, 0x7a, 0x79, 0x70, 0xa6, 0x85, 0xd6, 0x21, 0x63, 0x0d, 0x45, 0x9a, 0x2e, 0x5e, 0xa7, - 0xb1, 0xea, 0x66, 0x6a, 0xbc, 0x62, 0x2d, 0x7b, 0x7d, 0x85, 0xea, 0x95, 0x2f, 0xc0, 0xe8, - 0x6f, 0x35, 0xa0, 0x3a, 0x02, 0x25, 0xbc, 0xb2, 0x5f, 0x5c, 0x43, 0x96, 0xcc, 0x26, 0xd2, - 0x16, 0xb4, 0x96, 0x73, 0xd7, 0x13, 0xc7, 0xae, 0x53, 0x15, 0x31, 0x89, 0x68, 0x66, 0x6d, - 0x2c, 0x92, 0x1f, 0xcc, 0x5b, 0xa7, 0x8f, 0x5d, 0xbb, 0xc9, 0xdb, 0xe8, 0x3b, 0x9d, 0x61, - 0x74, 0x8b, 0x05, 0xa1, 0x58, 0x52, 0x68, 0xee, 0x3d, 0x39, 0x79, 0xa0, 0x9b, 0xdd, 0xe1, - 0x55, 0xc9, 0x60, 0xeb, 0xad, 0xb8, 0x5b, 0xc2, 0x5a, 0xb5, 0x2c, 0x18, 0x55, 0xa9, 0x50, - 0xc3, 0xf6, 0x72, 0x5f, 0xcc, 0xe2, 0xf4, 0x55, 0xb5, 0xd6, 0xb5, 0x4a, 0x99, 0xa5, 0x28, - 0x74, 0x97, 0x18, 0xe8, 0xc0, 0x84, 0x89, 0x50, 0x03, 0x86, 0x4d, 0x1a, 0xb7, 0x09, 0x90, - 0xa2, 0x01, 0x04, 0xbb, 0x73, 0x62, 0xcb, 0x97, 0x22, 0x70, 0x5d, 0x52, 0x41, 0x8e, 0xd9, - 0x90, 0x15, 0xaa, 0xab, 0x0a, 0x31, 0x65, 0xb4, 0xda, 0xd0, 0xee, 0x24, 0xc9, 0x41, 0x91, - 0x1e, 0xbc, 0x46, 0x70, 0x40, 0x9d, 0xda, 0x0e, 0x2a, 0xe4, 0xb2, 0x4c, 0x9f, 0xf2, 0xfc, - 0xf3, 0x84, 0x17, 0x44, 0x1e, 0xd7, 0xca, 0x23, 0x1f, 0x3f, 0x5a, 0x22, 0x3d, 0xaf, 0x9b, - 0x2d, 0xfc, 0x41, 0xad, 0x26, 0xb4, 0x45, 0x67, 0x0b, 0x80, 0x0e, 0xf9, 0x61, 0x37, 0xec, - 0x3b, 0xf4, 0x4b, 0x14, 0xdf, 0x5a, 0x0c, 0x3a, 0x50, 0x0b, 0x14, 0x0c, 0x72, 0xae, 0xc6, - 0xc5, 0xec, 0x35, 0x53, 0x2d, 0x59, 0xed, 0x91, 0x74, 0xe2, 0xc4, 0xc8, 0xf2, 0x25, 0x6b, - 0x97, 0x6f, 0xc9, 0x76, 0xce, 0xa9, 0xb1, 0x99, 0x8f, 0x5a, 0x92, 0x3b, 0xc4, 0x8d, 0x54, - 0x50, 0x40, 0x72, 0xd6, 0x90, 0x83, 0xfc, 0xe5, 0x49, 0x8b, 0x17, 0xf5, 0xfd, 0x6b, 0x8d, - 0x32, 0x02, 0xe9, 0x0a, 0xfe, 0xbf, 0x00, 0x6b, 0xa3, 0xad, 0x5f, 0x09, 0x4b, 0x97, 0x2b, - 0x00, 0x58, 0x65, 0x2e, 0x07, 0x49, 0x0a, 0x3b, 0x6b, 0x2e, 0x50, 0x6c, 0x1d, 0xac, 0xb7, - 0x6a, 0x26, 0xd8, 0x13, 0xa4, 0xca, 0x16, 0xae, 0xab, 0x93, 0xb9, 0x1c, 0x1c, 0xb4, 0x47, - 0x6a, 0x38, 0x36, 0x17, 0x27, 0xc9, 0x7f, 0xc7, 0x64, 0xcb, 0x89, 0x58, 0xc5, 0x61, 0xc2, - 0xc6, 0xea, 0x15, 0x0b, 0x34, 0x0c, 0x5d, 0x61, 0x76, 0x6e, 0x2b, 0x62, 0x40, 0x92, 0xa3, - 0x6c, 0xef, 0xf4, 0xe4, 0xc3, 0xa1, 0xa8, 0xf5, 0x94, 0x79, 0x0d, 0xd1, 0x3d, 0xcb, 0x3d, - 0x40, 0xb6, 0xd0, 0xf0, 0x10, 0x54, 0xd8, 0x47, 0x25, 0x51, 0xc5, 0x41, 0x79, 0x00, 0xe5, - 0xa0, 0x72, 0xde, 0xbb, 0x3b, 0x62, 0x17, 0xf6, 0xbc, 0x5d, 0x00, 0x76, 0x2e, 0xa7, 0x3b, - 0xb6, 0xf1, 0x98, 0x72, 0x59, 0x2a, 0x73, 0xb0, 0x21, 0xd6, 0x49, 0xe0, 0xc0, 0xd5, 0xeb, - 0x02, 0x7d, 0x4b, 0x41, 0x28, 0x70, 0x2d, 0xec, 0x2b, 0x71, 0x1f, 0x0b, 0xb9, 0x71, 0x63, - 0x06, 0xe6, 0xbc, 0x60, 0xbb, 0xf4, 0x9a, 0x62, 0x43, 0x09, 0x18, 0x4e, 0x93, 0x06, 0x4d, - 0x76, 0xfa, 0x7f, 0xbd, 0x02, 0xe4, 0x50, 0x91, 0x12, 0xe5, 0x86, 0xff, 0x64, 0x1e, 0xaf, - 0x7e, 0xb3, 0xb2, 0xde, 0x89, 0xc1, 0xa2, 0x6f, 0x40, 0x7b, 0x41, 0x51, 0x63, 0xea, 0x25, - 0xd1, 0x97, 0x57, 0x92, 0xa8, 0x45, 0xa1, 0xa5, 0x45, 0x21, 0x43, 0x7f, 0x83, 0x15, 0x29, - 0xd0, 0x30, 0x53, 0x32, 0xb4, 0x5a, 0x17, 0x96, 0xbc, 0xc2, 0x68, 0xa9, 0xb7, 0xaf, 0xac, - 0xdf, 0xf1, 0xe3, 0x89, 0xba, 0x24, 0x79, 0x54, 0xc6, 0x14, 0x07, 0x1c, 0x1e, 0x0d, 0x3a, - 0x6b, 0xe5, 0x3d, 0x4e, 0x10, 0x60, 0x96, 0xec, 0x6c, 0xda, 0x47, 0xae, 0x03, 0x25, 0x39, - 0x1d, 0x74, 0xc8, 0xac, 0x6a, 0xf2, 0x6b, 0x05, 0x2a, 0x9a, 0xe7, 0xe8, 0x92, 0xd6, 0xc2, - 0x6d, 0xfa, 0xe8, 0xa7, 0x9d, 0x5f, 0x48, 0xc9, 0x75, 0xf1, 0x66, 0x6a, 0xdb, 0x5d, 0x9a, - 0xcd, 0x27, 0xdd, 0xb9, 0x24, 0x04, 0x9c, 0x18, 0xc2, 0x6d, 0x0c, 0x91, 0x34, 0x48, 0x42, - 0x6f, 0xe9, 0x59, 0x70, 0xc4, 0x7e, 0x81, 0x0e, 0x32, 0x0a, 0x93, 0x48, 0xb0, 0xc0, 0x15, - 0x9e, 0x05, 0xac, 0x36, 0x16, 0xcb, 0x59, 0x65, 0xa0, 0x83, 0xdf, 0x3e, 0xda, 0xfb, 0x1d, - 0x1a, 0xdb, 0x65, 0xec, 0x9a, 0xc6, 0xc3, 0x8e, 0x3c, 0x45, 0xfd, 0xc8, 0xf5, 0x1c, 0x6a, - 0x67, 0x0d, 0x8f, 0x99, 0x7d, 0x30, 0x21, 0x8c, 0xea, 0x22, 0x87, 0x65, 0xc9, 0xb2, 0x4c, - 0xe4, 0x1b, 0x46, 0xba, 0x54, 0xbd, 0x7c, 0xca, 0xd5, 0x8f, 0x5b, 0xa5, 0x01, 0x04, 0xd8, - 0x0a, 0x16, 0xbf, 0xb9, 0x50, 0x2e, 0x37, 0x2f, 0x64, 0xf3, 0x70, 0x11, 0x02, 0x05, 0x31, - 0x9b, 0xa0, 0xb2, 0x01, 0x5e, 0x4f, 0x19, 0xc9, 0xd4, 0xea, 0xa1, 0x79, 0x54, 0x53, 0xa7, - 0xde, 0x2f, 0x49, 0xd3, 0xd1, 0x63, 0xb5, 0x03, 0x15, 0x4e, 0xbf, 0x04, 0xb3, 0x26, 0x8b, - 0x20, 0xb2, 0x45, 0xcf, 0xcd, 0x5b, 0x82, 0x32, 0x88, 0x61, 0xa7, 0xa8, 0xb2, 0xa0, 0x72, - 0x96, 0xc0, 0xdb, 0x2b, 0xe2, 0x5f, 0xba, 0xe3, 0xf5, 0x8a, 0xde, 0xf1, 0x18, 0x01, 0x16, - 0x40, 0xd9, 0x86, 0x12, 0x09, 0x18, 0x1b, 0x05, 0x0c, 0xb1, 0xb5, 0x47, 0xe2, 0x43, 0xab, - 0xfe, 0x92, 0x63, 0x7e, 0x95, 0x2b, 0xf0, 0xaf, 0xe1, 0xf1, 0xc3, 0x4a, 0xff, 0x2b, 0x09, - 0xbb, 0x4a, 0x0e, 0x9a, 0xc4, 0xd8, 0x64, 0x7d, 0x83, 0xa0, 0x4f, 0x44, 0xdb, 0xc4, 0xa8, - 0x58, 0xef, 0xfc, 0x9e, 0x77, 0xf9, 0xa6, 0x8f, 0x58, 0x8b, 0x12, 0xf4, 0xe9, 0x81, 0x12, - 0x47, 0x51, 0x41, 0x83, 0xef, 0xf6, 0x73, 0xbc, 0x8e, 0x0f, 0x4c, 0x8f, 0x4e, 0x69, 0x90, - 0x77, 0x29, 0x5d, 0x92, 0xb0, 0x6d, 0x06, 0x67, 0x29, 0x60, 0xbd, 0x4b, 0x17, 0xc8, 0x89, - 0x69, 0x28, 0x29, 0xd6, 0x78, 0xcb, 0x11, 0x4c, 0xba, 0x8b, 0x68, 0xae, 0x7e, 0x9f, 0xef, - 0x95, 0xda, 0xe2, 0x9e, 0x7f, 0xe9, 0x55, 0xe5, 0xe1, 0xe2, 0xb7, 0xe6, 0x5f, 0xbb, 0x2c, - 0xa2, 0xe6, 0xee, 0xc7, 0x0a, 0x60, 0xa9, 0xd1, 0x80, 0xdf, 0x7f, 0xd6, 0x97, 0xab, 0x1d, - 0x22, 0x25, 0xfc, 0x79, 0x23, 0xe0, 0xae, 0xc5, 0xef, 0x16, 0xa4, 0xa1, 0x0f, 0x92, 0xa9, - 0xc7, 0xe3, 0x3a, 0x55, 0xdf, 0x62, 0x49, 0xd9, 0xf5, 0x84, 0x49, 0xc5, 0x90, 0x34, 0xd3, - 0xe1, 0xac, 0x99, 0x21, 0xb1, 0x02, 0x76, 0x4a, 0xfa, 0xd4, 0xbb, 0xa4, 0x9c, 0xa2, 0xe2, - 0xcb, 0x3d, 0x3b, 0x14, 0x75, 0x60, 0xd1, 0x02, 0xb4, 0xa3, 0xb4, 0x72, 0x06, 0xf9, 0x19, - 0x9c, 0xe2, 0xe4, 0xa7, 0x0f, 0x25, 0x88, 0xc6, 0x86, 0xd6, 0x8c, 0x74, 0x4e, 0x6e, 0xfc, - 0xa8, 0x48, 0x9e, 0xa7, 0x9d, 0x1a, 0x4b, 0x37, 0x09, 0xc8, 0xb0, 0x10, 0xbe, 0x6f, 0xfe, - 0xa3, 0xc4, 0x7a, 0xb5, 0x3d, 0xe8, 0x30, 0xf1, 0x0d, 0xa0, 0xb2, 0x44, 0xfc, 0x9b, 0x8c, - 0xf8, 0x61, 0xed, 0x81, 0xd1, 0x62, 0x11, 0xb4, 0xe1, 0xd5, 0x39, 0x52, 0x89, 0xd3, 0xa8, - 0x49, 0x31, 0xdf, 0xb6, 0xf9, 0x91, 0xf4, 0x1c, 0x9d, 0x09, 0x95, 0x40, 0x56, 0xe7, 0xe3, - 0xcd, 0x5c, 0x92, 0xc1, 0x1d, 0x6b, 0xe9, 0x78, 0x6f, 0x8e, 0x94, 0x42, 0x66, 0xa2, 0xaa, - 0xd3, 0xc8, 0x2e, 0xe3, 0xf6, 0x07, 0x72, 0x0b, 0x6b, 0x1e, 0x7b, 0xb9, 0x7c, 0xe0, 0xa0, - 0xbc, 0xd9, 0x25, 0xdf, 0x87, 0xa8, 0x5f, 0x9c, 0xcc, 0xf0, 0xdb, 0x42, 0x8e, 0x07, 0x31, - 0x13, 0x01, 0x66, 0x32, 0xd1, 0xb8, 0xd6, 0xe3, 0x5e, 0x12, 0x76, 0x61, 0xd3, 0x38, 0x89, - 0xe6, 0x17, 0x6f, 0xa5, 0xf2, 0x71, 0x0e, 0xa5, 0xe2, 0x88, 0x30, 0xbb, 0xbe, 0x8a, 0xea, - 0xc7, 0x62, 0xc4, 0xcf, 0xb8, 0xcd, 0x33, 0x8d, 0x3d, 0x3e, 0xb5, 0x60, 0x3a, 0x03, 0x92, - 0xe4, 0x6d, 0x1b, 0xe0, 0xb4, 0x84, 0x08, 0x55, 0x88, 0xa7, 0x3a, 0xb9, 0x3d, 0x43, 0xc3, - 0xc0, 0xfa, 0x07, 0x6a, 0xca, 0x94, 0xad, 0x99, 0x55, 0xf1, 0xf1, 0xc0, 0x23, 0x87, 0x1d, - 0x3d, 0x1c, 0xd1, 0x66, 0xa0, 0x57, 0x10, 0x52, 0xa2, 0x7f, 0xbe, 0xf9, 0x88, 0xb6, 0x02, - 0xbf, 0x08, 0x23, 0xa9, 0x0c, 0x63, 0x17, 0x2a, 0xae, 0xf5, 0xf7, 0xb7, 0x21, 0x83, 0x92, - 0x31, 0x23, 0x0d, 0x20, 0xc3, 0xc2, 0x05, 0x21, 0x62, 0x8e, 0x45, 0xe8, 0x14, 0xc1, 0xda, - 0x75, 0xb8, 0xf8, 0x92, 0x01, 0xd0, 0x5d, 0x18, 0x9f, 0x99, 0x11, 0x19, 0xf5, 0x35, 0xe8, - 0x7f, 0x20, 0x88, 0x8c, 0x05, 0x75, 0xf5, 0xd7, 0x40, 0x17, 0xbb, 0x1e, 0x36, 0x52, 0xd9, - 0xa4, 0x9c, 0xc2, 0x9d, 0x42, 0x81, 0xd8, 0xc7, 0x8a, 0xe7, 0x4c, 0x81, 0xe0, 0xb7, 0x57, - 0xed, 0x48, 0x8b, 0xf0, 0x97, 0x15, 0x61, 0xd9, 0x2c, 0x7c, 0x45, 0xaf, 0xc2, 0xcd, 0xfc, - 0xaa, 0x13, 0xad, 0x59, 0xcc, 0xb2, 0xb2, 0x6e, 0xdd, 0x63, 0x9c, 0x32, 0x0f, 0xec, 0x83, - 0xbe, 0x78, 0xac, 0x91, 0x44, 0x1a, 0x1f, 0xea, 0xfd, 0x5d, 0x8e, 0xb4, 0xc0, 0x84, 0xd4, - 0xac, 0xb4, 0x87, 0x5f, 0xac, 0xef, 0xdf, 0xcd, 0x12, 0x56, 0xc8, 0xcd, 0xfe, 0xc5, 0xda, - 0xd3, 0xc1, 0x69, 0xf3, 0x61, 0x05, 0xea, 0x25, 0xe2, 0x12, 0x05, 0x8f, 0x39, 0x08, 0x08, - 0x7c, 0x37, 0xb6, 0x7e, 0x5b, 0xd8, 0xb1, 0x0e, 0xf2, 0xdb, 0x4b, 0xf1, 0xad, 0x90, 0x01, - 0x57, 0xcd, 0xa0, 0xb4, 0x52, 0xe8, 0xf3, 0xd7, 0x8a, 0xbd, 0x4f, 0x9f, 0x21, 0x40, 0x72, - 0xa4, 0xfc, 0x0b, 0x01, 0x2b, 0x2f, 0xb6, 0x4c, 0x95, 0x2d, 0x35, 0x33, 0x41, 0x6b, 0xa0, - 0x93, 0xe7, 0x2c, 0xf2, 0xd3, 0x72, 0x8b, 0xf4, 0x4f, 0x15, 0x3c, 0xaf, 0xd6, 0x12, 0xde, - 0x3f, 0x83, 0x3f, 0xff, 0xf8, 0x7f, 0xf6, 0xcc, 0xa6, 0x7f, 0xc9, 0x9a, 0x6e, 0x1f, 0xc1, - 0x0c, 0xfb, 0xee, 0x9c, 0xe7, 0xaf, 0xc9, 0x26, 0x54, 0xef, 0xb0, 0x39, 0xef, 0xb2, 0xe9, - 0x23, 0xc4, 0xef, 0xd1, 0xa1, 0xa4, 0x25, 0x24, 0x6f, 0x8d, 0x6a, 0xe5, 0x8a, 0x32, 0x3a, - 0xaf, 0xfc, 0xda, 0xce, 0x18, 0x25, 0x42, 0x07, 0x4d, 0x45, 0x8b, 0xdf, 0x85, 0xcf, 0x55, - 0xb2, 0x24, 0xfe, 0x9c, 0x69, 0x74, 0xa7, 0x6e, 0xa0, 0xce, 0xc0, 0x39, 0xf4, 0x86, 0xc6, - 0x8d, 0xae, 0xb9, 0x48, 0x64, 0x13, 0x0b, 0x40, 0x81, 0xa2, 0xc9, 0xa8, 0x85, 0x51, 0xee, - 0x9f, 0xcf, 0xa2, 0x8c, 0x19, 0x52, 0x48, 0xe2, 0xc1, 0xa8, 0x58, 0xb4, 0x10, 0x24, 0x06, - 0x58, 0x51, 0xfc, 0xb9, 0x12, 0xec, 0xfd, 0x73, 0xb4, 0x6d, 0x84, 0xfa, 0x06, 0x8b, 0x05, - 0x0b, 0x2d, 0xd6, 0xd6, 0x1f, 0x29, 0x82, 0x9f, 0x19, 0x12, 0x1e, 0xb2, 0x04, 0x8f, 0x7f, - 0x4d, 0xbd, 0x30, 0x2e, 0xe3, 0xe0, 0x88, 0x29, 0xc5, 0x93, 0xd6, 0x6c, 0x1f, 0x29, 0x45, - 0x91, 0xa7, 0x58, 0xcd, 0x05, 0x17, 0xd6, 0x6d, 0xb3, 0xca, 0x66, 0xcc, 0x3c, 0x4a, 0x74, - 0xfd, 0x08, 0x10, 0xa6, 0x99, 0x92, 0x10, 0xd2, 0x85, 0xab, 0x6e, 0x1d, 0x0e, 0x8b, 0x26, - 0x46, 0xd1, 0x6c, 0x84, 0xc0, 0x26, 0x43, 0x59, 0x68, 0xf0, 0x13, 0x1d, 0xfb, 0xe3, 0xd1, - 0xd2, 0xb4, 0x71, 0x9e, 0xf2, 0x59, 0x6a, 0x33, 0x29, 0x79, 0xd2, 0xd7, 0x26, 0xf1, 0xae, - 0x78, 0x9e, 0x1f, 0x0f, 0x3f, 0xe3, 0xe8, 0xd0, 0x27, 0x78, 0x77, 0xf6, 0xac, 0x9c, 0x56, - 0x39, 0x73, 0x8a, 0x6b, 0x2f, 0x34, 0x78, 0xb1, 0x11, 0xdb, 0xa4, 0x5c, 0x80, 0x01, 0x71, - 0x6a, 0xc2, 0xd1, 0x2e, 0x5e, 0x76, 0x28, 0x70, 0x93, 0xae, 0x3e, 0x78, 0xb0, 0x1f, 0x0f, - 0xda, 0xbf, 0xfb, 0x8a, 0x67, 0x65, 0x4f, 0x91, 0xed, 0x49, 0x75, 0x78, 0x62, 0xa2, 0x93, - 0xb5, 0x70, 0x7f, 0x4d, 0x08, 0x4e, 0x79, 0x61, 0xa8, 0x5f, 0x7f, 0xb4, 0x65, 0x9f, 0x91, - 0x54, 0x3a, 0xe8, 0x50, 0x33, 0xd3, 0xd5, 0x8a, 0x7c, 0xf3, 0x9e, 0x8b, 0x77, 0x7b, 0xc6, - 0xc6, 0x0c, 0x45, 0x95, 0x1f, 0xb0, 0xd0, 0x0b, 0x27, 0x4a, 0xfd, 0xc7, 0xf7, 0x0d, 0x5a, - 0x43, 0xc9, 0x7d, 0x35, 0xb0, 0x7d, 0xc4, 0x9c, 0x57, 0x1e, 0x76, 0x0d, 0xf1, 0x95, 0x30, - 0x71, 0xcc, 0xb3, 0x66, 0x3b, 0x63, 0xa8, 0x6c, 0xa3, 0x43, 0xa0, 0x24, 0xcc, 0xb7, 0x53, - 0xfe, 0xfe, 0xbc, 0x6e, 0x60, 0x89, 0xaf, 0x16, 0x21, 0xc8, 0x91, 0x6a, 0x89, 0xce, 0x80, - 0x2c, 0xf1, 0x59, 0xce, 0xc3, 0x60, 0x61, 0x3b, 0x0b, 0x19, 0xfe, 0x99, 0xac, 0x65, 0x90, - 0x15, 0x12, 0x05, 0xac, 0x7e, 0xff, 0x98, 0x7b, 0x66, 0x64, 0x0e, 0x4b, 0x5b, 0xaa, 0x8d, - 0x3b, 0xd2, 0x56, 0xcf, 0x99, 0x39, 0xee, 0x22, 0x81, 0xd0, 0x60, 0x06, 0x66, 0x20, 0x81, - 0x48, 0x3c, 0x6f, 0x3a, 0x77, 0xba, 0xcb, 0x52, 0xac, 0x79, 0x56, 0xaf, 0xe9, 0x16, 0x17, - 0x0a, 0xa3, 0x82, 0x08, 0xd5, 0x3c, 0x97, 0xcb, 0x09, 0xff, 0x7f, 0xf9, 0x4f, 0x60, 0x05, - 0xb9, 0x53, 0x26, 0xaa, 0xb8, 0x50, 0xaa, 0x19, 0x25, 0xae, 0x5f, 0xea, 0x8a, 0xd0, 0x89, - 0x12, 0x80, 0x43, 0x50, 0x24, 0x12, 0x21, 0x14, 0xcd, 0x77, 0xeb, 0x21, 0xcc, 0x5c, 0x09, - 0x64, 0xf3, 0xc7, 0xcb, 0xc5, 0x4b, 0xc3, 0xe7, 0xed, 0xe7, 0x86, 0x2c, 0x1d, 0x8e, 0x19, - 0x52, 0x9b, 0x2a, 0x0c, 0x18, 0x72, 0x0b, 0x1e, 0x1b, 0xb0, 0x0f, 0x42, 0x99, 0x04, 0xae, - 0xd5, 0xb7, 0x89, 0x1a, 0xb9, 0x4f, 0xd6, 0xaf, 0xf3, 0xc9, 0x93, 0x6f, 0xb0, 0x60, 0x83, - 0x6e, 0x6b, 0xd1, 0x5f, 0x3f, 0x1a, 0x83, 0x1e, 0x24, 0x00, 0x87, 0xb5, 0x3e, 0xdb, 0xf9, - 0x4d, 0xa7, 0x16, 0x2e, 0x19, 0x5b, 0x8f, 0x1b, 0x0d, 0x47, 0x72, 0x42, 0xe9, 0x0a, 0x11, - 0x08, 0x2d, 0x88, 0x1c, 0xbc, 0xc7, 0xb4, 0xbe, 0x29, 0x4d, 0x03, 0x5e, 0xec, 0xdf, 0xf3, - 0x3d, 0x2f, 0xe8, 0x1d, 0x9a, 0xd2, 0xd1, 0xab, 0x41, 0x3d, 0x87, 0x11, 0x45, 0xb0, 0x0d, - 0x46, 0xf5, 0xe8, 0x95, 0x62, 0x1c, 0x68, 0xf7, 0xa6, 0x5b, 0x39, 0x4e, 0xbf, 0x47, 0xba, - 0x5d, 0x7f, 0xb7, 0x6a, 0xf4, 0xba, 0x1d, 0x69, 0xf6, 0xa4, 0xe7, 0xe4, 0x6b, 0x3b, 0x0d, - 0x23, 0x16, 0x4a, 0xb2, 0x68, 0xf0, 0xb2, 0x0d, 0x09, 0x17, 0x6a, 0x63, 0x8c, 0x83, 0xd3, - 0xbd, 0x05, 0xc9, 0xf6, 0xf0, 0xa1, 0x31, 0x0b, 0x2c, 0xac, 0x83, 0xac, 0x80, 0x34, 0x32, - 0xb4, 0xec, 0xd0, 0xbc, 0x54, 0x82, 0x9a, 0xc8, 0xf6, 0xa0, 0x7d, 0xc6, 0x79, 0x73, 0xf4, - 0x20, 0x99, 0xf3, 0xb4, 0x01, 0xde, 0x91, 0x27, 0xf2, 0xc0, 0xdc, 0x81, 0x00, 0x4e, 0x7e, - 0x07, 0x99, 0xc8, 0x3a, 0x51, 0xbc, 0x38, 0xd6, 0x8a, 0xa2, 0xde, 0x3b, 0x6a, 0x8c, 0x1a, - 0x7c, 0x81, 0x0f, 0x3a, 0x1f, 0xe4, 0x05, 0x7b, 0x20, 0x35, 0x6b, 0xa5, 0x6a, 0xa7, 0xe7, - 0xbc, 0x9c, 0x20, 0xec, 0x00, 0x15, 0xe2, 0x51, 0xaf, 0x77, 0xeb, 0x29, 0x3c, 0x7d, 0x2e, - 0x00, 0x5c, 0x81, 0x21, 0xfa, 0x35, 0x6f, 0x40, 0xef, 0xfb, 0xd1, 0x3f, 0xcc, 0x9d, 0x55, - 0x53, 0xfb, 0x5a, 0xa5, 0x56, 0x89, 0x0b, 0x52, 0xeb, 0x57, 0x73, 0x4f, 0x1b, 0x67, 0x24, - 0xcb, 0xb8, 0x6a, 0x10, 0x69, 0xd6, 0xfb, 0x52, 0x40, 0xff, 0x20, 0xa5, 0xf3, 0x72, 0xe1, - 0x3d, 0xa4, 0x8c, 0x81, 0x66, 0x16, 0x0d, 0x5d, 0xad, 0xa8, 0x50, 0x25, 0x78, 0x31, 0x77, - 0x0c, 0x57, 0xe4, 0xe9, 0x15, 0x2d, 0xdb, 0x07, 0x87, 0xc8, 0xb0, 0x43, 0xde, 0xfc, 0xfe, - 0xa9, 0xeb, 0xf5, 0xb0, 0xd3, 0x7b, 0xe9, 0x1f, 0x6e, 0xca, 0xe4, 0x03, 0x95, 0xc5, 0xd1, - 0x59, 0x72, 0x63, 0xf0, 0x86, 0x54, 0xe8, 0x16, 0x62, 0x0b, 0x35, 0x29, 0xc2, 0x68, 0xd0, - 0xd6, 0x3e, 0x90, 0x60, 0x57, 0x1d, 0xc9, 0xed, 0x3f, 0xed, 0xb0, 0x2f, 0x7e, 0x97, 0x02, - 0x51, 0xec, 0xee, 0x6f, 0x82, 0x74, 0x76, 0x7f, 0xfb, 0xd6, 0xc4, 0xc3, 0xdd, 0xe8, 0xb1, - 0x60, 0xfc, 0xc6, 0xb9, 0x0d, 0x6a, 0x33, 0x78, 0xc6, 0xc1, 0xbf, 0x86, 0x2c, 0x50, 0xcc, - 0x9a, 0x70, 0x8e, 0x7b, 0xec, 0xab, 0x95, 0xac, 0x53, 0xa0, 0x4b, 0x07, 0x88, 0xaf, 0x42, - 0xed, 0x19, 0x8d, 0xf6, 0x32, 0x17, 0x48, 0x47, 0x1d, 0x41, 0x6f, 0xfe, 0x2e, 0xa7, 0x8f, - 0x4b, 0xa0, 0x51, 0xf3, 0xbf, 0x02, 0x0a, 0x48, 0x58, 0xf7, 0xa1, 0x6d, 0xea, 0xa5, 0x13, - 0x5a, 0x5b, 0xea, 0x0c, 0x9e, 0x52, 0x4f, 0x9e, 0xb9, 0x71, 0x7f, 0x23, 0x83, 0xda, 0x1b, - 0x86, 0x9a, 0x41, 0x29, 0xda, 0x70, 0xe7, 0x64, 0xa1, 0x7b, 0xd5, 0x0a, 0x22, 0x0d, 0x5c, - 0x40, 0xc4, 0x81, 0x07, 0x25, 0x35, 0x4a, 0x1c, 0x10, 0xdb, 0x45, 0x0a, 0xff, 0x36, 0xd4, - 0xe0, 0xeb, 0x5f, 0x68, 0xd6, 0x67, 0xc6, 0xd0, 0x8b, 0x76, 0x1a, 0x7d, 0x59, 0x42, 0xa1, - 0xcb, 0x96, 0x4d, 0x84, 0x09, 0x9a, 0x3d, 0xe0, 0x52, 0x85, 0x6e, 0x48, 0x90, 0x85, 0x2a, - 0x63, 0xb2, 0x69, 0xd2, 0x00, 0x43, 0x31, 0x37, 0xb3, 0x52, 0xaf, 0x62, 0xfa, 0xc1, 0xe0, - 0x03, 0xfb, 0x62, 0xaa, 0x88, 0xc9, 0xb2, 0x2c, 0xd5, 0xa8, 0xf5, 0xa5, 0x4c, 0x12, 0x59, - 0x4e, 0x06, 0x5e, 0x9b, 0x15, 0x66, 0x11, 0xb2, 0x27, 0x92, 0xdc, 0x98, 0x59, 0xde, 0xdf, - 0xfa, 0x9a, 0x32, 0x2e, 0xc0, 0x5d, 0x3c, 0x33, 0x41, 0x6d, 0xaf, 0xb2, 0x25, 0x23, 0x14, - 0xa5, 0x7b, 0xc7, 0x9b, 0x68, 0xf3, 0xda, 0xeb, 0xe3, 0xa9, 0xe2, 0x6f, 0x0e, 0x1d, 0x1c, - 0xba, 0x55, 0xb6, 0x34, 0x6a, 0x93, 0x1f, 0x1f, 0xb8, 0x34, 0xc8, 0x84, 0x08, 0xb1, 0x6b, - 0x6a, 0x28, 0x74, 0x74, 0xe5, 0xeb, 0x75, 0xe9, 0x7c, 0xd8, 0xba, 0xd8, 0x42, 0xa5, 0xee, - 0x1f, 0x80, 0xd9, 0x96, 0xb2, 0x2e, 0xe7, 0xbf, 0xba, 0xeb, 0xd1, 0x69, 0xbb, 0x8f, 0xfd, - 0x5a, 0x63, 0x8f, 0x39, 0x7f, 0xdf, 0x1d, 0x37, 0xd2, 0x18, 0x35, 0x9d, 0xb6, 0xcc, 0xe4, - 0x27, 0x81, 0x89, 0x38, 0x38, 0x68, 0x33, 0xe7, 0x78, 0xd8, 0x76, 0xf5, 0xee, 0xd0, 0x4a, - 0x07, 0x69, 0x19, 0x7a, 0xad, 0x18, 0xb1, 0x94, 0x61, 0x45, 0x53, 0xa2, 0x48, 0xda, 0x96, - 0x4a, 0xf9, 0xee, 0x94, 0x2a, 0x1f, 0x6e, 0x18, 0x3c, 0x92, 0x46, 0xd1, 0x1a, 0x28, 0x18, - 0x32, 0x1f, 0x3a, 0x45, 0xbe, 0x04, 0x35, 0x92, 0xe5, 0xa3, 0xcb, 0xb5, 0x2e, 0x32, 0x43, - 0xac, 0x65, 0x17, 0x89, 0x99, 0x15, 0x03, 0x9e, 0xb1, 0x23, 0x2f, 0xed, 0x76, 0x4d, 0xd8, - 0xac, 0x21, 0x40, 0xc4, 0x99, 0x4e, 0x65, 0x71, 0x2c, 0xb3, 0x45, 0xab, 0xfb, 0xe7, 0x72, - 0x39, 0x56, 0x30, 0x6d, 0xfb, 0x74, 0xeb, 0x99, 0xf3, 0xcd, 0x57, 0x5c, 0x78, 0x75, 0xe9, - 0x8d, 0xc3, 0xa2, 0xfb, 0x5d, 0xe0, 0x90, 0xc5, 0x55, 0xad, 0x91, 0x53, 0x4e, 0x9e, 0xbd, - 0x8c, 0x49, 0xa4, 0xa4, 0x69, 0x10, 0x0c, 0xc5, 0x76, 0xe9, 0x25, 0x86, 0x8d, 0x66, 0x23, - 0xa8, 0xdb, 0x5c, 0xe8, 0xd9, 0x30, 0xe1, 0x15, 0x7b, 0xc0, 0x99, 0x0f, 0x03, 0xec, 0xaa, - 0x12, 0xef, 0xce, 0xd4, 0xea, 0x55, 0x5c, 0x08, 0x86, 0xf4, 0xf4, 0xb0, 0x83, 0x42, 0x95, - 0x37, 0xb6, 0x38, 0xe0, 0x2b, 0x54, 0x89, 0xbd, 0x4e, 0x20, 0x9d, 0x3f, 0xc3, 0x4b, 0xb7, - 0xec, 0xfa, 0x5a, 0x14, 0x03, 0xcb, 0x64, 0xc8, 0x34, 0x4a, 0x4b, 0x6e, 0xf8, 0x6e, 0x56, - 0xf6, 0xdd, 0x5f, 0xa1, 0x24, 0xe2, 0xd4, 0xd0, 0x82, 0x64, 0x1f, 0x8e, 0x9b, 0xfa, 0xb4, - 0xcb, 0xdb, 0x0a, 0xe8, 0x15, 0xfc, 0x15, 0xab, 0x4b, 0x18, 0xbf, 0xd4, 0x42, 0x14, 0x48, - 0x82, 0x85, 0xdd, 0xeb, 0x49, 0x1b, 0x0b, 0x0b, 0x05, 0xe9, 0xb4, 0xa1, 0x33, 0x0a, 0x5d, - 0x0e, 0x6c, 0x4b, 0xc0, 0xd6, 0x6c, 0x7c, 0xfb, 0x69, 0x0b, 0x53, 0x19, 0xe4, 0xf3, 0x35, - 0xfc, 0xbe, 0xa1, 0x34, 0x02, 0x09, 0x4f, 0x74, 0x86, 0x92, 0xcd, 0x5d, 0x1a, 0xc1, 0x27, - 0x0c, 0xf2, 0xc5, 0xcf, 0xdd, 0x23, 0x93, 0x02, 0xbd, 0x41, 0x5e, 0x42, 0xf0, 0xa0, 0x9d, - 0x0c, 0x72, 0xc8, 0xec, 0x32, 0x0a, 0x8a, 0xfd, 0x3d, 0x5a, 0x41, 0x27, 0x0c, 0x88, 0x59, - 0xad, 0x94, 0x2e, 0xef, 0x5d, 0x8f, 0xc7, 0xdf, 0x66, 0xe4, 0xdd, 0x56, 0x6c, 0x7b, 0xca, - 0x55, 0x81, 0xae, 0xae, 0x5c, 0x1b, 0x1a, 0xab, 0xae, 0x99, 0x8d, 0xcc, 0x42, 0x97, 0x59, - 0xf4, 0x14, 0x3f, 0x75, 0xc6, 0xd1, 0x88, 0xba, 0xaa, 0x84, 0x4a, 0xd0, 0x34, 0x08, 0x3b, - 0x7d, 0xdb, 0x15, 0x06, 0xb0, 0x5c, 0xbd, 0x40, 0xf5, 0xa8, 0xec, 0xae, 0x36, 0x40, 0xdd, - 0x90, 0x1c, 0x3e, 0x0d, 0x7e, 0x73, 0xc7, 0xc2, 0xc5, 0x6a, 0xff, 0x52, 0x05, 0x7f, 0xbe, - 0xd0, 0x92, 0xfd, 0xb3, 0x6f, 0xff, 0x5d, 0xb7, 0x97, 0x64, 0x73, 0x7b, 0xca, 0xd1, 0x98, - 0x24, 0x6b, 0x0b, 0x01, 0x68, 0xdd, 0x27, 0x85, 0x85, 0xb5, 0x83, 0xc1, 0xe0, 0x50, 0x64, - 0xc7, 0xaf, 0xf1, 0xc6, 0x4d, 0xb1, 0xef, 0xc9, 0xb4, 0x0a, 0x6d, 0x65, 0xf3, 0x47, 0xcc, - 0xa3, 0x02, 0x21, 0x0c, 0xbe, 0x22, 0x29, 0x05, 0xcf, 0x5f, 0xe8, 0x94, 0x6c, 0xe5, 0xdc, - 0xc4, 0xdf, 0xbe, 0x3e, 0xa8, 0xb4, 0x18, 0xb0, 0x99, 0xb8, 0x6f, 0xff, 0x5d, 0xb9, 0xfd, - 0x3b, 0x5d, 0x16, 0xbf, 0x3e, 0xd8, 0xb3, 0xd8, 0x08, 0x34, 0xf6, 0x47, 0x35, 0x5b, 0x72, - 0x1a, 0x33, 0xad, 0x52, 0x5d, 0xb8, 0xd0, 0x77, 0xc6, 0xab, 0xba, 0x55, 0x09, 0x5f, 0x02, - 0xf8, 0xd4, 0x5f, 0x53, 0x06, 0x91, 0xcd, 0x74, 0x42, 0xae, 0x54, 0x91, 0x81, 0x62, 0x13, - 0x6f, 0xd8, 0xa9, 0x77, 0xc3, 0x6c, 0xcb, 0xf1, 0x29, 0x5a, 0xcc, 0xda, 0x35, 0xbd, 0x52, - 0x23, 0xbe, 0x59, 0xeb, 0x12, 0x6d, 0xb7, 0x53, 0xee, 0xfc, 0xb4, 0x1b, 0x13, 0x5e, 0xba, - 0x16, 0x7c, 0xc5, 0xf3, 0xe3, 0x6d, 0x07, 0x78, 0xf5, 0x2b, 0x21, 0x05, 0x88, 0x4c, 0xc0, - 0xa1, 0xe3, 0x36, 0x10, 0xf8, 0x1b, 0xd8, 0x17, 0xfb, 0x6a, 0x4e, 0xd8, 0xb3, 0x47, 0x2d, - 0x99, 0xbd, 0xbb, 0x5d, 0x37, 0x7d, 0xba, 0xf1, 0xe1, 0x7c, 0xc0, 0xc5, 0x54, 0x62, 0x7f, - 0xcf, 0x5a, 0x4a, 0x93, 0xcc, 0xf1, 0x1b, 0x34, 0xc8, 0xa6, 0x05, 0x4c, 0x55, 0x8b, 0x54, - 0x84, 0xd5, 0x77, 0xeb, 0xc0, 0x6d, 0x3a, 0x29, 0xbd, 0x75, 0x61, 0x09, 0x9a, 0x2c, 0xbb, - 0xf7, 0x18, 0x79, 0x34, 0x90, 0x24, 0xa5, 0x81, 0x70, 0x87, 0xc5, 0x02, 0x7c, 0xba, 0xd4, - 0x5e, 0x14, 0x8e, 0xe4, 0xed, 0xa2, 0x61, 0x6a, 0xb9, 0x6e, 0xb5, 0x4a, 0xb9, 0x01, 0x46, - 0xf4, 0xcf, 0xbc, 0x09, 0x2f, 0x27, 0x4b, 0xbd, 0x86, 0x7a, 0x10, 0xe1, 0xd4, 0xc8, 0xd9, - 0x20, 0x8d, 0x8a, 0x63, 0x00, 0x63, 0x44, 0xeb, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7, - 0xad, 0xb9, 0xd1, 0x01, 0x80, 0x63, 0x25, 0xc8, 0x12, 0xa6, 0xce, 0x1e, 0xbe, 0xfe, 0x7e, - 0x5f, 0x3c, 0xdb, 0x34, 0xea, 0x37, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x8c, 0x9a, 0xb6, - 0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x1b, 0xb4, 0xea, 0x56, - 0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xd6, 0x2e, 0xde, 0x1f, 0x9d, - 0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x66, 0x4e, 0x1e, 0x9f, 0x9d, 0xb8, 0xf2, 0x47, - 0x0c, 0x9a, 0xb6, 0xee, 0x3f, 0xfc, 0x7a, 0x57, 0x0d, 0x79, 0x70, 0x62, 0x27, 0xad, 0xb9, - 0xd1, 0x01, 0x61, 0x40, 0x02, 0x67, 0x2d, 0xd8, 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xd7, 0x2c, - 0xbb, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x01, - 0x80, 0x63, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a, - 0x37, 0xcd, 0x18, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0xa8, 0xd2, 0x07, 0x6d, 0x58, 0x32, - 0xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x57, 0x0d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x6f, 0x5c, - 0x1b, 0x95, 0xa8, 0xb3, 0xc5, 0xe9, 0x31, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93, - 0x85, 0x69, 0x31, 0xc1, 0xe1, 0x21, 0xc0, 0xe3, 0x44, 0x0a, 0x77, 0x6c, 0x5a, 0x17, 0x8d, - 0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xf4, 0x4b, 0x14, - 0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xb3, 0xc5, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c, - 0xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xd9, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xa1, 0xc0, - 0x02, 0x86, 0x6f, 0x5c, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xdd, - 0x19, 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x7c, 0x5b, 0x15, 0x89, 0x90, 0x83, 0x84, 0x6b, 0x54, - 0x0b, 0x75, 0x68, 0x52, 0x07, 0x6d, 0x58, 0x32, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed, 0x58, - 0x32, 0xe6, 0x4e, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x38, 0xd3, 0x05, 0x88, 0x92, - 0xa6, 0xaf, 0xdc, 0x1b, 0xb4, 0xcb, 0xf5, 0x68, 0x52, 0x07, 0x8c, 0x7b, 0x55, 0x09, 0x90, - 0x83, 0x84, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x3b, 0xd5, 0x09, 0x90, 0xa2, 0xc6, 0x0e, 0x7f, - 0x7c, 0x7a, 0x57, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0x0c, 0x7b, 0x74, 0x4b, - 0x14, 0x8b, 0x94, 0xaa, 0xb7, 0xcd, 0x18, 0x93, 0xa4, 0xca, 0x16, 0xae, 0xbf, 0xdd, 0x19, - 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0xeb, 0x35, 0xc9, - 0x10, 0x83, 0x65, 0x48, 0x12, 0xa6, 0xce, 0x1e, 0x9f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60, - 0x23, 0xc4, 0xeb, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xcf, 0x81, 0x10, 0xac, 0x74 -}; - -// clang-format off diff --git a/drivers/sensors/pmw33xx_common.c b/drivers/sensors/pmw33xx_common.c new file mode 100644 index 0000000000..538c40c462 --- /dev/null +++ b/drivers/sensors/pmw33xx_common.c @@ -0,0 +1,218 @@ +// Copyright 2022 Stefan Kerkmann (KarlK90) +// Copyright 2022 Ulrich Spörlein (@uqs) +// Copyright 2021 Alabastard (@Alabastard-64) +// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) +// Copyright 2019 Sunjun Kim +// Copyright 2020 Ploopy Corporation +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "debug.h" +#include "pmw33xx_common.h" +#include "print.h" +#include "string.h" +#include "wait.h" +#include "spi_master.h" +#include "progmem.h" + +extern const uint8_t pmw33xx_firmware_data[PMW33XX_FIRMWARE_LENGTH] PROGMEM; +extern const uint8_t pmw33xx_firmware_signature[3] PROGMEM; + +static const pin_t cs_pins[] = PMW33XX_CS_PINS; +static bool in_burst[sizeof(cs_pins) / sizeof(pin_t)] = {0}; + +const size_t pmw33xx_number_of_sensors = sizeof(cs_pins) / sizeof(pin_t); + +bool __attribute__((cold)) pmw33xx_upload_firmware(uint8_t sensor); +bool __attribute__((cold)) pmw33xx_check_signature(uint8_t sensor); + +void pmw33xx_set_cpi_all_sensors(uint16_t cpi) { + for (uint8_t sensor = 0; sensor < pmw33xx_number_of_sensors; sensor++) { + pmw33xx_set_cpi(sensor, cpi); + } +} + +bool pmw33xx_spi_start(uint8_t sensor) { + if (!spi_start(cs_pins[sensor], false, 3, PMW33XX_SPI_DIVISOR)) { + spi_stop(); + return false; + } + // tNCS-SCLK, 10ns + wait_us(1); + return true; +} + +bool pmw33xx_write(uint8_t sensor, uint8_t reg_addr, uint8_t data) { + if (!pmw33xx_spi_start(sensor)) { + return false; + } + + if (reg_addr != REG_Motion_Burst) { + in_burst[sensor] = false; + } + + // send address of the register, with MSBit = 1 to indicate it's a write + uint8_t command[2] = {reg_addr | 0x80, data}; + if (spi_transmit(command, sizeof(command)) != SPI_STATUS_SUCCESS) { + return false; + } + + // tSCLK-NCS for write operation is 35us + wait_us(35); + spi_stop(); + + // tSWW/tSWR (=18us) minus tSCLK-NCS. Could be shortened, but it looks like + // a safe lower bound + wait_us(145); + return true; +} + +uint8_t pmw33xx_read(uint8_t sensor, uint8_t reg_addr) { + if (!pmw33xx_spi_start(sensor)) { + return 0; + } + + // send adress of the register, with MSBit = 0 to indicate it's a read + spi_write(reg_addr & 0x7f); + // tSRAD (=160us) + wait_us(160); + uint8_t data = spi_read(); + + // tSCLK-NCS, 120ns + wait_us(1); + spi_stop(); + + // tSRW/tSRR (=20us) mins tSCLK-NCS + wait_us(19); + return data; +} + +bool pmw33xx_check_signature(uint8_t sensor) { + uint8_t signature_dump[3] = { + pmw33xx_read(sensor, REG_Product_ID), + pmw33xx_read(sensor, REG_Inverse_Product_ID), + pmw33xx_read(sensor, REG_SROM_ID), + }; + + return memcmp(pmw33xx_firmware_signature, signature_dump, sizeof(signature_dump)) == 0; +} + +bool pmw33xx_upload_firmware(uint8_t sensor) { + // Datasheet claims we need to disable REST mode first, but during startup + // it's already disabled and we're not turning it on ... + // pmw33xx_write(REG_Config2, 0x00); // disable REST mode + if (!pmw33xx_write(sensor, REG_SROM_Enable, 0x1d)) { + return false; + } + wait_ms(10); + pmw33xx_write(sensor, REG_SROM_Enable, 0x18); + + if (!pmw33xx_spi_start(sensor)) { + return false; + } + + spi_write(REG_SROM_Load_Burst | 0x80); + wait_us(15); + + for (size_t i = 0; i < PMW33XX_FIRMWARE_LENGTH; i++) { + spi_write(pgm_read_byte(pmw33xx_firmware_data + i)); + wait_us(15); + } + wait_us(200); + + pmw33xx_read(sensor, REG_SROM_ID); + pmw33xx_write(sensor, REG_Config2, 0x00); + + return true; +} + +bool pmw33xx_init(uint8_t sensor) { + if (sensor >= pmw33xx_number_of_sensors) { + return false; + } + spi_init(); + + // power up, need to first drive NCS high then low. the datasheet does not + // say for how long, 40us works well in practice. + if (!pmw33xx_spi_start(sensor)) { + return false; + } + wait_us(40); + spi_stop(); + wait_us(40); + + if (!pmw33xx_write(sensor, REG_Power_Up_Reset, 0x5a)) { + return false; + } + wait_ms(50); + + // read registers and discard + pmw33xx_read(sensor, REG_Motion); + pmw33xx_read(sensor, REG_Delta_X_L); + pmw33xx_read(sensor, REG_Delta_X_H); + pmw33xx_read(sensor, REG_Delta_Y_L); + pmw33xx_read(sensor, REG_Delta_Y_H); + + if (!pmw33xx_upload_firmware(sensor)) { + dprintf("PMW33XX (%d): firmware upload failed!\n", sensor); + return false; + } + + spi_stop(); + + wait_ms(10); + pmw33xx_set_cpi(sensor, PMW33XX_CPI); + + wait_ms(1); + + pmw33xx_write(sensor, REG_Config2, 0x00); + pmw33xx_write(sensor, REG_Angle_Tune, CONSTRAIN(ROTATIONAL_TRANSFORM_ANGLE, -127, 127)); + pmw33xx_write(sensor, REG_Lift_Config, PMW33XX_LIFTOFF_DISTANCE); + + if (!pmw33xx_check_signature(sensor)) { + dprintf("PMW33XX (%d): firmware signature verification failed!\n", sensor); + return false; + } + + return true; +} + +pmw33xx_report_t pmw33xx_read_burst(uint8_t sensor) { + pmw33xx_report_t report = {0}; + + if (sensor >= pmw33xx_number_of_sensors) { + return report; + } + + if (!in_burst[sensor]) { + dprintf("PMW33XX (%d): burst\n", sensor); + if (!pmw33xx_write(sensor, REG_Motion_Burst, 0x00)) { + return report; + } + in_burst[sensor] = true; + } + + if (!pmw33xx_spi_start(sensor)) { + return report; + } + + spi_write(REG_Motion_Burst); + wait_us(35); // waits for tSRAD_MOTBR + + spi_receive((uint8_t*)&report, sizeof(report)); + + // panic recovery, sometimes burst mode works weird. + if (report.motion.w & 0b111) { + in_burst[sensor] = false; + } + + spi_stop(); + + if (debug_config.mouse) { + dprintf("PMW33XX (%d): motion: 0x%x dx: %i dy: %i\n", sensor, report.motion.w, report.delta_x, report.delta_y); + } + + report.delta_x *= -1; + report.delta_y *= -1; + + return report; +} diff --git a/drivers/sensors/pmw33xx_common.h b/drivers/sensors/pmw33xx_common.h new file mode 100644 index 0000000000..181bea3d43 --- /dev/null +++ b/drivers/sensors/pmw33xx_common.h @@ -0,0 +1,145 @@ +// Copyright 2022 Stefan Kerkmann (KarlK90) +// Copyright 2022 Ulrich Spörlein (@uqs) +// Copyright 2021 Alabastard (@Alabastard-64) +// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) +// Copyright 2019 Sunjun Kim +// Copyright 2020 Ploopy Corporation +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "spi_master.h" +#include "util.h" + +#if defined(POINTING_DEVICE_DRIVER_pmw3360) +# include "pmw3360.h" +#elif defined(POINTING_DEVICE_DRIVER_pmw3389) +# include "pmw3389.h" +#endif + +typedef struct __attribute__((packed)) { + union { + struct { + bool capture_from_raw_data : 1; // FRAME_RData_1st + uint8_t operation_mode : 2; // OP_MODE + bool is_lifted : 1; // Lift_stat + bool raw_data_grab_is_raw_data : 1; // RData_1st + uint8_t _reserved : 2; // 1 + Reserved + bool is_motion : 1; // MOT + } b; + uint8_t w; + } motion; + uint8_t observation; + int16_t delta_x; // displacement on x directions. Unit: Count. (CPI * Count = Inch value) + int16_t delta_y; // displacement on y directions. +} pmw33xx_report_t; + +_Static_assert(sizeof(pmw33xx_report_t) == 6, "pmw33xx_report_t must be 6 bytes in size"); +_Static_assert(sizeof((pmw33xx_report_t){0}.motion) == 1, "pmw33xx_report_t.motion must be 1 byte in size"); + +#if !defined(PMW33XX_CLOCK_SPEED) +# define PMW33XX_CLOCK_SPEED 2000000 +#endif + +#if !defined(PMW33XX_SPI_DIVISOR) +# ifdef __AVR__ +# define PMW33XX_SPI_DIVISOR (F_CPU / PMW33XX_CLOCK_SPEED) +# else +# define PMW33XX_SPI_DIVISOR 64 +# endif +#endif + +#if !defined(PMW33XX_LIFTOFF_DISTANCE) +# define PMW33XX_LIFTOFF_DISTANCE 0x02 +#endif + +#if !defined(ROTATIONAL_TRANSFORM_ANGLE) +# define ROTATIONAL_TRANSFORM_ANGLE 0x00 +#endif + +// Support single and plural spellings +#ifndef PMW33XX_CS_PINS +# ifndef PMW33XX_CS_PIN +# error "No chip select pin defined -- missing PMW33XX_CS_PIN or PMW33XX_CS_PINS" +# else +# define PMW33XX_CS_PINS \ + { PMW33XX_CS_PIN } +# endif +#endif + +#if PMW33XX_CPI > PMW33XX_CPI_MAX || PMW33XX_CPI < PMW33XX_CPI_MIN || (PMW33XX_CPI % PMW33XX_CPI_STEP) != 0U +# pragma message "PMW33XX_CPI has to be in the range of " STR(PMW33XX_CPI_MAX) "-" STR(PMW33XX_CPI_MIN) " in increments of " STR(PMW33XX_CPI_STEP) ". But it is " STR(PMW33XX_CPI) "." +# error Use correct PMW33XX_CPI value. +#endif + +#define CONSTRAIN(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) + +/** + * @brief Initializes the given sensor so it is in a working state and ready to + * be polled for data. + * + * @param sensor Index of the sensors chip select pin + * @return true Initialization was a success + * @return false Initialization failed, do not proceed operation + */ +bool __attribute__((cold)) pmw33xx_init(uint8_t sensor); + +/** + * @brief Gets the currently set CPI value from the sensor. CPI is often + * refereed to as the sensors sensitivity. + * + * @param sensor Index of the sensors chip select pin + * @return uint16_t Current CPI value of the sensor + */ +uint16_t pmw33xx_get_cpi(uint8_t sensor); + +/** + * @brief Sets the given CPI value for the given PMW33XX sensor. CIP is often + * refereed to as the sensors sensitivity. Values outside of the allow range are + * constrained into legal values. + * + * @param sensor Index of the sensors chip select pin + * @param cpi CPI value to set, legal range depends on the PMW sensor type + */ +void pmw33xx_set_cpi(uint8_t sensor, uint16_t cpi); + +/** + * @brief Sets the given CPI value to all registered PMW33XX sensors. CPI is + * often refereed to as the sensors sensitivity. Values outside of the allow + * range are constrained into legal values. + * + * @param sensor Index of the sensors chip select pin + * @param cpi CPI value to set, legal range depends on the PMW sensor type + */ +void pmw33xx_set_cpi_all_sensors(uint16_t cpi); + +/** + * @brief Reads and clears the current delta, and motion register values on the + * given sensor. + * + * @param sensor Index of the sensors chip select pin + * @return pmw33xx_report_t Current values of the sensor, if errors occurred all + * fields are set to zero + */ +pmw33xx_report_t pmw33xx_read_burst(uint8_t sensor); + +/** + * @brief Read one byte of data from the given register on the sensor + * + * @param sensor Index of the sensors chip select pin + * @param reg_addr Register address to read from + * @return uint8_t + */ +uint8_t pmw33xx_read(uint8_t sensor, uint8_t reg_addr); + +/** + * @brief Writes one byte of data to the given register on the sensor + * + * @param sensor Index of the sensors chip select pin + * @param reg_addr Registers address to write to + * @param data Data to write to the register + * @return true Write was a success + * @return false Write failed, do not proceed operation + */ +bool pmw33xx_write(uint8_t sensor, uint8_t reg_addr, uint8_t data); diff --git a/keyboards/bastardkb/charybdis/3x5/config.h b/keyboards/bastardkb/charybdis/3x5/config.h index 89b896bc35..b12603fade 100644 --- a/keyboards/bastardkb/charybdis/3x5/config.h +++ b/keyboards/bastardkb/charybdis/3x5/config.h @@ -58,8 +58,8 @@ /* Set 0 if debouncing isn't needed. */ #define DEBOUNCE 5 -/* PMW3360 settings. */ -#define PMW3360_CS_PIN B0 +/* PMW33XX settings. */ +#define PMW33XX_CS_PIN B0 // Trackball angle adjustment. #define ROTATIONAL_TRANSFORM_ANGLE -25 diff --git a/keyboards/bastardkb/charybdis/3x5/keymaps/drashna/config.h b/keyboards/bastardkb/charybdis/3x5/keymaps/drashna/config.h index 0f08aee9ef..39204a3667 100644 --- a/keyboards/bastardkb/charybdis/3x5/keymaps/drashna/config.h +++ b/keyboards/bastardkb/charybdis/3x5/keymaps/drashna/config.h @@ -98,10 +98,8 @@ along with this program. If not, see . // #define EXTERNAL_EEPROM_ADDRESS_SIZE 2 /* pmw3360 config */ -#undef PMW3360_CS_PIN -#define PMW3360_CS_PIN B0 -#define PMW3360_SPI_MODE 3 -#define PMW3360_SPI_DIVISOR 64 +#undef PMW33XX_CS_PIN +#define PMW33XX_CS_PIN B0 #define CHARYBDIS_MINIMUM_DEFAULT_DPI 1200 #define CHARYBDIS_DEFAULT_DPI_CONFIG_STEP 400 diff --git a/keyboards/bastardkb/charybdis/4x6/config.h b/keyboards/bastardkb/charybdis/4x6/config.h index 423f12fdbe..6760129ef8 100644 --- a/keyboards/bastardkb/charybdis/4x6/config.h +++ b/keyboards/bastardkb/charybdis/4x6/config.h @@ -60,8 +60,8 @@ /* Set 0 if debouncing isn't needed */ #define DEBOUNCE 5 -/* PMW3360 settings. */ -#define PMW3360_CS_PIN B0 +/* PMW33XX settings. */ +#define PMW33XX_CS_PIN B0 #define RGB_DI_PIN D3 #define RGBLED_NUM 56 diff --git a/keyboards/bastardkb/charybdis/4x6/keymaps/drashna/config.h b/keyboards/bastardkb/charybdis/4x6/keymaps/drashna/config.h index 2b6e11ec61..63e67aa6d8 100644 --- a/keyboards/bastardkb/charybdis/4x6/keymaps/drashna/config.h +++ b/keyboards/bastardkb/charybdis/4x6/keymaps/drashna/config.h @@ -87,11 +87,9 @@ #define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN A4 #define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 64 -#undef PMW3360_CS_PIN -#define PMW3360_CS_PIN A15 // b14 -#define PMW3360_CS_MODE 3 -#define PMW3360_CS_DIVISOR 64 -#define PMW3360_LIFTOFF_DISTANCE 0b1111 +#undef PMW33XX_CS_PIN +#define PMW33XX_CS_PIN A15 // b14 +#define PMW33XX_LIFTOFF_DISTANCE 0b1111 #undef ROTATIONAL_TRANSFORM_ANGLE #define ROTATIONAL_TRANSFORM_ANGLE -65 diff --git a/keyboards/bbrfkr/dynamis/config.h b/keyboards/bbrfkr/dynamis/config.h index 0c11416612..abf4058e7b 100644 --- a/keyboards/bbrfkr/dynamis/config.h +++ b/keyboards/bbrfkr/dynamis/config.h @@ -52,5 +52,5 @@ #define ENCODERS_PAD_A { B7 } #define ENCODERS_PAD_B { E6 } -#define PMW3360_CS_PIN SPI_SS_PIN +#define PMW33XX_CS_PIN SPI_SS_PIN #define POINTING_DEVICE_INVERT_Y diff --git a/keyboards/handwired/tractyl_manuform/4x6_right/config.h b/keyboards/handwired/tractyl_manuform/4x6_right/config.h index ab46bc5276..5bfb17ee31 100644 --- a/keyboards/handwired/tractyl_manuform/4x6_right/config.h +++ b/keyboards/handwired/tractyl_manuform/4x6_right/config.h @@ -85,7 +85,7 @@ along with this program. If not, see . //#define NO_ACTION_TAPPING //#define NO_ACTION_ONESHOT -/* PMW3360 Settings */ -#define PMW3360_CS_PIN B0 +/* PMW33XX Settings */ +#define PMW33XX_CS_PIN B0 #define POINTING_DEVICE_RIGHT diff --git a/keyboards/handwired/tractyl_manuform/4x6_right/info.json b/keyboards/handwired/tractyl_manuform/4x6_right/info.json index e3da8b444c..3d428260ad 100644 --- a/keyboards/handwired/tractyl_manuform/4x6_right/info.json +++ b/keyboards/handwired/tractyl_manuform/4x6_right/info.json @@ -3,7 +3,7 @@ "url": "", "maintainer": "drashna", "layouts": { - "LAYOUT_5x6_right": { + "LAYOUT_4x6_right": { "layout": [ {"label":"L00", "x":0, "y":0}, {"label":"L01", "x":1, "y":0}, diff --git a/keyboards/handwired/tractyl_manuform/5x6_right/elite_c/config.h b/keyboards/handwired/tractyl_manuform/5x6_right/elite_c/config.h index d8d36e824c..ab72957b5c 100644 --- a/keyboards/handwired/tractyl_manuform/5x6_right/elite_c/config.h +++ b/keyboards/handwired/tractyl_manuform/5x6_right/elite_c/config.h @@ -47,5 +47,5 @@ along with this program. If not, see . #define ENCODERS_PAD_B \ { C7 } -/* PMW3360 Settings */ -#define PMW3360_CS_PIN B6 +/* PMW33XX Settings */ +#define PMW33XX_CS_PIN B6 diff --git a/keyboards/handwired/tractyl_manuform/5x6_right/f303/config.h b/keyboards/handwired/tractyl_manuform/5x6_right/f303/config.h index f9a44587b0..809acdcd94 100644 --- a/keyboards/handwired/tractyl_manuform/5x6_right/f303/config.h +++ b/keyboards/handwired/tractyl_manuform/5x6_right/f303/config.h @@ -99,6 +99,5 @@ along with this program. If not, see . // #define DEBUG_EEPROM_OUTPUT /* pmw3360 config */ -#define PMW3360_CS_PIN B9 -#define PMW3360_SPI_MODE 3 -#define PMW3360_SPI_DIVISOR 8 +#define PMW33XX_CS_PIN B9 +#define PMW33XX_SPI_DIVISOR 8 diff --git a/keyboards/handwired/tractyl_manuform/5x6_right/f411/config.h b/keyboards/handwired/tractyl_manuform/5x6_right/f411/config.h index 5f0350810c..0eb5b2a217 100644 --- a/keyboards/handwired/tractyl_manuform/5x6_right/f411/config.h +++ b/keyboards/handwired/tractyl_manuform/5x6_right/f411/config.h @@ -102,7 +102,4 @@ along with this program. If not, see . #define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 64 /* pmw3360 config */ -#define PMW3360_CS_PIN B0 -#define PMW3360_SPI_MODE 3 -#define PMW3360_SPI_DIVISOR 64 -#define PMW3360_FIRMWARE_UPLOAD_FAST +#define PMW33XX_CS_PIN B0 diff --git a/keyboards/handwired/tractyl_manuform/5x6_right/teensy2pp/config.h b/keyboards/handwired/tractyl_manuform/5x6_right/teensy2pp/config.h index 442d474920..6eb3186332 100644 --- a/keyboards/handwired/tractyl_manuform/5x6_right/teensy2pp/config.h +++ b/keyboards/handwired/tractyl_manuform/5x6_right/teensy2pp/config.h @@ -51,5 +51,5 @@ along with this program. If not, see . #define ENCODERS_PAD_B \ { D4 } -/* PMW3360 Settings */ -#define PMW3360_CS_PIN B0 +/* PMW33XX Settings */ +#define PMW33XX_CS_PIN B0 diff --git a/keyboards/oddball/config.h b/keyboards/oddball/config.h index cfb134c4e3..1aaead0cae 100644 --- a/keyboards/oddball/config.h +++ b/keyboards/oddball/config.h @@ -56,4 +56,4 @@ // #define BOOTMAGIC_LITE_COLUMN 0 #define ADNS9800_CS_PIN SPI_SS_PIN -#define PMW3360_CS_PIN SPI_SS_PIN +#define PMW33XX_CS_PIN SPI_SS_PIN diff --git a/keyboards/ploopyco/mouse/config.h b/keyboards/ploopyco/mouse/config.h index 98fc81bb05..a3e4b76893 100644 --- a/keyboards/ploopyco/mouse/config.h +++ b/keyboards/ploopyco/mouse/config.h @@ -77,5 +77,5 @@ // #define DEBUG_LED_PIN F7 -/* PMW3360 Settings */ -#define PMW3360_CS_PIN B0 +/* PMW33XX Settings */ +#define PMW33XX_CS_PIN B0 diff --git a/keyboards/ploopyco/trackball/config.h b/keyboards/ploopyco/trackball/config.h index dd068e4838..5c151c2e73 100644 --- a/keyboards/ploopyco/trackball/config.h +++ b/keyboards/ploopyco/trackball/config.h @@ -53,6 +53,6 @@ // If board has a debug LED, you can enable it by defining this // #define DEBUG_LED_PIN F7 -/* PMW3360 Settings */ -#define PMW3360_CS_PIN B0 +/* PMW33XX Settings */ +#define PMW33XX_CS_PIN B0 #define POINTING_DEVICE_INVERT_Y diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h index 8225e55aa2..a8e8e75e87 100644 --- a/quantum/pointing_device.h +++ b/quantum/pointing_device.h @@ -46,12 +46,9 @@ along with this program. If not, see . # ifdef PIMORONI_TRACKBALL_ROTATE # define POINTING_DEVICE_ROTATION_90 # endif -#elif defined(POINTING_DEVICE_DRIVER_pmw3360) +#elif defined(POINTING_DEVICE_DRIVER_pmw3360) || defined(POINTING_DEVICE_DRIVER_pmw3389) # include "spi_master.h" -# include "drivers/sensors/pmw3360.h" -#elif defined(POINTING_DEVICE_DRIVER_pmw3389) -# include "spi_master.h" -# include "drivers/sensors/pmw3389.h" +# include "drivers/sensors/pmw33xx_common.h" #else void pointing_device_driver_init(void); report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report); diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c index 8f510b3a98..b7e98e897e 100644 --- a/quantum/pointing_device_drivers.c +++ b/quantum/pointing_device_drivers.c @@ -257,81 +257,48 @@ const pointing_device_driver_t pointing_device_driver = { }; // clang-format on -#elif defined(POINTING_DEVICE_DRIVER_pmw3360) -static void pmw3360_device_init(void) { - pmw3360_init(0); +#elif defined(POINTING_DEVICE_DRIVER_pmw3360) || defined(POINTING_DEVICE_DRIVER_pmw3389) +static void pmw33xx_init_wrapper(void) { + pmw33xx_init(0); } -report_mouse_t pmw3360_get_report(report_mouse_t mouse_report) { - report_pmw3360_t data = pmw3360_read_burst(0); - static uint16_t MotionStart = 0; // Timer for accel, 0 is resting state - - if (data.isOnSurface && data.isMotion) { - // Reset timer if stopped moving - if (!data.isMotion) { - if (MotionStart != 0) MotionStart = 0; - return mouse_report; - } - - // Set timer if new motion - if ((MotionStart == 0) && data.isMotion) { -# ifdef CONSOLE_ENABLE - if (debug_mouse) dprintf("Starting motion.\n"); -# endif - MotionStart = timer_read(); - } - mouse_report.x = CONSTRAIN_HID_XY(data.dx); - mouse_report.y = CONSTRAIN_HID_XY(data.dy); - } - - return mouse_report; +static void pmw33xx_set_cpi_wrapper(uint16_t cpi) { + pmw33xx_set_cpi(0, cpi); } -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = pmw3360_device_init, - .get_report = pmw3360_get_report, - .set_cpi = pmw3360_set_cpi, - .get_cpi = pmw3360_get_cpi -}; -// clang-format on - -#elif defined(POINTING_DEVICE_DRIVER_pmw3389) -static void pmw3389_device_init(void) { - pmw3389_init(); +static uint16_t pmw33xx_get_cpi_wrapper(void) { + return pmw33xx_get_cpi(0); } -report_mouse_t pmw3389_get_report(report_mouse_t mouse_report) { - report_pmw3389_t data = pmw3389_read_burst(); - static uint16_t MotionStart = 0; // Timer for accel, 0 is resting state +report_mouse_t pmw33xx_get_report(report_mouse_t mouse_report) { + pmw33xx_report_t report = pmw33xx_read_burst(0); + static bool in_motion = false; - if (data.isOnSurface && data.isMotion) { - // Reset timer if stopped moving - if (!data.isMotion) { - if (MotionStart != 0) MotionStart = 0; - return mouse_report; - } + if (report.motion.b.is_lifted) { + return mouse_report; + } - // Set timer if new motion - if ((MotionStart == 0) && data.isMotion) { -# ifdef CONSOLE_ENABLE - if (debug_mouse) dprintf("Starting motion.\n"); -# endif - MotionStart = timer_read(); - } - mouse_report.x = CONSTRAIN_HID_XY(data.dx); - mouse_report.y = CONSTRAIN_HID_XY(data.dy); + if (!report.motion.b.is_motion) { + in_motion = false; + return mouse_report; + } + + if (!in_motion) { + in_motion = true; + dprintf("PWM3360 (0): starting motion\n"); } + mouse_report.x = CONSTRAIN_HID_XY(report.delta_x); + mouse_report.y = CONSTRAIN_HID_XY(report.delta_y); return mouse_report; } // clang-format off const pointing_device_driver_t pointing_device_driver = { - .init = pmw3389_device_init, - .get_report = pmw3389_get_report, - .set_cpi = pmw3389_set_cpi, - .get_cpi = pmw3389_get_cpi + .init = pmw33xx_init_wrapper, + .get_report = pmw33xx_get_report, + .set_cpi = pmw33xx_set_cpi_wrapper, + .get_cpi = pmw33xx_get_cpi_wrapper }; // clang-format on -- cgit v1.2.3 From 300dab7962ba50dcb4c550c91097573fa09b8dea Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Thu, 14 Jul 2022 19:22:53 +0800 Subject: [Code] Add solid reactive gradient mode (#17228) --- docs/feature_rgb_matrix.md | 10 ++++++++++ quantum/rgb_matrix/animations/solid_reactive_anim.h | 3 +++ quantum/rgb_matrix/animations/solid_reactive_cross.h | 3 +++ quantum/rgb_matrix/animations/solid_reactive_nexus.h | 3 +++ quantum/rgb_matrix/animations/solid_reactive_simple_anim.h | 3 +++ quantum/rgb_matrix/animations/solid_reactive_wide.h | 3 +++ 6 files changed, 25 insertions(+) (limited to 'quantum') diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md index 2debfd1c2f..f9ab395488 100644 --- a/docs/feature_rgb_matrix.md +++ b/docs/feature_rgb_matrix.md @@ -688,6 +688,16 @@ Remove the spread effect entirely. #define RGB_MATRIX_TYPING_HEATMAP_SLIM ``` +### RGB Matrix Effect Solid Reactive :id=rgb-matrix-effect-solid-reactive + +Solid reactive effects will pulse RGB light on key presses with user configurable hues. To enable gradient mode that will automatically change reactive color, add the following define: + +```c +#define RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE +``` + +Gradient mode will loop through the color wheel hues over time and its duration can be controlled with the effect speed keycodes (`RGB_SPI`/`RGB_SPD`). + ## Custom RGB Matrix Effects :id=custom-rgb-matrix-effects By setting `RGB_MATRIX_CUSTOM_USER = yes` in `rules.mk`, new effects can be defined directly from your keymap or userspace, without having to edit any QMK core files. To declare new effects, create a `rgb_matrix_user.inc` file in the user keymap directory or userspace folder. diff --git a/quantum/rgb_matrix/animations/solid_reactive_anim.h b/quantum/rgb_matrix/animations/solid_reactive_anim.h index d3a7ebbdf7..052bfb22fd 100644 --- a/quantum/rgb_matrix/animations/solid_reactive_anim.h +++ b/quantum/rgb_matrix/animations/solid_reactive_anim.h @@ -4,6 +4,9 @@ RGB_MATRIX_EFFECT(SOLID_REACTIVE) # ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS static HSV SOLID_REACTIVE_math(HSV hsv, uint16_t offset) { +# ifdef RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE + hsv.h = scale16by8(g_rgb_timer, add8(rgb_matrix_config.speed, 1) >> 6); +# endif hsv.h += qsub8(130, offset); return hsv; } diff --git a/quantum/rgb_matrix/animations/solid_reactive_cross.h b/quantum/rgb_matrix/animations/solid_reactive_cross.h index 043a369b73..9e5703a0ea 100644 --- a/quantum/rgb_matrix/animations/solid_reactive_cross.h +++ b/quantum/rgb_matrix/animations/solid_reactive_cross.h @@ -19,6 +19,9 @@ static HSV SOLID_REACTIVE_CROSS_math(HSV hsv, int16_t dx, int16_t dy, uint8_t di dy = dy * 16 > 255 ? 255 : dy * 16; effect += dx > dy ? dy : dx; if (effect > 255) effect = 255; +# ifdef RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE + hsv.h = scale16by8(g_rgb_timer, add8(rgb_matrix_config.speed, 1) >> 6); +# endif hsv.v = qadd8(hsv.v, 255 - effect); return hsv; } diff --git a/quantum/rgb_matrix/animations/solid_reactive_nexus.h b/quantum/rgb_matrix/animations/solid_reactive_nexus.h index 8d62a49fea..64f5064cf9 100644 --- a/quantum/rgb_matrix/animations/solid_reactive_nexus.h +++ b/quantum/rgb_matrix/animations/solid_reactive_nexus.h @@ -16,6 +16,9 @@ static HSV SOLID_REACTIVE_NEXUS_math(HSV hsv, int16_t dx, int16_t dy, uint8_t di if (effect > 255) effect = 255; if (dist > 72) effect = 255; if ((dx > 8 || dx < -8) && (dy > 8 || dy < -8)) effect = 255; +# ifdef RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE + hsv.h = scale16by8(g_rgb_timer, add8(rgb_matrix_config.speed, 1) >> 6); +# endif hsv.v = qadd8(hsv.v, 255 - effect); hsv.h = rgb_matrix_config.hsv.h + dy / 4; return hsv; diff --git a/quantum/rgb_matrix/animations/solid_reactive_simple_anim.h b/quantum/rgb_matrix/animations/solid_reactive_simple_anim.h index 0d0a424cf3..bd3ce0817d 100644 --- a/quantum/rgb_matrix/animations/solid_reactive_simple_anim.h +++ b/quantum/rgb_matrix/animations/solid_reactive_simple_anim.h @@ -4,6 +4,9 @@ RGB_MATRIX_EFFECT(SOLID_REACTIVE_SIMPLE) # ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS static HSV SOLID_REACTIVE_SIMPLE_math(HSV hsv, uint16_t offset) { +# ifdef RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE + hsv.h = scale16by8(g_rgb_timer, add8(rgb_matrix_config.speed, 1) >> 6); +# endif hsv.v = scale8(255 - offset, hsv.v); return hsv; } diff --git a/quantum/rgb_matrix/animations/solid_reactive_wide.h b/quantum/rgb_matrix/animations/solid_reactive_wide.h index 7598796316..24fedc2020 100644 --- a/quantum/rgb_matrix/animations/solid_reactive_wide.h +++ b/quantum/rgb_matrix/animations/solid_reactive_wide.h @@ -14,6 +14,9 @@ RGB_MATRIX_EFFECT(SOLID_REACTIVE_MULTIWIDE) static HSV SOLID_REACTIVE_WIDE_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint16_t tick) { uint16_t effect = tick + dist * 5; if (effect > 255) effect = 255; +# ifdef RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE + hsv.h = scale16by8(g_rgb_timer, add8(rgb_matrix_config.speed, 1) >> 6); +# endif hsv.v = qadd8(hsv.v, 255 - effect); return hsv; } -- cgit v1.2.3 From 1862ac54540573843055b3b609b9f40d9f7dc21f Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Thu, 14 Jul 2022 19:36:51 +0800 Subject: Fix the use of LED limits (#17678) --- quantum/rgb_matrix/animations/raindrops_anim.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'quantum') diff --git a/quantum/rgb_matrix/animations/raindrops_anim.h b/quantum/rgb_matrix/animations/raindrops_anim.h index 2d4b53b7b0..a508e51183 100644 --- a/quantum/rgb_matrix/animations/raindrops_anim.h +++ b/quantum/rgb_matrix/animations/raindrops_anim.h @@ -14,23 +14,22 @@ static void raindrops_set_color(int i, effect_params_t* params) { deltaH += 256; } - hsv.h = rgb_matrix_config.hsv.h + (deltaH * (rand() & 0x03)); + hsv.h = rgb_matrix_config.hsv.h + (deltaH * (random8() & 0x03)); RGB rgb = rgb_matrix_hsv_to_rgb(hsv); rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); } bool RAINDROPS(effect_params_t* params) { + RGB_MATRIX_USE_LIMITS(led_min, led_max); if (!params->init) { // Change one LED every tick, make sure speed is not 0 if (scale16by8(g_rgb_timer, qadd8(rgb_matrix_config.speed, 16)) % 10 == 0) { - raindrops_set_color(rand() % DRIVER_LED_TOTAL, params); + raindrops_set_color(random8() % DRIVER_LED_TOTAL, params); + } + } else { + for (int i = led_min; i < led_max; i++) { + raindrops_set_color(i, params); } - return false; - } - - RGB_MATRIX_USE_LIMITS(led_min, led_max); - for (int i = led_min; i < led_max; i++) { - raindrops_set_color(i, params); } return rgb_matrix_check_finished_leds(led_max); } -- cgit v1.2.3 From 2f73e6583766bad3996f15955214800b1ad3b833 Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Thu, 14 Jul 2022 19:37:47 +0800 Subject: Add LED limit call (#17679) --- quantum/rgb_matrix/animations/pixel_rain_anim.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'quantum') diff --git a/quantum/rgb_matrix/animations/pixel_rain_anim.h b/quantum/rgb_matrix/animations/pixel_rain_anim.h index 03488b43df..ce2528a26d 100644 --- a/quantum/rgb_matrix/animations/pixel_rain_anim.h +++ b/quantum/rgb_matrix/animations/pixel_rain_anim.h @@ -20,17 +20,14 @@ RGB_MATRIX_EFFECT(PIXEL_RAIN) static bool PIXEL_RAIN(effect_params_t* params) { static uint32_t wait_timer = 0; - if (wait_timer > g_rgb_timer) { - return false; - } inline uint32_t interval(void) { return 500 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16); } - bool rain_pixel(uint8_t i, effect_params_t * params, bool off) { + void rain_pixel(uint8_t i, effect_params_t * params, bool off) { if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) { - return true; + return; } if (off) { rgb_matrix_set_color(i, 0, 0, 0); @@ -40,10 +37,13 @@ static bool PIXEL_RAIN(effect_params_t* params) { rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); } wait_timer = g_rgb_timer + interval(); - return false; } - return rain_pixel(mod8(random8(), DRIVER_LED_TOTAL), params, random8() & 2); + RGB_MATRIX_USE_LIMITS(led_min, led_max); + if (g_rgb_timer > wait_timer) { + rain_pixel(mod8(random8(), DRIVER_LED_TOTAL), params, random8() & 2); + } + return rgb_matrix_check_finished_leds(led_max); } # endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS -- cgit v1.2.3 From 42eff8c3726517304ad479f3e760dc34428b4f9f Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Mon, 18 Jul 2022 11:55:27 +0100 Subject: Allow dynamic keymap to compile without via.h (#17703) --- quantum/dynamic_keymap.c | 15 ++++++++------- quantum/via.h | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'quantum') diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index cbe9f13940..e80dd6d534 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c @@ -19,7 +19,13 @@ #include "progmem.h" // to read default from flash #include "quantum.h" // for send_string() #include "dynamic_keymap.h" -#include "via.h" // for default VIA_EEPROM_ADDR_END + +#ifdef VIA_ENABLE +# include "via.h" // for VIA_EEPROM_CONFIG_END +# define DYNAMIC_KEYMAP_EEPROM_START (VIA_EEPROM_CONFIG_END) +#else +# define DYNAMIC_KEYMAP_EEPROM_START (EECONFIG_SIZE) +#endif #ifdef ENCODER_ENABLE # include "encoder.h" @@ -55,13 +61,8 @@ #endif // If DYNAMIC_KEYMAP_EEPROM_ADDR not explicitly defined in config.h, -// default it start after VIA_EEPROM_CUSTOM_ADDR+VIA_EEPROM_CUSTOM_SIZE #ifndef DYNAMIC_KEYMAP_EEPROM_ADDR -# ifdef VIA_EEPROM_CUSTOM_CONFIG_ADDR -# define DYNAMIC_KEYMAP_EEPROM_ADDR (VIA_EEPROM_CUSTOM_CONFIG_ADDR + VIA_EEPROM_CUSTOM_CONFIG_SIZE) -# else -# error DYNAMIC_KEYMAP_EEPROM_ADDR not defined -# endif +# define DYNAMIC_KEYMAP_EEPROM_ADDR DYNAMIC_KEYMAP_EEPROM_START #endif // Dynamic encoders starts after dynamic keymaps diff --git a/quantum/via.h b/quantum/via.h index ac29a58902..31d9c21af4 100644 --- a/quantum/via.h +++ b/quantum/via.h @@ -54,6 +54,8 @@ # define VIA_EEPROM_CUSTOM_CONFIG_SIZE 0 #endif +#define VIA_EEPROM_CONFIG_END (VIA_EEPROM_CUSTOM_CONFIG_ADDR + VIA_EEPROM_CUSTOM_CONFIG_SIZE) + // This is changed only when the command IDs change, // so VIA Configurator can detect compatible firmware. #define VIA_PROTOCOL_VERSION 0x0009 -- cgit v1.2.3 From 12eb6444c67456d522c815120de8eed431ead2f8 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Tue, 19 Jul 2022 17:46:22 -0700 Subject: Add support for PAW3204 Optical Sensor (#17669) Co-authored-by: gompa Co-authored-by: Stefan Kerkmann --- builddefs/common_features.mk | 2 +- docs/feature_pointing_device.md | 18 ++++ drivers/sensors/paw3204.c | 172 ++++++++++++++++++++++++++++++++++++++ drivers/sensors/paw3204.h | 68 +++++++++++++++ quantum/pointing_device.h | 2 + quantum/pointing_device_drivers.c | 21 +++++ 6 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 drivers/sensors/paw3204.c create mode 100644 drivers/sensors/paw3204.h (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index d7a00ba944..9ee51149ef 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -126,7 +126,7 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes) SRC += $(QUANTUM_DIR)/mousekey.c endif -VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi pmw3360 pmw3389 pimoroni_trackball custom +VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3360 pmw3389 pimoroni_trackball custom ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),) $(call CATASTROPHIC_ERROR,Invalid POINTING_DEVICE_DRIVER,POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type) diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md index 6343ed073d..f0463a131d 100644 --- a/docs/feature_pointing_device.md +++ b/docs/feature_pointing_device.md @@ -136,6 +136,24 @@ Also see the `POINTING_DEVICE_TASK_THROTTLE_MS`, which defaults to 10ms when usi **`POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE`** is not specific to Cirque trackpad; any pointing device with a lift/contact status can integrate this gesture into its driver. e.g. PMW3360 can use Lift_Stat from Motion register. Note that `POINTING_DEVICE_MOTION_PIN` cannot be used with this feature; continuous polling of `pointing_device_get_report()` is needed to generate glide reports. +### PAW 3204 Sensor + +To use the paw 3204 sensor, add this to your `rules.mk` + +```make +POINTING_DEVICE_DRIVER = paw3204 +``` + +The paw 3204 sensor uses a serial type protocol for communication, and requires an additional light source. + +| Setting | Description | +|--------------------|---------------------------------------------------------------------| +|`PAW3204_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. | +|`PAW3204_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. | + +The CPI range is 400-1600, with supported values of (400, 500, 600, 800, 1000, 1200 and 1600). Defaults to 1000 CPI. + + ### Pimoroni Trackball To use the Pimoroni Trackball module, add this to your `rules.mk`: diff --git a/drivers/sensors/paw3204.c b/drivers/sensors/paw3204.c new file mode 100644 index 0000000000..a13753dd6f --- /dev/null +++ b/drivers/sensors/paw3204.c @@ -0,0 +1,172 @@ +/* Copyright 2021 Gompa (@Gompa) + * + * 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 . + */ + +// https://github.com/shinoaliceKabocha/choco60_track/tree/master/keymaps/default + +#include "paw3204.h" +#include "wait.h" +#include "debug.h" +#include "gpio.h" + +#define REG_PID1 0x00 +#define REG_PID2 0x01 +#define REG_STAT 0x02 +#define REG_X 0x03 +#define REG_Y 0x04 + +#define REG_SETUP 0x06 +#define REG_IMGQUAL 0x07 +#define REG_IMGREC 0x0E +#define REG_IMGTRASH 0x0D + +#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) + +// CPI values +enum cpi_values { + CPI400, // 0b000 + CPI500, // 0b001 + CPI600, // 0b010 + CPI800, // 0b011 + CPI1000, // 0b100 + CPI1200, // 0b101 + CPI1600, // 0b110 +}; + +uint8_t paw3204_serial_read(void); +void paw3204_serial_write(uint8_t reg_addr); +uint8_t paw3204_read_reg(uint8_t reg_addr); +void paw3204_write_reg(uint8_t reg_addr, uint8_t data); + +void paw3204_init(void) { + setPinOutput(PAW3204_SCLK_PIN); // setclockpin to output + setPinInputHigh(PAW3204_SDIO_PIN); // set datapin input high + + paw3204_write_reg(REG_SETUP, 0x86); // reset sensor and set 1600cpi + wait_us(5); + + paw3204_read_reg(0x00); // read id + paw3204_read_reg(0x01); // read id2 + // PAW3204_write_reg(REG_SETUP,0x06); // dont reset sensor and set cpi 1600 + paw3204_write_reg(REG_IMGTRASH, 0x32); // write image trashhold +} + +uint8_t paw3204_serial_read(void) { + setPinInput(PAW3204_SDIO_PIN); + uint8_t byte = 0; + + for (uint8_t i = 0; i < 8; ++i) { + writePinLow(PAW3204_SCLK_PIN); + wait_us(1); + + byte = (byte << 1) | readPin(PAW3204_SDIO_PIN); + + writePinHigh(PAW3204_SCLK_PIN); + wait_us(1); + } + + return byte; +} + +void paw3204_serial_write(uint8_t data) { + writePinLow(PAW3204_SDIO_PIN); + setPinOutput(PAW3204_SDIO_PIN); + + for (int8_t b = 7; b >= 0; b--) { + writePinLow(PAW3204_SCLK_PIN); + if (data & (1 << b)) { + writePinHigh(PAW3204_SDIO_PIN); + } else { + writePinLow(PAW3204_SDIO_PIN); + } + writePinHigh(PAW3204_SCLK_PIN); + } + + wait_us(4); +} + +report_paw3204_t paw3204_read(void) { + report_paw3204_t data = {0}; + + data.isMotion = paw3204_read_reg(REG_STAT) & (1 << 7); // check for motion only (bit 7 in field) + data.x = (int8_t)paw3204_read_reg(REG_X); + data.y = (int8_t)paw3204_read_reg(REG_Y); + + return data; +} + +void paw3204_write_reg(uint8_t reg_addr, uint8_t data) { + paw3204_serial_write(0b10000000 | reg_addr); + paw3204_serial_write(data); +} + +uint8_t paw3204_read_reg(uint8_t reg_addr) { + paw3204_serial_write(reg_addr); + wait_us(5); + return paw3204_serial_read(); +} + +void paw3204_set_cpi(uint16_t cpi) { + uint8_t cpival = CPI1000; + if (cpi <= 450) { + cpival = CPI400; + } else if (cpi <= 550) { + cpival = CPI500; + } else if (cpi <= 700) { + cpival = CPI600; + } else if (cpi <= 900) { + cpival = CPI800; + } else if (cpi <= 1100) { + cpival = CPI1000; + } else if (cpi <= 1400) { + cpival = CPI1200; + } else if (cpi > 1400) { + cpival = CPI1600; + } + paw3204_write_reg(REG_SETUP, cpival); +} + +uint16_t paw3204_get_cpi(void) { + uint16_t cpival = 1000; + + switch (paw3204_read_reg(REG_SETUP) & 0b111) { + case CPI400: + cpival = 400; + break; + case CPI500: + cpival = 500; + break; + case CPI600: + cpival = 600; + break; + case CPI800: + cpival = 800; + break; + case CPI1000: + cpival = 1000; + break; + case CPI1200: + cpival = 1200; + break; + case CPI1600: + cpival = 1600; + break; + } + return cpival; +} + +uint8_t read_pid_paw3204(void) { + return paw3204_read_reg(REG_PID1); +} diff --git a/drivers/sensors/paw3204.h b/drivers/sensors/paw3204.h new file mode 100644 index 0000000000..bf6dbd04a0 --- /dev/null +++ b/drivers/sensors/paw3204.h @@ -0,0 +1,68 @@ +/* Copyright 2021 Gompa (@Gompa) + * + * 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 . + */ + +#pragma once + +#include +#include + +#ifndef PAW3204_SCLK_PIN +# error "No clock pin defined -- missing PAW3204_SCLK_PIN" +#endif +#ifndef PAW3204_SDIO_PIN +# error "No data pin defined -- missing PAW3204_SDIO_PIN" +#endif + +typedef struct { + int16_t x; + int16_t y; + bool isMotion; +} report_paw3204_t; + +/** + * @brief Initializes the sensor so it is in a working state and ready to + * be polled for data. + * + * @return true Initialization was a success + * @return false Initialization failed, do not proceed operation + */ +void paw3204_init(void); + +/** + * @brief Reads and clears the current delta, and motion register values on the + * given sensor. + * + * @return pmw33xx_report_t Current values of the sensor, if errors occurred all + * fields are set to zero + */ + +report_paw3204_t paw3204_read(void); +/** + * @brief Sets the given CPI value the sensor. CPI is often refereed to + * as the sensors sensitivity. Values outside of the allowed range are + * constrained into legal values. + * + * @param cpi CPI value to set + */ +void paw3204_set_cpi(uint16_t cpi); + +/** + * @brief Gets the currently set CPI value from the sensor. CPI is often + * refereed to as the sensors sensitivity. + * + * @return uint16_t Current CPI value of the sensor + */ +uint16_t paw3204_get_cpi(void); diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h index a8e8e75e87..77db5471ea 100644 --- a/quantum/pointing_device.h +++ b/quantum/pointing_device.h @@ -33,6 +33,8 @@ along with this program. If not, see . # include "drivers/sensors/cirque_pinnacle.h" # include "drivers/sensors/cirque_pinnacle_gestures.h" # include "pointing_device_gestures.h" +#elif defined(POINTING_DEVICE_DRIVER_paw3204) +# include "drivers/sensors/paw3204.h" #elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) # include "i2c_master.h" # include "drivers/sensors/pimoroni_trackball.h" diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c index b7e98e897e..d0b545d22d 100644 --- a/quantum/pointing_device_drivers.c +++ b/quantum/pointing_device_drivers.c @@ -26,6 +26,7 @@ #define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt))) // get_report functions should probably be moved to their respective drivers. + #if defined(POINTING_DEVICE_DRIVER_adns5050) report_mouse_t adns5050_get_report(report_mouse_t mouse_report) { report_adns5050_t data = adns5050_read_burst(); @@ -198,7 +199,27 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = cirque_pinnacle_get_cpi }; // clang-format on +#elif defined(POINTING_DEVICE_DRIVER_paw3204) + +report_mouse_t paw3204_get_report(report_mouse_t mouse_report) { + report_paw3204_t data = paw3204_read(); + if (data.isMotion) { +# ifdef CONSOLE_ENABLE + dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y); +# endif + + mouse_report.x = data.x; + mouse_report.y = data.y; + } + return mouse_report; +} +const pointing_device_driver_t pointing_device_driver = { + .init = paw3204_init, + .get_report = paw3204_get_report, + .set_cpi = paw3204_set_cpi, + .get_cpi = paw3204_get_cpi, +}; #elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) mouse_xy_report_t pimoroni_trackball_adapt_values(clamp_range_t* offset) { -- cgit v1.2.3 From ee17ffadea41241fc2b397e0bbea8903591dd21c Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Wed, 20 Jul 2022 09:32:00 -0700 Subject: Move Pointing Device code to a subdirectory (#17684) --- builddefs/common_features.mk | 9 +- quantum/pointing_device.c | 470 --------------------- quantum/pointing_device.h | 117 ----- quantum/pointing_device/pointing_device.c | 470 +++++++++++++++++++++ quantum/pointing_device/pointing_device.h | 117 +++++ quantum/pointing_device/pointing_device_drivers.c | 345 +++++++++++++++ quantum/pointing_device/pointing_device_gestures.c | 133 ++++++ quantum/pointing_device/pointing_device_gestures.h | 58 +++ quantum/pointing_device_drivers.c | 345 --------------- quantum/pointing_device_gestures.c | 133 ------ quantum/pointing_device_gestures.h | 58 --- 11 files changed, 1128 insertions(+), 1127 deletions(-) delete mode 100644 quantum/pointing_device.c delete mode 100644 quantum/pointing_device.h create mode 100644 quantum/pointing_device/pointing_device.c create mode 100644 quantum/pointing_device/pointing_device.h create mode 100644 quantum/pointing_device/pointing_device_drivers.c create mode 100644 quantum/pointing_device/pointing_device_gestures.c create mode 100644 quantum/pointing_device/pointing_device_gestures.h delete mode 100644 quantum/pointing_device_drivers.c delete mode 100644 quantum/pointing_device_gestures.c delete mode 100644 quantum/pointing_device_gestures.h (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 9ee51149ef..8d31f694a7 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -133,8 +133,9 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) else OPT_DEFS += -DPOINTING_DEVICE_ENABLE MOUSE_ENABLE := yes - SRC += $(QUANTUM_DIR)/pointing_device.c - SRC += $(QUANTUM_DIR)/pointing_device_drivers.c + VPATH += $(QUANTUM_DIR)/pointing_device + SRC += $(QUANTUM_DIR)/pointing_device/pointing_device.c + SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_drivers.c ifneq ($(strip $(POINTING_DEVICE_DRIVER)), custom) SRC += drivers/sensors/$(strip $(POINTING_DEVICE_DRIVER)).c OPT_DEFS += -DPOINTING_DEVICE_DRIVER_$(strip $(shell echo $(POINTING_DEVICE_DRIVER) | tr '[:lower:]' '[:upper:]')) @@ -150,13 +151,13 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) OPT_DEFS += -DSTM32_I2C -DHAL_USE_I2C=TRUE SRC += drivers/sensors/cirque_pinnacle.c SRC += drivers/sensors/cirque_pinnacle_gestures.c - SRC += $(QUANTUM_DIR)/pointing_device_gestures.c + SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_gestures.c QUANTUM_LIB_SRC += i2c_master.c else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), cirque_pinnacle_spi) OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE SRC += drivers/sensors/cirque_pinnacle.c SRC += drivers/sensors/cirque_pinnacle_gestures.c - SRC += $(QUANTUM_DIR)/pointing_device_gestures.c + SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_gestures.c QUANTUM_LIB_SRC += spi_master.c else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball) OPT_DEFS += -DSTM32_SPI -DHAL_USE_I2C=TRUE diff --git a/quantum/pointing_device.c b/quantum/pointing_device.c deleted file mode 100644 index 3aa4941687..0000000000 --- a/quantum/pointing_device.c +++ /dev/null @@ -1,470 +0,0 @@ -/* Copyright 2017 Joshua Broekhuijsen - * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2021 Dasky (@daskygit) - * - * 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 . - */ - -#include "pointing_device.h" -#include -#include "timer.h" -#ifdef MOUSEKEY_ENABLE -# include "mousekey.h" -#endif -#if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1 -# error More than one rotation selected. This is not supported. -#endif - -#if defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT) || defined(POINTING_DEVICE_COMBINED) -# ifndef SPLIT_POINTING_ENABLE -# error "Using POINTING_DEVICE_LEFT or POINTING_DEVICE_RIGHT or POINTING_DEVICE_COMBINED, then SPLIT_POINTING_ENABLE is required but has not been defined" -# endif -#endif - -#if defined(SPLIT_POINTING_ENABLE) -# include "transactions.h" -# include "keyboard.h" - -report_mouse_t shared_mouse_report = {}; -uint16_t shared_cpi = 0; - -/** - * @brief Sets the shared mouse report used be pointing device task - * - * NOTE : Only available when using SPLIT_POINTING_ENABLE - * - * @param[in] new_mouse_report report_mouse_t - */ -void pointing_device_set_shared_report(report_mouse_t new_mouse_report) { - shared_mouse_report = new_mouse_report; -} - -/** - * @brief Gets current pointing device CPI if supported - * - * Gets current cpi of the shared report and returns it as uint16_t - * - * NOTE : Only available when using SPLIT_POINTING_ENABLE - * - * @return cpi value as uint16_t - */ -uint16_t pointing_device_get_shared_cpi(void) { - return shared_cpi; -} - -# if defined(POINTING_DEVICE_LEFT) -# define POINTING_DEVICE_THIS_SIDE is_keyboard_left() -# elif defined(POINTING_DEVICE_RIGHT) -# define POINTING_DEVICE_THIS_SIDE !is_keyboard_left() -# elif defined(POINTING_DEVICE_COMBINED) -# define POINTING_DEVICE_THIS_SIDE true -# endif - -#endif // defined(SPLIT_POINTING_ENABLE) - -static report_mouse_t local_mouse_report = {}; - -extern const pointing_device_driver_t pointing_device_driver; - -/** - * @brief Keyboard level code pointing device initialisation - * - */ -__attribute__((weak)) void pointing_device_init_kb(void) {} - -/** - * @brief User level code pointing device initialisation - * - */ -__attribute__((weak)) void pointing_device_init_user(void) {} - -/** - * @brief Weak function allowing for keyboard level mouse report modification - * - * Takes report_mouse_t struct allowing modification at keyboard level then returns report_mouse_t. - * - * @param[in] mouse_report report_mouse_t - * @return report_mouse_t - */ -__attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { - return pointing_device_task_user(mouse_report); -} - -/** - * @brief Weak function allowing for user level mouse report modification - * - * Takes report_mouse_t struct allowing modification at user level then returns report_mouse_t. - * - * @param[in] mouse_report report_mouse_t - * @return report_mouse_t - */ -__attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { - return mouse_report; -} - -/** - * @brief Handles pointing device buttons - * - * Returns modified button bitmask using bool pressed and selected pointing_device_buttons_t button in uint8_t buttons bitmask. - * - * @param buttons[in] uint8_t bitmask - * @param pressed[in] bool - * @param button[in] pointing_device_buttons_t value - * @return Modified uint8_t bitmask buttons - */ -__attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) { - if (pressed) { - buttons |= 1 << (button); - } else { - buttons &= ~(1 << (button)); - } - return buttons; -} - -/** - * @brief Initialises pointing device - * - * Initialises pointing device, perform driver init and optional keyboard/user level code. - */ -__attribute__((weak)) void pointing_device_init(void) { -#if defined(SPLIT_POINTING_ENABLE) - if (!(POINTING_DEVICE_THIS_SIDE)) { - return; - } -#endif - pointing_device_driver.init(); -#ifdef POINTING_DEVICE_MOTION_PIN - setPinInputHigh(POINTING_DEVICE_MOTION_PIN); -#endif - pointing_device_init_kb(); - pointing_device_init_user(); -} - -/** - * @brief Sends processed mouse report to host - * - * This sends the mouse report generated by pointing_device_task if changed since the last report. Once send zeros mouse report except buttons. - * - */ -__attribute__((weak)) void pointing_device_send(void) { - static report_mouse_t old_report = {}; - - // If you need to do other things, like debugging, this is the place to do it. - if (has_mouse_report_changed(&local_mouse_report, &old_report)) { - host_mouse_send(&local_mouse_report); - } - // send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device - local_mouse_report.x = 0; - local_mouse_report.y = 0; - local_mouse_report.v = 0; - local_mouse_report.h = 0; - - memcpy(&old_report, &local_mouse_report, sizeof(local_mouse_report)); -} - -/** - * @brief Adjust mouse report by any optional common pointing configuration defines - * - * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines. - * - * @param mouse_report[in] takes a report_mouse_t to be adjusted - * @return report_mouse_t with adjusted values - */ -report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report) { - // Support rotation of the sensor data -#if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270) - mouse_xy_report_t x = mouse_report.x; - mouse_xy_report_t y = mouse_report.y; -# if defined(POINTING_DEVICE_ROTATION_90) - mouse_report.x = y; - mouse_report.y = -x; -# elif defined(POINTING_DEVICE_ROTATION_180) - mouse_report.x = -x; - mouse_report.y = -y; -# elif defined(POINTING_DEVICE_ROTATION_270) - mouse_report.x = -y; - mouse_report.y = x; -# else -# error "How the heck did you get here?!" -# endif -#endif - // Support Inverting the X and Y Axises -#if defined(POINTING_DEVICE_INVERT_X) - mouse_report.x = -mouse_report.x; -#endif -#if defined(POINTING_DEVICE_INVERT_Y) - mouse_report.y = -mouse_report.y; -#endif - return mouse_report; -} - -/** - * @brief Retrieves and processes pointing device data. - * - * This function is part of the keyboard loop and retrieves the mouse report from the pointing device driver. - * It applies any optional configuration e.g. rotation or axis inversion and then initiates a send. - * - */ -__attribute__((weak)) void pointing_device_task(void) { -#if defined(SPLIT_POINTING_ENABLE) - // Don't poll the target side pointing device. - if (!is_keyboard_master()) { - return; - }; -#endif - -#if (POINTING_DEVICE_TASK_THROTTLE_MS > 0) - static uint32_t last_exec = 0; - if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) { - return; - } - last_exec = timer_read32(); -#endif - - // Gather report info -#ifdef POINTING_DEVICE_MOTION_PIN -# if defined(SPLIT_POINTING_ENABLE) -# error POINTING_DEVICE_MOTION_PIN not supported when sharing the pointing device report between sides. -# endif - if (!readPin(POINTING_DEVICE_MOTION_PIN)) -#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; -# 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 -# error "You need to define the side(s) the pointing device is on. POINTING_DEVICE_COMBINED / POINTING_DEVICE_LEFT / POINTING_DEVICE_RIGHT" -# endif -#else - local_mouse_report = pointing_device_driver.get_report(local_mouse_report); -#endif // defined(SPLIT_POINTING_ENABLE) - - // allow kb to intercept and modify report -#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) - if (is_keyboard_left()) { - local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); - shared_mouse_report = pointing_device_adjust_by_defines_right(shared_mouse_report); - } else { - local_mouse_report = pointing_device_adjust_by_defines_right(local_mouse_report); - shared_mouse_report = pointing_device_adjust_by_defines(shared_mouse_report); - } - local_mouse_report = is_keyboard_left() ? pointing_device_task_combined_kb(local_mouse_report, shared_mouse_report) : pointing_device_task_combined_kb(shared_mouse_report, local_mouse_report); -#else - local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); - local_mouse_report = pointing_device_task_kb(local_mouse_report); -#endif - // combine with mouse report to ensure that the combined is sent correctly -#ifdef MOUSEKEY_ENABLE - report_mouse_t mousekey_report = mousekey_get_report(); - local_mouse_report.buttons = local_mouse_report.buttons | mousekey_report.buttons; -#endif - pointing_device_send(); -} - -/** - * @brief Gets current mouse report used by pointing device task - * - * @return report_mouse_t - */ -report_mouse_t pointing_device_get_report(void) { - return local_mouse_report; -} - -/** - * @brief Sets mouse report used be pointing device task - * - * @param[in] mouse_report - */ -void pointing_device_set_report(report_mouse_t mouse_report) { - local_mouse_report = mouse_report; -} - -/** - * @brief Gets current pointing device CPI if supported - * - * Gets current cpi from pointing device driver if supported and returns it as uint16_t - * - * @return cpi value as uint16_t - */ -uint16_t pointing_device_get_cpi(void) { -#if defined(SPLIT_POINTING_ENABLE) - return POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_cpi() : shared_cpi; -#else - return pointing_device_driver.get_cpi(); -#endif -} - -/** - * @brief Set pointing device CPI if supported - * - * Takes a uint16_t value to set pointing device cpi if supported by driver. - * - * @param[in] cpi uint16_t value. - */ -void pointing_device_set_cpi(uint16_t cpi) { -#if defined(SPLIT_POINTING_ENABLE) - if (POINTING_DEVICE_THIS_SIDE) { - pointing_device_driver.set_cpi(cpi); - } else { - shared_cpi = cpi; - } -#else - pointing_device_driver.set_cpi(cpi); -#endif -} - -#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) -/** - * @brief Set pointing device CPI if supported - * - * Takes a bool and uint16_t and allows setting cpi for a single side when using 2 pointing devices with a split keyboard. - * - * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED - * - * @param[in] left true = left, false = right. - * @param[in] cpi uint16_t value. - */ -void pointing_device_set_cpi_on_side(bool left, uint16_t cpi) { - bool local = (is_keyboard_left() & left) ? true : false; - if (local) { - pointing_device_driver.set_cpi(cpi); - } else { - shared_cpi = cpi; - } -} - -/** - * @brief clamps int16_t to int8_t - * - * @param[in] int16_t value - * @return int8_t clamped value - */ -static inline int8_t pointing_device_hv_clamp(int16_t value) { - if (value < INT8_MIN) { - return INT8_MIN; - } else if (value > INT8_MAX) { - return INT8_MAX; - } else { - return value; - } -} - -/** - * @brief clamps int16_t to int8_t - * - * @param[in] clamp_range_t value - * @return mouse_xy_report_t clamped value - */ -static inline mouse_xy_report_t pointing_device_xy_clamp(clamp_range_t value) { - if (value < XY_REPORT_MIN) { - return XY_REPORT_MIN; - } else if (value > XY_REPORT_MAX) { - return XY_REPORT_MAX; - } else { - return value; - } -} -/** - * @brief combines 2 mouse reports and returns 2 - * - * Combines 2 report_mouse_t structs, clamping movement values to int8_t and ignores report_id then returns the resulting report_mouse_t struct. - * - * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED - * - * @param[in] left_report left report_mouse_t - * @param[in] right_report right report_mouse_t - * @return combined report_mouse_t of left_report and right_report - */ -report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report) { - left_report.x = pointing_device_xy_clamp((clamp_range_t)left_report.x + right_report.x); - left_report.y = pointing_device_xy_clamp((clamp_range_t)left_report.y + right_report.y); - left_report.h = pointing_device_hv_clamp((int16_t)left_report.h + right_report.h); - left_report.v = pointing_device_hv_clamp((int16_t)left_report.v + right_report.v); - left_report.buttons |= right_report.buttons; - return left_report; -} - -/** - * @brief Adjust mouse report by any optional right pointing configuration defines - * - * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines. - * - * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED - * - * @param[in] mouse_report report_mouse_t to be adjusted - * @return report_mouse_t with adjusted values - */ -report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report) { - // Support rotation of the sensor data -# if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) - mouse_xy_report_t x = mouse_report.x; - mouse_xy_report_t y = mouse_report.y; -# if defined(POINTING_DEVICE_ROTATION_90_RIGHT) - mouse_report.x = y; - mouse_report.y = -x; -# elif defined(POINTING_DEVICE_ROTATION_180_RIGHT) - mouse_report.x = -x; - mouse_report.y = -y; -# elif defined(POINTING_DEVICE_ROTATION_270_RIGHT) - mouse_report.x = -y; - mouse_report.y = x; -# else -# error "How the heck did you get here?!" -# endif -# endif - // Support Inverting the X and Y Axises -# if defined(POINTING_DEVICE_INVERT_X_RIGHT) - mouse_report.x = -mouse_report.x; -# endif -# if defined(POINTING_DEVICE_INVERT_Y_RIGHT) - mouse_report.y = -mouse_report.y; -# endif - return mouse_report; -} - -/** - * @brief Weak function allowing for keyboard level mouse report modification - * - * Takes 2 report_mouse_t structs allowing individual modification of sides at keyboard level then returns pointing_device_task_combined_user. - * - * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED - * - * @param[in] left_report report_mouse_t - * @param[in] right_report report_mouse_t - * @return pointing_device_task_combined_user(left_report, right_report) by default - */ -__attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report) { - return pointing_device_task_combined_user(left_report, right_report); -} - -/** - * @brief Weak function allowing for user level mouse report modification - * - * Takes 2 report_mouse_t structs allowing individual modification of sides at user level then returns pointing_device_combine_reports. - * - * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED - * - * @param[in] left_report report_mouse_t - * @param[in] right_report report_mouse_t - * @return pointing_device_combine_reports(left_report, right_report) by default - */ -__attribute__((weak)) report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) { - return pointing_device_combine_reports(left_report, right_report); -} -#endif diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h deleted file mode 100644 index 77db5471ea..0000000000 --- a/quantum/pointing_device.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -Copyright 2017 Joshua Broekhuijsen - -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 . -*/ - -#pragma once - -#include -#include "host.h" -#include "report.h" - -#if defined(POINTING_DEVICE_DRIVER_adns5050) -# include "drivers/sensors/adns5050.h" -#elif defined(POINTING_DEVICE_DRIVER_adns9800) -# include "spi_master.h" -# include "drivers/sensors/adns9800.h" -#elif defined(POINTING_DEVICE_DRIVER_analog_joystick) -# include "analog.h" -# include "drivers/sensors/analog_joystick.h" -#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) -# include "drivers/sensors/cirque_pinnacle.h" -# include "drivers/sensors/cirque_pinnacle_gestures.h" -# include "pointing_device_gestures.h" -#elif defined(POINTING_DEVICE_DRIVER_paw3204) -# include "drivers/sensors/paw3204.h" -#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) -# include "i2c_master.h" -# include "drivers/sensors/pimoroni_trackball.h" -// support for legacy pimoroni defines -# ifdef PIMORONI_TRACKBALL_INVERT_X -# define POINTING_DEVICE_INVERT_X -# endif -# ifdef PIMORONI_TRACKBALL_INVERT_Y -# define POINTING_DEVICE_INVERT_Y -# endif -# ifdef PIMORONI_TRACKBALL_ROTATE -# define POINTING_DEVICE_ROTATION_90 -# endif -#elif defined(POINTING_DEVICE_DRIVER_pmw3360) || defined(POINTING_DEVICE_DRIVER_pmw3389) -# include "spi_master.h" -# include "drivers/sensors/pmw33xx_common.h" -#else -void pointing_device_driver_init(void); -report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report); -uint16_t pointing_device_driver_get_cpi(void); -void pointing_device_driver_set_cpi(uint16_t cpi); -#endif - -typedef struct { - void (*init)(void); - report_mouse_t (*get_report)(report_mouse_t mouse_report); - void (*set_cpi)(uint16_t); - uint16_t (*get_cpi)(void); -} pointing_device_driver_t; - -typedef enum { - POINTING_DEVICE_BUTTON1, - POINTING_DEVICE_BUTTON2, - POINTING_DEVICE_BUTTON3, - POINTING_DEVICE_BUTTON4, - POINTING_DEVICE_BUTTON5, - POINTING_DEVICE_BUTTON6, - POINTING_DEVICE_BUTTON7, - POINTING_DEVICE_BUTTON8, -} pointing_device_buttons_t; - -#ifdef MOUSE_EXTENDED_REPORT -# define XY_REPORT_MIN INT16_MIN -# define XY_REPORT_MAX INT16_MAX -typedef int32_t clamp_range_t; -#else -# define XY_REPORT_MIN INT8_MIN -# define XY_REPORT_MAX INT8_MAX -typedef int16_t clamp_range_t; -#endif - -void pointing_device_init(void); -void pointing_device_task(void); -void pointing_device_send(void); -report_mouse_t pointing_device_get_report(void); -void pointing_device_set_report(report_mouse_t mouse_report); -uint16_t pointing_device_get_cpi(void); -void pointing_device_set_cpi(uint16_t cpi); - -void pointing_device_init_kb(void); -void pointing_device_init_user(void); -report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report); -report_mouse_t pointing_device_task_user(report_mouse_t mouse_report); -uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button); -report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report); - -#if defined(SPLIT_POINTING_ENABLE) -void pointing_device_set_shared_report(report_mouse_t report); -uint16_t pointing_device_get_shared_cpi(void); -# if !defined(POINTING_DEVICE_TASK_THROTTLE_MS) -# define POINTING_DEVICE_TASK_THROTTLE_MS 1 -# endif -# if defined(POINTING_DEVICE_COMBINED) -void pointing_device_set_cpi_on_side(bool left, uint16_t cpi); -report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report); -report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report); -report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report); -report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report); -# endif // defined(POINTING_DEVICE_COMBINED) -#endif // defined(SPLIT_POINTING_ENABLE) diff --git a/quantum/pointing_device/pointing_device.c b/quantum/pointing_device/pointing_device.c new file mode 100644 index 0000000000..3aa4941687 --- /dev/null +++ b/quantum/pointing_device/pointing_device.c @@ -0,0 +1,470 @@ +/* Copyright 2017 Joshua Broekhuijsen + * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) + * Copyright 2021 Dasky (@daskygit) + * + * 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 . + */ + +#include "pointing_device.h" +#include +#include "timer.h" +#ifdef MOUSEKEY_ENABLE +# include "mousekey.h" +#endif +#if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1 +# error More than one rotation selected. This is not supported. +#endif + +#if defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT) || defined(POINTING_DEVICE_COMBINED) +# ifndef SPLIT_POINTING_ENABLE +# error "Using POINTING_DEVICE_LEFT or POINTING_DEVICE_RIGHT or POINTING_DEVICE_COMBINED, then SPLIT_POINTING_ENABLE is required but has not been defined" +# endif +#endif + +#if defined(SPLIT_POINTING_ENABLE) +# include "transactions.h" +# include "keyboard.h" + +report_mouse_t shared_mouse_report = {}; +uint16_t shared_cpi = 0; + +/** + * @brief Sets the shared mouse report used be pointing device task + * + * NOTE : Only available when using SPLIT_POINTING_ENABLE + * + * @param[in] new_mouse_report report_mouse_t + */ +void pointing_device_set_shared_report(report_mouse_t new_mouse_report) { + shared_mouse_report = new_mouse_report; +} + +/** + * @brief Gets current pointing device CPI if supported + * + * Gets current cpi of the shared report and returns it as uint16_t + * + * NOTE : Only available when using SPLIT_POINTING_ENABLE + * + * @return cpi value as uint16_t + */ +uint16_t pointing_device_get_shared_cpi(void) { + return shared_cpi; +} + +# if defined(POINTING_DEVICE_LEFT) +# define POINTING_DEVICE_THIS_SIDE is_keyboard_left() +# elif defined(POINTING_DEVICE_RIGHT) +# define POINTING_DEVICE_THIS_SIDE !is_keyboard_left() +# elif defined(POINTING_DEVICE_COMBINED) +# define POINTING_DEVICE_THIS_SIDE true +# endif + +#endif // defined(SPLIT_POINTING_ENABLE) + +static report_mouse_t local_mouse_report = {}; + +extern const pointing_device_driver_t pointing_device_driver; + +/** + * @brief Keyboard level code pointing device initialisation + * + */ +__attribute__((weak)) void pointing_device_init_kb(void) {} + +/** + * @brief User level code pointing device initialisation + * + */ +__attribute__((weak)) void pointing_device_init_user(void) {} + +/** + * @brief Weak function allowing for keyboard level mouse report modification + * + * Takes report_mouse_t struct allowing modification at keyboard level then returns report_mouse_t. + * + * @param[in] mouse_report report_mouse_t + * @return report_mouse_t + */ +__attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { + return pointing_device_task_user(mouse_report); +} + +/** + * @brief Weak function allowing for user level mouse report modification + * + * Takes report_mouse_t struct allowing modification at user level then returns report_mouse_t. + * + * @param[in] mouse_report report_mouse_t + * @return report_mouse_t + */ +__attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { + return mouse_report; +} + +/** + * @brief Handles pointing device buttons + * + * Returns modified button bitmask using bool pressed and selected pointing_device_buttons_t button in uint8_t buttons bitmask. + * + * @param buttons[in] uint8_t bitmask + * @param pressed[in] bool + * @param button[in] pointing_device_buttons_t value + * @return Modified uint8_t bitmask buttons + */ +__attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) { + if (pressed) { + buttons |= 1 << (button); + } else { + buttons &= ~(1 << (button)); + } + return buttons; +} + +/** + * @brief Initialises pointing device + * + * Initialises pointing device, perform driver init and optional keyboard/user level code. + */ +__attribute__((weak)) void pointing_device_init(void) { +#if defined(SPLIT_POINTING_ENABLE) + if (!(POINTING_DEVICE_THIS_SIDE)) { + return; + } +#endif + pointing_device_driver.init(); +#ifdef POINTING_DEVICE_MOTION_PIN + setPinInputHigh(POINTING_DEVICE_MOTION_PIN); +#endif + pointing_device_init_kb(); + pointing_device_init_user(); +} + +/** + * @brief Sends processed mouse report to host + * + * This sends the mouse report generated by pointing_device_task if changed since the last report. Once send zeros mouse report except buttons. + * + */ +__attribute__((weak)) void pointing_device_send(void) { + static report_mouse_t old_report = {}; + + // If you need to do other things, like debugging, this is the place to do it. + if (has_mouse_report_changed(&local_mouse_report, &old_report)) { + host_mouse_send(&local_mouse_report); + } + // send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device + local_mouse_report.x = 0; + local_mouse_report.y = 0; + local_mouse_report.v = 0; + local_mouse_report.h = 0; + + memcpy(&old_report, &local_mouse_report, sizeof(local_mouse_report)); +} + +/** + * @brief Adjust mouse report by any optional common pointing configuration defines + * + * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines. + * + * @param mouse_report[in] takes a report_mouse_t to be adjusted + * @return report_mouse_t with adjusted values + */ +report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report) { + // Support rotation of the sensor data +#if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270) + mouse_xy_report_t x = mouse_report.x; + mouse_xy_report_t y = mouse_report.y; +# if defined(POINTING_DEVICE_ROTATION_90) + mouse_report.x = y; + mouse_report.y = -x; +# elif defined(POINTING_DEVICE_ROTATION_180) + mouse_report.x = -x; + mouse_report.y = -y; +# elif defined(POINTING_DEVICE_ROTATION_270) + mouse_report.x = -y; + mouse_report.y = x; +# else +# error "How the heck did you get here?!" +# endif +#endif + // Support Inverting the X and Y Axises +#if defined(POINTING_DEVICE_INVERT_X) + mouse_report.x = -mouse_report.x; +#endif +#if defined(POINTING_DEVICE_INVERT_Y) + mouse_report.y = -mouse_report.y; +#endif + return mouse_report; +} + +/** + * @brief Retrieves and processes pointing device data. + * + * This function is part of the keyboard loop and retrieves the mouse report from the pointing device driver. + * It applies any optional configuration e.g. rotation or axis inversion and then initiates a send. + * + */ +__attribute__((weak)) void pointing_device_task(void) { +#if defined(SPLIT_POINTING_ENABLE) + // Don't poll the target side pointing device. + if (!is_keyboard_master()) { + return; + }; +#endif + +#if (POINTING_DEVICE_TASK_THROTTLE_MS > 0) + static uint32_t last_exec = 0; + if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) { + return; + } + last_exec = timer_read32(); +#endif + + // Gather report info +#ifdef POINTING_DEVICE_MOTION_PIN +# if defined(SPLIT_POINTING_ENABLE) +# error POINTING_DEVICE_MOTION_PIN not supported when sharing the pointing device report between sides. +# endif + if (!readPin(POINTING_DEVICE_MOTION_PIN)) +#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; +# 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 +# error "You need to define the side(s) the pointing device is on. POINTING_DEVICE_COMBINED / POINTING_DEVICE_LEFT / POINTING_DEVICE_RIGHT" +# endif +#else + local_mouse_report = pointing_device_driver.get_report(local_mouse_report); +#endif // defined(SPLIT_POINTING_ENABLE) + + // allow kb to intercept and modify report +#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) + if (is_keyboard_left()) { + local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); + shared_mouse_report = pointing_device_adjust_by_defines_right(shared_mouse_report); + } else { + local_mouse_report = pointing_device_adjust_by_defines_right(local_mouse_report); + shared_mouse_report = pointing_device_adjust_by_defines(shared_mouse_report); + } + local_mouse_report = is_keyboard_left() ? pointing_device_task_combined_kb(local_mouse_report, shared_mouse_report) : pointing_device_task_combined_kb(shared_mouse_report, local_mouse_report); +#else + local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); + local_mouse_report = pointing_device_task_kb(local_mouse_report); +#endif + // combine with mouse report to ensure that the combined is sent correctly +#ifdef MOUSEKEY_ENABLE + report_mouse_t mousekey_report = mousekey_get_report(); + local_mouse_report.buttons = local_mouse_report.buttons | mousekey_report.buttons; +#endif + pointing_device_send(); +} + +/** + * @brief Gets current mouse report used by pointing device task + * + * @return report_mouse_t + */ +report_mouse_t pointing_device_get_report(void) { + return local_mouse_report; +} + +/** + * @brief Sets mouse report used be pointing device task + * + * @param[in] mouse_report + */ +void pointing_device_set_report(report_mouse_t mouse_report) { + local_mouse_report = mouse_report; +} + +/** + * @brief Gets current pointing device CPI if supported + * + * Gets current cpi from pointing device driver if supported and returns it as uint16_t + * + * @return cpi value as uint16_t + */ +uint16_t pointing_device_get_cpi(void) { +#if defined(SPLIT_POINTING_ENABLE) + return POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_cpi() : shared_cpi; +#else + return pointing_device_driver.get_cpi(); +#endif +} + +/** + * @brief Set pointing device CPI if supported + * + * Takes a uint16_t value to set pointing device cpi if supported by driver. + * + * @param[in] cpi uint16_t value. + */ +void pointing_device_set_cpi(uint16_t cpi) { +#if defined(SPLIT_POINTING_ENABLE) + if (POINTING_DEVICE_THIS_SIDE) { + pointing_device_driver.set_cpi(cpi); + } else { + shared_cpi = cpi; + } +#else + pointing_device_driver.set_cpi(cpi); +#endif +} + +#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) +/** + * @brief Set pointing device CPI if supported + * + * Takes a bool and uint16_t and allows setting cpi for a single side when using 2 pointing devices with a split keyboard. + * + * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED + * + * @param[in] left true = left, false = right. + * @param[in] cpi uint16_t value. + */ +void pointing_device_set_cpi_on_side(bool left, uint16_t cpi) { + bool local = (is_keyboard_left() & left) ? true : false; + if (local) { + pointing_device_driver.set_cpi(cpi); + } else { + shared_cpi = cpi; + } +} + +/** + * @brief clamps int16_t to int8_t + * + * @param[in] int16_t value + * @return int8_t clamped value + */ +static inline int8_t pointing_device_hv_clamp(int16_t value) { + if (value < INT8_MIN) { + return INT8_MIN; + } else if (value > INT8_MAX) { + return INT8_MAX; + } else { + return value; + } +} + +/** + * @brief clamps int16_t to int8_t + * + * @param[in] clamp_range_t value + * @return mouse_xy_report_t clamped value + */ +static inline mouse_xy_report_t pointing_device_xy_clamp(clamp_range_t value) { + if (value < XY_REPORT_MIN) { + return XY_REPORT_MIN; + } else if (value > XY_REPORT_MAX) { + return XY_REPORT_MAX; + } else { + return value; + } +} +/** + * @brief combines 2 mouse reports and returns 2 + * + * Combines 2 report_mouse_t structs, clamping movement values to int8_t and ignores report_id then returns the resulting report_mouse_t struct. + * + * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED + * + * @param[in] left_report left report_mouse_t + * @param[in] right_report right report_mouse_t + * @return combined report_mouse_t of left_report and right_report + */ +report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report) { + left_report.x = pointing_device_xy_clamp((clamp_range_t)left_report.x + right_report.x); + left_report.y = pointing_device_xy_clamp((clamp_range_t)left_report.y + right_report.y); + left_report.h = pointing_device_hv_clamp((int16_t)left_report.h + right_report.h); + left_report.v = pointing_device_hv_clamp((int16_t)left_report.v + right_report.v); + left_report.buttons |= right_report.buttons; + return left_report; +} + +/** + * @brief Adjust mouse report by any optional right pointing configuration defines + * + * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines. + * + * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED + * + * @param[in] mouse_report report_mouse_t to be adjusted + * @return report_mouse_t with adjusted values + */ +report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report) { + // Support rotation of the sensor data +# if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) + mouse_xy_report_t x = mouse_report.x; + mouse_xy_report_t y = mouse_report.y; +# if defined(POINTING_DEVICE_ROTATION_90_RIGHT) + mouse_report.x = y; + mouse_report.y = -x; +# elif defined(POINTING_DEVICE_ROTATION_180_RIGHT) + mouse_report.x = -x; + mouse_report.y = -y; +# elif defined(POINTING_DEVICE_ROTATION_270_RIGHT) + mouse_report.x = -y; + mouse_report.y = x; +# else +# error "How the heck did you get here?!" +# endif +# endif + // Support Inverting the X and Y Axises +# if defined(POINTING_DEVICE_INVERT_X_RIGHT) + mouse_report.x = -mouse_report.x; +# endif +# if defined(POINTING_DEVICE_INVERT_Y_RIGHT) + mouse_report.y = -mouse_report.y; +# endif + return mouse_report; +} + +/** + * @brief Weak function allowing for keyboard level mouse report modification + * + * Takes 2 report_mouse_t structs allowing individual modification of sides at keyboard level then returns pointing_device_task_combined_user. + * + * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED + * + * @param[in] left_report report_mouse_t + * @param[in] right_report report_mouse_t + * @return pointing_device_task_combined_user(left_report, right_report) by default + */ +__attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report) { + return pointing_device_task_combined_user(left_report, right_report); +} + +/** + * @brief Weak function allowing for user level mouse report modification + * + * Takes 2 report_mouse_t structs allowing individual modification of sides at user level then returns pointing_device_combine_reports. + * + * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED + * + * @param[in] left_report report_mouse_t + * @param[in] right_report report_mouse_t + * @return pointing_device_combine_reports(left_report, right_report) by default + */ +__attribute__((weak)) report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) { + return pointing_device_combine_reports(left_report, right_report); +} +#endif diff --git a/quantum/pointing_device/pointing_device.h b/quantum/pointing_device/pointing_device.h new file mode 100644 index 0000000000..77db5471ea --- /dev/null +++ b/quantum/pointing_device/pointing_device.h @@ -0,0 +1,117 @@ +/* +Copyright 2017 Joshua Broekhuijsen + +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 . +*/ + +#pragma once + +#include +#include "host.h" +#include "report.h" + +#if defined(POINTING_DEVICE_DRIVER_adns5050) +# include "drivers/sensors/adns5050.h" +#elif defined(POINTING_DEVICE_DRIVER_adns9800) +# include "spi_master.h" +# include "drivers/sensors/adns9800.h" +#elif defined(POINTING_DEVICE_DRIVER_analog_joystick) +# include "analog.h" +# include "drivers/sensors/analog_joystick.h" +#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) +# include "drivers/sensors/cirque_pinnacle.h" +# include "drivers/sensors/cirque_pinnacle_gestures.h" +# include "pointing_device_gestures.h" +#elif defined(POINTING_DEVICE_DRIVER_paw3204) +# include "drivers/sensors/paw3204.h" +#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) +# include "i2c_master.h" +# include "drivers/sensors/pimoroni_trackball.h" +// support for legacy pimoroni defines +# ifdef PIMORONI_TRACKBALL_INVERT_X +# define POINTING_DEVICE_INVERT_X +# endif +# ifdef PIMORONI_TRACKBALL_INVERT_Y +# define POINTING_DEVICE_INVERT_Y +# endif +# ifdef PIMORONI_TRACKBALL_ROTATE +# define POINTING_DEVICE_ROTATION_90 +# endif +#elif defined(POINTING_DEVICE_DRIVER_pmw3360) || defined(POINTING_DEVICE_DRIVER_pmw3389) +# include "spi_master.h" +# include "drivers/sensors/pmw33xx_common.h" +#else +void pointing_device_driver_init(void); +report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report); +uint16_t pointing_device_driver_get_cpi(void); +void pointing_device_driver_set_cpi(uint16_t cpi); +#endif + +typedef struct { + void (*init)(void); + report_mouse_t (*get_report)(report_mouse_t mouse_report); + void (*set_cpi)(uint16_t); + uint16_t (*get_cpi)(void); +} pointing_device_driver_t; + +typedef enum { + POINTING_DEVICE_BUTTON1, + POINTING_DEVICE_BUTTON2, + POINTING_DEVICE_BUTTON3, + POINTING_DEVICE_BUTTON4, + POINTING_DEVICE_BUTTON5, + POINTING_DEVICE_BUTTON6, + POINTING_DEVICE_BUTTON7, + POINTING_DEVICE_BUTTON8, +} pointing_device_buttons_t; + +#ifdef MOUSE_EXTENDED_REPORT +# define XY_REPORT_MIN INT16_MIN +# define XY_REPORT_MAX INT16_MAX +typedef int32_t clamp_range_t; +#else +# define XY_REPORT_MIN INT8_MIN +# define XY_REPORT_MAX INT8_MAX +typedef int16_t clamp_range_t; +#endif + +void pointing_device_init(void); +void pointing_device_task(void); +void pointing_device_send(void); +report_mouse_t pointing_device_get_report(void); +void pointing_device_set_report(report_mouse_t mouse_report); +uint16_t pointing_device_get_cpi(void); +void pointing_device_set_cpi(uint16_t cpi); + +void pointing_device_init_kb(void); +void pointing_device_init_user(void); +report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report); +report_mouse_t pointing_device_task_user(report_mouse_t mouse_report); +uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button); +report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report); + +#if defined(SPLIT_POINTING_ENABLE) +void pointing_device_set_shared_report(report_mouse_t report); +uint16_t pointing_device_get_shared_cpi(void); +# if !defined(POINTING_DEVICE_TASK_THROTTLE_MS) +# define POINTING_DEVICE_TASK_THROTTLE_MS 1 +# endif +# if defined(POINTING_DEVICE_COMBINED) +void pointing_device_set_cpi_on_side(bool left, uint16_t cpi); +report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report); +report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report); +report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report); +report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report); +# endif // defined(POINTING_DEVICE_COMBINED) +#endif // defined(SPLIT_POINTING_ENABLE) diff --git a/quantum/pointing_device/pointing_device_drivers.c b/quantum/pointing_device/pointing_device_drivers.c new file mode 100644 index 0000000000..d0b545d22d --- /dev/null +++ b/quantum/pointing_device/pointing_device_drivers.c @@ -0,0 +1,345 @@ +/* Copyright 2017 Joshua Broekhuijsen + * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) + * Copyright 2021 Dasky (@daskygit) + * + * 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 . + */ + +#include "pointing_device.h" +#include "debug.h" +#include "wait.h" +#include "timer.h" +#include + +#define CONSTRAIN_HID(amt) ((amt) < INT8_MIN ? INT8_MIN : ((amt) > INT8_MAX ? INT8_MAX : (amt))) +#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt))) + +// get_report functions should probably be moved to their respective drivers. + +#if defined(POINTING_DEVICE_DRIVER_adns5050) +report_mouse_t adns5050_get_report(report_mouse_t mouse_report) { + report_adns5050_t data = adns5050_read_burst(); + + if (data.dx != 0 || data.dy != 0) { +# ifdef CONSOLE_ENABLE + if (debug_mouse) dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy); +# endif + + mouse_report.x = (mouse_xy_report_t)data.dx; + mouse_report.y = (mouse_xy_report_t)data.dy; + } + + return mouse_report; +} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = adns5050_init, + .get_report = adns5050_get_report, + .set_cpi = adns5050_set_cpi, + .get_cpi = adns5050_get_cpi, +}; +// clang-format on + +#elif defined(POINTING_DEVICE_DRIVER_adns9800) + +report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report) { + report_adns9800_t sensor_report = adns9800_get_report(); + + mouse_report.x = CONSTRAIN_HID_XY(sensor_report.x); + mouse_report.y = CONSTRAIN_HID_XY(sensor_report.y); + + return mouse_report; +} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = adns9800_init, + .get_report = adns9800_get_report_driver, + .set_cpi = adns9800_set_cpi, + .get_cpi = adns9800_get_cpi +}; +// clang-format on + +#elif defined(POINTING_DEVICE_DRIVER_analog_joystick) +report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report) { + report_analog_joystick_t data = analog_joystick_read(); + +# ifdef CONSOLE_ENABLE + if (debug_mouse) dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y); +# endif + + mouse_report.x = data.x; + mouse_report.y = data.y; + + mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, data.button, POINTING_DEVICE_BUTTON1); + + return mouse_report; +} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = analog_joystick_init, + .get_report = analog_joystick_get_report, + .set_cpi = NULL, + .get_cpi = NULL +}; +// clang-format on + +#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +static bool cursor_glide_enable = true; + +static cursor_glide_context_t glide = {.config = { + .coef = 102, /* Good default friction coef */ + .interval = 10, /* 100sps */ + .trigger_px = 10, /* Default threshold in case of hover, set to 0 if you'd like */ + }}; + +void cirque_pinnacle_enable_cursor_glide(bool enable) { + cursor_glide_enable = enable; +} + +void cirque_pinnacle_configure_cursor_glide(float trigger_px) { + glide.config.trigger_px = trigger_px; +} +# endif + +report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { + pinnacle_data_t touchData = cirque_pinnacle_read_data(); + mouse_xy_report_t report_x = 0, report_y = 0; + static mouse_xy_report_t x = 0, y = 0; +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE + cursor_glide_t glide_report = {0}; + + if (cursor_glide_enable) { + glide_report = cursor_glide_check(&glide); + } +# endif + +# if !CIRQUE_PINNACLE_POSITION_MODE +# error Cirque Pinnacle with relative mode not implemented yet. +# endif + + if (!touchData.valid) { +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE + if (cursor_glide_enable && glide_report.valid) { + report_x = glide_report.dx; + report_y = glide_report.dy; + goto mouse_report_update; + } +# endif + return mouse_report; + } + +# if CONSOLE_ENABLE + if (debug_mouse && touchData.touchDown) { + dprintf("cirque_pinnacle touchData x=%4d y=%4d z=%2d\n", touchData.xValue, touchData.yValue, touchData.zValue); + } +# endif + + // Scale coordinates to arbitrary X, Y resolution + cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); + + if (!cirque_pinnacle_gestures(&mouse_report, touchData)) { + if (x && y && touchData.xValue && touchData.yValue) { + report_x = (mouse_xy_report_t)(touchData.xValue - x); + report_y = (mouse_xy_report_t)(touchData.yValue - y); + } + x = touchData.xValue; + y = touchData.yValue; + +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE + if (cursor_glide_enable) { + if (touchData.touchDown) { + cursor_glide_update(&glide, report_x, report_y, touchData.zValue); + } else if (!glide_report.valid) { + glide_report = cursor_glide_start(&glide); + if (glide_report.valid) { + report_x = glide_report.dx; + report_y = glide_report.dy; + } + } + } +# endif + } + +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +mouse_report_update: +# endif + mouse_report.x = report_x; + mouse_report.y = report_y; + + return mouse_report; +} + +uint16_t cirque_pinnacle_get_cpi(void) { + return CIRQUE_PINNACLE_PX_TO_INCH(cirque_pinnacle_get_scale()); +} +void cirque_pinnacle_set_cpi(uint16_t cpi) { + cirque_pinnacle_set_scale(CIRQUE_PINNACLE_INCH_TO_PX(cpi)); +} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = cirque_pinnacle_init, + .get_report = cirque_pinnacle_get_report, + .set_cpi = cirque_pinnacle_set_cpi, + .get_cpi = cirque_pinnacle_get_cpi +}; +// clang-format on +#elif defined(POINTING_DEVICE_DRIVER_paw3204) + +report_mouse_t paw3204_get_report(report_mouse_t mouse_report) { + report_paw3204_t data = paw3204_read(); + if (data.isMotion) { +# ifdef CONSOLE_ENABLE + dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y); +# endif + + mouse_report.x = data.x; + mouse_report.y = data.y; + } + + return mouse_report; +} +const pointing_device_driver_t pointing_device_driver = { + .init = paw3204_init, + .get_report = paw3204_get_report, + .set_cpi = paw3204_set_cpi, + .get_cpi = paw3204_get_cpi, +}; +#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) + +mouse_xy_report_t pimoroni_trackball_adapt_values(clamp_range_t* offset) { + if (*offset > XY_REPORT_MAX) { + *offset -= XY_REPORT_MAX; + return (mouse_xy_report_t)XY_REPORT_MAX; + } else if (*offset < XY_REPORT_MIN) { + *offset += XY_REPORT_MAX; + return (mouse_xy_report_t)XY_REPORT_MIN; + } else { + mouse_xy_report_t temp_return = *offset; + *offset = 0; + return temp_return; + } +} + +report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) { + static uint16_t debounce = 0; + static uint8_t error_count = 0; + pimoroni_data_t pimoroni_data = {0}; + static clamp_range_t x_offset = 0, y_offset = 0; + + if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) { + i2c_status_t status = read_pimoroni_trackball(&pimoroni_data); + + if (status == I2C_STATUS_SUCCESS) { + error_count = 0; + + if (!(pimoroni_data.click & 128)) { + mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1); + if (!debounce) { + x_offset += pimoroni_trackball_get_offsets(pimoroni_data.right, pimoroni_data.left, PIMORONI_TRACKBALL_SCALE); + y_offset += pimoroni_trackball_get_offsets(pimoroni_data.down, pimoroni_data.up, PIMORONI_TRACKBALL_SCALE); + mouse_report.x = pimoroni_trackball_adapt_values(&x_offset); + mouse_report.y = pimoroni_trackball_adapt_values(&y_offset); + } else { + debounce--; + } + } else { + mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); + debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES; + } + } else { + error_count++; + } + } + return mouse_report; +} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = pimoroni_trackball_device_init, + .get_report = pimoroni_trackball_get_report, + .set_cpi = pimoroni_trackball_set_cpi, + .get_cpi = pimoroni_trackball_get_cpi +}; +// clang-format on + +#elif defined(POINTING_DEVICE_DRIVER_pmw3360) || defined(POINTING_DEVICE_DRIVER_pmw3389) +static void pmw33xx_init_wrapper(void) { + pmw33xx_init(0); +} + +static void pmw33xx_set_cpi_wrapper(uint16_t cpi) { + pmw33xx_set_cpi(0, cpi); +} + +static uint16_t pmw33xx_get_cpi_wrapper(void) { + return pmw33xx_get_cpi(0); +} + +report_mouse_t pmw33xx_get_report(report_mouse_t mouse_report) { + pmw33xx_report_t report = pmw33xx_read_burst(0); + static bool in_motion = false; + + if (report.motion.b.is_lifted) { + return mouse_report; + } + + if (!report.motion.b.is_motion) { + in_motion = false; + return mouse_report; + } + + if (!in_motion) { + in_motion = true; + dprintf("PWM3360 (0): starting motion\n"); + } + + mouse_report.x = CONSTRAIN_HID_XY(report.delta_x); + mouse_report.y = CONSTRAIN_HID_XY(report.delta_y); + return mouse_report; +} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = pmw33xx_init_wrapper, + .get_report = pmw33xx_get_report, + .set_cpi = pmw33xx_set_cpi_wrapper, + .get_cpi = pmw33xx_get_cpi_wrapper +}; +// clang-format on + +#else +__attribute__((weak)) void pointing_device_driver_init(void) {} +__attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) { + return mouse_report; +} +__attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) { + return 0; +} +__attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) {} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = pointing_device_driver_init, + .get_report = pointing_device_driver_get_report, + .get_cpi = pointing_device_driver_get_cpi, + .set_cpi = pointing_device_driver_set_cpi +}; +// clang-format on + +#endif diff --git a/quantum/pointing_device/pointing_device_gestures.c b/quantum/pointing_device/pointing_device_gestures.c new file mode 100644 index 0000000000..02b11ebe3f --- /dev/null +++ b/quantum/pointing_device/pointing_device_gestures.c @@ -0,0 +1,133 @@ +/* Copyright 2022 Daniel Kao + * + * 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 . + */ +#include +#include "pointing_device_gestures.h" +#include "timer.h" + +#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +# ifdef POINTING_DEVICE_MOTION_PIN +# error POINTING_DEVICE_MOTION_PIN not supported when using inertial cursor. Need repeated calls to get_report() to generate glide events. +# endif + +static void cursor_glide_stop(cursor_glide_context_t* glide) { + memset(&glide->status, 0, sizeof(glide->status)); +} + +static cursor_glide_t cursor_glide(cursor_glide_context_t* glide) { + cursor_glide_status_t* status = &glide->status; + cursor_glide_t report; + int32_t p; + int32_t x, y; + + if (status->v0 == 0) { + report.dx = 0; + report.dy = 0; + report.valid = false; + cursor_glide_stop(glide); + goto exit; + } + + status->counter++; + /* Calculate current 1D position */ + p = status->v0 * status->counter - (int32_t)glide->config.coef * status->counter * status->counter / 2; + /* + * Translate to x & y axes + * Done this way instead of applying friction to each axis separately, so we don't end up with the shorter axis stuck at 0 towards the end of diagonal movements. + */ + x = (int32_t)(p * status->dx0 / status->v0); + y = (int32_t)(p * status->dy0 / status->v0); + report.dx = (mouse_xy_report_t)(x - status->x); + report.dy = (mouse_xy_report_t)(y - status->y); + report.valid = true; + if (report.dx <= 1 && report.dx >= -1 && report.dy <= 1 && report.dy >= -1) { + /* Stop gliding once speed is low enough */ + cursor_glide_stop(glide); + goto exit; + } + status->x = x; + status->y = y; + status->timer = timer_read(); + +exit: + return report; +} + +cursor_glide_t cursor_glide_check(cursor_glide_context_t* glide) { + cursor_glide_t invalid_report = {0, 0, false}; + cursor_glide_status_t* status = &glide->status; + + if (status->z || (status->dx0 == 0 && status->dy0 == 0) || timer_elapsed(status->timer) < glide->config.interval) { + return invalid_report; + } else { + return cursor_glide(glide); + } +} + +static inline uint16_t sqrt32(uint32_t x) { + uint32_t l, m, h; + + if (x == 0) { + return 0; + } else if (x > (UINT16_MAX >> 2)) { + /* Safe upper bound to avoid integer overflow with m * m */ + h = UINT16_MAX; + } else { + /* Upper bound based on closest log2 */ + h = (1 << (((__builtin_clzl(1) - __builtin_clzl(x) + 1) + 1) >> 1)); + } + /* Lower bound based on closest log2 */ + l = (1 << ((__builtin_clzl(1) - __builtin_clzl(x)) >> 1)); + + /* Binary search to find integer square root */ + while (l != h - 1) { + m = (l + h) / 2; + if (m * m <= x) { + l = m; + } else { + h = m; + } + } + return l; +} + +cursor_glide_t cursor_glide_start(cursor_glide_context_t* glide) { + cursor_glide_t invalid_report = {0, 0, false}; + cursor_glide_status_t* status = &glide->status; + + status->timer = timer_read(); + status->counter = 0; + status->v0 = (status->dx0 == 0 && status->dy0 == 0) ? 0.0 : sqrt32(((int32_t)status->dx0 * 256 * status->dx0 * 256) + ((int32_t)status->dy0 * 256 * status->dy0 * 256)); // skip trigonometry if not needed, calculate distance in Q8 + status->x = 0; + status->y = 0; + status->z = 0; + + if (status->v0 < ((uint32_t)glide->config.trigger_px * 256)) { /* Q8 comparison */ + /* Not enough velocity to be worth gliding, abort */ + cursor_glide_stop(glide); + return invalid_report; + } + + return cursor_glide(glide); +} + +void cursor_glide_update(cursor_glide_context_t* glide, mouse_xy_report_t dx, mouse_xy_report_t dy, uint16_t z) { + cursor_glide_status_t* status = &glide->status; + + status->dx0 = dx; + status->dy0 = dy; + status->z = z; +} +#endif diff --git a/quantum/pointing_device/pointing_device_gestures.h b/quantum/pointing_device/pointing_device_gestures.h new file mode 100644 index 0000000000..d2ea44971b --- /dev/null +++ b/quantum/pointing_device/pointing_device_gestures.h @@ -0,0 +1,58 @@ +/* Copyright 2022 Daniel Kao + * + * 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 . + */ +#pragma once + +#include +#include "report.h" + +#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +typedef struct { + mouse_xy_report_t dx; + mouse_xy_report_t dy; + bool valid; +} cursor_glide_t; + +typedef struct { + uint16_t trigger_px; /* Pixels of movement needed to trigger cursor glide */ + uint16_t coef; /* Coefficient of friction */ + uint16_t interval; /* Glide report interval, in milliseconds */ +} cursor_glide_config_t; + +typedef struct { + int32_t v0; + int32_t x; + int32_t y; + uint16_t z; + uint16_t timer; + uint16_t counter; + mouse_xy_report_t dx0; + mouse_xy_report_t dy0; +} cursor_glide_status_t; + +typedef struct { + cursor_glide_config_t config; + cursor_glide_status_t status; +} cursor_glide_context_t; + +/* Check glide report conditions, calculates glide coordinates */ +cursor_glide_t cursor_glide_check(cursor_glide_context_t* glide); + +/* Start glide reporting, gives first set of glide coordinates */ +cursor_glide_t cursor_glide_start(cursor_glide_context_t* glide); + +/* Update glide engine on the latest cursor movement, cursor glide is based on the final movement */ +void cursor_glide_update(cursor_glide_context_t* glide, mouse_xy_report_t dx, mouse_xy_report_t dy, uint16_t z); +#endif diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c deleted file mode 100644 index d0b545d22d..0000000000 --- a/quantum/pointing_device_drivers.c +++ /dev/null @@ -1,345 +0,0 @@ -/* Copyright 2017 Joshua Broekhuijsen - * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) - * Copyright 2021 Dasky (@daskygit) - * - * 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 . - */ - -#include "pointing_device.h" -#include "debug.h" -#include "wait.h" -#include "timer.h" -#include - -#define CONSTRAIN_HID(amt) ((amt) < INT8_MIN ? INT8_MIN : ((amt) > INT8_MAX ? INT8_MAX : (amt))) -#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt))) - -// get_report functions should probably be moved to their respective drivers. - -#if defined(POINTING_DEVICE_DRIVER_adns5050) -report_mouse_t adns5050_get_report(report_mouse_t mouse_report) { - report_adns5050_t data = adns5050_read_burst(); - - if (data.dx != 0 || data.dy != 0) { -# ifdef CONSOLE_ENABLE - if (debug_mouse) dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy); -# endif - - mouse_report.x = (mouse_xy_report_t)data.dx; - mouse_report.y = (mouse_xy_report_t)data.dy; - } - - return mouse_report; -} - -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = adns5050_init, - .get_report = adns5050_get_report, - .set_cpi = adns5050_set_cpi, - .get_cpi = adns5050_get_cpi, -}; -// clang-format on - -#elif defined(POINTING_DEVICE_DRIVER_adns9800) - -report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report) { - report_adns9800_t sensor_report = adns9800_get_report(); - - mouse_report.x = CONSTRAIN_HID_XY(sensor_report.x); - mouse_report.y = CONSTRAIN_HID_XY(sensor_report.y); - - return mouse_report; -} - -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = adns9800_init, - .get_report = adns9800_get_report_driver, - .set_cpi = adns9800_set_cpi, - .get_cpi = adns9800_get_cpi -}; -// clang-format on - -#elif defined(POINTING_DEVICE_DRIVER_analog_joystick) -report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report) { - report_analog_joystick_t data = analog_joystick_read(); - -# ifdef CONSOLE_ENABLE - if (debug_mouse) dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y); -# endif - - mouse_report.x = data.x; - mouse_report.y = data.y; - - mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, data.button, POINTING_DEVICE_BUTTON1); - - return mouse_report; -} - -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = analog_joystick_init, - .get_report = analog_joystick_get_report, - .set_cpi = NULL, - .get_cpi = NULL -}; -// clang-format on - -#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE -static bool cursor_glide_enable = true; - -static cursor_glide_context_t glide = {.config = { - .coef = 102, /* Good default friction coef */ - .interval = 10, /* 100sps */ - .trigger_px = 10, /* Default threshold in case of hover, set to 0 if you'd like */ - }}; - -void cirque_pinnacle_enable_cursor_glide(bool enable) { - cursor_glide_enable = enable; -} - -void cirque_pinnacle_configure_cursor_glide(float trigger_px) { - glide.config.trigger_px = trigger_px; -} -# endif - -report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { - pinnacle_data_t touchData = cirque_pinnacle_read_data(); - mouse_xy_report_t report_x = 0, report_y = 0; - static mouse_xy_report_t x = 0, y = 0; -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE - cursor_glide_t glide_report = {0}; - - if (cursor_glide_enable) { - glide_report = cursor_glide_check(&glide); - } -# endif - -# if !CIRQUE_PINNACLE_POSITION_MODE -# error Cirque Pinnacle with relative mode not implemented yet. -# endif - - if (!touchData.valid) { -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE - if (cursor_glide_enable && glide_report.valid) { - report_x = glide_report.dx; - report_y = glide_report.dy; - goto mouse_report_update; - } -# endif - return mouse_report; - } - -# if CONSOLE_ENABLE - if (debug_mouse && touchData.touchDown) { - dprintf("cirque_pinnacle touchData x=%4d y=%4d z=%2d\n", touchData.xValue, touchData.yValue, touchData.zValue); - } -# endif - - // Scale coordinates to arbitrary X, Y resolution - cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); - - if (!cirque_pinnacle_gestures(&mouse_report, touchData)) { - if (x && y && touchData.xValue && touchData.yValue) { - report_x = (mouse_xy_report_t)(touchData.xValue - x); - report_y = (mouse_xy_report_t)(touchData.yValue - y); - } - x = touchData.xValue; - y = touchData.yValue; - -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE - if (cursor_glide_enable) { - if (touchData.touchDown) { - cursor_glide_update(&glide, report_x, report_y, touchData.zValue); - } else if (!glide_report.valid) { - glide_report = cursor_glide_start(&glide); - if (glide_report.valid) { - report_x = glide_report.dx; - report_y = glide_report.dy; - } - } - } -# endif - } - -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE -mouse_report_update: -# endif - mouse_report.x = report_x; - mouse_report.y = report_y; - - return mouse_report; -} - -uint16_t cirque_pinnacle_get_cpi(void) { - return CIRQUE_PINNACLE_PX_TO_INCH(cirque_pinnacle_get_scale()); -} -void cirque_pinnacle_set_cpi(uint16_t cpi) { - cirque_pinnacle_set_scale(CIRQUE_PINNACLE_INCH_TO_PX(cpi)); -} - -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = cirque_pinnacle_init, - .get_report = cirque_pinnacle_get_report, - .set_cpi = cirque_pinnacle_set_cpi, - .get_cpi = cirque_pinnacle_get_cpi -}; -// clang-format on -#elif defined(POINTING_DEVICE_DRIVER_paw3204) - -report_mouse_t paw3204_get_report(report_mouse_t mouse_report) { - report_paw3204_t data = paw3204_read(); - if (data.isMotion) { -# ifdef CONSOLE_ENABLE - dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y); -# endif - - mouse_report.x = data.x; - mouse_report.y = data.y; - } - - return mouse_report; -} -const pointing_device_driver_t pointing_device_driver = { - .init = paw3204_init, - .get_report = paw3204_get_report, - .set_cpi = paw3204_set_cpi, - .get_cpi = paw3204_get_cpi, -}; -#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) - -mouse_xy_report_t pimoroni_trackball_adapt_values(clamp_range_t* offset) { - if (*offset > XY_REPORT_MAX) { - *offset -= XY_REPORT_MAX; - return (mouse_xy_report_t)XY_REPORT_MAX; - } else if (*offset < XY_REPORT_MIN) { - *offset += XY_REPORT_MAX; - return (mouse_xy_report_t)XY_REPORT_MIN; - } else { - mouse_xy_report_t temp_return = *offset; - *offset = 0; - return temp_return; - } -} - -report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) { - static uint16_t debounce = 0; - static uint8_t error_count = 0; - pimoroni_data_t pimoroni_data = {0}; - static clamp_range_t x_offset = 0, y_offset = 0; - - if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) { - i2c_status_t status = read_pimoroni_trackball(&pimoroni_data); - - if (status == I2C_STATUS_SUCCESS) { - error_count = 0; - - if (!(pimoroni_data.click & 128)) { - mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1); - if (!debounce) { - x_offset += pimoroni_trackball_get_offsets(pimoroni_data.right, pimoroni_data.left, PIMORONI_TRACKBALL_SCALE); - y_offset += pimoroni_trackball_get_offsets(pimoroni_data.down, pimoroni_data.up, PIMORONI_TRACKBALL_SCALE); - mouse_report.x = pimoroni_trackball_adapt_values(&x_offset); - mouse_report.y = pimoroni_trackball_adapt_values(&y_offset); - } else { - debounce--; - } - } else { - mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); - debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES; - } - } else { - error_count++; - } - } - return mouse_report; -} - -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = pimoroni_trackball_device_init, - .get_report = pimoroni_trackball_get_report, - .set_cpi = pimoroni_trackball_set_cpi, - .get_cpi = pimoroni_trackball_get_cpi -}; -// clang-format on - -#elif defined(POINTING_DEVICE_DRIVER_pmw3360) || defined(POINTING_DEVICE_DRIVER_pmw3389) -static void pmw33xx_init_wrapper(void) { - pmw33xx_init(0); -} - -static void pmw33xx_set_cpi_wrapper(uint16_t cpi) { - pmw33xx_set_cpi(0, cpi); -} - -static uint16_t pmw33xx_get_cpi_wrapper(void) { - return pmw33xx_get_cpi(0); -} - -report_mouse_t pmw33xx_get_report(report_mouse_t mouse_report) { - pmw33xx_report_t report = pmw33xx_read_burst(0); - static bool in_motion = false; - - if (report.motion.b.is_lifted) { - return mouse_report; - } - - if (!report.motion.b.is_motion) { - in_motion = false; - return mouse_report; - } - - if (!in_motion) { - in_motion = true; - dprintf("PWM3360 (0): starting motion\n"); - } - - mouse_report.x = CONSTRAIN_HID_XY(report.delta_x); - mouse_report.y = CONSTRAIN_HID_XY(report.delta_y); - return mouse_report; -} - -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = pmw33xx_init_wrapper, - .get_report = pmw33xx_get_report, - .set_cpi = pmw33xx_set_cpi_wrapper, - .get_cpi = pmw33xx_get_cpi_wrapper -}; -// clang-format on - -#else -__attribute__((weak)) void pointing_device_driver_init(void) {} -__attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) { - return mouse_report; -} -__attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) { - return 0; -} -__attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) {} - -// clang-format off -const pointing_device_driver_t pointing_device_driver = { - .init = pointing_device_driver_init, - .get_report = pointing_device_driver_get_report, - .get_cpi = pointing_device_driver_get_cpi, - .set_cpi = pointing_device_driver_set_cpi -}; -// clang-format on - -#endif diff --git a/quantum/pointing_device_gestures.c b/quantum/pointing_device_gestures.c deleted file mode 100644 index 02b11ebe3f..0000000000 --- a/quantum/pointing_device_gestures.c +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright 2022 Daniel Kao - * - * 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 . - */ -#include -#include "pointing_device_gestures.h" -#include "timer.h" - -#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE -# ifdef POINTING_DEVICE_MOTION_PIN -# error POINTING_DEVICE_MOTION_PIN not supported when using inertial cursor. Need repeated calls to get_report() to generate glide events. -# endif - -static void cursor_glide_stop(cursor_glide_context_t* glide) { - memset(&glide->status, 0, sizeof(glide->status)); -} - -static cursor_glide_t cursor_glide(cursor_glide_context_t* glide) { - cursor_glide_status_t* status = &glide->status; - cursor_glide_t report; - int32_t p; - int32_t x, y; - - if (status->v0 == 0) { - report.dx = 0; - report.dy = 0; - report.valid = false; - cursor_glide_stop(glide); - goto exit; - } - - status->counter++; - /* Calculate current 1D position */ - p = status->v0 * status->counter - (int32_t)glide->config.coef * status->counter * status->counter / 2; - /* - * Translate to x & y axes - * Done this way instead of applying friction to each axis separately, so we don't end up with the shorter axis stuck at 0 towards the end of diagonal movements. - */ - x = (int32_t)(p * status->dx0 / status->v0); - y = (int32_t)(p * status->dy0 / status->v0); - report.dx = (mouse_xy_report_t)(x - status->x); - report.dy = (mouse_xy_report_t)(y - status->y); - report.valid = true; - if (report.dx <= 1 && report.dx >= -1 && report.dy <= 1 && report.dy >= -1) { - /* Stop gliding once speed is low enough */ - cursor_glide_stop(glide); - goto exit; - } - status->x = x; - status->y = y; - status->timer = timer_read(); - -exit: - return report; -} - -cursor_glide_t cursor_glide_check(cursor_glide_context_t* glide) { - cursor_glide_t invalid_report = {0, 0, false}; - cursor_glide_status_t* status = &glide->status; - - if (status->z || (status->dx0 == 0 && status->dy0 == 0) || timer_elapsed(status->timer) < glide->config.interval) { - return invalid_report; - } else { - return cursor_glide(glide); - } -} - -static inline uint16_t sqrt32(uint32_t x) { - uint32_t l, m, h; - - if (x == 0) { - return 0; - } else if (x > (UINT16_MAX >> 2)) { - /* Safe upper bound to avoid integer overflow with m * m */ - h = UINT16_MAX; - } else { - /* Upper bound based on closest log2 */ - h = (1 << (((__builtin_clzl(1) - __builtin_clzl(x) + 1) + 1) >> 1)); - } - /* Lower bound based on closest log2 */ - l = (1 << ((__builtin_clzl(1) - __builtin_clzl(x)) >> 1)); - - /* Binary search to find integer square root */ - while (l != h - 1) { - m = (l + h) / 2; - if (m * m <= x) { - l = m; - } else { - h = m; - } - } - return l; -} - -cursor_glide_t cursor_glide_start(cursor_glide_context_t* glide) { - cursor_glide_t invalid_report = {0, 0, false}; - cursor_glide_status_t* status = &glide->status; - - status->timer = timer_read(); - status->counter = 0; - status->v0 = (status->dx0 == 0 && status->dy0 == 0) ? 0.0 : sqrt32(((int32_t)status->dx0 * 256 * status->dx0 * 256) + ((int32_t)status->dy0 * 256 * status->dy0 * 256)); // skip trigonometry if not needed, calculate distance in Q8 - status->x = 0; - status->y = 0; - status->z = 0; - - if (status->v0 < ((uint32_t)glide->config.trigger_px * 256)) { /* Q8 comparison */ - /* Not enough velocity to be worth gliding, abort */ - cursor_glide_stop(glide); - return invalid_report; - } - - return cursor_glide(glide); -} - -void cursor_glide_update(cursor_glide_context_t* glide, mouse_xy_report_t dx, mouse_xy_report_t dy, uint16_t z) { - cursor_glide_status_t* status = &glide->status; - - status->dx0 = dx; - status->dy0 = dy; - status->z = z; -} -#endif diff --git a/quantum/pointing_device_gestures.h b/quantum/pointing_device_gestures.h deleted file mode 100644 index d2ea44971b..0000000000 --- a/quantum/pointing_device_gestures.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 2022 Daniel Kao - * - * 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 . - */ -#pragma once - -#include -#include "report.h" - -#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE -typedef struct { - mouse_xy_report_t dx; - mouse_xy_report_t dy; - bool valid; -} cursor_glide_t; - -typedef struct { - uint16_t trigger_px; /* Pixels of movement needed to trigger cursor glide */ - uint16_t coef; /* Coefficient of friction */ - uint16_t interval; /* Glide report interval, in milliseconds */ -} cursor_glide_config_t; - -typedef struct { - int32_t v0; - int32_t x; - int32_t y; - uint16_t z; - uint16_t timer; - uint16_t counter; - mouse_xy_report_t dx0; - mouse_xy_report_t dy0; -} cursor_glide_status_t; - -typedef struct { - cursor_glide_config_t config; - cursor_glide_status_t status; -} cursor_glide_context_t; - -/* Check glide report conditions, calculates glide coordinates */ -cursor_glide_t cursor_glide_check(cursor_glide_context_t* glide); - -/* Start glide reporting, gives first set of glide coordinates */ -cursor_glide_t cursor_glide_start(cursor_glide_context_t* glide); - -/* Update glide engine on the latest cursor movement, cursor glide is based on the final movement */ -void cursor_glide_update(cursor_glide_context_t* glide, mouse_xy_report_t dx, mouse_xy_report_t dy, uint16_t z); -#endif -- cgit v1.2.3 From 9a31bbb3fa4389ea0d0efcb0d283664eaf684190 Mon Sep 17 00:00:00 2001 From: mknj Date: Wed, 20 Jul 2022 23:59:18 +0200 Subject: fix syntax error (#17732) --- quantum/keymap_extras/keymap_turkish_f.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_turkish_f.h b/quantum/keymap_extras/keymap_turkish_f.h index f86ef21546..aaee2aa480 100644 --- a/quantum/keymap_extras/keymap_turkish_f.h +++ b/quantum/keymap_extras/keymap_turkish_f.h @@ -187,7 +187,7 @@ #define TR_CURR S(ALGR(TR_4)) // ¤ #define TR_IQUE S(ALGR(TR_SLSH)) // ¿ // Row 2 -#define TR_REGD S(ALGR(TR_I) // ® +#define TR_REGD S(ALGR(TR_I)) // ® // Row 3 #define TR_SECT S(ALGR(TR_IDOT)) // § #define TR_FORD S(ALGR(TR_A)) // ª -- cgit v1.2.3 From 4efe6330c49f076b9c01d3f609dea0cd9f9b0214 Mon Sep 17 00:00:00 2001 From: Wilba Date: Thu, 21 Jul 2022 09:53:42 +1000 Subject: VIA Encoder Map Support (#17734) --- quantum/via.c | 12 ++++++++++++ quantum/via.h | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/via.c b/quantum/via.c index d2ef0862cc..37e2046a10 100644 --- a/quantum/via.c +++ b/quantum/via.c @@ -397,6 +397,18 @@ void raw_hid_receive(uint8_t *data, uint8_t length) { dynamic_keymap_set_buffer(offset, size, &command_data[3]); break; } +#ifdef ENCODER_MAP_ENABLE + case id_dynamic_keymap_get_encoder: { + uint16_t keycode = dynamic_keymap_get_encoder(command_data[0], command_data[1], command_data[2] != 0); + command_data[3] = keycode >> 8; + command_data[4] = keycode & 0xFF; + break; + } + case id_dynamic_keymap_set_encoder: { + dynamic_keymap_set_encoder(command_data[0], command_data[1], command_data[2] != 0, (command_data[3] << 8) | command_data[4]); + break; + } +#endif default: { // The command ID is not known // Return the unhandled state diff --git a/quantum/via.h b/quantum/via.h index 31d9c21af4..558ae95de4 100644 --- a/quantum/via.h +++ b/quantum/via.h @@ -58,7 +58,7 @@ // This is changed only when the command IDs change, // so VIA Configurator can detect compatible firmware. -#define VIA_PROTOCOL_VERSION 0x0009 +#define VIA_PROTOCOL_VERSION 0x000A enum via_command_id { id_get_protocol_version = 0x01, // always 0x01 @@ -80,6 +80,8 @@ enum via_command_id { id_dynamic_keymap_get_layer_count = 0x11, id_dynamic_keymap_get_buffer = 0x12, id_dynamic_keymap_set_buffer = 0x13, + id_dynamic_keymap_get_encoder = 0x14, + id_dynamic_keymap_set_encoder = 0x15, id_unhandled = 0xFF, }; -- cgit v1.2.3 From 5f32690cba8789c1ac98e71cb8ae8a4b6a5ee2d2 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Thu, 21 Jul 2022 10:16:44 -0700 Subject: Move Pointing Device Initialization (#17740) Move Pointing Device Initialization to after Split Post Initialization If both pointing device and split is enabled, the pointing device init needs to be called after the split post init, otherwise the connection (serial/etc) isn't initialized yet, and any commands that need to send data over (such as calling the set cpi command) never get sent over. --- quantum/keyboard.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'quantum') diff --git a/quantum/keyboard.c b/quantum/keyboard.c index 8273299a9a..2364e3167b 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c @@ -384,9 +384,6 @@ void keyboard_init(void) { #ifdef STENO_ENABLE_ALL steno_init(); #endif -#ifdef POINTING_DEVICE_ENABLE - pointing_device_init(); -#endif #if defined(NKRO_ENABLE) && defined(FORCE_NKRO) keymap_config.nkro = 1; eeconfig_update_keymap(keymap_config.raw); @@ -403,6 +400,10 @@ void keyboard_init(void) { #ifdef SPLIT_KEYBOARD split_post_init(); #endif +#ifdef POINTING_DEVICE_ENABLE + // init after split init + pointing_device_init(); +#endif #if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE) debug_enable = true; -- cgit v1.2.3 From a6f3194397a515ade82f10b5547e82e2863c8685 Mon Sep 17 00:00:00 2001 From: jack <0x6A73@pm.me> Date: Sat, 23 Jul 2022 10:43:32 -0600 Subject: Add ability to enter bootloader mode from `QK_MAKE` (#17745) --- docs/keycodes.md | 14 +++++++------- docs/quantum_keycodes.md | 14 +++++++------- quantum/quantum.c | 3 +++ 3 files changed, 17 insertions(+), 14 deletions(-) (limited to 'quantum') diff --git a/docs/keycodes.md b/docs/keycodes.md index 37e9d00392..d0ba8e25bf 100644 --- a/docs/keycodes.md +++ b/docs/keycodes.md @@ -219,13 +219,13 @@ See also: [Basic Keycodes](keycodes_basic.md) See also: [Quantum Keycodes](quantum_keycodes.md#qmk-keycodes) -|Key |Aliases |Description | -|-----------------|---------|---------------------------------------------------------------------------------| -|`QK_BOOTLOADER` |`QK_BOOT`|Put the keyboard into bootloader mode for flashing | -|`QK_DEBUG_TOGGLE`|`DB_TOGG`|Toggle debug mode | -|`QK_CLEAR_EEPROM`|`EE_CLR` |Reinitializes the keyboard's EEPROM (persistent memory) | -|`QK_MAKE` | |Sends `qmk compile -kb (keyboard) -km (keymap)`, or `qmk flash` if shift is held | -|`QK_REBOOT` |`QK_RBT` |Resets the keyboard. Does not load the bootloader | +|Key |Aliases |Description | +|-----------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------| +|`QK_BOOTLOADER` |`QK_BOOT`|Put the keyboard into bootloader mode for flashing | +|`QK_DEBUG_TOGGLE`|`DB_TOGG`|Toggle debug mode | +|`QK_CLEAR_EEPROM`|`EE_CLR` |Reinitializes the keyboard's EEPROM (persistent memory) | +|`QK_MAKE` | |Sends `qmk compile -kb (keyboard) -km (keymap)`, or `qmk flash` if shift is held. Puts keyboard into bootloader mode if shift & control are held | +|`QK_REBOOT` |`QK_RBT` |Resets the keyboard. Does not load the bootloader | ## Audio Keys :id=audio-keys diff --git a/docs/quantum_keycodes.md b/docs/quantum_keycodes.md index a1923777ef..bc68cbc922 100644 --- a/docs/quantum_keycodes.md +++ b/docs/quantum_keycodes.md @@ -8,10 +8,10 @@ On this page we have documented keycodes between `0x00FF` and `0xFFFF` which are ## QMK Keycodes :id=qmk-keycodes -|Key |Aliases |Description | -|-----------------|---------|---------------------------------------------------------------------------------| -|`QK_BOOTLOADER` |`QK_BOOT`|Put the keyboard into bootloader mode for flashing | -|`QK_DEBUG_TOGGLE`|`DB_TOGG`|Toggle debug mode | -|`QK_CLEAR_EEPROM`|`EE_CLR` |Reinitializes the keyboard's EEPROM (persistent memory) | -|`QK_MAKE` | |Sends `qmk compile -kb (keyboard) -km (keymap)`, or `qmk flash` if shift is held | -|`QK_REBOOT` |`QK_RBT` |Resets the keyboard. Does not load the bootloader | +|Key |Aliases |Description | +|-----------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------| +|`QK_BOOTLOADER` |`QK_BOOT`|Put the keyboard into bootloader mode for flashing | +|`QK_DEBUG_TOGGLE`|`DB_TOGG`|Toggle debug mode | +|`QK_CLEAR_EEPROM`|`EE_CLR` |Reinitializes the keyboard's EEPROM (persistent memory) | +|`QK_MAKE` | |Sends `qmk compile -kb (keyboard) -km (keymap)`, or `qmk flash` if shift is held. Puts keyboard into bootloader mode if shift & control are held | +|`QK_REBOOT` |`QK_RBT` |Resets the keyboard. Does not load the bootloader | diff --git a/quantum/quantum.c b/quantum/quantum.c index d1cfb5fbe0..0d5f398585 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -400,6 +400,9 @@ bool process_record_quantum(keyrecord_t *record) { SEND_STRING_DELAY(" compile ", TAP_CODE_DELAY); } SEND_STRING_DELAY("-kb " QMK_KEYBOARD " -km " QMK_KEYMAP SS_TAP(X_ENTER), TAP_CODE_DELAY); + if (temp_mod & MOD_MASK_CS) { + reset_keyboard(); + } } #endif } -- cgit v1.2.3 From d02cefe613f5ba252c6917c7b0fc6b5b87993062 Mon Sep 17 00:00:00 2001 From: JayceFayne <13365789+JayceFayne@users.noreply.github.com> Date: Sat, 23 Jul 2022 20:21:20 +0200 Subject: implement `tap_code16_delay` (#17748) --- docs/feature_macros.md | 2 +- quantum/quantum.c | 21 ++++++++++++++++----- quantum/quantum.h | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) (limited to 'quantum') diff --git a/docs/feature_macros.md b/docs/feature_macros.md index f5b163d5df..f5bd5be41b 100644 --- a/docs/feature_macros.md +++ b/docs/feature_macros.md @@ -349,7 +349,7 @@ If the keycode is `KC_CAPS`, it waits `TAP_HOLD_CAPS_DELAY` milliseconds instead Like `tap_code()`, but with a `delay` parameter for specifying arbitrary intervals before sending the unregister event. -#### `register_code16();`, `unregister_code16();` and `tap_code16();` +#### `register_code16();`, `unregister_code16();`, `tap_code16();` and `tap_code16_delay(, );` These functions work similar to their regular counterparts, but allow you to use modded keycodes (with Shift, Alt, Control, and/or GUI applied to them). diff --git a/quantum/quantum.c b/quantum/quantum.c index 0d5f398585..80fa1a3ced 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -93,16 +93,27 @@ __attribute__((weak)) void unregister_code16(uint16_t code) { } } -__attribute__((weak)) void tap_code16(uint16_t code) { +/** \brief Tap a keycode with a delay. + * + * \param code The modded keycode to tap. + * \param delay The amount of time in milliseconds to leave the keycode registered, before unregistering it. + */ +__attribute__((weak)) void tap_code16_delay(uint16_t code, uint16_t delay) { register_code16(code); - if (code == KC_CAPS_LOCK) { - wait_ms(TAP_HOLD_CAPS_DELAY); - } else if (TAP_CODE_DELAY > 0) { - wait_ms(TAP_CODE_DELAY); + for (uint16_t i = delay; i > 0; i--) { + wait_ms(1); } unregister_code16(code); } +/** \brief Tap a keycode with the default delay. + * + * \param code The modded keycode to tap. If `code` is `KC_CAPS_LOCK`, the delay will be `TAP_HOLD_CAPS_DELAY`, otherwise `TAP_CODE_DELAY`, if defined. + */ +__attribute__((weak)) void tap_code16(uint16_t code) { + tap_code16_delay(code, code == KC_CAPS_LOCK ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY); +} + __attribute__((weak)) bool process_action_kb(keyrecord_t *record) { return true; } diff --git a/quantum/quantum.h b/quantum/quantum.h index f3a8a323c7..8d74f2be38 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -264,6 +264,7 @@ void shutdown_user(void); void register_code16(uint16_t code); void unregister_code16(uint16_t code); void tap_code16(uint16_t code); +void tap_code16_delay(uint16_t code, uint16_t delay); const char *get_numeric_str(char *buf, size_t buf_len, uint32_t curr_num, char curr_pad); const char *get_u8_str(uint8_t curr_num, char curr_pad); -- cgit v1.2.3 From 325da02e57fe7374e77b82cb00360ba45167e25c Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Mon, 25 Jul 2022 15:06:26 -0700 Subject: Fix QK_MAKE's reboot check (#17795) --- quantum/quantum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/quantum.c b/quantum/quantum.c index 80fa1a3ced..9a0016b150 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -411,7 +411,7 @@ bool process_record_quantum(keyrecord_t *record) { SEND_STRING_DELAY(" compile ", TAP_CODE_DELAY); } SEND_STRING_DELAY("-kb " QMK_KEYBOARD " -km " QMK_KEYMAP SS_TAP(X_ENTER), TAP_CODE_DELAY); - if (temp_mod & MOD_MASK_CS) { + if (temp_mod & MOD_MASK_SHIFT && temp_mod & MOD_MASK_CTRL) { reset_keyboard(); } } -- cgit v1.2.3 From 1de6811ebebba77b4604fb01276d42a8d9003374 Mon Sep 17 00:00:00 2001 From: Daniel Kao Date: Mon, 25 Jul 2022 23:19:33 -0700 Subject: Cirque circular scroll: Support POINTING_DEVICE_COMBINED (#17654) --- drivers/sensors/cirque_pinnacle_gestures.c | 29 +++++++++++++++++------------ quantum/pointing_device/pointing_device.c | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'quantum') diff --git a/drivers/sensors/cirque_pinnacle_gestures.c b/drivers/sensors/cirque_pinnacle_gestures.c index 70f16527ba..dc2f682a83 100644 --- a/drivers/sensors/cirque_pinnacle_gestures.c +++ b/drivers/sensors/cirque_pinnacle_gestures.c @@ -20,6 +20,9 @@ #include "pointing_device.h" #include "timer.h" #include "wait.h" +#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) +# include "keyboard.h" +#endif #if defined(CIRQUE_PINNACLE_TAP_ENABLE) || defined(CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE) static cirque_pinnacle_features_t features = {.tap_enable = true, .circular_scroll_enable = true}; @@ -92,18 +95,28 @@ static inline uint16_t atan2_16(int32_t dy, int32_t dx) { static circular_scroll_t circular_scroll(pinnacle_data_t touchData) { circular_scroll_t report = {0, 0, false}; int8_t x, y, wheel_clicks; - uint8_t center = 256 / 2, mag; + uint8_t center = INT8_MAX, mag; int16_t ang, dot, det, opposite_side, adjacent_side; uint16_t scale = cirque_pinnacle_get_scale(); if (touchData.zValue) { /* * Place origin at center of trackpad, treat coordinates as vectors. - * Scale to fixed int8_t size; angles are independent of resolution. + * Scale to +/-INT8_MAX; angles are independent of resolution. */ if (scale) { - x = (int8_t)((int32_t)touchData.xValue * 256 / scale - center); - y = (int8_t)((int32_t)touchData.yValue * 256 / scale - center); + /* Rotate coordinates into a consistent orientation */ + report_mouse_t rot = {.x = (int8_t)((int32_t)touchData.xValue * INT8_MAX * 2 / scale - center), .y = (int8_t)((int32_t)touchData.yValue * INT8_MAX * 2 / scale - center)}; +# if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) + if (!is_keyboard_left()) { + rot = pointing_device_adjust_by_defines_right(rot); + } else +# endif + { + rot = pointing_device_adjust_by_defines(rot); + } + x = rot.x; + y = rot.y; } else { x = 0; y = 0; @@ -125,15 +138,7 @@ static circular_scroll_t circular_scroll(pinnacle_data_t touchData) { * Horizontal if started from left half * Flipped for left-handed */ -# if defined(POINTING_DEVICE_ROTATION_90) - scroll.axis = y < 0; -# elif defined(POINTING_DEVICE_ROTATION_180) - scroll.axis = x > 0; -# elif defined(POINTING_DEVICE_ROTATION_270) - scroll.axis = y > 0; -# else scroll.axis = x < 0; -# endif } } else if (scroll.state == SCROLL_DETECTING) { report.suppress_touch = true; diff --git a/quantum/pointing_device/pointing_device.c b/quantum/pointing_device/pointing_device.c index 3aa4941687..09f9e5efb7 100644 --- a/quantum/pointing_device/pointing_device.c +++ b/quantum/pointing_device/pointing_device.c @@ -412,7 +412,7 @@ report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, repor */ report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report) { // Support rotation of the sensor data -# if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) +# if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_180_RIGHT) || defined(POINTING_DEVICE_ROTATION_270_RIGHT) mouse_xy_report_t x = mouse_report.x; mouse_xy_report_t y = mouse_report.y; # if defined(POINTING_DEVICE_ROTATION_90_RIGHT) -- cgit v1.2.3 From c982d6c5e3f5b113322beabb8a51c3153cab3d54 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Tue, 26 Jul 2022 17:38:28 +0100 Subject: Avoid OOB in dynamic_keymap_reset (#17695) --- quantum/dynamic_keymap.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'quantum') diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index e80dd6d534..01be9806e4 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c @@ -149,18 +149,25 @@ void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwis void dynamic_keymap_reset(void) { // Reset the keymaps in EEPROM to what is in flash. - // All keyboards using dynamic keymaps should define a layout - // for the same number of layers as DYNAMIC_KEYMAP_LAYER_COUNT. for (int layer = 0; layer < DYNAMIC_KEYMAP_LAYER_COUNT; layer++) { for (int row = 0; row < MATRIX_ROWS; row++) { for (int column = 0; column < MATRIX_COLS; column++) { - dynamic_keymap_set_keycode(layer, row, column, pgm_read_word(&keymaps[layer][row][column])); + if (layer < keymap_layer_count()) { + dynamic_keymap_set_keycode(layer, row, column, pgm_read_word(&keymaps[layer][row][column])); + } else { + dynamic_keymap_set_keycode(layer, row, column, KC_TRANSPARENT); + } } } #ifdef ENCODER_MAP_ENABLE for (int encoder = 0; encoder < NUM_ENCODERS; encoder++) { - dynamic_keymap_set_encoder(layer, encoder, true, pgm_read_word(&encoder_map[layer][encoder][0])); - dynamic_keymap_set_encoder(layer, encoder, false, pgm_read_word(&encoder_map[layer][encoder][1])); + if (layer < encodermap_layer_count()) { + dynamic_keymap_set_encoder(layer, encoder, true, pgm_read_word(&encoder_map[layer][encoder][0])); + dynamic_keymap_set_encoder(layer, encoder, false, pgm_read_word(&encoder_map[layer][encoder][1])); + } else { + dynamic_keymap_set_encoder(layer, encoder, true, KC_TRANSPARENT); + dynamic_keymap_set_encoder(layer, encoder, false, KC_TRANSPARENT); + } } #endif // ENCODER_MAP_ENABLE } -- cgit v1.2.3 From b8b2e9997680bbc0aef074ad0bfb2eb130aafe04 Mon Sep 17 00:00:00 2001 From: Daniel Kao Date: Tue, 26 Jul 2022 11:35:41 -0700 Subject: Constrain Cirque Pinnacle coordinates (#17803) Static x & y should be the same type as touchData.xValue & touchData.yValue: uint16_t. Their delta could be larger than int8_t and should be constrained to mouse_xy_report_t. --- quantum/pointing_device/pointing_device_drivers.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'quantum') diff --git a/quantum/pointing_device/pointing_device_drivers.c b/quantum/pointing_device/pointing_device_drivers.c index d0b545d22d..3780f3d2da 100644 --- a/quantum/pointing_device/pointing_device_drivers.c +++ b/quantum/pointing_device/pointing_device_drivers.c @@ -117,11 +117,11 @@ void cirque_pinnacle_configure_cursor_glide(float trigger_px) { # endif report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { - pinnacle_data_t touchData = cirque_pinnacle_read_data(); - mouse_xy_report_t report_x = 0, report_y = 0; - static mouse_xy_report_t x = 0, y = 0; + pinnacle_data_t touchData = cirque_pinnacle_read_data(); + mouse_xy_report_t report_x = 0, report_y = 0; + static uint16_t x = 0, y = 0; # ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE - cursor_glide_t glide_report = {0}; + cursor_glide_t glide_report = {0}; if (cursor_glide_enable) { glide_report = cursor_glide_check(&glide); @@ -154,8 +154,8 @@ report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { if (!cirque_pinnacle_gestures(&mouse_report, touchData)) { if (x && y && touchData.xValue && touchData.yValue) { - report_x = (mouse_xy_report_t)(touchData.xValue - x); - report_y = (mouse_xy_report_t)(touchData.yValue - y); + report_x = CONSTRAIN_HID_XY((int16_t)(touchData.xValue - x)); + report_y = CONSTRAIN_HID_XY((int16_t)(touchData.yValue - y)); } x = touchData.xValue; y = touchData.yValue; -- cgit v1.2.3 From 95c1cc425e596ddcfff7bebd678635fea7ffbcdc Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Fri, 29 Jul 2022 06:51:01 +0200 Subject: Rename postprocess_steno_user → post_process_steno_user (#17823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/feature_stenography.md | 2 +- docs/ja/feature_stenography.md | 2 +- quantum/process_keycode/process_steno.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'quantum') diff --git a/docs/feature_stenography.md b/docs/feature_stenography.md index e13fe845c5..62d4dabf81 100644 --- a/docs/feature_stenography.md +++ b/docs/feature_stenography.md @@ -133,7 +133,7 @@ bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; } This function is called when a keypress has come in, before it is processed. The keycode should be one of `QK_STENO_BOLT`, `QK_STENO_GEMINI`, or one of the `STN_*` key values. ```c -bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys); +bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys); ``` This function is called after a key has been processed, but before any decision about whether or not to send a chord. This is where to put hooks for things like, say, live displays of steno chords or keys. diff --git a/docs/ja/feature_stenography.md b/docs/ja/feature_stenography.md index f8f7df11e1..b280084ae3 100644 --- a/docs/ja/feature_stenography.md +++ b/docs/ja/feature_stenography.md @@ -77,7 +77,7 @@ bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; } この関数はキーが押されるとキーが処理される前に呼び出されます。キーコードは `QK_STENO_BOLT`、`QK_STENO_GEMINI` あるいは `STN_*` キー値のいずれかでなければなりません。 ```c -bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed); +bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed); ``` この関数はキーが処理された後、ただしコードを送信するかどうかを決める前に呼び出されます。`IS_PRESSED(record->event)` が false で、`pressed` が 0 または 1 の場合は、コードはまもなく送信されますが、まだ送信されてはいません。ここが速記コードあるいはキーのライブ表示などのフックを配置する場所です。 diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c index 20b8b9db4b..30a0d4056f 100644 --- a/quantum/process_keycode/process_steno.c +++ b/quantum/process_keycode/process_steno.c @@ -148,7 +148,7 @@ __attribute__((weak)) bool send_steno_chord_user(steno_mode_t mode, uint8_t chor return true; } -__attribute__((weak)) bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys) { +__attribute__((weak)) bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys) { return true; } @@ -209,12 +209,12 @@ bool process_steno(uint16_t keycode, keyrecord_t *record) { default: return false; } - if (!postprocess_steno_user(keycode, record, mode, chord, n_pressed_keys)) { + if (!post_process_steno_user(keycode, record, mode, chord, n_pressed_keys)) { return false; } } else { // is released n_pressed_keys--; - if (!postprocess_steno_user(keycode, record, mode, chord, n_pressed_keys)) { + if (!post_process_steno_user(keycode, record, mode, chord, n_pressed_keys)) { return false; } if (n_pressed_keys > 0) { -- cgit v1.2.3 From 0b726a437b8906fb52662504ccb6e4f052890f3c Mon Sep 17 00:00:00 2001 From: Drzony Date: Sat, 30 Jul 2022 06:20:34 +0200 Subject: Implement relative mode for Cirque trackpad (#17760) --- docs/feature_pointing_device.md | 75 +++++++++++++------- drivers/sensors/cirque_pinnacle.c | 83 +++++++++++++++++++---- drivers/sensors/cirque_pinnacle.h | 51 ++++++++------ drivers/sensors/cirque_pinnacle_gestures.c | 12 +++- drivers/sensors/cirque_pinnacle_gestures.h | 5 +- drivers/sensors/cirque_pinnacle_regdefs.h | 2 +- quantum/pointing_device/pointing_device_drivers.c | 51 ++++++++++---- 7 files changed, 202 insertions(+), 77 deletions(-) (limited to 'quantum') diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md index f8a55c1c86..17acc15ff0 100644 --- a/docs/feature_pointing_device.md +++ b/docs/feature_pointing_device.md @@ -89,17 +89,16 @@ POINTING_DEVICE_DRIVER = cirque_pinnacle_spi This supports the Cirque Pinnacle 1CA027 Touch Controller, which is used in the TM040040, TM035035 and the TM023023 trackpads. These are I2C or SPI compatible, and both configurations are supported. +#### Common settings + | Setting | Description | Default | | -------------------------------- | ---------------------------------------------------------- | ------------------ | -| `CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` | -| `CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` | -| `CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` | -| `CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` | | `CIRQUE_PINNACLE_DIAMETER_MM` | (Optional) Diameter of the trackpad sensor in millimeters. | `40` | | `CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `ADC_ATTENUATE_4X` | | `CIRQUE_PINNACLE_CURVED_OVERLAY` | (Optional) Applies settings tuned for curved overlay. | _not defined_ | +| `CIRQUE_PINNACLE_POSITION_MODE` | (Optional) Mode of operation. | _not defined_ | -**`CIRQUE_PINNACLE_ATTENUATION`** is a measure of how much data is suppressed in regards to sensitivity. The higher the attenuation, the less sensitive the touchpad will be. +**`CIRQUE_PINNACLE_ATTENUATION`** is a measure of how much data is suppressed in regards to sensitivity. The higher the attenuation, the less sensitive the touchpad will be. Default attenuation is set to 4X, although if you are using a thicker overlay (such as the curved overlay) you will want a lower attenuation such as 2X. The possible values are: * `ADC_ATTENUATE_4X`: Least sensitive @@ -107,6 +106,11 @@ Default attenuation is set to 4X, although if you are using a thicker overlay (s * `ADC_ATTENUATE_2X` * `ADC_ATTENUATE_1X`: Most sensitive +**`CIRQUE_PINNACLE_POSITION_MODE`** can be `CIRQUE_PINNACLE_ABSOLUTE_MODE` or `CIRQUE_PINNACLE_RELATIVE_MODE`. Modes differ in supported features/gestures. + +* `CIRQUE_PINNACLE_ABSOLUTE_MODE`: Reports absolute x, y, z (touch pressure) coordinates and up to 5 hw buttons connected to the trackpad +* `CIRQUE_PINNACLE_RELATIVE_MODE`: Reports x/y deltas, scroll and up to 3 buttons (2 of them can be from taps, see gestures) connected to trackpad. Supports taps on secondary side of split. Saves about 2k of flash compared to absolute mode with all features. + | I2C Setting | Description | Default | | ------------------------- | ------------------------------------------------------------------------------- | ------- | | `CIRQUE_PINNACLE_ADDR` | (Required) Sets the I2C Address for the Cirque Trackpad | `0x2A` | @@ -124,16 +128,37 @@ Default Scaling is 1024. Actual CPI depends on trackpad diameter. Also see the `POINTING_DEVICE_TASK_THROTTLE_MS`, which defaults to 10ms when using Cirque Pinnacle, which matches the internal update rate of the position registers (in standard configuration). Advanced configuration for pen/stylus usage might require lower values. -#### Cirque Trackpad gestures +#### Absolute mode settings -| Gesture Setting | Description | Default | -| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- | -| `CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE` | (Optional) Enable circular scroll. Touch originating in outer ring can trigger scroll by moving along the perimeter. Near side triggers vertical scroll and far side triggers horizontal scroll. | _not defined_ | -| `CIRQUE_PINNACLE_TAP_ENABLE` | (Optional) Enable tap to click. This currently only works on the master side. | _not defined_ | -| `CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | -| `CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | +| Setting | Description | Default | +| -------------------------------- | ---------------------------------------------------------- | ------------------ | +| `CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` | +| `CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` | +| `CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` | +| `CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` | + +#### Absolute mode gestures + +| Gesture Setting | Description | Default | +| ---------------------------------------------- | ------------------------------------------------------------------------------ | -------------------- | +| `CIRQUE_PINNACLE_TAP_ENABLE` | (Optional) Enable tap to click. This currently only works on the master side. | _not defined_ | +| `CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | +| `CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` | + +`POINTING_DEVICE_GESTURES_SCROLL_ENABLE` in this mode enables circular scroll. Touch originating in outer ring can trigger scroll by moving along the perimeter. Near side triggers vertical scroll and far side triggers horizontal scroll. -Additionally, `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` is supported on the Cirque. +Additionally, `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` is supported in this mode. + +#### Relative mode gestures + +| Gesture Setting | Description | Default | +| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| `CIRQUE_PINNACLE_TAP_ENABLE` | (Optional) Enable tap to "left click". Works on both sides of a split keyboard. | _not defined_ | +| `CIRQUE_PINNACLE_SECONDARY_TAP_ENABLE` | (Optional) Tap in upper right corner (half of the finger needs to be outside of the trackpad) of the trackpad will result in "right click". `CIRQUE_PINNACLE_TAP_ENABLE` must be enabled. | _not defined_ | + +Tapping term and debounce are not configurable in this mode since it's handled by trackpad internally. + +`POINTING_DEVICE_GESTURES_SCROLL_ENABLE` in this mode enables side scroll. Touch originating on the right side can trigger vertical scroll (IntelliSense trackpad style). ### PAW 3204 Sensor @@ -152,7 +177,6 @@ The paw 3204 sensor uses a serial type protocol for communication, and requires The CPI range is 400-1600, with supported values of (400, 500, 600, 800, 1000, 1200 and 1600). Defaults to 1000 CPI. - ### Pimoroni Trackball To use the Pimoroni Trackball module, add this to your `rules.mk`: @@ -254,17 +278,18 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {} ## Common Configuration -| Setting | Description | Default | -| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------- | -| `MOUSE_EXTENDED_REPORT` | (Optional) Enables support for extended mouse reports. (-32767 to 32767, instead of just -127 to 127). | _not defined_ | -| `POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ | -| `POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ | -| `POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ | -| `POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ | -| `POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ | -| `POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ | -| `POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _not defined_ | -| `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` | (Optional) Enable inertial cursor. Cursor continues moving after a flick gesture and slows down by kinetic friction. | _not defined_ | +| Setting | Description | Default | +| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| `MOUSE_EXTENDED_REPORT` | (Optional) Enables support for extended mouse reports. (-32767 to 32767, instead of just -127 to 127). | _not defined_ | +| `POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ | +| `POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ | +| `POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ | +| `POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ | +| `POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ | +| `POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ | +| `POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _not defined_ | +| `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` | (Optional) Enable inertial cursor. Cursor continues moving after a flick gesture and slows down by kinetic friction. | _not defined_ | +| `POINTING_DEVICE_GESTURES_SCROLL_ENABLE` | (Optional) Enable scroll gesture. The gesture that activates the scroll is device dependent. | _not defined_ | !> When using `SPLIT_POINTING_ENABLE` the `POINTING_DEVICE_MOTION_PIN` functionality is not supported and `POINTING_DEVICE_TASK_THROTTLE_MS` will default to `1`. Increasing this value will increase transport performance at the cost of possible mouse responsiveness. diff --git a/drivers/sensors/cirque_pinnacle.c b/drivers/sensors/cirque_pinnacle.c index c50d5a2525..8bd4eb736e 100644 --- a/drivers/sensors/cirque_pinnacle.c +++ b/drivers/sensors/cirque_pinnacle.c @@ -9,6 +9,8 @@ #include "wait.h" #include "timer.h" +#include + #ifndef CIRQUE_PINNACLE_ATTENUATION # ifdef CIRQUE_PINNACLE_CURVED_OVERLAY # define CIRQUE_PINNACLE_ATTENUATION EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_2X @@ -31,6 +33,7 @@ void print_byte(uint8_t byte) { } #endif +#if CIRQUE_PINNACLE_POSITION_MODE /* Logical Scaling Functions */ // Clips raw coordinates to "reachable" window of sensor // NOTE: values outside this window can only appear as a result of noise @@ -46,6 +49,7 @@ void ClipCoordinates(pinnacle_data_t* coordinates) { coordinates->yValue = CIRQUE_PINNACLE_Y_UPPER; } } +#endif uint16_t cirque_pinnacle_get_scale(void) { return scale_data; @@ -56,6 +60,7 @@ void cirque_pinnacle_set_scale(uint16_t scale) { // Scales data to desired X & Y resolution void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution) { +#if CIRQUE_PINNACLE_POSITION_MODE uint32_t xTemp = 0; uint32_t yTemp = 0; @@ -71,6 +76,22 @@ void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResoluti // scale coordinates to (xResolution, yResolution) range coordinates->xValue = (uint16_t)(xTemp * xResolution / CIRQUE_PINNACLE_X_RANGE); coordinates->yValue = (uint16_t)(yTemp * yResolution / CIRQUE_PINNACLE_Y_RANGE); +#else + int32_t xTemp = 0, yTemp = 0; + ldiv_t temp; + static int32_t xRemainder, yRemainder; + + temp = ldiv(((int32_t)coordinates->xDelta) * (int32_t)xResolution + xRemainder, (int32_t)CIRQUE_PINNACLE_X_RANGE); + xTemp = temp.quot; + xRemainder = temp.rem; + + temp = ldiv(((int32_t)coordinates->yDelta) * (int32_t)yResolution + yRemainder, (int32_t)CIRQUE_PINNACLE_Y_RANGE); + yTemp = temp.quot; + yRemainder = temp.rem; + + coordinates->xDelta = (int16_t)xTemp; + coordinates->yDelta = (int16_t)yTemp; +#endif } // Clears Status1 register flags (SW_CC and SW_DR) @@ -142,14 +163,20 @@ void ERA_WriteByte(uint16_t address, uint8_t data) { cirque_pinnacle_clear_flags(); } -void cirque_pinnacle_set_adc_attenuation(uint8_t adcGain) { +bool cirque_pinnacle_set_adc_attenuation(uint8_t adcGain) { uint8_t adcconfig = 0x00; ERA_ReadBytes(EXTREG__TRACK_ADCCONFIG, &adcconfig, 1); - adcconfig &= EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK; + adcGain &= EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK; + if (adcGain == (adcconfig & EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK)) { + return false; + } + adcconfig &= ~EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK; adcconfig |= adcGain; ERA_WriteByte(EXTREG__TRACK_ADCCONFIG, adcconfig); ERA_ReadBytes(EXTREG__TRACK_ADCCONFIG, &adcconfig, 1); + + return true; } // Changes thresholds to improve detection of fingers @@ -207,30 +234,52 @@ void cirque_pinnacle_init(void) { touchpad_init = true; - // Host clears SW_CC flag - cirque_pinnacle_clear_flags(); - // send a RESET command now, in case QMK had a soft-reset without a power cycle RAP_Write(HOSTREG__SYSCONFIG1, HOSTREG__SYSCONFIG1__RESET); wait_ms(30); // Pinnacle needs 10-15ms to boot, so wait long enough before configuring RAP_Write(HOSTREG__SYSCONFIG1, HOSTREG__SYSCONFIG1_DEFVAL); wait_us(50); - // FeedConfig2 (Feature flags for Relative Mode Only) + // Host clears SW_CC flag + cirque_pinnacle_clear_flags(); + +#if CIRQUE_PINNACLE_POSITION_MODE RAP_Write(HOSTREG__FEEDCONFIG2, HOSTREG__FEEDCONFIG2_DEFVAL); +#else + // FeedConfig2 (Feature flags for Relative Mode Only) + uint8_t feedconfig2 = HOSTREG__FEEDCONFIG2__GLIDE_EXTEND_DISABLE | HOSTREG__FEEDCONFIG2__INTELLIMOUSE_MODE; +# if !defined(CIRQUE_PINNACLE_TAP_ENABLE) + feedconfig2 |= HOSTREG__FEEDCONFIG2__ALL_TAP_DISABLE; +# endif +# if !defined(CIRQUE_PINNACLE_SECONDARY_TAP_ENABLE) + feedconfig2 |= HOSTREG__FEEDCONFIG2__SECONDARY_TAP_DISABLE; +# elif !defined(CIRQUE_PINNACLE_TAP_ENABLE) +# error CIRQUE_PINNACLE_TAP_ENABLE must be defined for CIRQUE_PINNACLE_SECONDARY_TAP_ENABLE to work +# endif +# if !defined(CIRQUE_PINNACLE_SIDE_SCROLL_ENABLE) + feedconfig2 |= HOSTREG__FEEDCONFIG2__SCROLL_DISABLE; +# endif + RAP_Write(HOSTREG__FEEDCONFIG2, feedconfig2); +#endif // FeedConfig1 (Data Output Flags) RAP_Write(HOSTREG__FEEDCONFIG1, CIRQUE_PINNACLE_POSITION_MODE ? HOSTREG__FEEDCONFIG1__DATA_TYPE__REL0_ABS1 : HOSTREG__FEEDCONFIG1_DEFVAL); +#if CIRQUE_PINNACLE_POSITION_MODE // Host sets z-idle packet count to 5 (default is 0x1E/30) RAP_Write(HOSTREG__ZIDLE, 5); +#endif + + bool calibrate = cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION); - cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION); #ifdef CIRQUE_PINNACLE_CURVED_OVERLAY cirque_pinnacle_tune_edge_sensitivity(); + calibrate = true; #endif - // Force a calibration after setting ADC attenuation - cirque_pinnacle_calibrate(); + if (calibrate) { + // Force a calibration after setting ADC attenuation + cirque_pinnacle_calibrate(); + } cirque_pinnacle_enable_feed(true); } @@ -265,10 +314,18 @@ pinnacle_data_t cirque_pinnacle_read_data(void) { #else // Decode data for relative mode // Registers 0x16 and 0x17 are unused in this mode - result.buttons = data[0] & 0x07; // bit0 = primary button, bit1 = secondary button, bit2 = auxilary button, if Taps enabled then also software-recognized taps are reported - result.xDelta = data[1]; - result.yDelta = data[2]; - result.wheelCount = data[3]; + result.buttons = data[0] & 0x07; // Only three buttons are supported + if ((data[0] & 0x10) && data[1] != 0) { + result.xDelta = -((int16_t)256 - (int16_t)(data[1])); + } else { + result.xDelta = data[1]; + } + if ((data[0] & 0x20) && data[2] != 0) { + result.yDelta = ((int16_t)256 - (int16_t)(data[2])); + } else { + result.yDelta = -((int16_t)data[2]); + } + result.wheelCount = ((int8_t*)data)[3]; #endif result.valid = true; diff --git a/drivers/sensors/cirque_pinnacle.h b/drivers/sensors/cirque_pinnacle.h index 1c9bf06fd3..e9bb9621e4 100644 --- a/drivers/sensors/cirque_pinnacle.h +++ b/drivers/sensors/cirque_pinnacle.h @@ -21,24 +21,35 @@ # define CIRQUE_PINNACLE_DIAMETER_MM 40 #endif +#if CIRQUE_PINNACLE_POSITION_MODE // Coordinate scaling values -#ifndef CIRQUE_PINNACLE_X_LOWER -# define CIRQUE_PINNACLE_X_LOWER 127 // min "reachable" X value -#endif -#ifndef CIRQUE_PINNACLE_X_UPPER -# define CIRQUE_PINNACLE_X_UPPER 1919 // max "reachable" X value -#endif -#ifndef CIRQUE_PINNACLE_Y_LOWER -# define CIRQUE_PINNACLE_Y_LOWER 63 // min "reachable" Y value -#endif -#ifndef CIRQUE_PINNACLE_Y_UPPER -# define CIRQUE_PINNACLE_Y_UPPER 1471 // max "reachable" Y value -#endif -#ifndef CIRQUE_PINNACLE_X_RANGE -# define CIRQUE_PINNACLE_X_RANGE (CIRQUE_PINNACLE_X_UPPER - CIRQUE_PINNACLE_X_LOWER) -#endif -#ifndef CIRQUE_PINNACLE_Y_RANGE -# define CIRQUE_PINNACLE_Y_RANGE (CIRQUE_PINNACLE_Y_UPPER - CIRQUE_PINNACLE_Y_LOWER) +# ifndef CIRQUE_PINNACLE_X_LOWER +# define CIRQUE_PINNACLE_X_LOWER 127 // min "reachable" X value +# endif +# ifndef CIRQUE_PINNACLE_X_UPPER +# define CIRQUE_PINNACLE_X_UPPER 1919 // max "reachable" X value +# endif +# ifndef CIRQUE_PINNACLE_Y_LOWER +# define CIRQUE_PINNACLE_Y_LOWER 63 // min "reachable" Y value +# endif +# ifndef CIRQUE_PINNACLE_Y_UPPER +# define CIRQUE_PINNACLE_Y_UPPER 1471 // max "reachable" Y value +# endif +# ifndef CIRQUE_PINNACLE_X_RANGE +# define CIRQUE_PINNACLE_X_RANGE (CIRQUE_PINNACLE_X_UPPER - CIRQUE_PINNACLE_X_LOWER) +# endif +# ifndef CIRQUE_PINNACLE_Y_RANGE +# define CIRQUE_PINNACLE_Y_RANGE (CIRQUE_PINNACLE_Y_UPPER - CIRQUE_PINNACLE_Y_LOWER) +# endif +# if defined(POINTING_DEVICE_GESTURE_SCROLL_ENABLE) +# define CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE +# endif +#else +# define CIRQUE_PINNACLE_X_RANGE 256 +# define CIRQUE_PINNACLE_Y_RANGE 256 +# if defined(POINTING_DEVICE_GESTURE_SCROLL_ENABLE) +# define CIRQUE_PINNACLE_SIDE_SCROLL_ENABLE +# endif #endif #if !defined(POINTING_DEVICE_TASK_THROTTLE_MS) # define POINTING_DEVICE_TASK_THROTTLE_MS 10 // Cirque Pinnacle in normal operation produces data every 10ms. Advanced configuration for pen/stylus usage might require lower values. @@ -86,9 +97,9 @@ typedef struct { uint8_t buttonFlags; bool touchDown; #else - uint8_t xDelta; - uint8_t yDelta; - uint8_t wheelCount; + int16_t xDelta; + int16_t yDelta; + int8_t wheelCount; uint8_t buttons; #endif } pinnacle_data_t; diff --git a/drivers/sensors/cirque_pinnacle_gestures.c b/drivers/sensors/cirque_pinnacle_gestures.c index dc2f682a83..a73b745e59 100644 --- a/drivers/sensors/cirque_pinnacle_gestures.c +++ b/drivers/sensors/cirque_pinnacle_gestures.c @@ -24,11 +24,11 @@ # include "keyboard.h" #endif -#if defined(CIRQUE_PINNACLE_TAP_ENABLE) || defined(CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE) +#if (defined(CIRQUE_PINNACLE_TAP_ENABLE) || defined(CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE)) && CIRQUE_PINNACLE_POSITION_MODE static cirque_pinnacle_features_t features = {.tap_enable = true, .circular_scroll_enable = true}; #endif -#ifdef CIRQUE_PINNACLE_TAP_ENABLE +#if defined(CIRQUE_PINNACLE_TAP_ENABLE) && CIRQUE_PINNACLE_POSITION_MODE static trackpad_tap_context_t tap; static report_mouse_t trackpad_tap(report_mouse_t mouse_report, pinnacle_data_t touchData) { @@ -62,6 +62,9 @@ void cirque_pinnacle_enable_tap(bool enable) { #endif #ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE +# if !CIRQUE_PINNACLE_POSITION_MODE +# error "Circular scroll is not supported in relative mode" +# endif /* To set a trackpad exclusively as scroll wheel: outer_ring_pct = 100, trigger_px = 0, trigger_ang = 0 */ static circular_scroll_context_t scroll = {.config = {.outer_ring_pct = 33, .trigger_px = 16, @@ -213,6 +216,9 @@ bool cirque_pinnacle_gestures(report_mouse_t* mouse_report, pinnacle_data_t touc bool suppress_mouse_update = false; #ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE +# if !CIRQUE_PINNACLE_POSITION_MODE +# error "Circular scroll is not supported in relative mode" +# endif circular_scroll_t scroll_report; if (features.circular_scroll_enable) { scroll_report = circular_scroll(touchData); @@ -222,7 +228,7 @@ bool cirque_pinnacle_gestures(report_mouse_t* mouse_report, pinnacle_data_t touc } #endif -#ifdef CIRQUE_PINNACLE_TAP_ENABLE +#if defined(CIRQUE_PINNACLE_TAP_ENABLE) && CIRQUE_PINNACLE_POSITION_MODE if (features.tap_enable) { *mouse_report = trackpad_tap(*mouse_report, touchData); } diff --git a/drivers/sensors/cirque_pinnacle_gestures.h b/drivers/sensors/cirque_pinnacle_gestures.h index f39782b467..d2aa206b2b 100644 --- a/drivers/sensors/cirque_pinnacle_gestures.h +++ b/drivers/sensors/cirque_pinnacle_gestures.h @@ -24,7 +24,7 @@ typedef struct { bool circular_scroll_enable; } cirque_pinnacle_features_t; -#ifdef CIRQUE_PINNACLE_TAP_ENABLE +#if defined(CIRQUE_PINNACLE_TAP_ENABLE) && CIRQUE_PINNACLE_POSITION_MODE # ifndef CIRQUE_PINNACLE_TAPPING_TERM # include "action.h" # include "action_tapping.h" @@ -44,6 +44,9 @@ void cirque_pinnacle_enable_tap(bool enable); #endif #ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE +# if !CIRQUE_PINNACLE_POSITION_MODE +# error "Circular scroll is not supported in relative mode" +# endif typedef enum { SCROLL_UNINITIALIZED, SCROLL_DETECTING, diff --git a/drivers/sensors/cirque_pinnacle_regdefs.h b/drivers/sensors/cirque_pinnacle_regdefs.h index 993da1e757..fb9e09af6e 100644 --- a/drivers/sensors/cirque_pinnacle_regdefs.h +++ b/drivers/sensors/cirque_pinnacle_regdefs.h @@ -384,7 +384,7 @@ #define EXTREG__TRACK_ADCCONFIG 0x0187 // ADC-attenuation settings (held in BIT_7 and BIT_6) // 1X = most sensitive, 4X = least sensitive -# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK 0x3F +# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK 0xC0 # define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_1X 0x00 # define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_2X 0x40 # define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_3X 0x80 diff --git a/quantum/pointing_device/pointing_device_drivers.c b/quantum/pointing_device/pointing_device_drivers.c index 3780f3d2da..b96f8ff4b3 100644 --- a/quantum/pointing_device/pointing_device_drivers.c +++ b/quantum/pointing_device/pointing_device_drivers.c @@ -116,38 +116,35 @@ void cirque_pinnacle_configure_cursor_glide(float trigger_px) { } # endif +# if CIRQUE_PINNACLE_POSITION_MODE report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { pinnacle_data_t touchData = cirque_pinnacle_read_data(); mouse_xy_report_t report_x = 0, report_y = 0; static uint16_t x = 0, y = 0; -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE cursor_glide_t glide_report = {0}; if (cursor_glide_enable) { glide_report = cursor_glide_check(&glide); } -# endif - -# if !CIRQUE_PINNACLE_POSITION_MODE -# error Cirque Pinnacle with relative mode not implemented yet. -# endif +# endif if (!touchData.valid) { -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE if (cursor_glide_enable && glide_report.valid) { report_x = glide_report.dx; report_y = glide_report.dy; goto mouse_report_update; } -# endif +# endif return mouse_report; } -# if CONSOLE_ENABLE +# if CONSOLE_ENABLE if (debug_mouse && touchData.touchDown) { dprintf("cirque_pinnacle touchData x=%4d y=%4d z=%2d\n", touchData.xValue, touchData.yValue, touchData.zValue); } -# endif +# endif // Scale coordinates to arbitrary X, Y resolution cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); @@ -160,7 +157,7 @@ report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { x = touchData.xValue; y = touchData.yValue; -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE if (cursor_glide_enable) { if (touchData.touchDown) { cursor_glide_update(&glide, report_x, report_y, touchData.zValue); @@ -172,12 +169,12 @@ report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { } } } -# endif +# endif } -# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE +# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE mouse_report_update: -# endif +# endif mouse_report.x = report_x; mouse_report.y = report_y; @@ -199,6 +196,32 @@ const pointing_device_driver_t pointing_device_driver = { .get_cpi = cirque_pinnacle_get_cpi }; // clang-format on +# else +report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) { + pinnacle_data_t touchData = cirque_pinnacle_read_data(); + + // Scale coordinates to arbitrary X, Y resolution + cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); + + if (touchData.valid) { + mouse_report.buttons = touchData.buttons; + mouse_report.x = CONSTRAIN_HID_XY(touchData.xDelta); + mouse_report.y = CONSTRAIN_HID_XY(touchData.yDelta); + mouse_report.v = touchData.wheelCount; + } + return mouse_report; +} + +// clang-format off +const pointing_device_driver_t pointing_device_driver = { + .init = cirque_pinnacle_init, + .get_report = cirque_pinnacle_get_report, + .set_cpi = cirque_pinnacle_set_scale, + .get_cpi = cirque_pinnacle_get_scale +}; +// clang-format on +# endif + #elif defined(POINTING_DEVICE_DRIVER_paw3204) report_mouse_t paw3204_get_report(report_mouse_t mouse_report) { -- cgit v1.2.3 From 2bdd73f80135965c1047b24b78fdf15c1ebbbee7 Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Sun, 31 Jul 2022 21:58:25 -0500 Subject: Add ST7735 driver to Quantum Painter (#17848) --- docs/quantum_painter.md | 29 +++++- drivers/painter/st77xx/qp_st7735.c | 144 +++++++++++++++++++++++++++++ drivers/painter/st77xx/qp_st7735.h | 45 +++++++++ drivers/painter/st77xx/qp_st7735_opcodes.h | 31 +++++++ quantum/painter/qp.h | 4 + quantum/painter/rules.mk | 13 ++- 6 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 drivers/painter/st77xx/qp_st7735.c create mode 100644 drivers/painter/st77xx/qp_st7735.h create mode 100644 drivers/painter/st77xx/qp_st7735_opcodes.h (limited to 'quantum') diff --git a/docs/quantum_painter.md b/docs/quantum_painter.md index 2386a70933..6d4e2764d4 100644 --- a/docs/quantum_painter.md +++ b/docs/quantum_painter.md @@ -27,6 +27,7 @@ Hardware supported: | ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9488_spi` | | SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ssd1351_spi` | | ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = st7789_spi` | +| ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = st7735_spi` | ## Quantum Painter Configuration :id=quantum-painter-config @@ -727,4 +728,30 @@ The maximum number of displays can be configured by changing the following in yo #define ST7789_NUM_DEVICES 3 ``` -!> Some ST7789 devices are known to have different drawing offsets -- despite being a 240x320 pixel display controller internally, some display panels are only 240x240, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered. \ No newline at end of file +!> Some ST7789 devices are known to have different drawing offsets -- despite being a 240x320 pixel display controller internally, some display panels are only 240x240, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered. + +### ST7735 :id=qp-driver-st7735 + +Enabling support for the ST7735 in Quantum Painter is done by adding the following to `rules.mk`: + +```make +QUANTUM_PAINTER_ENABLE = yes +QUANTUM_PAINTER_DRIVERS = st7735_spi +``` + +Creating a ST7735 device in firmware can then be done with the following API: + +```c +painter_device_t qp_st7735_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); +``` + +The device handle returned from the `qp_st7735_make_spi_device` function can be used to perform all other drawing operations. + +The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): + +```c +// 3 displays: +#define ST7735_NUM_DEVICES 3 +``` + +!> Some ST7735 devices are known to have different drawing offsets -- despite being a 132x162 pixel display controller internally, some display panels are only 80x160, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered. \ No newline at end of file diff --git a/drivers/painter/st77xx/qp_st7735.c b/drivers/painter/st77xx/qp_st7735.c new file mode 100644 index 0000000000..e434e31b92 --- /dev/null +++ b/drivers/painter/st77xx/qp_st7735.c @@ -0,0 +1,144 @@ +// Copyright 2021 Paul Cotter (@gr1mr3aver) +// Copyright 2021 Nick Brassel (@tzarc) +// Copyright 2022 David Hoelscher (@customMK) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qp_internal.h" +#include "qp_comms.h" +#include "qp_st7735.h" +#include "qp_st77xx_opcodes.h" +#include "qp_st7735_opcodes.h" +#include "qp_tft_panel.h" + +#ifdef QUANTUM_PAINTER_ST7735_SPI_ENABLE +# include "qp_comms_spi.h" +#endif // QUANTUM_PAINTER_ST7735_SPI_ENABLE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common + +// Driver storage +tft_panel_dc_reset_painter_device_t st7735_drivers[ST7735_NUM_DEVICES] = {0}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Automatic viewport offsets + +#ifndef ST7735_NO_AUTOMATIC_OFFSETS +static inline void st7735_automatic_viewport_offsets(painter_device_t device, painter_rotation_t rotation) { + struct painter_driver_t *driver = (struct painter_driver_t *)device; + + // clang-format off + const struct { + uint16_t offset_x; + uint16_t offset_y; + } rotation_offsets_80x160[] = { + [QP_ROTATION_0] = { .offset_x = 24, .offset_y = 0 }, + [QP_ROTATION_90] = { .offset_x = 0, .offset_y = 24 }, + [QP_ROTATION_180] = { .offset_x = 24, .offset_y = 0 }, + [QP_ROTATION_270] = { .offset_x = 0, .offset_y = 24 }, + }; + // clang-format on + + if (driver->panel_width == 80 && driver->panel_height == 160) { + driver->offset_x = rotation_offsets_80x160[rotation].offset_x; + driver->offset_y = rotation_offsets_80x160[rotation].offset_y; + } +} +#endif // ST7735_NO_AUTOMATIC_OFFSETS + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Initialization + +bool qp_st7735_init(painter_device_t device, painter_rotation_t rotation) { + // clang-format off + const uint8_t st7735_init_sequence[] = { + // Command, Delay, N, Data[N] + ST77XX_CMD_RESET, 120, 0, + ST77XX_CMD_SLEEP_OFF, 5, 0, + ST77XX_SET_PIX_FMT, 0, 1, 0x55, + ST77XX_CMD_INVERT_OFF, 0, 0, + ST77XX_CMD_NORMAL_ON, 0, 0, + ST77XX_CMD_DISPLAY_ON, 20, 0 + }; + // clang-format on + qp_comms_bulk_command_sequence(device, st7735_init_sequence, sizeof(st7735_init_sequence)); + + // Configure the rotation (i.e. the ordering and direction of memory writes in GRAM) + const uint8_t madctl[] = { + [QP_ROTATION_0] = ST77XX_MADCTL_BGR, + [QP_ROTATION_90] = ST77XX_MADCTL_BGR | ST77XX_MADCTL_MX | ST77XX_MADCTL_MV, + [QP_ROTATION_180] = ST77XX_MADCTL_BGR | ST77XX_MADCTL_MX | ST77XX_MADCTL_MY, + [QP_ROTATION_270] = ST77XX_MADCTL_BGR | ST77XX_MADCTL_MV | ST77XX_MADCTL_MY, + }; + qp_comms_command_databyte(device, ST77XX_SET_MADCTL, madctl[rotation]); + +#ifndef ST7735_NO_AUTOMATIC_VIEWPORT_OFFSETS + st7735_automatic_viewport_offsets(device, rotation); +#endif // ST7735_NO_AUTOMATIC_VIEWPORT_OFFSETS + + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Driver vtable + +const struct tft_panel_dc_reset_painter_driver_vtable_t st7735_driver_vtable = { + .base = + { + .init = qp_st7735_init, + .power = qp_tft_panel_power, + .clear = qp_tft_panel_clear, + .flush = qp_tft_panel_flush, + .pixdata = qp_tft_panel_pixdata, + .viewport = qp_tft_panel_viewport, + .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, + .append_pixels = qp_tft_panel_append_pixels_rgb565, + }, + .num_window_bytes = 2, + .swap_window_coords = false, + .opcodes = + { + .display_on = ST77XX_CMD_DISPLAY_ON, + .display_off = ST77XX_CMD_DISPLAY_OFF, + .set_column_address = ST77XX_SET_COL_ADDR, + .set_row_address = ST77XX_SET_ROW_ADDR, + .enable_writes = ST77XX_SET_MEM, + }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SPI + +#ifdef QUANTUM_PAINTER_ST7735_SPI_ENABLE + +// Factory function for creating a handle to the ST7735 device +painter_device_t qp_st7735_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode) { + for (uint32_t i = 0; i < ST7735_NUM_DEVICES; ++i) { + tft_panel_dc_reset_painter_device_t *driver = &st7735_drivers[i]; + if (!driver->base.driver_vtable) { + driver->base.driver_vtable = (const struct painter_driver_vtable_t *)&st7735_driver_vtable; + driver->base.comms_vtable = (const struct painter_comms_vtable_t *)&spi_comms_with_dc_vtable; + driver->base.panel_width = panel_width; + driver->base.panel_height = panel_height; + driver->base.rotation = QP_ROTATION_0; + driver->base.offset_x = 0; + driver->base.offset_y = 0; + driver->base.native_bits_per_pixel = 16; // RGB565 + + // SPI and other pin configuration + driver->base.comms_config = &driver->spi_dc_reset_config; + driver->spi_dc_reset_config.spi_config.chip_select_pin = chip_select_pin; + driver->spi_dc_reset_config.spi_config.divisor = spi_divisor; + driver->spi_dc_reset_config.spi_config.lsb_first = false; + driver->spi_dc_reset_config.spi_config.mode = spi_mode; + driver->spi_dc_reset_config.dc_pin = dc_pin; + driver->spi_dc_reset_config.reset_pin = reset_pin; + return (painter_device_t)driver; + } + } + return NULL; +} + +#endif // QUANTUM_PAINTER_ST7735_SPI_ENABLE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/drivers/painter/st77xx/qp_st7735.h b/drivers/painter/st77xx/qp_st7735.h new file mode 100644 index 0000000000..a9ce16bef1 --- /dev/null +++ b/drivers/painter/st77xx/qp_st7735.h @@ -0,0 +1,45 @@ +// Copyright 2021 Paul Cotter (@gr1mr3aver) +// Copyright 2021 Nick Brassel (@tzarc) +// Copyright 2022 David Hoelscher (@customMK) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "gpio.h" +#include "qp_internal.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter ST7735 configurables (add to your keyboard's config.h) + +#ifndef ST7735_NUM_DEVICES +/** + * @def This controls the maximum number of ST7735 devices that Quantum Painter can communicate with at any one time. + * Increasing this number allows for multiple displays to be used. + */ +# define ST7735_NUM_DEVICES 1 +#endif + +// Additional configuration options to be copied to your keyboard's config.h (don't change here): + +// If you know exactly which offsets should be used on your panel with respect to selected rotation, then this config +// option allows you to save some flash space -- you'll need to invoke qp_set_viewport_offsets() instead from your keyboard. +// #define ST7735_NO_AUTOMATIC_VIEWPORT_OFFSETS + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter ST7735 device factories + +#ifdef QUANTUM_PAINTER_ST7735_SPI_ENABLE +/** + * Factory method for an ST7735 SPI LCD device. + * + * @param panel_width[in] the width of the display panel + * @param panel_height[in] the height of the display panel + * @param chip_select_pin[in] the GPIO pin used for SPI chip select + * @param dc_pin[in] the GPIO pin used for D/C control + * @param reset_pin[in] the GPIO pin used for RST + * @param spi_divisor[in] the SPI divisor to use when communicating with the display + * @param spi_mode[in] the SPI mode to use when communicating with the display + * @return the device handle used with all drawing routines in Quantum Painter + */ +painter_device_t qp_st7735_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); +#endif // QUANTUM_PAINTER_ST7735_SPI_ENABLE \ No newline at end of file diff --git a/drivers/painter/st77xx/qp_st7735_opcodes.h b/drivers/painter/st77xx/qp_st7735_opcodes.h new file mode 100644 index 0000000000..3cbef78537 --- /dev/null +++ b/drivers/painter/st77xx/qp_st7735_opcodes.h @@ -0,0 +1,31 @@ +// Copyright 2022 David Hoelscher (@customMK) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter ST7735 additional command opcodes + +// Panel Function Commands +#define ST7735_SET_FRAME_RATE_CTL_1 0xB1 // Set frame rate control 1 +#define ST7735_SET_FRAME_RATE_CTL_2 0xB2 // Set frame rate control 2 +#define ST7735_SET_FRAME_RATE_CTL_3 0xB3 // Set frame rate control 3 +#define ST7735_SET_INVERSION_CTL 0xB4 // Set inversion mode control +#define ST7735_SET_DISPLAY_CTL 0xB6 // Set display control 5 +#define ST7735_SET_POWER_CTL_1 0xC0 // Set GVDD +#define ST7735_SET_POWER_CTL_2 0xC1 // Set VGH and VGL +#define ST7735_SET_POWER_CTL_3 0xC2 // Set normal mode op amp current +#define ST7735_SET_POWER_CTL_4 0xC3 // Set idle mode op amp current +#define ST7735_SET_POWER_CTL_5 0xC4 // Set partial mode op amp current +#define ST7735_SET_VCOM_CTL 0xC5 // Set VCOM voltages +#define ST7735_SET_VCOM_OFFSET_CTL 0xC7 // Set VCOM offset ctl +#define ST7735_SET_LCD_ID 0xD1 // Set LCD module version +#define ST7735_SET_PROJECT_ID 0xD2 // Set product project ID +#define ST7735_SET_POWER_CTL_6 0xFC // Set partial+idle op amp current +#define ST7735_SET_NVMEM_CTL_STATUS 0xD9 // EEPROM Control Status +#define ST7735_SET_NVMEM_READ_CMD 0xCC // EEPROM Read Command +#define ST7735_SET_NVMEM_WRITE_CMD 0xDF // EEPROM Write Command +#define ST7735_SET_PGAMMA 0xE0 // Set positive gamma +#define ST7735_SET_NGAMMA 0xE1 // Set negative gamma +#define ST7735_SET_EXTENSION_ENABLE 0xF0 // Enable extension command +#define ST7735_SET_VCOM_DELAY 0xFF // Set VCOM delay time diff --git a/quantum/painter/qp.h b/quantum/painter/qp.h index 47f077d0cf..fb6904de22 100644 --- a/quantum/painter/qp.h +++ b/quantum/painter/qp.h @@ -448,6 +448,10 @@ int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, pai # include "qp_st7789.h" #endif // QUANTUM_PAINTER_ST7789_ENABLE +#ifdef QUANTUM_PAINTER_ST7735_ENABLE +# include "qp_st7735.h" +#endif // QUANTUM_PAINTER_ST7735_ENABLE + #ifdef QUANTUM_PAINTER_GC9A01_ENABLE # include "qp_gc9a01.h" #endif // QUANTUM_PAINTER_GC9A01_ENABLE diff --git a/quantum/painter/rules.mk b/quantum/painter/rules.mk index 675a1a5460..91787dfe0e 100644 --- a/quantum/painter/rules.mk +++ b/quantum/painter/rules.mk @@ -3,7 +3,7 @@ QUANTUM_PAINTER_DRIVERS ?= QUANTUM_PAINTER_ANIMATIONS_ENABLE ?= yes # The list of permissible drivers that can be listed in QUANTUM_PAINTER_DRIVERS -VALID_QUANTUM_PAINTER_DRIVERS := ili9163_spi ili9341_spi ili9488_spi st7789_spi gc9a01_spi ssd1351_spi +VALID_QUANTUM_PAINTER_DRIVERS := ili9163_spi ili9341_spi ili9488_spi st7789_spi st7735_spi gc9a01_spi ssd1351_spi #------------------------------------------------------------------------------- @@ -83,6 +83,17 @@ define handle_quantum_painter_driver $(DRIVER_PATH)/painter/tft_panel/qp_tft_panel.c \ $(DRIVER_PATH)/painter/st77xx/qp_st7789.c + else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),st7735_spi) + QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes + QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes + OPT_DEFS += -DQUANTUM_PAINTER_ST7735_ENABLE -DQUANTUM_PAINTER_ST7735_SPI_ENABLE + COMMON_VPATH += \ + $(DRIVER_PATH)/painter/tft_panel \ + $(DRIVER_PATH)/painter/st77xx + SRC += \ + $(DRIVER_PATH)/painter/tft_panel/qp_tft_panel.c \ + $(DRIVER_PATH)/painter/st77xx/qp_st7735.c + else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),gc9a01_spi) QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes -- cgit v1.2.3 From ed9bdcbc3608819e17ff7a11221e651bf51ec1cc Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Sat, 6 Aug 2022 10:46:59 +0200 Subject: [Core] guard RPC invocation by checking RPC info against crc checksum (#17840) --- quantum/split_common/transactions.c | 18 ++++++++++++------ quantum/split_common/transport.h | 9 ++++++--- 2 files changed, 18 insertions(+), 9 deletions(-) (limited to 'quantum') diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c index 9e3df534e3..719068908f 100644 --- a/quantum/split_common/transactions.c +++ b/quantum/split_common/transactions.c @@ -694,7 +694,7 @@ split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = { #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) [PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback), [PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer), - [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.transaction_id, slave_rpc_exec_callback), + [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.payload.transaction_id, slave_rpc_exec_callback), [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer), #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) }; @@ -760,7 +760,8 @@ bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false; // Prepare the metadata block - rpc_sync_info_t info = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size}; + rpc_sync_info_t info = {.payload = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size}}; + info.checksum = crc8(&info.payload, sizeof(info.payload)); // Make sure the local side knows that we're not sending the full block of data split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size; @@ -791,18 +792,23 @@ void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *i // Ignore the args -- the `split_shmem` already has the info, we just need to act upon it. // We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime. - split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.m2s_length; - split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.s2m_length; + split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.payload.m2s_length; + split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.payload.s2m_length; } void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) { // We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed. // Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs. - int8_t transaction_id = split_shmem->rpc_info.transaction_id; + // As a safety precaution we check that the received payload matches its checksum first. + if (crc8(&split_shmem->rpc_info.payload, sizeof(split_shmem->rpc_info.payload)) != split_shmem->rpc_info.checksum) { + return; + } + + int8_t transaction_id = split_shmem->rpc_info.payload.transaction_id; if (transaction_id < NUM_TOTAL_TRANSACTIONS) { split_transaction_desc_t *trans = &split_transaction_table[transaction_id]; if (trans->slave_callback) { - trans->slave_callback(split_shmem->rpc_info.m2s_length, split_shmem->rpc_m2s_buffer, split_shmem->rpc_info.s2m_length, split_shmem->rpc_s2m_buffer); + trans->slave_callback(split_shmem->rpc_info.payload.m2s_length, split_shmem->rpc_m2s_buffer, split_shmem->rpc_info.payload.s2m_length, split_shmem->rpc_s2m_buffer); } } } diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h index e62679990a..06778ad14a 100644 --- a/quantum/split_common/transport.h +++ b/quantum/split_common/transport.h @@ -116,9 +116,12 @@ typedef struct _split_slave_pointing_sync_t { #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) typedef struct _rpc_sync_info_t { - int8_t transaction_id; - uint8_t m2s_length; - uint8_t s2m_length; + uint8_t checksum; + struct { + int8_t transaction_id; + uint8_t m2s_length; + uint8_t s2m_length; + } payload; } rpc_sync_info_t; #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) -- cgit v1.2.3 From f27b617f36d55ac5469247016a1b79304f892366 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Sat, 6 Aug 2022 12:51:13 +0200 Subject: [Core] Process all changed keys in one scan loop, deprecate `QMK_KEYS_PER_SCAN` (#15292) --- data/mappings/info_config.json | 2 +- docs/config_options.md | 9 -- docs/ja/config_options.md | 2 - .../gherkin/keymaps/stevexyz/config.h | 2 - keyboards/ai03/jp60/keymaps/default/config.h | 20 --- keyboards/ai03/jp60/keymaps/via/config.h | 20 --- keyboards/bioi/morgan65/config.h | 2 - keyboards/doio/kb16/config.h | 3 - .../dztech/dz60rgb/keymaps/kgreulich/config.h | 2 - .../dztech/dz60rgb/keymaps/matthewrobo/config.h | 2 - keyboards/dztech/dz60rgb/keymaps/xunz/config.h | 2 - .../dztech/dz65rgb/keymaps/matthewrobo/config.h | 2 - keyboards/dztech/dz65rgb/keymaps/yuannan/config.h | 2 - .../ergodox_ez/keymaps/dvorak_42_key/keymap.c | 2 - .../ergodox_ez/keymaps/hacker_dvorak/config.h | 1 - keyboards/ergodox_ez/keymaps/rgb_layer/config.h | 6 +- keyboards/ergodox_ez/keymaps/rmw/config.h | 1 - keyboards/eternal_keypad/keymaps/kyek/config.h | 2 - keyboards/gmmk/gmmk2/p96/config.h | 4 - keyboards/gmmk/pro/config.h | 3 - keyboards/gopolar/gg86/config.h | 3 - keyboards/handwired/marauder/config.h | 2 +- keyboards/handwired/xealous/config.h | 1 - .../horrortroll/chinese_pcb/black_e65/config.h | 3 - .../horrortroll/chinese_pcb/devil68_pro/config.h | 3 - keyboards/horrortroll/handwired_k552/config.h | 3 - keyboards/horrortroll/lemon40/config.h | 3 - keyboards/horrortroll/paws60/config.h | 3 - keyboards/ianklug/grooveboard/config.h | 2 - keyboards/jadookb/jkb2/keymaps/via/config.h | 19 --- keyboards/jadookb/jkb65/keymaps/via/config.h | 19 --- .../kbdfans/kbd67/mkiirgb/keymaps/dnsnrk/config.h | 2 - .../kbd67/mkiirgb/keymaps/pascalpfeil/config.h | 3 - keyboards/keystonecaps/gameroyadvance/config.h | 4 - .../kprepublic/bm40hsrgb/keymaps/34keys/config.h | 5 +- .../bm40hsrgb/keymaps/gabustoledo/config.h | 3 - .../bm68hsrgb/rev1/keymaps/peepeetee/config.h | 1 - .../bm80hsrgb/keymaps/peepeetee/config.h | 1 - .../kprepublic/jj40/keymaps/stevexyz/config.h | 2 - keyboards/lets_split/keymaps/piemod/config.h | 3 - .../lfkpad/keymaps/pascalpfeil/config.h | 3 - .../minidox/keymaps/norman/config.h | 1 - keyboards/massdrop/alt/keymaps/b_/config.h | 1 - keyboards/massdrop/alt/keymaps/pregame/config.h | 1 - keyboards/massdrop/ctrl/keymaps/endgame/config.h | 1 - .../massdrop/ctrl/keymaps/matthewrobo/config.h | 1 - keyboards/massdrop/ctrl/keymaps/xanimos/config.h | 1 - keyboards/ml/gas75/config.h | 3 - keyboards/mmkzoo65/config.h | 1 - keyboards/mss_studio/m63_rgb/config.h | 3 - keyboards/mss_studio/m64_rgb/config.h | 3 - .../mwstudio/mw65_rgb/keymaps/horrortroll/config.h | 4 - .../mwstudio/mw65_rgb/keymaps/thearesia/config.h | 4 - keyboards/pierce/keymaps/durken1/config.h | 4 - .../rgbkb/zen/rev1/keymaps/cwebster2/config.h | 2 - keyboards/sanctified/dystopia/config.h | 2 - keyboards/signum/3_0/keymaps/sgurenkov/config.h | 3 - keyboards/skme/zeno/config.h | 3 - keyboards/sofle/keymaps/killmaster/config.h | 1 - keyboards/splitkb/kyria/keymaps/cwebster2/config.h | 2 - keyboards/synthlabs/solo/config.h | 2 - keyboards/xelus/dharma/keymaps/default/config.h | 18 --- keyboards/xelus/dharma/keymaps/via/config.h | 18 --- keyboards/xelus/kangaroo/keymaps/default/config.h | 18 --- keyboards/xelus/kangaroo/keymaps/via/config.h | 18 --- keyboards/xelus/la_plus/keymaps/default/config.h | 19 --- keyboards/xelus/la_plus/keymaps/via/config.h | 2 - .../xelus/pachi/mini_32u4/keymaps/default/config.h | 18 --- .../xelus/pachi/mini_32u4/keymaps/via/config.h | 2 - .../xelus/pachi/rev1/keymaps/default/config.h | 18 --- keyboards/xelus/pachi/rev1/keymaps/via/config.h | 2 - keyboards/xelus/pachi/rgb/keymaps/default/config.h | 18 --- keyboards/xelus/pachi/rgb/keymaps/via/config.h | 2 - keyboards/xelus/rs60/keymaps/default/config.h | 18 --- keyboards/xelus/rs60/keymaps/via/config.h | 18 --- .../xelus/valor/rev2/keymaps/default/config.h | 18 --- keyboards/xelus/valor/rev2/keymaps/via/config.h | 2 - .../xelus/valor_frl_tkl/keymaps/default/config.h | 18 --- keyboards/xelus/valor_frl_tkl/keymaps/via/config.h | 18 --- keyboards/xelus/xs60/keymaps/default/config.h | 18 --- keyboards/xelus/xs60/keymaps/via/config.h | 2 - keyboards/xiudi/xd75/keymaps/tdl-jturner/config.h | 1 - .../65_ansi_blocker/brandonschlack/config.h | 2 - .../brandonschlack-split/config.h | 2 - quantum/keyboard.c | 138 +++++++++++---------- quantum/keyboard.h | 8 +- tests/basic/test_keypress.cpp | 22 ---- tests/tap_dance/test_examples.cpp | 3 +- users/curry/config.h | 4 - users/drashna/post_config.h | 4 - users/ishtob/config.h | 1 - users/issmirnov/config.h | 3 - users/kuchosauronad0/config.h | 4 - users/miles2go/config.h | 4 - users/yet-another-developer/config.h | 4 - users/zer09/config.h | 4 - 96 files changed, 86 insertions(+), 603 deletions(-) delete mode 100644 keyboards/ai03/jp60/keymaps/default/config.h delete mode 100644 keyboards/ai03/jp60/keymaps/via/config.h delete mode 100644 keyboards/jadookb/jkb2/keymaps/via/config.h delete mode 100644 keyboards/jadookb/jkb65/keymaps/via/config.h delete mode 100644 keyboards/xelus/dharma/keymaps/default/config.h delete mode 100644 keyboards/xelus/dharma/keymaps/via/config.h delete mode 100644 keyboards/xelus/kangaroo/keymaps/default/config.h delete mode 100644 keyboards/xelus/kangaroo/keymaps/via/config.h delete mode 100644 keyboards/xelus/la_plus/keymaps/default/config.h delete mode 100644 keyboards/xelus/pachi/mini_32u4/keymaps/default/config.h delete mode 100644 keyboards/xelus/pachi/rev1/keymaps/default/config.h delete mode 100644 keyboards/xelus/pachi/rgb/keymaps/default/config.h delete mode 100644 keyboards/xelus/rs60/keymaps/default/config.h delete mode 100644 keyboards/xelus/rs60/keymaps/via/config.h delete mode 100644 keyboards/xelus/valor/rev2/keymaps/default/config.h delete mode 100644 keyboards/xelus/valor_frl_tkl/keymaps/default/config.h delete mode 100644 keyboards/xelus/valor_frl_tkl/keymaps/via/config.h delete mode 100644 keyboards/xelus/xs60/keymaps/default/config.h (limited to 'quantum') diff --git a/data/mappings/info_config.json b/data/mappings/info_config.json index 3891ef6437..d03f50c51e 100644 --- a/data/mappings/info_config.json +++ b/data/mappings/info_config.json @@ -82,7 +82,6 @@ "VENDOR_ID": {"info_key": "usb.vid", "value_type": "hex"}, "QMK_ESC_OUTPUT": {"info_key": "qmk_lufa_bootloader.esc_output"}, "QMK_ESC_INPUT": {"info_key": "qmk_lufa_bootloader.esc_input"}, - "QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int"}, "QMK_LED": {"info_key": "qmk_lufa_bootloader.led"}, "QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"}, "SECURE_UNLOCK_SEQUENCE": {"info_key": "secure.unlock_sequence", "value_type": "array.array.int", "to_json": false}, @@ -114,4 +113,5 @@ "DEBOUNCING_DELAY": {"info_key": "_invalid.debouncing_delay", "invalid": true}, "PREVENT_STUCK_MODIFIERS": {"info_key": "_invalid.prevent_stuck_mods", "invalid": true}, "RGBLIGHT_ANIMATIONS": {"info_key": "rgblight.animations.all", "value_type": "bool", "deprecated": true}, + "QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int", "deprecated": true}, } diff --git a/docs/config_options.md b/docs/config_options.md index f50748b950..c0a150e405 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -182,15 +182,6 @@ If you define these options you will enable the associated feature, which may in * how long before oneshot times out * `#define ONESHOT_TAP_TOGGLE 2` * how many taps before oneshot toggle is triggered -* `#define QMK_KEYS_PER_SCAN 4` - * Allows sending more than one key per scan. By default, only one key event gets - sent via `process_record()` per scan. This has little impact on most typing, but - if you're doing a lot of chords, or your scan rate is slow to begin with, you can - have some delay in processing key events. Each press and release is a separate - event. For a keyboard with 1ms or so scan times, even a very fast typist isn't - going to produce the 500 keystrokes a second needed to actually get more than a - few ms of delay from this. But if you're doing chording on something with 3-4ms - scan times? You probably want this. * `#define COMBO_COUNT 2` * Set this to the number of combos that you're using in the [Combo](feature_combo.md) feature. Or leave it undefined and programmatically set the count. * `#define COMBO_TERM 200` diff --git a/docs/ja/config_options.md b/docs/ja/config_options.md index 5236230a10..c95753bd5d 100644 --- a/docs/ja/config_options.md +++ b/docs/ja/config_options.md @@ -181,8 +181,6 @@ QMK での全ての利用可能な設定にはデフォルトがあります。 * ワンショットがタイムアウトするまでの時間 * `#define ONESHOT_TAP_TOGGLE 2` * ワンショットトグルが引き起こされるまでのタップ数 -* `#define QMK_KEYS_PER_SCAN 4` - * 走査ごとに1つ以上のキーを送信できるようにします。デフォルトでは、走査ごとに `process_record()` 経由で1つのキーイベントのみが送信されます。これはほとんどのタイピングにほとんど影響しませんが、多くのコードを入力しているか、走査レートが最初から遅い場合、キーイベントの処理に多少の遅延が生じる可能性があります。それぞれのプレスとリリースは別のイベントです。スキャン時間が 1ms 程度のキーボードの場合、とても高速なタイピストでさえ、実際にキーボードから数 ms 以上の遅延を発生させるのに必要な 500 キーストロークを1秒間に生成することはないでしょう。しかし、3~4ms の走査時間でコードを入力している場合はどうでしょうか?おそらくこれが必要です。 * `#define COMBO_COUNT 2` * [コンボ](ja/feature_combo.md)機能で使っているコンボの数にこれを設定します。 * `#define COMBO_TERM 200` diff --git a/keyboards/40percentclub/gherkin/keymaps/stevexyz/config.h b/keyboards/40percentclub/gherkin/keymaps/stevexyz/config.h index c708babf16..d837be8ba1 100644 --- a/keyboards/40percentclub/gherkin/keymaps/stevexyz/config.h +++ b/keyboards/40percentclub/gherkin/keymaps/stevexyz/config.h @@ -39,8 +39,6 @@ // how long before oneshot times out #define ONESHOT_TAP_TOGGLE 2 // how many taps before oneshot toggle is triggered - #define QMK_KEYS_PER_SCAN 4 - // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. #define COMBO_COUNT 2 // Set this to the number of combos that you're using in the Combo feature. #define COMBO_TERM 200 diff --git a/keyboards/ai03/jp60/keymaps/default/config.h b/keyboards/ai03/jp60/keymaps/default/config.h deleted file mode 100644 index 9e0623524a..0000000000 --- a/keyboards/ai03/jp60/keymaps/default/config.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2021 ai03 - * - * 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 . - */ - -#pragma once - -/* Increase scan quantity for improved performance */ -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/ai03/jp60/keymaps/via/config.h b/keyboards/ai03/jp60/keymaps/via/config.h deleted file mode 100644 index 9e0623524a..0000000000 --- a/keyboards/ai03/jp60/keymaps/via/config.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2021 ai03 - * - * 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 . - */ - -#pragma once - -/* Increase scan quantity for improved performance */ -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/bioi/morgan65/config.h b/keyboards/bioi/morgan65/config.h index e4ad58c3a7..2ce3c7a56b 100644 --- a/keyboards/bioi/morgan65/config.h +++ b/keyboards/bioi/morgan65/config.h @@ -37,8 +37,6 @@ along with this program. If not, see . #define MATRIX_ROW_PINS { E6, C6, F4, B2, D4 } #define MATRIX_COL_PINS { F5, F6, F7, C7, B0, B7, B5, D5, B4, D7, D6, D1, D0, B3 } -//#define QMK_KEYS_PER_SCAN 4 - /* Backlight Setup */ #define BACKLIGHT_PIN B6 #define BACKLIGHT_LEVELS 12 diff --git a/keyboards/doio/kb16/config.h b/keyboards/doio/kb16/config.h index 043a492006..911ba9d3d5 100644 --- a/keyboards/doio/kb16/config.h +++ b/keyboards/doio/kb16/config.h @@ -39,9 +39,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Larger keys per scan */ -#define QMK_KEYS_PER_SCAN 12 - /* Use the custom font */ #define OLED_FONT_H "lib/glcdfont.c" diff --git a/keyboards/dztech/dz60rgb/keymaps/kgreulich/config.h b/keyboards/dztech/dz60rgb/keymaps/kgreulich/config.h index fc836b5ebb..e3250acef1 100644 --- a/keyboards/dztech/dz60rgb/keymaps/kgreulich/config.h +++ b/keyboards/dztech/dz60rgb/keymaps/kgreulich/config.h @@ -7,8 +7,6 @@ #define TAP_HOLD_CAPS_DELAY 0 #define USB_POLLING_INTERVAL_MS 1 -#define QMK_KEYS_PER_SCAN 4 - // some speed shit #define NO_ACTION_MACRO #define NO_ACTION_FUNCTION diff --git a/keyboards/dztech/dz60rgb/keymaps/matthewrobo/config.h b/keyboards/dztech/dz60rgb/keymaps/matthewrobo/config.h index c2b14f5284..ca64eeb69b 100644 --- a/keyboards/dztech/dz60rgb/keymaps/matthewrobo/config.h +++ b/keyboards/dztech/dz60rgb/keymaps/matthewrobo/config.h @@ -51,8 +51,6 @@ // #undef ENABLE_RGB_MATRIX_SOLID_SPLASH // #undef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH -#define QMK_KEYS_PER_SCAN 4 - // #define RGB_MATRIX_KEYRELEASES // some speed shit diff --git a/keyboards/dztech/dz60rgb/keymaps/xunz/config.h b/keyboards/dztech/dz60rgb/keymaps/xunz/config.h index cfeba003bd..2fdb3e5f4c 100644 --- a/keyboards/dztech/dz60rgb/keymaps/xunz/config.h +++ b/keyboards/dztech/dz60rgb/keymaps/xunz/config.h @@ -46,8 +46,6 @@ // #undef ENABLE_RGB_MATRIX_SOLID_SPLASH // #undef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH -#define QMK_KEYS_PER_SCAN 4 - // #define RGB_MATRIX_KEYRELEASES #define NO_ACTION_ONESHOT diff --git a/keyboards/dztech/dz65rgb/keymaps/matthewrobo/config.h b/keyboards/dztech/dz65rgb/keymaps/matthewrobo/config.h index 586e5765aa..25842ac186 100644 --- a/keyboards/dztech/dz65rgb/keymaps/matthewrobo/config.h +++ b/keyboards/dztech/dz65rgb/keymaps/matthewrobo/config.h @@ -47,8 +47,6 @@ // #undef ENABLE_RGB_MATRIX_SOLID_SPLASH // #undef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH -#define QMK_KEYS_PER_SCAN 4 - // #define RGB_MATRIX_KEYRELEASES // some speed shit diff --git a/keyboards/dztech/dz65rgb/keymaps/yuannan/config.h b/keyboards/dztech/dz65rgb/keymaps/yuannan/config.h index 0a005cbca3..ef5023f8c6 100644 --- a/keyboards/dztech/dz65rgb/keymaps/yuannan/config.h +++ b/keyboards/dztech/dz65rgb/keymaps/yuannan/config.h @@ -30,8 +30,6 @@ #define RGB_MATRIX_VAL_STEP 8 #define RGB_MATRIX_SPD_STEP 8 -//#define QMK_KEYS_PER_SCAN 12nn - #define MOUSEKEY_DELAY 0 #define MOUSEKEY_INTERVAL 1 #define MOUSEKEY_MOVE_DELTA 1 diff --git a/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c b/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c index ff9ae77bdd..93b82df8cf 100644 --- a/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c +++ b/keyboards/ergodox_ez/keymaps/dvorak_42_key/keymap.c @@ -20,8 +20,6 @@ // debounce settings // remove these after getting a new keyboard // #define DEBOUNCE 50 -// #define QMK_KEYS_PER_SCAN 4 - enum custom_keycodes { PLACEHOLDER = SAFE_RANGE, // can always be here diff --git a/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h b/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h index c35963d842..acd3a44e16 100644 --- a/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h +++ b/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h @@ -25,7 +25,6 @@ #define LEADER_TIMEOUT 1000 #define PERMISSIVE_HOLD -#define QMK_KEYS_PER_SCAN 4 #define DANCING_TERM 175 #define ONESHOT_TAP_TOGGLE 5 diff --git a/keyboards/ergodox_ez/keymaps/rgb_layer/config.h b/keyboards/ergodox_ez/keymaps/rgb_layer/config.h index 1913a2d369..84c5adfc9e 100644 --- a/keyboards/ergodox_ez/keymaps/rgb_layer/config.h +++ b/keyboards/ergodox_ez/keymaps/rgb_layer/config.h @@ -2,13 +2,9 @@ #define KEYMAP_CONFIG_H - #define RGBLIGHT_SLEEP +#define RGBLIGHT_SLEEP -#ifndef QMK_KEYS_PER_SCAN -#define QMK_KEYS_PER_SCAN 4 -#endif // !QMK_KEYS_PER_SCAN - #define IGNORE_MOD_TAP_INTERRUPT #undef PERMISSIVE_HOLD diff --git a/keyboards/ergodox_ez/keymaps/rmw/config.h b/keyboards/ergodox_ez/keymaps/rmw/config.h index 1ecf8b8b79..1b7528a4a7 100644 --- a/keyboards/ergodox_ez/keymaps/rmw/config.h +++ b/keyboards/ergodox_ez/keymaps/rmw/config.h @@ -22,7 +22,6 @@ along with this program. If not, see . #define USB_MAX_POWER_CONSUMPTION 500 -#define QMK_KEYS_PER_SCAN 4 /* Set 0 if debouncing isn't needed */ #undef DEBOUNCE #define DEBOUNCE 5 diff --git a/keyboards/eternal_keypad/keymaps/kyek/config.h b/keyboards/eternal_keypad/keymaps/kyek/config.h index 226b16e546..36ab46334c 100644 --- a/keyboards/eternal_keypad/keymaps/kyek/config.h +++ b/keyboards/eternal_keypad/keymaps/kyek/config.h @@ -17,5 +17,3 @@ #define ONESHOT_TIMEOUT 2000 #define FORCE_NKRO -#define USB_POLLING_INTERVAL_MS 1 -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/gmmk/gmmk2/p96/config.h b/keyboards/gmmk/gmmk2/p96/config.h index 1b3a92dd53..fec383c240 100644 --- a/keyboards/gmmk/gmmk2/p96/config.h +++ b/keyboards/gmmk/gmmk2/p96/config.h @@ -119,10 +119,6 @@ #define ENABLE_RGB_MATRIX_SOLID_SPLASH #define ENABLE_RGB_MATRIX_SOLID_MULTISPLASH - -/* Send up to 4 key press events per scan */ -#define QMK_KEYS_PER_SCAN 4 - /* Set debounce time to 5ms */ #define DEBOUNCE 5 diff --git a/keyboards/gmmk/pro/config.h b/keyboards/gmmk/pro/config.h index aba69c8872..aea22c5434 100644 --- a/keyboards/gmmk/pro/config.h +++ b/keyboards/gmmk/pro/config.h @@ -113,9 +113,6 @@ #define ENABLE_RGB_MATRIX_SOLID_SPLASH #define ENABLE_RGB_MATRIX_SOLID_MULTISPLASH -/* Send up to 4 key press events per scan */ -#define QMK_KEYS_PER_SCAN 4 - /* Set debounce time to 5ms */ #define DEBOUNCE 5 diff --git a/keyboards/gopolar/gg86/config.h b/keyboards/gopolar/gg86/config.h index 7566bd2c3f..7964834623 100644 --- a/keyboards/gopolar/gg86/config.h +++ b/keyboards/gopolar/gg86/config.h @@ -35,9 +35,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Change larger keys per scan for elite gaming */ -#define QMK_KEYS_PER_SCAN 12 - /* Use the custom font */ #define OLED_FONT_H "lib/glcdfont.c" diff --git a/keyboards/handwired/marauder/config.h b/keyboards/handwired/marauder/config.h index fdc269fb7f..a3165c480d 100644 --- a/keyboards/handwired/marauder/config.h +++ b/keyboards/handwired/marauder/config.h @@ -36,7 +36,7 @@ #define MATRIX_COL_PINS { B6, B2, B3, B1, F7, F6, F5, F4, B0 } #define DIODE_DIRECTION COL2ROW #define LAYER_STATE_8BIT -#define QMK_KEYS_PER_SCAN 12 // moar gaming code + #define RGB_DI_PIN D3 #ifdef RGB_DI_PIN #define RGBLED_NUM 7 diff --git a/keyboards/handwired/xealous/config.h b/keyboards/handwired/xealous/config.h index 5c1469b1f0..2502b4d196 100644 --- a/keyboards/handwired/xealous/config.h +++ b/keyboards/handwired/xealous/config.h @@ -29,7 +29,6 @@ along with this program. If not, see . //#define DEBUG_MATRIX_SCAN_RATE //Use this to determine scan-rate. #define FORCE_NKRO -#define QMK_KEYS_PER_SCAN 4 //if we press four keys simultaneously, lets process them simultaneously... #define DIODE_DIRECTION COL2ROW diff --git a/keyboards/horrortroll/chinese_pcb/black_e65/config.h b/keyboards/horrortroll/chinese_pcb/black_e65/config.h index f544206b81..bcd38d62c7 100644 --- a/keyboards/horrortroll/chinese_pcb/black_e65/config.h +++ b/keyboards/horrortroll/chinese_pcb/black_e65/config.h @@ -38,9 +38,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Change larger keys per scan for elite gaming */ -#define QMK_KEYS_PER_SCAN 12 - /* LED Indicator */ #define LED_CAPS_LOCK_PIN C7 diff --git a/keyboards/horrortroll/chinese_pcb/devil68_pro/config.h b/keyboards/horrortroll/chinese_pcb/devil68_pro/config.h index 82465cf99c..8a227f3c49 100644 --- a/keyboards/horrortroll/chinese_pcb/devil68_pro/config.h +++ b/keyboards/horrortroll/chinese_pcb/devil68_pro/config.h @@ -38,9 +38,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Change larger keys per scan for elite gaming */ -#define QMK_KEYS_PER_SCAN 12 - #ifdef RGB_MATRIX_ENABLE #define DRIVER_LED_TOTAL 86 #define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 diff --git a/keyboards/horrortroll/handwired_k552/config.h b/keyboards/horrortroll/handwired_k552/config.h index 09e89b13c4..d3c385f64e 100644 --- a/keyboards/horrortroll/handwired_k552/config.h +++ b/keyboards/horrortroll/handwired_k552/config.h @@ -39,9 +39,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Change larger keys per scan for elite gaming */ -#define QMK_KEYS_PER_SCAN 12 - /* EEPROM size */ #define EEPROM_PAGE_SIZE #define FEE_PAGE_SIZE 0x800 diff --git a/keyboards/horrortroll/lemon40/config.h b/keyboards/horrortroll/lemon40/config.h index 600ef01657..c3e1972ae3 100644 --- a/keyboards/horrortroll/lemon40/config.h +++ b/keyboards/horrortroll/lemon40/config.h @@ -38,9 +38,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Larger keys per scan */ -#define QMK_KEYS_PER_SCAN 12 - /* RGB light config */ #ifdef RGBLIGHT_ENABLE diff --git a/keyboards/horrortroll/paws60/config.h b/keyboards/horrortroll/paws60/config.h index 7bd3ac8be3..055a6ae319 100644 --- a/keyboards/horrortroll/paws60/config.h +++ b/keyboards/horrortroll/paws60/config.h @@ -37,6 +37,3 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO - -/* Larger keys per scan */ -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/ianklug/grooveboard/config.h b/keyboards/ianklug/grooveboard/config.h index 007a86529c..2d255a2c18 100644 --- a/keyboards/ianklug/grooveboard/config.h +++ b/keyboards/ianklug/grooveboard/config.h @@ -142,5 +142,3 @@ along with this program. If not, see . /* Bootmagic Lite key configuration */ //#define BOOTMAGIC_LITE_ROW 0 //#define BOOTMAGIC_LITE_COLUMN 0 - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/jadookb/jkb2/keymaps/via/config.h b/keyboards/jadookb/jkb2/keymaps/via/config.h deleted file mode 100644 index 31022ca535..0000000000 --- a/keyboards/jadookb/jkb2/keymaps/via/config.h +++ /dev/null @@ -1,19 +0,0 @@ - - /* Copyright 2021 Wizard-GG - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/jadookb/jkb65/keymaps/via/config.h b/keyboards/jadookb/jkb65/keymaps/via/config.h deleted file mode 100644 index 9d4eaf74ee..0000000000 --- a/keyboards/jadookb/jkb65/keymaps/via/config.h +++ /dev/null @@ -1,19 +0,0 @@ - /* Copyright 2021 Wizard-GG - * - * 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 . - */ - -#pragma once - -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/kbdfans/kbd67/mkiirgb/keymaps/dnsnrk/config.h b/keyboards/kbdfans/kbd67/mkiirgb/keymaps/dnsnrk/config.h index 25f645f734..bb3409256c 100644 --- a/keyboards/kbdfans/kbd67/mkiirgb/keymaps/dnsnrk/config.h +++ b/keyboards/kbdfans/kbd67/mkiirgb/keymaps/dnsnrk/config.h @@ -16,8 +16,6 @@ #pragma once /* place overrides here */ -#undef QMK_KEYS_PER_SCAN -#define QMK_KEYS_PER_SCAN 4 #undef DEBOUNCE #define DEBOUNCE 8 #undef TAPPING_TOGGLE diff --git a/keyboards/kbdfans/kbd67/mkiirgb/keymaps/pascalpfeil/config.h b/keyboards/kbdfans/kbd67/mkiirgb/keymaps/pascalpfeil/config.h index 2cd513223a..cda14c4bc0 100644 --- a/keyboards/kbdfans/kbd67/mkiirgb/keymaps/pascalpfeil/config.h +++ b/keyboards/kbdfans/kbd67/mkiirgb/keymaps/pascalpfeil/config.h @@ -19,9 +19,6 @@ /* 1000Hz USB polling */ #define USB_POLLING_INTERVAL_MS 1 -/* Send up to 4 key press events per scan */ -#define QMK_KEYS_PER_SCAN 4 - /* Force NKRO on boot up */ #define FORCE_NKRO diff --git a/keyboards/keystonecaps/gameroyadvance/config.h b/keyboards/keystonecaps/gameroyadvance/config.h index b8d5a69122..06b40b5e66 100644 --- a/keyboards/keystonecaps/gameroyadvance/config.h +++ b/keyboards/keystonecaps/gameroyadvance/config.h @@ -55,10 +55,6 @@ along with this program. If not, see . /* Locking resynchronize hack */ #define LOCKING_RESYNC_ENABLE - - -#define QMK_KEYS_PER_SCAN 12 - #define RGB_DI_PIN C7 #ifdef RGB_DI_PIN #define RGBLIGHT_EFFECT_BREATHING diff --git a/keyboards/kprepublic/bm40hsrgb/keymaps/34keys/config.h b/keyboards/kprepublic/bm40hsrgb/keymaps/34keys/config.h index 63176adb50..2534ffd554 100644 --- a/keyboards/kprepublic/bm40hsrgb/keymaps/34keys/config.h +++ b/keyboards/kprepublic/bm40hsrgb/keymaps/34keys/config.h @@ -14,9 +14,6 @@ // Enable rapid switch from tap to hold, disables double tap hold auto-repeat. #define TAPPING_FORCE_HOLD -// Recommended for heavy chording. -#define QMK_KEYS_PER_SCAN 4 - // Mouse key speed and acceleration. #undef MOUSEKEY_DELAY #define MOUSEKEY_DELAY 0 @@ -56,4 +53,4 @@ # undef ENABLE_RGB_MATRIX_DIGITAL_RAIN # undef RGB_MATRIX_STARTUP_MODE // # define RGBLIGHT_HUE_STEP 20 -#endif \ No newline at end of file +#endif diff --git a/keyboards/kprepublic/bm40hsrgb/keymaps/gabustoledo/config.h b/keyboards/kprepublic/bm40hsrgb/keymaps/gabustoledo/config.h index ba18295ead..e71078415a 100644 --- a/keyboards/kprepublic/bm40hsrgb/keymaps/gabustoledo/config.h +++ b/keyboards/kprepublic/bm40hsrgb/keymaps/gabustoledo/config.h @@ -30,9 +30,6 @@ #define AUTO_SHIFT_TIMEOUT TAPPING_TERM #define AUTO_SHIFT_NO_SETUP -// Recommended for heavy chording. -#define QMK_KEYS_PER_SCAN 4 - // Mouse key speed and acceleration. #undef MOUSEKEY_DELAY #define MOUSEKEY_DELAY 0 diff --git a/keyboards/kprepublic/bm68hsrgb/rev1/keymaps/peepeetee/config.h b/keyboards/kprepublic/bm68hsrgb/rev1/keymaps/peepeetee/config.h index 0748f83cdc..3ddb813486 100644 --- a/keyboards/kprepublic/bm68hsrgb/rev1/keymaps/peepeetee/config.h +++ b/keyboards/kprepublic/bm68hsrgb/rev1/keymaps/peepeetee/config.h @@ -35,7 +35,6 @@ // #define MOUSEKEY_MAX_SPEED 10 // #define MOUSEKEY_WHEEL_DELAY 0 #define FORCE_NKRO // NKRO by default requires to be turned on, this forces it on during keyboard startup regardless of EEPROM setting. NKRO can still be turned off but will be turned on again if the keyboard reboots. -// #define QMK_KEYS_PER_SCAN 4 // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. // #define STRICT_LAYER_RELEASE // Force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) // #define LOCKING_SUPPORT_ENABLE // Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap // #define LOCKING_RESYNC_ENABLE // Tries to keep switch state consistent with keyboard LED state diff --git a/keyboards/kprepublic/bm80hsrgb/keymaps/peepeetee/config.h b/keyboards/kprepublic/bm80hsrgb/keymaps/peepeetee/config.h index b322afae9b..97cae26cbd 100644 --- a/keyboards/kprepublic/bm80hsrgb/keymaps/peepeetee/config.h +++ b/keyboards/kprepublic/bm80hsrgb/keymaps/peepeetee/config.h @@ -22,7 +22,6 @@ // #define TERMINAL_HELP #define FORCE_NKRO // NKRO by default requires to be turned on, this forces it on during keyboard startup regardless of EEPROM setting. NKRO can still be turned off but will be turned on again if the keyboard reboots. -// #define QMK_KEYS_PER_SCAN 4 // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. // #define STRICT_LAYER_RELEASE // Force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) // #define TAPPING_TERM 200 // How long before a tap becomes a hold, if set above 500, a key tapped during the tapping term will turn it into a hold too // #define TAPPING_TERM_PER_KEY // Enables handling for per key TAPPING_TERM settings diff --git a/keyboards/kprepublic/jj40/keymaps/stevexyz/config.h b/keyboards/kprepublic/jj40/keymaps/stevexyz/config.h index 84c02dddd6..a4d3d37561 100644 --- a/keyboards/kprepublic/jj40/keymaps/stevexyz/config.h +++ b/keyboards/kprepublic/jj40/keymaps/stevexyz/config.h @@ -34,8 +34,6 @@ // how long before oneshot times out #define ONESHOT_TAP_TOGGLE 2 // how many taps before oneshot toggle is triggered - #define QMK_KEYS_PER_SCAN 4 - // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. #define COMBO_COUNT 2 // Set this to the number of combos that you're using in the Combo feature. #define COMBO_TERM 200 diff --git a/keyboards/lets_split/keymaps/piemod/config.h b/keyboards/lets_split/keymaps/piemod/config.h index 1b3fd7544e..c3975da3ca 100644 --- a/keyboards/lets_split/keymaps/piemod/config.h +++ b/keyboards/lets_split/keymaps/piemod/config.h @@ -42,7 +42,4 @@ along with this program. If not, see . #define RGBLIGHT_EFFECT_SNAKE_LENGTH 1 #define RGBLIGHT_EFFECT_KNIGHT_LENGTH 1 -// Typing Options -#define QMK_KEYS_PER_SCAN 4 - #endif diff --git a/keyboards/lfkeyboards/lfkpad/keymaps/pascalpfeil/config.h b/keyboards/lfkeyboards/lfkpad/keymaps/pascalpfeil/config.h index a9f61f849c..0f9ddaef31 100644 --- a/keyboards/lfkeyboards/lfkpad/keymaps/pascalpfeil/config.h +++ b/keyboards/lfkeyboards/lfkpad/keymaps/pascalpfeil/config.h @@ -19,9 +19,6 @@ /* 1000Hz USB polling */ #define USB_POLLING_INTERVAL_MS 1 -/* Send up to 4 key press events per scan */ -#define QMK_KEYS_PER_SCAN 4 - /* Force NKRO on boot up */ #define FORCE_NKRO diff --git a/keyboards/maple_computing/minidox/keymaps/norman/config.h b/keyboards/maple_computing/minidox/keymaps/norman/config.h index 0d3542a03e..ecdf080c2c 100644 --- a/keyboards/maple_computing/minidox/keymaps/norman/config.h +++ b/keyboards/maple_computing/minidox/keymaps/norman/config.h @@ -1,5 +1,4 @@ #pragma once #define PERMISSIVE_HOLD -#define QMK_KEYS_PER_SCAN 4 #define TAPPING_TERM 160 diff --git a/keyboards/massdrop/alt/keymaps/b_/config.h b/keyboards/massdrop/alt/keymaps/b_/config.h index ca4424bd3f..b7112c9ea7 100644 --- a/keyboards/massdrop/alt/keymaps/b_/config.h +++ b/keyboards/massdrop/alt/keymaps/b_/config.h @@ -23,7 +23,6 @@ // #define MOUSEKEY_MAX_SPEED 10 // #define MOUSEKEY_WHEEL_DELAY 0 //#define FORCE_NKRO // NKRO by default requires to be turned on, this forces it on during keyboard startup regardless of EEPROM setting. NKRO can still be turned off but will be turned on again if the keyboard reboots. -// #define QMK_KEYS_PER_SCAN 4 // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. // #define STRICT_LAYER_RELEASE // Force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) // #define LOCKING_SUPPORT_ENABLE // Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap // #define LOCKING_RESYNC_ENABLE // Tries to keep switch state consistent with keyboard LED state diff --git a/keyboards/massdrop/alt/keymaps/pregame/config.h b/keyboards/massdrop/alt/keymaps/pregame/config.h index 19fc4fed34..936951e34a 100644 --- a/keyboards/massdrop/alt/keymaps/pregame/config.h +++ b/keyboards/massdrop/alt/keymaps/pregame/config.h @@ -36,7 +36,6 @@ // #define MOUSEKEY_MAX_SPEED 10 // #define MOUSEKEY_WHEEL_DELAY 0 #define FORCE_NKRO // NKRO by default requires to be turned on, this forces it on during keyboard startup regardless of EEPROM setting. NKRO can still be turned off but will be turned on again if the keyboard reboots. -// #define QMK_KEYS_PER_SCAN 4 // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. // #define STRICT_LAYER_RELEASE // Force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) // #define LOCKING_SUPPORT_ENABLE // Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap // #define LOCKING_RESYNC_ENABLE // Tries to keep switch state consistent with keyboard LED state diff --git a/keyboards/massdrop/ctrl/keymaps/endgame/config.h b/keyboards/massdrop/ctrl/keymaps/endgame/config.h index 4850d7eed2..d0bbfd2103 100644 --- a/keyboards/massdrop/ctrl/keymaps/endgame/config.h +++ b/keyboards/massdrop/ctrl/keymaps/endgame/config.h @@ -20,7 +20,6 @@ #define MOUSEKEY_MAX_SPEED 10 #define MOUSEKEY_WHEEL_DELAY 0 #define FORCE_NKRO // NKRO by default requires to be turned on, this forces it on during keyboard startup regardless of EEPROM setting. NKRO can still be turned off but will be turned on again if the keyboard reboots. -// #define QMK_KEYS_PER_SCAN 4 // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. // #define STRICT_LAYER_RELEASE // Force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) // #define LOCKING_SUPPORT_ENABLE // Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap // #define LOCKING_RESYNC_ENABLE // Tries to keep switch state consistent with keyboard LED state diff --git a/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h b/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h index 81e7764a9e..692faa35a2 100644 --- a/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h +++ b/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h @@ -37,7 +37,6 @@ along with this program. If not, see . // #define MOUSEKEY_MAX_SPEED 10 // #define MOUSEKEY_WHEEL_DELAY 0 #define FORCE_NKRO // NKRO by default requires to be turned on, this forces it on during keyboard startup regardless of EEPROM setting. NKRO can still be turned off but will be turned on again if the keyboard reboots. -// #define QMK_KEYS_PER_SCAN 4 // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. // #define STRICT_LAYER_RELEASE // Force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) // #define LOCKING_SUPPORT_ENABLE // Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap // #define LOCKING_RESYNC_ENABLE // Tries to keep switch state consistent with keyboard LED state diff --git a/keyboards/massdrop/ctrl/keymaps/xanimos/config.h b/keyboards/massdrop/ctrl/keymaps/xanimos/config.h index 37987340ce..f1cbd5f3b0 100644 --- a/keyboards/massdrop/ctrl/keymaps/xanimos/config.h +++ b/keyboards/massdrop/ctrl/keymaps/xanimos/config.h @@ -36,7 +36,6 @@ #define MOUSEKEY_MAX_SPEED 10 #define MOUSEKEY_WHEEL_DELAY 0 #define FORCE_NKRO // NKRO by default requires to be turned on, this forces it on during keyboard startup regardless of EEPROM setting. NKRO can still be turned off but will be turned on again if the keyboard reboots. -// #define QMK_KEYS_PER_SCAN 4 // Allows sending more than one key per scan. By default, only one key event gets sent via process_record() per scan. This has little impact on most typing, but if you're doing a lot of chords, or your scan rate is slow to begin with, you can have some delay in processing key events. Each press and release is a separate event. For a keyboard with 1ms or so scan times, even a very fast typist isn't going to produce the 500 keystrokes a second needed to actually get more than a few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. // #define STRICT_LAYER_RELEASE // Force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) // #define LOCKING_SUPPORT_ENABLE // Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap // #define LOCKING_RESYNC_ENABLE // Tries to keep switch state consistent with keyboard LED state diff --git a/keyboards/ml/gas75/config.h b/keyboards/ml/gas75/config.h index 4f35c4c265..82d8c134a0 100644 --- a/keyboards/ml/gas75/config.h +++ b/keyboards/ml/gas75/config.h @@ -38,9 +38,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Larger keys per scan */ -#define QMK_KEYS_PER_SCAN 12 - /* Encoder pins */ #define ENCODERS_PAD_A { F0 } #define ENCODERS_PAD_B { F1 } diff --git a/keyboards/mmkzoo65/config.h b/keyboards/mmkzoo65/config.h index b562a40859..b874fdef8a 100644 --- a/keyboards/mmkzoo65/config.h +++ b/keyboards/mmkzoo65/config.h @@ -38,4 +38,3 @@ /* 将USB 轮询速率更改为 1000hz 并为精英游戏每次扫描使用更大的密钥*/ #define USB_POLLING_INTERVAL_MS 2 -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/mss_studio/m63_rgb/config.h b/keyboards/mss_studio/m63_rgb/config.h index e2aae8469f..a7220ab1c6 100644 --- a/keyboards/mss_studio/m63_rgb/config.h +++ b/keyboards/mss_studio/m63_rgb/config.h @@ -36,9 +36,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Change larger keys per scan for elite gaming */ -#define QMK_KEYS_PER_SCAN 12 - #ifdef RGB_MATRIX_ENABLE #define DRIVER_LED_TOTAL 75 #define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 diff --git a/keyboards/mss_studio/m64_rgb/config.h b/keyboards/mss_studio/m64_rgb/config.h index d8ac27024b..c9a1e3f3db 100644 --- a/keyboards/mss_studio/m64_rgb/config.h +++ b/keyboards/mss_studio/m64_rgb/config.h @@ -36,9 +36,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Change larger keys per scan for elite gaming */ -#define QMK_KEYS_PER_SCAN 12 - #ifdef RGB_MATRIX_ENABLE #define DRIVER_LED_TOTAL 76 #define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 diff --git a/keyboards/mwstudio/mw65_rgb/keymaps/horrortroll/config.h b/keyboards/mwstudio/mw65_rgb/keymaps/horrortroll/config.h index 13cffea4da..0d2051ffd5 100644 --- a/keyboards/mwstudio/mw65_rgb/keymaps/horrortroll/config.h +++ b/keyboards/mwstudio/mw65_rgb/keymaps/horrortroll/config.h @@ -21,10 +21,6 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO -/* Change USB Polling Rate to 1000hz and a larger keys per scan for elite gaming */ -#define USB_POLLING_INTERVAL_MS 1 -#define QMK_KEYS_PER_SCAN 12 - #ifdef RGB_MATRIX_ENABLE /* RGB Matrix config */ #undef ENABLE_RGB_MATRIX_BAND_SAT diff --git a/keyboards/mwstudio/mw65_rgb/keymaps/thearesia/config.h b/keyboards/mwstudio/mw65_rgb/keymaps/thearesia/config.h index ba574e1e3c..fef62c6374 100644 --- a/keyboards/mwstudio/mw65_rgb/keymaps/thearesia/config.h +++ b/keyboards/mwstudio/mw65_rgb/keymaps/thearesia/config.h @@ -20,7 +20,3 @@ /* Forcing to use NKRO instead 6KRO */ #define FORCE_NKRO - -/* Change USB Polling Rate to 1000hz and a larger keys per scan for elite gaming */ -#define USB_POLLING_INTERVAL_MS 1 -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/pierce/keymaps/durken1/config.h b/keyboards/pierce/keymaps/durken1/config.h index 7d19a0b83b..bc0bb1c4b8 100644 --- a/keyboards/pierce/keymaps/durken1/config.h +++ b/keyboards/pierce/keymaps/durken1/config.h @@ -27,9 +27,6 @@ #define PERMISSIVE_HOLD -// Recommended for heavy chording. -#define QMK_KEYS_PER_SCAN 4 - // Combo settings #define COMBO_COUNT 3 #define COMBO_TERM 35 @@ -74,4 +71,3 @@ #ifdef AUTO_BUTTONS #define AUTO_BUTTONS_TIMEOUT 750 #endif - diff --git a/keyboards/rgbkb/zen/rev1/keymaps/cwebster2/config.h b/keyboards/rgbkb/zen/rev1/keymaps/cwebster2/config.h index 211e3517ec..cdffe6fd50 100644 --- a/keyboards/rgbkb/zen/rev1/keymaps/cwebster2/config.h +++ b/keyboards/rgbkb/zen/rev1/keymaps/cwebster2/config.h @@ -29,6 +29,4 @@ along with this program. If not, see . #define COMBO_COUNT 2 #endif -#define QMK_KEYS_PER_SCAN 4 - #define EE_HANDS diff --git a/keyboards/sanctified/dystopia/config.h b/keyboards/sanctified/dystopia/config.h index a818d3e84f..cf9d91d551 100644 --- a/keyboards/sanctified/dystopia/config.h +++ b/keyboards/sanctified/dystopia/config.h @@ -27,5 +27,3 @@ #define MATRIX_COL_PINS { F0, F1, F4, F5, F6, F7, C7, C6, B6, B5, D4, D6, D7, B4 } #define DIODE_DIRECTION COL2ROW - -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/signum/3_0/keymaps/sgurenkov/config.h b/keyboards/signum/3_0/keymaps/sgurenkov/config.h index 5f8d0d02b8..7d164aa3a9 100644 --- a/keyboards/signum/3_0/keymaps/sgurenkov/config.h +++ b/keyboards/signum/3_0/keymaps/sgurenkov/config.h @@ -29,9 +29,6 @@ // Auto Shift and Retro Shift (Auto Shift for Tap Hold). #define AUTO_SHIFT_TIMEOUT TAPPING_TERM -// Recommended for heavy chording. -#define QMK_KEYS_PER_SCAN 4 - // Mouse key speed and acceleration. #undef MOUSEKEY_DELAY #define MOUSEKEY_DELAY 0 diff --git a/keyboards/skme/zeno/config.h b/keyboards/skme/zeno/config.h index a6404a8ff4..53aa1cd621 100644 --- a/keyboards/skme/zeno/config.h +++ b/keyboards/skme/zeno/config.h @@ -34,6 +34,3 @@ along with this program. If not, see . #define LOCKING_SUPPORT_ENABLE /* Locking resynchronize hack */ #define LOCKING_RESYNC_ENABLE -/*Enable 1khz polling by default*/ -#define USB_POLLING_INTERVAL_MS 1 -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/sofle/keymaps/killmaster/config.h b/keyboards/sofle/keymaps/killmaster/config.h index 2e6abe84e3..9d1de12d5a 100644 --- a/keyboards/sofle/keymaps/killmaster/config.h +++ b/keyboards/sofle/keymaps/killmaster/config.h @@ -61,4 +61,3 @@ for more options. #define MEDIA_KEY_DELAY 2 #define USB_POLLING_INTERVAL_MS 1 -#define QMK_KEYS_PER_SCAN 12 diff --git a/keyboards/splitkb/kyria/keymaps/cwebster2/config.h b/keyboards/splitkb/kyria/keymaps/cwebster2/config.h index 9a58f7751a..59994e01fa 100644 --- a/keyboards/splitkb/kyria/keymaps/cwebster2/config.h +++ b/keyboards/splitkb/kyria/keymaps/cwebster2/config.h @@ -47,8 +47,6 @@ #define COMBO_COUNT 5 #endif -#define QMK_KEYS_PER_SCAN 4 - #define EE_HANDS //#define DEBUG_MATRIX_SCAN_RATE diff --git a/keyboards/synthlabs/solo/config.h b/keyboards/synthlabs/solo/config.h index affb70befc..112d12d1ee 100644 --- a/keyboards/synthlabs/solo/config.h +++ b/keyboards/synthlabs/solo/config.h @@ -16,8 +16,6 @@ #define MATRIX_ROWS 3 #define MATRIX_COLS 7 -#define QMK_KEYS_PER_SCAN 17 - /* * Force NKRO * diff --git a/keyboards/xelus/dharma/keymaps/default/config.h b/keyboards/xelus/dharma/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/dharma/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/dharma/keymaps/via/config.h b/keyboards/xelus/dharma/keymaps/via/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/dharma/keymaps/via/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/kangaroo/keymaps/default/config.h b/keyboards/xelus/kangaroo/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/kangaroo/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/kangaroo/keymaps/via/config.h b/keyboards/xelus/kangaroo/keymaps/via/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/kangaroo/keymaps/via/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/la_plus/keymaps/default/config.h b/keyboards/xelus/la_plus/keymaps/default/config.h deleted file mode 100644 index e559a15426..0000000000 --- a/keyboards/xelus/la_plus/keymaps/default/config.h +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ - -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/la_plus/keymaps/via/config.h b/keyboards/xelus/la_plus/keymaps/via/config.h index 58c086282c..43760bd281 100644 --- a/keyboards/xelus/la_plus/keymaps/via/config.h +++ b/keyboards/xelus/la_plus/keymaps/via/config.h @@ -18,5 +18,3 @@ // Enable RGB Matrix #define VIA_QMK_RGBLIGHT_ENABLE - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/pachi/mini_32u4/keymaps/default/config.h b/keyboards/xelus/pachi/mini_32u4/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/pachi/mini_32u4/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/pachi/mini_32u4/keymaps/via/config.h b/keyboards/xelus/pachi/mini_32u4/keymaps/via/config.h index fc3a2bd0b2..47bbf2bf81 100644 --- a/keyboards/xelus/pachi/mini_32u4/keymaps/via/config.h +++ b/keyboards/xelus/pachi/mini_32u4/keymaps/via/config.h @@ -18,5 +18,3 @@ // 3 layers or else it will not fit in EEPROM #define DYNAMIC_KEYMAP_LAYER_COUNT 3 - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/pachi/rev1/keymaps/default/config.h b/keyboards/xelus/pachi/rev1/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/pachi/rev1/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/pachi/rev1/keymaps/via/config.h b/keyboards/xelus/pachi/rev1/keymaps/via/config.h index fc3a2bd0b2..47bbf2bf81 100644 --- a/keyboards/xelus/pachi/rev1/keymaps/via/config.h +++ b/keyboards/xelus/pachi/rev1/keymaps/via/config.h @@ -18,5 +18,3 @@ // 3 layers or else it will not fit in EEPROM #define DYNAMIC_KEYMAP_LAYER_COUNT 3 - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/pachi/rgb/keymaps/default/config.h b/keyboards/xelus/pachi/rgb/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/pachi/rgb/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/pachi/rgb/keymaps/via/config.h b/keyboards/xelus/pachi/rgb/keymaps/via/config.h index 1213e7a8f2..0e34ad2c1a 100644 --- a/keyboards/xelus/pachi/rgb/keymaps/via/config.h +++ b/keyboards/xelus/pachi/rgb/keymaps/via/config.h @@ -21,5 +21,3 @@ // Enable RGB Matrix #define VIA_QMK_RGBLIGHT_ENABLE - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/rs60/keymaps/default/config.h b/keyboards/xelus/rs60/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/rs60/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/rs60/keymaps/via/config.h b/keyboards/xelus/rs60/keymaps/via/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/rs60/keymaps/via/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/valor/rev2/keymaps/default/config.h b/keyboards/xelus/valor/rev2/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/valor/rev2/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/valor/rev2/keymaps/via/config.h b/keyboards/xelus/valor/rev2/keymaps/via/config.h index 490964f272..e7fb31cb23 100644 --- a/keyboards/xelus/valor/rev2/keymaps/via/config.h +++ b/keyboards/xelus/valor/rev2/keymaps/via/config.h @@ -20,5 +20,3 @@ // More layers #define DYNAMIC_KEYMAP_LAYER_COUNT 8 - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/valor_frl_tkl/keymaps/default/config.h b/keyboards/xelus/valor_frl_tkl/keymaps/default/config.h deleted file mode 100644 index 7b8de5510e..0000000000 --- a/keyboards/xelus/valor_frl_tkl/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2020 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/valor_frl_tkl/keymaps/via/config.h b/keyboards/xelus/valor_frl_tkl/keymaps/via/config.h deleted file mode 100644 index 7b8de5510e..0000000000 --- a/keyboards/xelus/valor_frl_tkl/keymaps/via/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2020 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/xs60/keymaps/default/config.h b/keyboards/xelus/xs60/keymaps/default/config.h deleted file mode 100644 index 5d972dd48c..0000000000 --- a/keyboards/xelus/xs60/keymaps/default/config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2021 Harrison Chan (Xelus) - * - * 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 . - */ -#pragma once - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xelus/xs60/keymaps/via/config.h b/keyboards/xelus/xs60/keymaps/via/config.h index b608adcfc4..8c0ed0c6e3 100644 --- a/keyboards/xelus/xs60/keymaps/via/config.h +++ b/keyboards/xelus/xs60/keymaps/via/config.h @@ -17,5 +17,3 @@ // More layers #define DYNAMIC_KEYMAP_LAYER_COUNT 8 - -#define QMK_KEYS_PER_SCAN 4 diff --git a/keyboards/xiudi/xd75/keymaps/tdl-jturner/config.h b/keyboards/xiudi/xd75/keymaps/tdl-jturner/config.h index 596aaff665..210c4441c3 100644 --- a/keyboards/xiudi/xd75/keymaps/tdl-jturner/config.h +++ b/keyboards/xiudi/xd75/keymaps/tdl-jturner/config.h @@ -24,7 +24,6 @@ //#define TAPPING_TERM 200 #define TAPPING_TOGGLE 2 //#define PERMISSIVE_HOLD -//#define QMK_KEYS_PER_SCAN 4 #define FORCE_NKRO #define MOUSEKEY_INTERVAL 16 diff --git a/layouts/community/65_ansi_blocker/brandonschlack/config.h b/layouts/community/65_ansi_blocker/brandonschlack/config.h index ea8ca61901..d7687315ed 100644 --- a/layouts/community/65_ansi_blocker/brandonschlack/config.h +++ b/layouts/community/65_ansi_blocker/brandonschlack/config.h @@ -54,8 +54,6 @@ # undef ENABLE_RGB_MATRIX_SOLID_SPLASH # undef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH -# define QMK_KEYS_PER_SCAN 4 - # define USB_LED_CAPS_LOCK_SCANCODE 30 #endif diff --git a/layouts/community/65_ansi_blocker_split_bs/brandonschlack-split/config.h b/layouts/community/65_ansi_blocker_split_bs/brandonschlack-split/config.h index fe3dcd41c2..38b827ba32 100644 --- a/layouts/community/65_ansi_blocker_split_bs/brandonschlack-split/config.h +++ b/layouts/community/65_ansi_blocker_split_bs/brandonschlack-split/config.h @@ -54,8 +54,6 @@ # undef ENABLE_RGB_MATRIX_SOLID_SPLASH # undef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH -# define QMK_KEYS_PER_SCAN 4 - # define USB_LED_CAPS_LOCK_SCANCODE 30 #endif diff --git a/quantum/keyboard.c b/quantum/keyboard.c index 2364e3167b..1c62a43d9d 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c @@ -212,6 +212,12 @@ static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) { return false; } +#else + +static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) { + return false; +} + #endif /** \brief matrix_setup @@ -426,64 +432,74 @@ void switch_events(uint8_t row, uint8_t col, bool pressed) { #endif } -/** \brief Perform scan of keyboard matrix +/** + * @brief Generates a tick event at a maximum rate of 1KHz that drives the + * internal QMK state machine. + */ +static inline void generate_tick_event(void) { + static uint16_t last_tick = 0; + const uint16_t now = timer_read(); + if (TIMER_DIFF_16(now, last_tick) != 0) { + action_exec(TICK_EVENT); + last_tick = now; + } +} + +/** + * @brief This task scans the keyboards matrix and processes any key presses + * that occur. * - * Any detected changes in state are sent out as part of the processing + * @return true Matrix did change + * @return false Matrix didn't change */ -bool matrix_scan_task(void) { - static matrix_row_t matrix_prev[MATRIX_ROWS]; - matrix_row_t matrix_row = 0; - matrix_row_t matrix_change = 0; -#ifdef QMK_KEYS_PER_SCAN - uint8_t keys_processed = 0; -#endif +static bool matrix_task(void) { + static matrix_row_t matrix_previous[MATRIX_ROWS]; - uint8_t matrix_changed = matrix_scan(); - if (matrix_changed) last_matrix_activity_trigger(); + matrix_scan(); - for (uint8_t r = 0; r < MATRIX_ROWS; r++) { - matrix_row = matrix_get_row(r); - matrix_change = matrix_row ^ matrix_prev[r]; - if (matrix_change) { -#ifdef MATRIX_HAS_GHOST - if (has_ghost_in_row(r, matrix_row)) { - continue; - } -#endif - if (debug_matrix) matrix_print(); - matrix_row_t col_mask = 1; - for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) { - if (matrix_change & col_mask) { - if (should_process_keypress()) { - action_exec((keyevent_t){ - .key = (keypos_t){.row = r, .col = c}, .pressed = (matrix_row & col_mask), .time = (timer_read() | 1) /* time should not be 0 */ - }); - } - // record a processed key - matrix_prev[r] ^= col_mask; - - switch_events(r, c, (matrix_row & col_mask)); - -#ifdef QMK_KEYS_PER_SCAN - // only jump out if we have processed "enough" keys. - if (++keys_processed >= QMK_KEYS_PER_SCAN) -#endif - // process a key per task call - goto MATRIX_LOOP_END; + bool matrix_changed = false; + for (uint8_t row = 0; row < MATRIX_ROWS && !matrix_changed; row++) { + matrix_changed |= matrix_previous[row] ^ matrix_get_row(row); + } + + matrix_scan_perf_task(); + + // Short-circuit the complete matrix processing if it is not necessary + if (!matrix_changed) { + generate_tick_event(); + return matrix_changed; + } + + if (debug_config.matrix) { + matrix_print(); + } + + const bool process_keypress = should_process_keypress(); + + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + const matrix_row_t current_row = matrix_get_row(row); + const matrix_row_t row_changes = current_row ^ matrix_previous[row]; + + if (!row_changes || has_ghost_in_row(row, current_row)) { + continue; + } + + matrix_row_t col_mask = 1; + for (uint8_t col = 0; col < MATRIX_COLS; col++, col_mask <<= 1) { + if (row_changes & col_mask) { + const bool key_pressed = current_row & col_mask; + + if (process_keypress) { + action_exec(MAKE_KEYEVENT(row, col, key_pressed)); } + + switch_events(row, col, key_pressed); } } - } - // call with pseudo tick event when no real key event. -#ifdef QMK_KEYS_PER_SCAN - // we can get here with some keys processed now. - if (!keys_processed) -#endif - action_exec(TICK_EVENT); -MATRIX_LOOP_END: + matrix_previous[row] = current_row; + } - matrix_scan_perf_task(); return matrix_changed; } @@ -562,20 +578,12 @@ void quantum_task(void) { #endif } -/** \brief Keyboard task: Do keyboard routine jobs - * - * Do routine keyboard jobs: - * - * * scan matrix - * * handle mouse movements - * * handle midi commands - * * light LEDs - * - * This is repeatedly called as fast as possible. - */ +/** \brief Main task that is repeatedly called as fast as possible. */ void keyboard_task(void) { - bool matrix_changed = matrix_scan_task(); - (void)matrix_changed; + const bool matrix_changed = matrix_task(); + if (matrix_changed) { + last_matrix_activity_trigger(); + } quantum_task(); @@ -597,8 +605,10 @@ void keyboard_task(void) { #endif #ifdef ENCODER_ENABLE - bool encoders_changed = encoder_read(); - if (encoders_changed) last_encoder_activity_trigger(); + const bool encoders_changed = encoder_read(); + if (encoders_changed) { + last_encoder_activity_trigger(); + } #endif #ifdef OLED_ENABLE diff --git a/quantum/keyboard.h b/quantum/keyboard.h index fe0736a515..86ce65aac1 100644 --- a/quantum/keyboard.h +++ b/quantum/keyboard.h @@ -71,9 +71,15 @@ static inline bool IS_RELEASED(keyevent_t event) { /* Common keyevent object factory */ #define MAKE_KEYPOS(row_num, col_num) ((keypos_t){.row = (row_num), .col = (col_num)}) + +/** + * @brief Constructs a key event for a pressed or released key. + */ #define MAKE_KEYEVENT(row_num, col_num, press) ((keyevent_t){.key = MAKE_KEYPOS((row_num), (col_num)), .pressed = (press), .time = (timer_read() | 1)}) -/* Tick event */ +/** + * @brief Constructs a internal tick event that is used to drive the internal QMK state machine. + */ #define TICK_EVENT MAKE_KEYEVENT(KEYLOC_TICK, KEYLOC_TICK, false) #ifdef ENCODER_MAP_ENABLE diff --git a/tests/basic/test_keypress.cpp b/tests/basic/test_keypress.cpp index bb68ced557..6d5b502a00 100644 --- a/tests/basic/test_keypress.cpp +++ b/tests/basic/test_keypress.cpp @@ -64,11 +64,7 @@ TEST_F(KeyPress, CorrectKeysAreReportedWhenTwoKeysArePressed) { key_b.press(); key_c.press(); - // Note that QMK only processes one key at a time - // See issue #1476 for more information EXPECT_REPORT(driver, (key_b.report_code)); - keyboard_task(); - EXPECT_REPORT(driver, (key_b.report_code, key_c.report_code)); keyboard_task(); @@ -76,8 +72,6 @@ TEST_F(KeyPress, CorrectKeysAreReportedWhenTwoKeysArePressed) { key_c.release(); // Note that the first key released is the first one in the matrix order EXPECT_REPORT(driver, (key_c.report_code)); - keyboard_task(); - EXPECT_EMPTY_REPORT(driver); keyboard_task(); } @@ -92,10 +86,7 @@ TEST_F(KeyPress, LeftShiftIsReportedCorrectly) { key_lsft.press(); key_a.press(); - // Unfortunately modifiers are also processed in the wrong order - // See issue #1476 for more information EXPECT_REPORT(driver, (key_a.report_code)); - keyboard_task(); EXPECT_REPORT(driver, (key_a.report_code, key_lsft.report_code)); keyboard_task(); @@ -118,11 +109,7 @@ TEST_F(KeyPress, PressLeftShiftAndControl) { key_lsft.press(); key_lctrl.press(); - // Unfortunately modifiers are also processed in the wrong order - // See issue #1476 for more information EXPECT_REPORT(driver, (key_lsft.report_code)); - keyboard_task(); - EXPECT_REPORT(driver, (key_lsft.report_code, key_lctrl.report_code)); keyboard_task(); @@ -130,8 +117,6 @@ TEST_F(KeyPress, PressLeftShiftAndControl) { key_lctrl.release(); EXPECT_REPORT(driver, (key_lctrl.report_code)); - keyboard_task(); - EXPECT_EMPTY_REPORT(driver); keyboard_task(); } @@ -145,20 +130,13 @@ TEST_F(KeyPress, LeftAndRightShiftCanBePressedAtTheSameTime) { key_lsft.press(); key_rsft.press(); - // Unfortunately modifiers are also processed in the wrong order - // See issue #1476 for more information EXPECT_REPORT(driver, (key_lsft.report_code)); - keyboard_task(); - EXPECT_REPORT(driver, (key_lsft.report_code, key_rsft.report_code)); keyboard_task(); key_lsft.release(); key_rsft.release(); - EXPECT_REPORT(driver, (key_rsft.report_code)); - keyboard_task(); - EXPECT_EMPTY_REPORT(driver); keyboard_task(); } diff --git a/tests/tap_dance/test_examples.cpp b/tests/tap_dance/test_examples.cpp index e67e6cb907..6dabc45513 100644 --- a/tests/tap_dance/test_examples.cpp +++ b/tests/tap_dance/test_examples.cpp @@ -92,10 +92,9 @@ TEST_F(TapDance, DoubleTapWithMod) { key_shift.release(); key_esc_caps.press(); EXPECT_REPORT(driver, (KC_LSFT, KC_CAPS)); + EXPECT_REPORT(driver, (KC_CAPS)); run_one_scan_loop(); key_esc_caps.release(); - EXPECT_REPORT(driver, (KC_LSFT)); - run_one_scan_loop(); EXPECT_EMPTY_REPORT(driver); run_one_scan_loop(); } diff --git a/users/curry/config.h b/users/curry/config.h index 3301ebe533..0c96293bd5 100644 --- a/users/curry/config.h +++ b/users/curry/config.h @@ -65,10 +65,6 @@ # define ONESHOT_TIMEOUT 3000 #endif // !ONESHOT_TIMEOUT -#if !defined(QMK_KEYS_PER_SCAN) -# define QMK_KEYS_PER_SCAN 4 -#endif // !QMK_KEYS_PER_SCAN - #define IGNORE_MOD_TAP_INTERRUPT #undef PERMISSIVE_HOLD diff --git a/users/drashna/post_config.h b/users/drashna/post_config.h index 2d5e6438d6..85c028076e 100644 --- a/users/drashna/post_config.h +++ b/users/drashna/post_config.h @@ -37,10 +37,6 @@ # define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_REST_MODE #endif -#ifndef QMK_KEYS_PER_SCAN -# define QMK_KEYS_PER_SCAN 8 -#endif - #ifdef MOUSEKEY_ENABLE // mouse movement config # ifdef MK_3_SPEED diff --git a/users/ishtob/config.h b/users/ishtob/config.h index 6c07d2f2fd..695077528c 100755 --- a/users/ishtob/config.h +++ b/users/ishtob/config.h @@ -16,7 +16,6 @@ //#define LEADER_TIMEOUT 300 //#define BACKLIGHT_BREATHING //#define PERMISSIVE_HOLD -// #define QMK_KEYS_PER_SCAN 4 //audio clicky //#define AUDIO_CLICKY diff --git a/users/issmirnov/config.h b/users/issmirnov/config.h index 664ebfe8a3..5fe78f7a53 100644 --- a/users/issmirnov/config.h +++ b/users/issmirnov/config.h @@ -1,8 +1,5 @@ #pragma once -// Allows sending more than one key per scan. Useful for chords. -#define QMK_KEYS_PER_SCAN 4 - // how long before a tap becomes a hold #undef TAPPING_TERM #define TAPPING_TERM 100 diff --git a/users/kuchosauronad0/config.h b/users/kuchosauronad0/config.h index 58542dc184..8502031f02 100644 --- a/users/kuchosauronad0/config.h +++ b/users/kuchosauronad0/config.h @@ -41,10 +41,6 @@ # define ONESHOT_TIMEOUT 3000 #endif// !ONESHOT_TIMEOUT -#ifndef QMK_KEYS_PER_SCAN -# define QMK_KEYS_PER_SCAN 4 -#endif // !QMK_KEYS_PER_SCAN - #if defined(LEADER_ENABLE) # define LEADER_PER_KEY_TIMING # define LEADER_TIMEOUT 250 diff --git a/users/miles2go/config.h b/users/miles2go/config.h index a704df4b55..2a1d6504d6 100644 --- a/users/miles2go/config.h +++ b/users/miles2go/config.h @@ -6,10 +6,6 @@ #define RGBLIGHT_EFFECT_BREATHING #endif // RGBLIGHT_ENABLE -#ifndef QMK_KEYS_PER_SCAN -#define QMK_KEYS_PER_SCAN 4 -#endif // !QMK_KEYS_PER_SCAN - #undef FORCE_NKRO #ifndef TAPPING_TOGGLE diff --git a/users/yet-another-developer/config.h b/users/yet-another-developer/config.h index d46d487fe3..6d1bf83f0b 100644 --- a/users/yet-another-developer/config.h +++ b/users/yet-another-developer/config.h @@ -11,10 +11,6 @@ #define ONESHOT_TIMEOUT 2000 #endif // !ONESHOT_TIMEOUT -#ifndef QMK_KEYS_PER_SCAN - #define QMK_KEYS_PER_SCAN 4 -#endif // !QMK_KEYS_PER_SCAN - #if defined(LEADER_ENABLE) #define LEADER_PER_KEY_TIMING #define LEADER_TIMEOUT 250 diff --git a/users/zer09/config.h b/users/zer09/config.h index c5ab32f8d4..0324aaa7d3 100644 --- a/users/zer09/config.h +++ b/users/zer09/config.h @@ -1,10 +1,6 @@ #ifndef USERSPACE_CONFIG_H #define USERSPACE_CONFIG_H -#ifndef QMK_KEYS_PER_SCAN -#define QMK_KEYS_PER_SCAN 4 -#endif // !QMK_KEYS_PER_SCAN - // this makes it possible to do rolling combos (zx) with keys that // convert to other keys on hold (z becomes ctrl when you hold it, // and when this option isn't enabled, z rapidly followed by x -- cgit v1.2.3 From ac25109312a49b6b50e54d61430c959652307810 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sun, 7 Aug 2022 02:18:03 -0700 Subject: Always run pointing device init (#17936) --- quantum/pointing_device/pointing_device.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'quantum') diff --git a/quantum/pointing_device/pointing_device.c b/quantum/pointing_device/pointing_device.c index 09f9e5efb7..505a7a6ffd 100644 --- a/quantum/pointing_device/pointing_device.c +++ b/quantum/pointing_device/pointing_device.c @@ -139,14 +139,15 @@ __attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bo */ __attribute__((weak)) void pointing_device_init(void) { #if defined(SPLIT_POINTING_ENABLE) - if (!(POINTING_DEVICE_THIS_SIDE)) { - return; - } + if ((POINTING_DEVICE_THIS_SIDE)) #endif - pointing_device_driver.init(); + { + pointing_device_driver.init(); #ifdef POINTING_DEVICE_MOTION_PIN - setPinInputHigh(POINTING_DEVICE_MOTION_PIN); + setPinInputHigh(POINTING_DEVICE_MOTION_PIN); #endif + } + pointing_device_init_kb(); pointing_device_init_user(); } -- cgit v1.2.3 From cde9dd8b90ed41bd3f960833b7ceab891baf7560 Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Fri, 12 Aug 2022 05:41:42 +0800 Subject: Refactor Pixel Fractal effect (#17602) * Refactor effect with smaller array * Add RGB_MATRIX_USE_LIMITS call * Remove spaces Co-authored-by: Drashna Jaelre Co-authored-by: Drashna Jaelre --- quantum/rgb_matrix/animations/pixel_fractal_anim.h | 78 ++++++++-------------- 1 file changed, 28 insertions(+), 50 deletions(-) (limited to 'quantum') diff --git a/quantum/rgb_matrix/animations/pixel_fractal_anim.h b/quantum/rgb_matrix/animations/pixel_fractal_anim.h index 906da1a48e..b26d5c4100 100644 --- a/quantum/rgb_matrix/animations/pixel_fractal_anim.h +++ b/quantum/rgb_matrix/animations/pixel_fractal_anim.h @@ -1,19 +1,5 @@ -/* Copyright (C) 2021 @filterpaper - * - * 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 . - */ - +// Copyright (C) 2022 @filterpaper +// SPDX-License-Identifier: GPL-2.0-or-later // Inspired from 4x12 fractal created by @schwarzgrau #ifdef ENABLE_RGB_MATRIX_PIXEL_FRACTAL @@ -22,12 +8,8 @@ RGB_MATRIX_EFFECT(PIXEL_FRACTAL) static bool PIXEL_FRACTAL(effect_params_t* params) { # define MID_COL MATRIX_COLS / 2 - static bool led[MATRIX_ROWS][MATRIX_COLS]; - + static bool led[MATRIX_ROWS][MID_COL]; static uint32_t wait_timer = 0; - if (wait_timer > g_rgb_timer) { - return false; - } inline uint32_t interval(void) { return 3000 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16); @@ -37,44 +19,40 @@ static bool PIXEL_FRACTAL(effect_params_t* params) { rgb_matrix_set_color_all(0, 0, 0); } - RGB rgb = rgb_matrix_hsv_to_rgb(rgb_matrix_config.hsv); - for (uint8_t h = 0; h < MATRIX_ROWS; ++h) { - for (uint8_t l = 0; l < MID_COL - 1; ++l) { // Light and move left columns outwards - if (led[h][l]) { - rgb_matrix_set_color(g_led_config.matrix_co[h][l], rgb.r, rgb.g, rgb.b); - } else { - rgb_matrix_set_color(g_led_config.matrix_co[h][l], 0, 0, 0); + RGB_MATRIX_USE_LIMITS(led_min, led_max); + + if (g_rgb_timer > wait_timer) { + RGB rgb = rgb_matrix_hsv_to_rgb(rgb_matrix_config.hsv); + for (uint8_t h = 0; h < MATRIX_ROWS; ++h) { + // Light and copy columns outward + for (uint8_t l = 0; l < MID_COL - 1; ++l) { + if (led[h][l]) { + rgb_matrix_set_color(g_led_config.matrix_co[h][l], rgb.r, rgb.g, rgb.b); + rgb_matrix_set_color(g_led_config.matrix_co[h][MATRIX_COLS - 1 - l], rgb.r, rgb.g, rgb.b); + } else { + rgb_matrix_set_color(g_led_config.matrix_co[h][l], 0, 0, 0); + rgb_matrix_set_color(g_led_config.matrix_co[h][MATRIX_COLS - 1 - l], 0, 0, 0); + } + led[h][l] = led[h][l + 1]; } - led[h][l] = led[h][l + 1]; - } - for (uint8_t r = MATRIX_COLS - 1; r > MID_COL; --r) { // Light and move right columns outwards - if (led[h][r]) { - rgb_matrix_set_color(g_led_config.matrix_co[h][r], rgb.r, rgb.g, rgb.b); + // Light both middle columns + if (led[h][MID_COL - 1]) { + rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL - 1], rgb.r, rgb.g, rgb.b); + rgb_matrix_set_color(g_led_config.matrix_co[h][MATRIX_COLS - MID_COL], rgb.r, rgb.g, rgb.b); } else { - rgb_matrix_set_color(g_led_config.matrix_co[h][r], 0, 0, 0); + rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL - 1], 0, 0, 0); + rgb_matrix_set_color(g_led_config.matrix_co[h][MATRIX_COLS - MID_COL], 0, 0, 0); } - led[h][r] = led[h][r - 1]; - } - // Light both middle columns - if (led[h][MID_COL]) { - rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL], rgb.r, rgb.g, rgb.b); - } else { - rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL], 0, 0, 0); - } - if (led[h][MID_COL - 1]) { - rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL - 1], rgb.r, rgb.g, rgb.b); - } else { - rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL - 1], 0, 0, 0); + // Generate new random fractal column + led[h][MID_COL - 1] = (random8() & 3) ? false : true; } - // Generate new random fractal columns - led[h][MID_COL] = led[h][MID_COL - 1] = (random8() & 3) ? false : true; + wait_timer = g_rgb_timer + interval(); } - wait_timer = g_rgb_timer + interval(); - return false; + return rgb_matrix_check_finished_leds(led_max); } # endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS #endif // ENABLE_RGB_MATRIX_PIXEL_FRACTAL -- cgit v1.2.3 From db4c4b1f7868a99c094ee277f7b17ffffe2fea7b Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sat, 13 Aug 2022 04:13:22 +0200 Subject: Fix Bépo's BP_NNBS (narrow non-breaking space) (#17999) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ryan --- quantum/keymap_extras/keymap_bepo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_bepo.h b/quantum/keymap_extras/keymap_bepo.h index 72d5b81f32..6361823242 100644 --- a/quantum/keymap_extras/keymap_bepo.h +++ b/quantum/keymap_extras/keymap_bepo.h @@ -237,4 +237,4 @@ #define BP_DDAG S(ALGR(BP_H)) // ‡ #define BP_FORD S(ALGR(BP_F)) // ª // Row 5 -#define BP_NNBS S(ALGR(BP_)) //   (narrow non-breaking space) +#define BP_NNBS S(ALGR(KC_SPC)) //   (narrow non-breaking space) -- cgit v1.2.3 From b4fbb340c51dc4353ec821a70adc529698549ef0 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sat, 13 Aug 2022 04:13:43 +0200 Subject: Use LT_ZCAR in place of LT_PLUS for modded kc definitions (#18000) --- quantum/keymap_extras/keymap_lithuanian_qwerty.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_lithuanian_qwerty.h b/quantum/keymap_extras/keymap_lithuanian_qwerty.h index 2dbb3649f7..fb0468a20a 100644 --- a/quantum/keymap_extras/keymap_lithuanian_qwerty.h +++ b/quantum/keymap_extras/keymap_lithuanian_qwerty.h @@ -137,7 +137,7 @@ #define LT_6 ALGR(LT_SCAR) // 6 #define LT_7 ALGR(LT_UOGO) // 7 #define LT_8 ALGR(LT_UMAC) // 8 -#define LT_EQL ALGR(LT_PLUS) // = +#define LT_EQL ALGR(LT_ZCAR) // = // Row 2 #define LT_EURO ALGR(LT_E) // € @@ -163,4 +163,4 @@ #define LT_CIRC S(ALGR(LT_SCAR)) // ^ #define LT_AMPR S(ALGR(LT_UOGO)) // & #define LT_ASTR S(ALGR(LT_UMAC)) // * -#define LT_PLUS S(ALGR(LT_PLUS)) // + +#define LT_PLUS S(ALGR(LT_ZCAR)) // + -- cgit v1.2.3 From 20f0f402207e38d074aa4ca713fcc0d9c2e391c9 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sat, 13 Aug 2022 04:16:50 +0200 Subject: Remove invisible variation selector-15 from keymap_japanese.h (#18007) --- quantum/keymap_extras/keymap_japanese.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_japanese.h b/quantum/keymap_extras/keymap_japanese.h index d10feb5856..df78af8399 100644 --- a/quantum/keymap_extras/keymap_japanese.h +++ b/quantum/keymap_extras/keymap_japanese.h @@ -28,7 +28,7 @@ /* * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ - * │Z↔︎H│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ ^ │ ¥ │ │ + * │Z↔H│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ ^ │ ¥ │ │ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┤ * │ │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ @ │ [ │ │ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │ @@ -40,7 +40,7 @@ * └─────┴───┴─────┴─────┴─────────┴─────┴───┴───┴───┴───┴─────┘ */ // Row 1 -#define JP_ZKHK KC_GRV // Zenkaku ↔︎ Hankaku ↔ Kanji (半角 ↔ 全角 ↔ 漢字) +#define JP_ZKHK KC_GRV // Zenkaku ↔ Hankaku ↔ Kanji (半角 ↔ 全角 ↔ 漢字) #define JP_1 KC_1 // 1 #define JP_2 KC_2 // 2 #define JP_3 KC_3 // 3 -- cgit v1.2.3 From e3415d6b973868e99eef83a9bb92726eba796e4f Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sat, 13 Aug 2022 04:20:35 +0200 Subject: define CZ_PERC S(CZ_PLUS) → define CZ_PERC S(CZ_EQL) (#18008) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quantum/keymap_extras/keymap_czech.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_czech.h b/quantum/keymap_extras/keymap_czech.h index 2b1fb5da29..a8f522d31c 100644 --- a/quantum/keymap_extras/keymap_czech.h +++ b/quantum/keymap_extras/keymap_czech.h @@ -111,7 +111,7 @@ #define CZ_8 S(CZ_AACU) // 8 #define CZ_9 S(CZ_IACU) // 9 #define CZ_0 S(CZ_EACU) // 0 -#define CZ_PERC S(CZ_PLUS) // % +#define CZ_PERC S(CZ_EQL) // % #define CZ_CARN S(CZ_ACUT) // ˇ (dead) // Row 2 #define CZ_SLSH S(CZ_UACU) // / -- cgit v1.2.3 From 4ff39b5652b7f3338ac6e046e784da7a3d351d58 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sat, 13 Aug 2022 04:20:58 +0200 Subject: KR_DQUO S(KR_COLN) → KR_DQUO S(KR_QUOT) (#18011) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quantum/keymap_extras/keymap_korean.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_korean.h b/quantum/keymap_extras/keymap_korean.h index 74be122dad..3d41a98b88 100644 --- a/quantum/keymap_extras/keymap_korean.h +++ b/quantum/keymap_extras/keymap_korean.h @@ -121,7 +121,7 @@ #define KR_PIPE S(KR_WON) // | // Row 3 #define KR_COLN S(KR_SCLN) // : -#define KR_DQUO S(KR_COLN) // " +#define KR_DQUO S(KR_QUOT) // " // Row 4 #define KR_LABK S(KR_COMM) // < #define KR_RABK S(KR_DOT) // > -- cgit v1.2.3 From a02aff9c77c15ca9e248f84b09a88386a8f4b0a6 Mon Sep 17 00:00:00 2001 From: lokher Date: Sat, 13 Aug 2022 21:39:06 +0800 Subject: Add led matrix support for CKLED2001 (#17643) --- builddefs/common_features.mk | 9 +- drivers/led/ckled2001-simple.c | 218 +++++++++++++++++++++ drivers/led/ckled2001-simple.h | 337 ++++++++++++++++++++++++++++++++ drivers/led/ckled2001.c | 21 +- drivers/led/ckled2001.h | 4 +- quantum/led_matrix/led_matrix.h | 3 + quantum/led_matrix/led_matrix_drivers.c | 51 ++++- 7 files changed, 627 insertions(+), 16 deletions(-) create mode 100644 drivers/led/ckled2001-simple.c create mode 100644 drivers/led/ckled2001-simple.h (limited to 'quantum') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 755a1735e0..a23b5e82b9 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -332,7 +332,7 @@ ifeq ($(strip $(RGBLIGHT_ENABLE)), yes) endif LED_MATRIX_ENABLE ?= no -VALID_LED_MATRIX_TYPES := IS31FL3731 IS31FL3742A IS31FL3743A IS31FL3745 IS31FL3746A custom +VALID_LED_MATRIX_TYPES := IS31FL3731 IS31FL3742A IS31FL3743A IS31FL3745 IS31FL3746A CKLED2001 custom # TODO: IS31FL3733 IS31FL3737 IS31FL3741 ifeq ($(strip $(LED_MATRIX_ENABLE)), yes) @@ -388,6 +388,13 @@ endif QUANTUM_LIB_SRC += i2c_master.c endif + ifeq ($(strip $(LED_MATRIX_DRIVER)), CKLED2001) + OPT_DEFS += -DCKLED2001 -DSTM32_I2C -DHAL_USE_I2C=TRUE + COMMON_VPATH += $(DRIVER_PATH)/led + SRC += ckled2001-simple.c + QUANTUM_LIB_SRC += i2c_master.c + endif + endif RGB_MATRIX_ENABLE ?= no diff --git a/drivers/led/ckled2001-simple.c b/drivers/led/ckled2001-simple.c new file mode 100644 index 0000000000..da4bf20b99 --- /dev/null +++ b/drivers/led/ckled2001-simple.c @@ -0,0 +1,218 @@ +/* Copyright 2021 @ Keychron (https://www.keychron.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 . + */ + +#include "ckled2001-simple.h" +#include "i2c_master.h" +#include "wait.h" + +#ifndef CKLED2001_TIMEOUT +# define CKLED2001_TIMEOUT 100 +#endif + +#ifndef CKLED2001_PERSISTENCE +# define CKLED2001_PERSISTENCE 0 +#endif + +#ifndef PHASE_CHANNEL +# define PHASE_CHANNEL MSKPHASE_12CHANNEL +#endif + +#ifndef CKLED2001_CURRENT_TUNE +# define CKLED2001_CURRENT_TUNE \ + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// These buffers match the CKLED2001 PWM registers. +// The control buffers match the PG0 LED On/Off registers. +// Storing them like this is optimal for I2C transfers to the registers. +// We could optimize this and take out the unused registers from these +// buffers and the transfers in CKLED2001_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[DRIVER_COUNT][192]; +bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; + +uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0}; +bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; + +bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) { + // If the transaction fails function returns false. + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + +#if CKLED2001_PERSISTENCE > 0 + for (uint8_t i = 0; i < CKLED2001_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, CKLED2001_TIMEOUT) != 0) { + return false; + } + } +#else + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, CKLED2001_TIMEOUT) != 0) { + return false; + } +#endif + return true; +} + +bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { + // Assumes PG1 is already selected. + // If any of the transactions fails function returns false. + // Transmit PWM registers in 12 transfers of 16 bytes. + // g_twi_transfer_buffer[] is 20 bytes + + // Iterate over the pwm_buffer contents at 16 byte intervals. + for (int i = 0; i < 192; i += 16) { + g_twi_transfer_buffer[0] = i; + // Copy the data from i to i+15. + // Device will auto-increment register for data after the first byte + // Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer. + for (int j = 0; j < 16; j++) { + g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j]; + } + +#if CKLED2001_PERSISTENCE > 0 + for (uint8_t i = 0; i < CKLED2001_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, CKLED2001_TIMEOUT) != 0) { + return false; + } + } +#else + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, CKLED2001_TIMEOUT) != 0) { + return false; + } +#endif + } + return true; +} + +void CKLED2001_init(uint8_t addr) { + // Select to function page + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + // Setting LED driver to shutdown mode + CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); + // Setting internal channel pulldown/pullup + CKLED2001_write_register(addr, PDU_REG, MSKSET_CA_CB_CHANNEL); + // Select number of scan phase + CKLED2001_write_register(addr, SCAN_PHASE_REG, PHASE_CHANNEL); + // Setting PWM Delay Phase + CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE1_REG, MSKPWM_DELAY_PHASE_ENABLE); + // Setting Driving/Sinking Channel Slew Rate + CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE2_REG, MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE); + // Setting Iref + CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_DISABLE); + // Set LED CONTROL PAGE (Page 0) + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) { + CKLED2001_write_register(addr, i, 0x00); + } + + // Set PWM PAGE (Page 1) + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); + for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) { + CKLED2001_write_register(addr, i, 0x00); + } + + // Set CURRENT PAGE (Page 4) + uint8_t current_tuen_reg_list[LED_CURRENT_TUNE_LENGTH] = CKLED2001_CURRENT_TUNE; + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE); + for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) { + CKLED2001_write_register(addr, i, current_tuen_reg_list[i]); + } + + // Enable LEDs ON/OFF + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) { + CKLED2001_write_register(addr, i, 0xFF); + } + + // Select to function page + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + // Setting LED driver to normal mode + CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); +} + +void CKLED2001_set_value(int index, uint8_t value) { + ckled2001_led led; + if (index >= 0 && index < DRIVER_LED_TOTAL) { + memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led)); + + g_pwm_buffer[led.driver][led.v] = value; + g_pwm_buffer_update_required[led.driver] = true; + } +} + +void CKLED2001_set_value_all(uint8_t value) { + for (int i = 0; i < DRIVER_LED_TOTAL; i++) { + CKLED2001_set_value(i, value); + } +} + +void CKLED2001_set_led_control_register(uint8_t index, bool value) { + ckled2001_led led; + memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led)); + + uint8_t control_register = led.v / 8; + uint8_t bit_value = led.v % 8; + + if (value) { + g_led_control_registers[led.driver][control_register] |= (1 << bit_value); + } else { + g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value); + } + + g_led_control_registers_update_required[led.driver] = true; +} + +void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index) { + if (g_pwm_buffer_update_required[index]) { + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); + + // If any of the transactions fail we risk writing dirty PG0, + // refresh page 0 just in case. + if (!CKLED2001_write_pwm_buffer(addr, g_pwm_buffer[index])) { + g_led_control_registers_update_required[index] = true; + } + } + g_pwm_buffer_update_required[index] = false; +} + +void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index) { + if (g_led_control_registers_update_required[index]) { + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + for (int i = 0; i < 24; i++) { + CKLED2001_write_register(addr, i, g_led_control_registers[index][i]); + } + } + g_led_control_registers_update_required[index] = false; +} + +void CKLED2001_sw_return_normal(uint8_t addr) { + // Select to function page + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + // Setting LED driver to normal mode + CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); +} + +void CKLED2001_sw_shutdown(uint8_t addr) { + // Select to function page + CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + // Setting LED driver to shutdown mode + CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); + // Write SW Sleep Register + CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_ENABLE); +} diff --git a/drivers/led/ckled2001-simple.h b/drivers/led/ckled2001-simple.h new file mode 100644 index 0000000000..731da2e1cd --- /dev/null +++ b/drivers/led/ckled2001-simple.h @@ -0,0 +1,337 @@ +/* Copyright 2021 @ Keychron (https://www.keychron.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 . + */ + +#pragma once + +#include +#include +#include "progmem.h" + +typedef struct ckled2001_led { + uint8_t driver : 2; + uint8_t v; +} __attribute__((packed)) ckled2001_led; + +extern const ckled2001_led PROGMEM g_ckled2001_leds[DRIVER_LED_TOTAL]; + +void CKLED2001_init(uint8_t addr); +bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); + +void CKLED2001_set_value(int index, uint8_t value); +void CKLED2001_set_value_all(uint8_t value); + +void CKLED2001_set_led_control_register(uint8_t index, bool value); + +// This should not be called from an interrupt +// (eg. from a timer interrupt). +// Call this while idle (in between matrix scans). +// If the buffer is dirty, it will update the driver with the buffer. +void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index); +void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index); + +void CKLED2001_sw_return_normal(uint8_t addr); +void CKLED2001_sw_shutdown(uint8_t addr); + +// Registers Page Define +#define CONFIGURE_CMD_PAGE 0xFD +#define LED_CONTROL_PAGE 0x00 +#define LED_PWM_PAGE 0x01 +#define FUNCTION_PAGE 0x03 +#define CURRENT_TUNE_PAGE 0x04 + +// Function Register: address 0x00 +#define CONFIGURATION_REG 0x00 +#define MSKSW_SHUT_DOWN_MODE (0x0 << 0) +#define MSKSW_NORMAL_MODE (0x1 << 0) + +#define DRIVER_ID_REG 0x11 +#define CKLED2001_ID 0x8A + +#define PDU_REG 0x13 +#define MSKSET_CA_CB_CHANNEL 0xAA +#define MSKCLR_CA_CB_CHANNEL 0x00 + +#define SCAN_PHASE_REG 0x14 +#define MSKPHASE_12CHANNEL 0x00 +#define MSKPHASE_11CHANNEL 0x01 +#define MSKPHASE_10CHANNEL 0x02 +#define MSKPHASE_9CHANNEL 0x03 +#define MSKPHASE_8CHANNEL 0x04 +#define MSKPHASE_7CHANNEL 0x05 +#define MSKPHASE_6CHANNEL 0x06 +#define MSKPHASE_5CHANNEL 0x07 +#define MSKPHASE_4CHANNEL 0x08 +#define MSKPHASE_3CHANNEL 0x09 +#define MSKPHASE_2CHANNEL 0x0A +#define MSKPHASE_1CHANNEL 0x0B + +#define SLEW_RATE_CONTROL_MODE1_REG 0x15 +#define MSKPWM_DELAY_PHASE_ENABLE 0x04 +#define MSKPWM_DELAY_PHASE_DISABLE 0x00 + +#define SLEW_RATE_CONTROL_MODE2_REG 0x16 +#define MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE 0xC0 +#define MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_DISABLE 0x00 + +#define OPEN_SHORT_ENABLE_REG 0x17 +#define MSKOPEN_DETECTION_ENABLE (0x01 << 7) +#define MSKOPEN_DETECTION_DISABLE (0x00) + +#define MSKSHORT_DETECTION_ENABLE (0x01 << 6) +#define MSKSHORT_DETECTION_DISABLE (0x00) + +#define OPEN_SHORT_DUTY_REG 0x18 +#define OPEN_SHORT_FLAG_REG 0x19 + +#define MSKOPEN_DETECTION_INTERRUPT_ENABLE (0x01 << 7) +#define MSKOPEN_DETECTION_INTERRUPT_DISABLE (0x00) + +#define MSKSHORT_DETECTION_INTERRUPT_ENABLE (0x01 << 6) +#define MSKSHORT_DETECTION_INTERRUPT_DISABLE (0x00) + +#define SOFTWARE_SLEEP_REG 0x1A +#define MSKSLEEP_ENABLE 0x02 +#define MSKSLEEP_DISABLE 0x00 + +// LED Control Registers +#define LED_CONTROL_ON_OFF_FIRST_ADDR 0x0 +#define LED_CONTROL_ON_OFF_LAST_ADDR 0x17 +#define LED_CONTROL_ON_OFF_LENGTH ((LED_CONTROL_ON_OFF_LAST_ADDR - LED_CONTROL_ON_OFF_FIRST_ADDR) + 1) + +#define LED_CONTROL_OPEN_FIRST_ADDR 0x18 +#define LED_CONTROL_OPEN_LAST_ADDR 0x2F +#define LED_CONTROL_OPEN_LENGTH ((LED_CONTROL_OPEN_LAST_ADDR - LED_CONTROL_OPEN_FIRST_ADDR) + 1) + +#define LED_CONTROL_SHORT_FIRST_ADDR 0x30 +#define LED_CONTROL_SHORT_LAST_ADDR 0x47 +#define LED_CONTROL_SHORT_LENGTH ((LED_CONTROL_SHORT_LAST_ADDR - LED_CONTROL_SHORT_FIRST_ADDR) + 1) + +#define LED_CONTROL_PAGE_LENGTH 0x48 + +// LED Control Registers +#define LED_PWM_FIRST_ADDR 0x00 +#define LED_PWM_LAST_ADDR 0xBF +#define LED_PWM_LENGTH 0xC0 + +// Current Tune Registers +#define LED_CURRENT_TUNE_FIRST_ADDR 0x00 +#define LED_CURRENT_TUNE_LAST_ADDR 0x0B +#define LED_CURRENT_TUNE_LENGTH 0x0C + +#define A_1 0x00 +#define A_2 0x01 +#define A_3 0x02 +#define A_4 0x03 +#define A_5 0x04 +#define A_6 0x05 +#define A_7 0x06 +#define A_8 0x07 +#define A_9 0x08 +#define A_10 0x09 +#define A_11 0x0A +#define A_12 0x0B +#define A_13 0x0C +#define A_14 0x0D +#define A_15 0x0E +#define A_16 0x0F + +#define B_1 0x10 +#define B_2 0x11 +#define B_3 0x12 +#define B_4 0x13 +#define B_5 0x14 +#define B_6 0x15 +#define B_7 0x16 +#define B_8 0x17 +#define B_9 0x18 +#define B_10 0x19 +#define B_11 0x1A +#define B_12 0x1B +#define B_13 0x1C +#define B_14 0x1D +#define B_15 0x1E +#define B_16 0x1F + +#define C_1 0x20 +#define C_2 0x21 +#define C_3 0x22 +#define C_4 0x23 +#define C_5 0x24 +#define C_6 0x25 +#define C_7 0x26 +#define C_8 0x27 +#define C_9 0x28 +#define C_10 0x29 +#define C_11 0x2A +#define C_12 0x2B +#define C_13 0x2C +#define C_14 0x2D +#define C_15 0x2E +#define C_16 0x2F + +#define D_1 0x30 +#define D_2 0x31 +#define D_3 0x32 +#define D_4 0x33 +#define D_5 0x34 +#define D_6 0x35 +#define D_7 0x36 +#define D_8 0x37 +#define D_9 0x38 +#define D_10 0x39 +#define D_11 0x3A +#define D_12 0x3B +#define D_13 0x3C +#define D_14 0x3D +#define D_15 0x3E +#define D_16 0x3F + +#define E_1 0x40 +#define E_2 0x41 +#define E_3 0x42 +#define E_4 0x43 +#define E_5 0x44 +#define E_6 0x45 +#define E_7 0x46 +#define E_8 0x47 +#define E_9 0x48 +#define E_10 0x49 +#define E_11 0x4A +#define E_12 0x4B +#define E_13 0x4C +#define E_14 0x4D +#define E_15 0x4E +#define E_16 0x4F + +#define F_1 0x50 +#define F_2 0x51 +#define F_3 0x52 +#define F_4 0x53 +#define F_5 0x54 +#define F_6 0x55 +#define F_7 0x56 +#define F_8 0x57 +#define F_9 0x58 +#define F_10 0x59 +#define F_11 0x5A +#define F_12 0x5B +#define F_13 0x5C +#define F_14 0x5D +#define F_15 0x5E +#define F_16 0x5F + +#define G_1 0x60 +#define G_2 0x61 +#define G_3 0x62 +#define G_4 0x63 +#define G_5 0x64 +#define G_6 0x65 +#define G_7 0x66 +#define G_8 0x67 +#define G_9 0x68 +#define G_10 0x69 +#define G_11 0x6A +#define G_12 0x6B +#define G_13 0x6C +#define G_14 0x6D +#define G_15 0x6E +#define G_16 0x6F + +#define H_1 0x70 +#define H_2 0x71 +#define H_3 0x72 +#define H_4 0x73 +#define H_5 0x74 +#define H_6 0x75 +#define H_7 0x76 +#define H_8 0x77 +#define H_9 0x78 +#define H_10 0x79 +#define H_11 0x7A +#define H_12 0x7B +#define H_13 0x7C +#define H_14 0x7D +#define H_15 0x7E +#define H_16 0x7F + +#define I_1 0x80 +#define I_2 0x81 +#define I_3 0x82 +#define I_4 0x83 +#define I_5 0x84 +#define I_6 0x85 +#define I_7 0x86 +#define I_8 0x87 +#define I_9 0x88 +#define I_10 0x89 +#define I_11 0x8A +#define I_12 0x8B +#define I_13 0x8C +#define I_14 0x8D +#define I_15 0x8E +#define I_16 0x8F + +#define J_1 0x90 +#define J_2 0x91 +#define J_3 0x92 +#define J_4 0x93 +#define J_5 0x94 +#define J_6 0x95 +#define J_7 0x96 +#define J_8 0x97 +#define J_9 0x98 +#define J_10 0x99 +#define J_11 0x9A +#define J_12 0x9B +#define J_13 0x9C +#define J_14 0x9D +#define J_15 0x9E +#define J_16 0x9F + +#define K_1 0xA0 +#define K_2 0xA1 +#define K_3 0xA2 +#define K_4 0xA3 +#define K_5 0xA4 +#define K_6 0xA5 +#define K_7 0xA6 +#define K_8 0xA7 +#define K_9 0xA8 +#define K_10 0xA9 +#define K_11 0xAA +#define K_12 0xAB +#define K_13 0xAC +#define K_14 0xAD +#define K_15 0xAE +#define K_16 0xAF + +#define L_1 0xB0 +#define L_2 0xB1 +#define L_3 0xB2 +#define L_4 0xB3 +#define L_5 0xB4 +#define L_6 0xB5 +#define L_7 0xB6 +#define L_8 0xB7 +#define L_9 0xB8 +#define L_10 0xB9 +#define L_11 0xBA +#define L_12 0xBB +#define L_13 0xBC +#define L_14 0xBD +#define L_15 0xBE +#define L_16 0xBF \ No newline at end of file diff --git a/drivers/led/ckled2001.c b/drivers/led/ckled2001.c index 8d71805a24..b7e7db06cc 100644 --- a/drivers/led/ckled2001.c +++ b/drivers/led/ckled2001.c @@ -30,6 +30,11 @@ # define PHASE_CHANNEL MSKPHASE_12CHANNEL #endif +#ifndef CKLED2001_CURRENT_TUNE +# define CKLED2001_CURRENT_TUNE \ + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } +#endif + // Transfer buffer for TWITransmitData() uint8_t g_twi_transfer_buffer[20]; @@ -123,18 +128,10 @@ void CKLED2001_init(uint8_t addr) { } // Set CURRENT PAGE (Page 4) + uint8_t current_tuen_reg_list[LED_CURRENT_TUNE_LENGTH] = CKLED2001_CURRENT_TUNE; CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE); for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) { - switch (i) { - case 2: - case 5: - case 8: - case 11: - CKLED2001_write_register(addr, i, 0xA0); - break; - default: - CKLED2001_write_register(addr, i, 0xFF); - } + CKLED2001_write_register(addr, i, current_tuen_reg_list[i]); } // Enable LEDs ON/OFF @@ -220,14 +217,14 @@ void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index) { g_led_control_registers_update_required[index] = false; } -void CKLED2001_return_normal(uint8_t addr) { +void CKLED2001_sw_return_normal(uint8_t addr) { // Select to function page CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to normal mode CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); } -void CKLED2001_shutdown(uint8_t addr) { +void CKLED2001_sw_shutdown(uint8_t addr) { // Select to function page CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to shutdown mode diff --git a/drivers/led/ckled2001.h b/drivers/led/ckled2001.h index 1967961d20..7d5ad34f95 100644 --- a/drivers/led/ckled2001.h +++ b/drivers/led/ckled2001.h @@ -45,8 +45,8 @@ void CKLED2001_set_led_control_register(uint8_t index, bool red, bool green, boo void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index); void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index); -void CKLED2001_return_normal(uint8_t addr); -void CKLED2001_shutdown(uint8_t addr); +void CKLED2001_sw_return_normal(uint8_t addr); +void CKLED2001_sw_shutdown(uint8_t addr); // Registers Page Define #define CONFIGURE_CMD_PAGE 0xFD diff --git a/quantum/led_matrix/led_matrix.h b/quantum/led_matrix/led_matrix.h index b2abec7eb1..446f293c78 100644 --- a/quantum/led_matrix/led_matrix.h +++ b/quantum/led_matrix/led_matrix.h @@ -33,6 +33,9 @@ #ifdef IS31FL3733 # include "is31fl3733-simple.h" #endif +#ifdef CKLED2001 +# include "ckled2001-simple.h" +#endif #ifndef LED_MATRIX_LED_FLUSH_LIMIT # define LED_MATRIX_LED_FLUSH_LIMIT 16 diff --git a/quantum/led_matrix/led_matrix_drivers.c b/quantum/led_matrix/led_matrix_drivers.c index 847ca1c310..f01b395c15 100644 --- a/quantum/led_matrix/led_matrix_drivers.c +++ b/quantum/led_matrix/led_matrix_drivers.c @@ -25,7 +25,7 @@ * in their own files. */ -#if defined(IS31FL3731) || defined(IS31FL3733) || defined(IS31FLCOMMON) +#if defined(IS31FL3731) || defined(IS31FL3733) || defined(IS31FLCOMMON) || defined(CKLED2001) # include "i2c_master.h" static void init(void) { @@ -78,6 +78,22 @@ static void init(void) { # endif # endif # endif +# elif defined(CKLED2001) +# if defined(LED_DRIVER_SHUTDOWN_PIN) + setPinOutput(LED_DRIVER_SHUTDOWN_PIN); + writePinHigh(LED_DRIVER_SHUTDOWN_PIN); +# endif + + CKLED2001_init(DRIVER_ADDR_1); +# if defined(DRIVER_ADDR_2) + CKLED2001_init(DRIVER_ADDR_2); +# if defined(DRIVER_ADDR_3) + CKLED2001_init(DRIVER_ADDR_3); +# if defined(DRIVER_ADDR_4) + CKLED2001_init(DRIVER_ADDR_4); +# endif +# endif +# endif # endif for (int index = 0; index < DRIVER_LED_TOTAL; index++) { @@ -87,6 +103,8 @@ static void init(void) { IS31FL3733_set_led_control_register(index, true); # elif defined(IS31FLCOMMON) IS31FL_simple_set_scaling_buffer(index, true); +# elif defined(CKLED2001) + CKLED2001_set_led_control_register(index, true); # endif } @@ -129,6 +147,17 @@ static void init(void) { # endif # endif # endif +# elif defined(CKLED2001) + CKLED2001_update_led_control_registers(DRIVER_ADDR_1, 0); +# if defined(DRIVER_ADDR_2) + CKLED2001_update_led_control_registers(DRIVER_ADDR_2, 1); +# if defined(DRIVER_ADDR_3) + CKLED2001_update_led_control_registers(DRIVER_ADDR_3, 2); +# if defined(DRIVER_ADDR_4) + CKLED2001_update_led_control_registers(DRIVER_ADDR_4, 3); +# endif +# endif +# endif # endif } @@ -194,5 +223,25 @@ const led_matrix_driver_t led_matrix_driver = { .set_value = IS31FL_simple_set_brightness, .set_value_all = IS31FL_simple_set_brigntness_all, }; +# elif defined(CKLED2001) +static void flush(void) { + CKLED2001_update_pwm_buffers(DRIVER_ADDR_1, 0); +# if defined(DRIVER_ADDR_2) + CKLED2001_update_pwm_buffers(DRIVER_ADDR_2, 1); +# if defined(DRIVER_ADDR_3) + CKLED2001_update_pwm_buffers(DRIVER_ADDR_3, 2); +# if defined(DRIVER_ADDR_4) + CKLED2001_update_pwm_buffers(DRIVER_ADDR_4, 3); +# endif +# endif +# endif +} + +const led_matrix_driver_t led_matrix_driver = { + .init = init, + .flush = flush, + .set_value = CKLED2001_set_value, + .set_value_all = CKLED2001_set_value_all, +}; # endif #endif -- cgit v1.2.3 From 6a0d90f81a9b9938591b32f9321530e68e5cea0b Mon Sep 17 00:00:00 2001 From: Pascal Getreuer <50221757+getreuer@users.noreply.github.com> Date: Sat, 13 Aug 2022 06:48:51 -0700 Subject: Fix Caps Word capitalization when used with Combos + Auto Shift. (#17549) --- quantum/process_keycode/process_auto_shift.c | 7 +- quantum/process_keycode/process_caps_word.c | 4 + quantum/process_keycode/process_combo.c | 9 + .../test_caps_word_autoshift.cpp | 64 +++++-- tests/caps_word/caps_word_combo/config.h | 20 ++ tests/caps_word/caps_word_combo/test.mk | 19 ++ .../caps_word_combo/test_caps_word_combo.cpp | 212 +++++++++++++++++++++ tests/test_common/test_fixture.cpp | 16 ++ tests/test_common/test_fixture.hpp | 7 + 9 files changed, 343 insertions(+), 15 deletions(-) create mode 100644 tests/caps_word/caps_word_combo/config.h create mode 100644 tests/caps_word/caps_word_combo/test.mk create mode 100644 tests/caps_word/caps_word_combo/test_caps_word_combo.cpp (limited to 'quantum') diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index 8cb45bc0ae..3ff188ba7e 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -123,7 +123,12 @@ bool get_autoshift_shift_state(uint16_t keycode) { /** \brief Restores the shift key if it was cancelled by Auto Shift */ static void autoshift_flush_shift(void) { autoshift_flags.holding_shift = false; - del_weak_mods(MOD_BIT(KC_LSFT)); +# ifdef CAPS_WORD_ENABLE + if (!is_caps_word_on()) +# endif // CAPS_WORD_ENABLE + { + del_weak_mods(MOD_BIT(KC_LSFT)); + } if (autoshift_flags.cancelling_lshift) { autoshift_flags.cancelling_lshift = false; add_mods(MOD_BIT(KC_LSFT)); diff --git a/quantum/process_keycode/process_caps_word.c b/quantum/process_keycode/process_caps_word.c index ffd509a914..bc4369846c 100644 --- a/quantum/process_keycode/process_caps_word.c +++ b/quantum/process_keycode/process_caps_word.c @@ -131,7 +131,11 @@ bool process_caps_word(uint16_t keycode, keyrecord_t* record) { #endif // SWAP_HANDS_ENABLE } +#ifdef AUTO_SHIFT_ENABLE + del_weak_mods(get_autoshift_state() ? ~MOD_BIT(KC_LSFT) : 0xff); +#else clear_weak_mods(); +#endif // AUTO_SHIFT_ENABLE if (caps_word_press_user(keycode)) { send_keyboard_report(); return true; diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c index d5a649adb3..e5135e5a64 100644 --- a/quantum/process_keycode/process_combo.c +++ b/quantum/process_keycode/process_combo.c @@ -227,7 +227,16 @@ static inline void dump_key_buffer(void) { #endif } record->event.time = 0; + +#if defined(CAPS_WORD_ENABLE) && defined(AUTO_SHIFT_ENABLE) + // Edge case: preserve the weak Left Shift mod if both Caps Word and + // Auto Shift are on. Caps Word capitalizes by setting the weak Left + // Shift mod during the press event, but Auto Shift doesn't send the + // key until it receives the release event. + del_weak_mods((is_caps_word_on() && get_autoshift_state()) ? ~MOD_BIT(KC_LSFT) : 0xff); +#else clear_weak_mods(); +#endif // defined(CAPS_WORD_ENABLE) && defined(AUTO_SHIFT_ENABLE) #if TAP_CODE_DELAY > 0 // only delay once and for a non-tapping key diff --git a/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp b/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp index deb4d95766..ba21c527a6 100644 --- a/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp +++ b/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp @@ -19,6 +19,14 @@ #include "test_fixture.hpp" #include "test_keymap_key.hpp" +// Allow reports with no keys or only KC_LSFT. +// clang-format off +#define EXPECT_EMPTY_OR_LSFT(driver) \ + EXPECT_CALL(driver, send_keyboard_mock(AnyOf( \ + KeyboardReport(), \ + KeyboardReport(KC_LSFT)))) +// clang-format on + using ::testing::_; using ::testing::AnyNumber; using ::testing::AnyOf; @@ -39,13 +47,7 @@ TEST_F(CapsWord, AutoShiftKeys) { KeymapKey key_spc(0, 1, 0, KC_SPC); set_keymap({key_a, key_spc}); - // Allow any number of reports with no keys or only KC_LSFT. - // clang-format off - EXPECT_CALL(driver, send_keyboard_mock(AnyOf( - KeyboardReport(), - KeyboardReport(KC_LSFT)))) - .Times(AnyNumber()); - // clang-format on + EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); { // Expect: "A, A, space, a". InSequence s; EXPECT_REPORT(driver, (KC_LSFT, KC_A)); @@ -65,6 +67,46 @@ TEST_F(CapsWord, AutoShiftKeys) { testing::Mock::VerifyAndClearExpectations(&driver); } +// Test Caps Word + Auto Shift where keys A and B are rolled. +TEST_F(CapsWord, AutoShiftRolledShiftedKeys) { + TestDriver driver; + KeymapKey key_a(0, 0, 0, KC_A); + KeymapKey key_b(0, 0, 1, KC_B); + set_keymap({key_a, key_b}); + + EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); + { // Expect: "A, B, A, B". + InSequence s; + EXPECT_REPORT(driver, (KC_LSFT, KC_A)); + EXPECT_REPORT(driver, (KC_LSFT, KC_B)); + EXPECT_REPORT(driver, (KC_LSFT, KC_A)); + EXPECT_REPORT(driver, (KC_LSFT, KC_B)); + } + + caps_word_on(); + + key_a.press(); // Overlapping taps: A down, B down, A up, B up. + run_one_scan_loop(); + key_b.press(); + run_one_scan_loop(); + key_a.release(); + run_one_scan_loop(); + key_b.release(); + run_one_scan_loop(); + + key_a.press(); // Nested taps: A down, B down, B up, A up. + run_one_scan_loop(); + key_b.press(); + run_one_scan_loop(); + key_b.release(); + run_one_scan_loop(); + key_a.release(); + run_one_scan_loop(); + + caps_word_off(); + testing::Mock::VerifyAndClearExpectations(&driver); +} + // Tests that with tap-hold keys with Retro Shift, letter keys are shifted by // Caps Word regardless of whether they are retroshifted. TEST_F(CapsWord, RetroShiftKeys) { @@ -73,13 +115,7 @@ TEST_F(CapsWord, RetroShiftKeys) { KeymapKey key_layertap_b(0, 1, 0, LT(1, KC_B)); set_keymap({key_modtap_a, key_layertap_b}); - // Allow any number of reports with no keys or only KC_LSFT. - // clang-format off - EXPECT_CALL(driver, send_keyboard_mock(AnyOf( - KeyboardReport(), - KeyboardReport(KC_LSFT)))) - .Times(AnyNumber()); - // clang-format on + EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); { // Expect: "B, A, B, A". InSequence s; EXPECT_REPORT(driver, (KC_LSFT, KC_B)); diff --git a/tests/caps_word/caps_word_combo/config.h b/tests/caps_word/caps_word_combo/config.h new file mode 100644 index 0000000000..92dbe045b2 --- /dev/null +++ b/tests/caps_word/caps_word_combo/config.h @@ -0,0 +1,20 @@ +// Copyright 2022 Google LLC +// +// 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 . + +#pragma once + +#include "test_common.h" + +#define TAPPING_TERM 200 diff --git a/tests/caps_word/caps_word_combo/test.mk b/tests/caps_word/caps_word_combo/test.mk new file mode 100644 index 0000000000..9f2e157189 --- /dev/null +++ b/tests/caps_word/caps_word_combo/test.mk @@ -0,0 +1,19 @@ +# Copyright 2022 Google LLC +# +# 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 . + +CAPS_WORD_ENABLE = yes +COMBO_ENABLE = yes +AUTO_SHIFT_ENABLE = yes + diff --git a/tests/caps_word/caps_word_combo/test_caps_word_combo.cpp b/tests/caps_word/caps_word_combo/test_caps_word_combo.cpp new file mode 100644 index 0000000000..3a0530b854 --- /dev/null +++ b/tests/caps_word/caps_word_combo/test_caps_word_combo.cpp @@ -0,0 +1,212 @@ +// Copyright 2022 Google LLC +// +// 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 . + +// Test Caps Word + Combos, with and without Auto Shift. + +#include +#include +#include + +#include "keyboard_report_util.hpp" +#include "keycode.h" +#include "test_common.hpp" +#include "test_fixture.hpp" +#include "test_keymap_key.hpp" + +// Allow reports with no keys or only KC_LSFT. +// clang-format off +#define EXPECT_EMPTY_OR_LSFT(driver) \ + EXPECT_CALL(driver, send_keyboard_mock(AnyOf( \ + KeyboardReport(), \ + KeyboardReport(KC_LSFT)))) +// clang-format on + +using ::testing::AnyNumber; +using ::testing::AnyOf; +using ::testing::InSequence; +using ::testing::TestParamInfo; + +extern "C" { +// Define some combos to use for the test, including overlapping combos and +// combos that chord tap-hold keys. +enum combo_events { AB_COMBO, BC_COMBO, AD_COMBO, DE_COMBO, FGHI_COMBO, COMBO_LENGTH }; +uint16_t COMBO_LEN = COMBO_LENGTH; + +const uint16_t ab_combo[] PROGMEM = {KC_A, KC_B, COMBO_END}; +const uint16_t bc_combo[] PROGMEM = {KC_B, KC_C, COMBO_END}; +const uint16_t ad_combo[] PROGMEM = {KC_A, LCTL_T(KC_D), COMBO_END}; +const uint16_t de_combo[] PROGMEM = {LCTL_T(KC_D), LT(1, KC_E), COMBO_END}; +const uint16_t fghi_combo[] PROGMEM = {KC_F, KC_G, KC_H, KC_I, COMBO_END}; + +// clang-format off +combo_t key_combos[] = { + [AB_COMBO] = COMBO(ab_combo, KC_SPC), // KC_A + KC_B = KC_SPC + [BC_COMBO] = COMBO(bc_combo, KC_X), // KC_B + KC_C = KC_X + [AD_COMBO] = COMBO(ad_combo, KC_Y), // KC_A + LCTL_T(KC_D) = KC_Y + [DE_COMBO] = COMBO(de_combo, KC_Z), // LCTL_T(KC_D) + LT(1, KC_E) = KC_Z + [FGHI_COMBO] = COMBO(fghi_combo, KC_W) // KC_F + KC_G + KC_H + KC_I = KC_W +}; +// clang-format on +} // extern "C" + +namespace { + +// To test combos thorougly, we test them with pressing the chord keys with +// a few different orders and timings. +struct TestParams { + std::string name; + bool autoshift_on; + + static const std::string& GetName(const TestParamInfo& info) { + return info.param.name; + } +}; + +class CapsWord : public ::testing::WithParamInterface, public TestFixture { + public: + void SetUp() override { + caps_word_off(); + if (GetParam().autoshift_on) { + autoshift_enable(); + } else { + autoshift_disable(); + } + } +}; + +// Test pressing the keys in a combo with different orders and timings. +TEST_P(CapsWord, SingleCombo) { + TestDriver driver; + KeymapKey key_b(0, 0, 1, KC_B); + KeymapKey key_c(0, 0, 2, KC_C); + set_keymap({key_b, key_c}); + + EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); + EXPECT_REPORT(driver, (KC_LSFT, KC_X)); + + caps_word_on(); + tap_combo({key_b, key_c}); + + EXPECT_TRUE(is_caps_word_on()); + caps_word_off(); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +// Test a longer 4-key combo. +TEST_P(CapsWord, LongerCombo) { + TestDriver driver; + KeymapKey key_f(0, 0, 0, KC_F); + KeymapKey key_g(0, 0, 1, KC_G); + KeymapKey key_h(0, 0, 2, KC_H); + KeymapKey key_i(0, 0, 3, KC_I); + set_keymap({key_f, key_g, key_h, key_i}); + + EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); + EXPECT_REPORT(driver, (KC_LSFT, KC_W)); + + caps_word_on(); + tap_combo({key_f, key_g, key_h, key_i}); + + EXPECT_TRUE(is_caps_word_on()); + caps_word_off(); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +// Test with two overlapping combos on regular keys: +// KC_A + KC_B = KC_SPC, +// KC_B + KC_C = KC_X. +TEST_P(CapsWord, ComboRegularKeys) { + TestDriver driver; + KeymapKey key_a(0, 0, 0, KC_A); + KeymapKey key_b(0, 0, 1, KC_B); + KeymapKey key_c(0, 0, 2, KC_C); + KeymapKey key_1(0, 0, 3, KC_1); + set_keymap({key_a, key_b, key_c, key_1}); + + EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); + { // Expect: "A, B, 1, X, 1, C, space, a". + InSequence s; + EXPECT_REPORT(driver, (KC_LSFT, KC_A)); + EXPECT_REPORT(driver, (KC_LSFT, KC_B)); + EXPECT_REPORT(driver, (KC_1)); + EXPECT_REPORT(driver, (KC_LSFT, KC_X)); + EXPECT_REPORT(driver, (KC_1)); + EXPECT_REPORT(driver, (KC_LSFT, KC_C)); + EXPECT_REPORT(driver, (KC_SPC)); + EXPECT_REPORT(driver, (KC_A)); + } + + caps_word_on(); + tap_key(key_a); + tap_key(key_b); + tap_key(key_1); + tap_combo({key_b, key_c}); // BC combo types "x". + tap_key(key_1); + tap_key(key_c); + tap_combo({key_a, key_b}); // AB combo types space. + tap_key(key_a); + + EXPECT_FALSE(is_caps_word_on()); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +// Test where combo chords involve tap-hold keys: +// KC_A + LCTL_T(KC_D) = KC_Y, +// LCTL_T(KC_D) + LT(1, KC_E) = KC_Z, +TEST_P(CapsWord, ComboModTapKey) { + TestDriver driver; + KeymapKey key_a(0, 0, 0, KC_A); + KeymapKey key_modtap_d(0, 0, 1, LCTL_T(KC_D)); + KeymapKey key_layertap_e(0, 0, 2, LT(1, KC_E)); + set_keymap({key_a, key_modtap_d, key_layertap_e}); + + EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); + { // Expect: "A, D, E, Y, Z". + InSequence s; + EXPECT_REPORT(driver, (KC_LSFT, KC_A)); + EXPECT_REPORT(driver, (KC_LSFT, KC_D)); + EXPECT_REPORT(driver, (KC_LSFT, KC_E)); + EXPECT_REPORT(driver, (KC_LSFT, KC_Y)); + EXPECT_REPORT(driver, (KC_LSFT, KC_Z)); + } + + caps_word_on(); + tap_key(key_a); + tap_key(key_modtap_d); + tap_key(key_layertap_e); + tap_combo({key_a, key_modtap_d}); // AD combo types "y". + tap_combo({key_modtap_d, key_layertap_e}); // DE combo types "z". + + EXPECT_TRUE(is_caps_word_on()); + caps_word_off(); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +// clang-format off +INSTANTIATE_TEST_CASE_P( + Combos, + CapsWord, + ::testing::Values( + TestParams{"AutoshiftDisabled", false}, + TestParams{"AutoshiftEnabled", true} + ), + TestParams::GetName + ); +// clang-format on + +} // namespace diff --git a/tests/test_common/test_fixture.cpp b/tests/test_common/test_fixture.cpp index 5fc6964054..44694cd390 100644 --- a/tests/test_common/test_fixture.cpp +++ b/tests/test_common/test_fixture.cpp @@ -108,6 +108,22 @@ void TestFixture::tap_key(KeymapKey key, unsigned delay_ms) { run_one_scan_loop(); } +void TestFixture::tap_combo(const std::vector& chord_keys, unsigned delay_ms) { + for (KeymapKey key : chord_keys) { // Press each key. + key.press(); + run_one_scan_loop(); + } + + if (delay_ms > 1) { + idle_for(delay_ms - 1); + } + + for (KeymapKey key : chord_keys) { // Release each key. + key.release(); + run_one_scan_loop(); + } +} + void TestFixture::set_keymap(std::initializer_list keys) { this->keymap.clear(); for (auto& key : keys) { diff --git a/tests/test_common/test_fixture.hpp b/tests/test_common/test_fixture.hpp index 81906f76c7..2590acd006 100644 --- a/tests/test_common/test_fixture.hpp +++ b/tests/test_common/test_fixture.hpp @@ -53,6 +53,13 @@ class TestFixture : public testing::Test { } } + /** + * @brief Taps a combo with `delay_ms` delay between press and release. + * + * Example: `tap_combo({key_a, key_b})` to tap the chord A + B. + */ + void tap_combo(const std::vector& chord_keys, unsigned delay_ms = 1); + void run_one_scan_loop(); void idle_for(unsigned ms); -- cgit v1.2.3 From 96731ba88e84e0cdd8144e6009fb086a9ccce743 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sat, 13 Aug 2022 19:24:15 +0200 Subject: Fix LV_CCAR and LV_NCED (#18025) --- quantum/keymap_extras/keymap_latvian.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_latvian.h b/quantum/keymap_extras/keymap_latvian.h index 3eaa2df274..087138cb72 100644 --- a/quantum/keymap_extras/keymap_latvian.h +++ b/quantum/keymap_extras/keymap_latvian.h @@ -161,8 +161,8 @@ #define LV_ACUT ALGR(LV_QUOT) // ´ (dead) // Row 4 #define LV_ZCAR ALGR(LV_Z) // Ž -#define LV_CCAR ALGR(LV_Z) // Č -#define LV_NCED ALGR(LV_Z) // Ņ +#define LV_CCAR ALGR(LV_C) // Č +#define LV_NCED ALGR(LV_N) // Ņ /* Shift+AltGr symbols * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ -- cgit v1.2.3 From 2c3b447641821c12b967058be6442fcfbc6c27d1 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sun, 14 Aug 2022 02:50:32 +0200 Subject: Use ANSI ASCII art and fix comments for LT_COLN and LT_UNDS in keymap_lithuanian_qwerty.h (#18028) --- quantum/keymap_extras/keymap_lithuanian_qwerty.h | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_lithuanian_qwerty.h b/quantum/keymap_extras/keymap_lithuanian_qwerty.h index fb0468a20a..afca2dc750 100644 --- a/quantum/keymap_extras/keymap_lithuanian_qwerty.h +++ b/quantum/keymap_extras/keymap_lithuanian_qwerty.h @@ -24,10 +24,10 @@ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ * │ ` │ Ą │ Č │ Ę │ Ė │ Į │ Š │ Ų │ Ū │ 9 │ 0 │ - │ Ž │ │ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ - * │ │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │ │ - * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │ - * │ │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ \ │ │ - * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤ + * │ │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │ \ │ + * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ + * │ │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ │ + * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ * │ │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │ │ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ * │ │ │ │ │ │ │ │ │ @@ -72,7 +72,7 @@ #define LT_L KC_L // L #define LT_SCLN KC_SCLN // ; #define LT_QUOT KC_QUOT // ' -#define LT_BSLS KC_NUHS // (backslash) +#define LT_BSLS KC_BSLS // (backslash) // Row 4 #define LT_Z KC_Z // Z #define LT_X KC_X // X @@ -89,10 +89,10 @@ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ * │ ~ │ │ │ │ │ │ │ │ │ ( │ ) │ _ │ │ │ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ - * │ │ │ │ │ │ │ │ │ │ │ │ { │ } │ │ - * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │ - * │ │ │ │ │ │ │ │ │ │ │ : │ " │ | │ │ - * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤ + * │ │ │ │ │ │ │ │ │ │ │ │ { │ } │ | │ + * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ + * │ │ │ │ │ │ │ │ │ │ │ : │ " │ │ + * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ * │ │ │ │ │ │ │ │ │ < │ > │ ? │ │ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ * │ │ │ │ │ │ │ │ │ @@ -102,12 +102,12 @@ #define LT_TILD S(LT_GRV) // ~ #define LT_LPRN S(LT_9) // ( #define LT_RPRN S(LT_0) // ) -#define LT_UNDS S(LT_MINS) // * +#define LT_UNDS S(LT_MINS) // _ // Row 2 #define LT_LCBR S(LT_LBRC) // { #define LT_RCBR S(LT_RBRC) // } // Row 3 -#define LT_COLN S(LT_SCLN) // ; +#define LT_COLN S(LT_SCLN) // : #define LT_DQUO S(LT_QUOT) // " #define LT_PIPE S(LT_BSLS) // | // Row 4 @@ -120,9 +120,9 @@ * │ │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ │ │ │ = │ │ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ * │ │ │ │ € │ │ │ │ │ │ │ │ │ │ │ - * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │ - * │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ - * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤ + * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ + * │ │ │ │ │ │ │ │ │ │ │ │ │ │ + * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ * │ │ │ │ │ │ │ │ │ │ │ │ │ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ * │ │ │ │ │ │ │ │ │ @@ -146,9 +146,9 @@ * │ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ │ │ │ + │ │ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ * │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ - * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │ - * │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ - * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤ + * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ + * │ │ │ │ │ │ │ │ │ │ │ │ │ │ + * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ * │ │ │ │ │ │ │ │ │ │ │ │ │ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ * │ │ │ │ │ │ │ │ │ -- cgit v1.2.3 From ba04ecfabd4f254bb89ccd7d1de9ac7fb228ce5b Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Sun, 14 Aug 2022 12:25:46 +0100 Subject: Align TO() max layers with other keycodes (#17989) --- quantum/action_code.h | 1 + quantum/keymap_common.c | 8 +++----- quantum/quantum_keycodes.h | 11 ++--------- 3 files changed, 6 insertions(+), 14 deletions(-) (limited to 'quantum') diff --git a/quantum/action_code.h b/quantum/action_code.h index 20b3e459d2..e107f0a740 100644 --- a/quantum/action_code.h +++ b/quantum/action_code.h @@ -234,6 +234,7 @@ enum layer_param_tap_op { #define ACTION_LAYER_INVERT(layer, on) ACTION_LAYER_BIT_XOR((layer) / 4, 1 << ((layer) % 4), (on)) #define ACTION_LAYER_ON(layer, on) ACTION_LAYER_BIT_OR((layer) / 4, 1 << ((layer) % 4), (on)) #define ACTION_LAYER_OFF(layer, on) ACTION_LAYER_BIT_AND((layer) / 4, ~(1 << ((layer) % 4)), (on)) +#define ACTION_LAYER_GOTO(layer) ACTION_LAYER_SET(layer, ON_PRESS) #define ACTION_LAYER_SET(layer, on) ACTION_LAYER_BIT_SET((layer) / 4, 1 << ((layer) % 4), (on)) #define ACTION_LAYER_ON_OFF(layer) ACTION_LAYER_TAP((layer), OP_ON_OFF) #define ACTION_LAYER_OFF_ON(layer) ACTION_LAYER_TAP((layer), OP_OFF_ON) diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c index c1940f0fd3..8d7a8bda9a 100644 --- a/quantum/keymap_common.c +++ b/quantum/keymap_common.c @@ -47,10 +47,9 @@ action_t action_for_keycode(uint16_t keycode) { keycode = keycode_config(keycode); action_t action = {}; - uint8_t action_layer, when, mod; + uint8_t action_layer, mod; (void)action_layer; - (void)when; (void)mod; switch (keycode) { @@ -85,9 +84,8 @@ action_t action_for_keycode(uint16_t keycode) { break; case QK_TO ... QK_TO_MAX:; // Layer set "GOTO" - when = (keycode >> 0x4) & 0x3; - action_layer = keycode & 0xF; - action.code = ACTION_LAYER_SET(action_layer, when); + action_layer = keycode & 0xFF; + action.code = ACTION_LAYER_GOTO(action_layer); break; case QK_MOMENTARY ... QK_MOMENTARY_MAX:; // Momentary action_layer diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index 456fad6f1b..7228ee9e08 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -797,15 +797,8 @@ enum quantum_keycodes { #define EH_LEFT MAGIC_EE_HANDS_LEFT #define EH_RGHT MAGIC_EE_HANDS_RIGHT -// GOTO layer - 16 layers max -// when: -// ON_PRESS = 1 -// ON_RELEASE = 2 -// Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default. -// In fact, we changed it to assume ON_PRESS for sanity/simplicity. If needed, you can add your own -// keycode modeled after the old version, kept below for this. -/* #define TO(layer, when) (QK_TO | (when << 0x4) | (layer & 0xFF)) */ -#define TO(layer) (QK_TO | (ON_PRESS << 0x4) | ((layer)&0xFF)) +// GOTO layer - 256 layer max +#define TO(layer) (QK_TO | ((layer)&0xFF)) // Momentary switch layer - 256 layer max #define MO(layer) (QK_MOMENTARY | ((layer)&0xFF)) -- cgit v1.2.3 From 0a6327d20c9cb63c80da2aff6e84c5b2d62c66e3 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Sun, 14 Aug 2022 18:18:42 +0200 Subject: Replace ; by : in the shifted symbols ASCII art of keymap_norman (#18029) Thanks! --- quantum/keymap_extras/keymap_norman.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_norman.h b/quantum/keymap_extras/keymap_norman.h index 7a5c1cbeb2..9f20f66873 100644 --- a/quantum/keymap_extras/keymap_norman.h +++ b/quantum/keymap_extras/keymap_norman.h @@ -89,7 +89,7 @@ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ * │ ~ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ ( │ ) │ _ │ + │ │ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ - * │ │ │ │ │ │ │ │ │ │ │ ; │ { │ } │ | │ + * │ │ │ │ │ │ │ │ │ │ │ : │ { │ } │ | │ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ * │ │ │ │ │ │ │ │ │ │ │ │ " │ │ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ -- cgit v1.2.3 From 6fc7c03e9581ddde68b32f2f76f8053628da6465 Mon Sep 17 00:00:00 2001 From: Chewxy Date: Mon, 15 Aug 2022 05:24:52 +1000 Subject: Added emacs as an "operating system" for input mode. (#16949) --- docs/feature_unicode.md | 3 +- quantum/process_keycode/process_unicode_common.c | 40 ++++++++++++++++++++---- quantum/process_keycode/process_unicode_common.h | 1 + quantum/quantum_keycodes.h | 3 ++ 4 files changed, 40 insertions(+), 7 deletions(-) (limited to 'quantum') diff --git a/docs/feature_unicode.md b/docs/feature_unicode.md index bced419a03..2389cb735c 100644 --- a/docs/feature_unicode.md +++ b/docs/feature_unicode.md @@ -127,7 +127,7 @@ The following input modes are available: By default, this mode uses Ctrl+Shift+U (`LCTL(LSFT(KC_U))`) to start Unicode input, but this can be changed by defining [`UNICODE_KEY_LNX`](#input-key-configuration) with a different keycode. This might be required for IBus versions ≥1.5.15, where Ctrl+Shift+U behavior is consolidated into Ctrl+Shift+E. Users who wish support in non-GTK apps without IBus may need to resort to a more indirect method, such as creating a custom keyboard layout ([more on this method](#custom-linux-layout)). - + * **`UC_WIN`**: _(not recommended)_ Windows built-in hex numpad Unicode input. Supports code points up to `0xFFFF`. To enable, create a registry key under `HKEY_CURRENT_USER\Control Panel\Input Method` of type `REG_SZ` called `EnableHexNumpad` and set its value to `1`. This can be done from the Command Prompt by running `reg add "HKCU\Control Panel\Input Method" -v EnableHexNumpad -t REG_SZ -d 1` with administrator privileges. Reboot afterwards. @@ -172,6 +172,7 @@ You can switch the input mode at any time by using the following keycodes. Addin |`UNICODE_MODE_WIN` |`UC_M_WI`|`UC_WIN` |Switch to Windows input | |`UNICODE_MODE_BSD` |`UC_M_BS`|`UC_BSD` |Switch to BSD input _(not implemented)_ | |`UNICODE_MODE_WINC` |`UC_M_WC`|`UC_WINC` |Switch to Windows input using WinCompose | +|`UNICODE_MODE_EMACS` |`UC_M_EM`|`UC_EMACS` |Switch to emacs (`C-x-8 RET`) | You can also switch the input mode by calling `set_unicode_input_mode(x)` in your code, where _x_ is one of the above input mode constants (e.g. `UC_LNX`). diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c index 6cb2ba8dbb..8de31c055c 100644 --- a/quantum/process_keycode/process_unicode_common.c +++ b/quantum/process_keycode/process_unicode_common.c @@ -117,6 +117,12 @@ __attribute__((weak)) void unicode_input_start(void) { tap_code(UNICODE_KEY_WINC); tap_code(KC_U); break; + case UC_EMACS: + // The usual way to type unicode in emacs is C-x-8 then the unicode number in hex + tap_code16(LCTL(KC_X)); + tap_code16(KC_8); + tap_code16(KC_ENTER); + break; } wait_ms(UNICODE_TYPE_DELAY); @@ -142,6 +148,9 @@ __attribute__((weak)) void unicode_input_finish(void) { case UC_WINC: tap_code(KC_ENTER); break; + case UC_EMACS: + tap_code16(KC_ENTER); + break; } set_mods(unicode_saved_mods); // Reregister previously set mods @@ -167,6 +176,9 @@ __attribute__((weak)) void unicode_input_cancel(void) { tap_code(KC_NUM_LOCK); } break; + case UC_EMACS: + tap_code16(LCTL(KC_G)); // C-g cancels + break; } set_mods(unicode_saved_mods); // Reregister previously set mods @@ -299,14 +311,30 @@ bool process_unicode_common(uint16_t keycode, keyrecord_t *record) { cycle_unicode_input_mode(shifted ? +1 : -1); audio_helper(); break; - - case UNICODE_MODE_MAC ... UNICODE_MODE_WINC: { - // Keycodes and input modes follow the same ordering - uint8_t delta = keycode - UNICODE_MODE_MAC; - set_unicode_input_mode(UC_MAC + delta); + case UNICODE_MODE_MAC: + set_unicode_input_mode(UC_MAC); + audio_helper(); + break; + case UNICODE_MODE_LNX: + set_unicode_input_mode(UC_LNX); + audio_helper(); + break; + case UNICODE_MODE_WIN: + set_unicode_input_mode(UC_WIN); + audio_helper(); + break; + case UNICODE_MODE_BSD: + set_unicode_input_mode(UC_BSD); + audio_helper(); + break; + case UNICODE_MODE_WINC: + set_unicode_input_mode(UC_WINC); + audio_helper(); + break; + case UNICODE_MODE_EMACS: + set_unicode_input_mode(UC_EMACS); audio_helper(); break; - } } } diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h index 8a4494c939..15e798dbb3 100644 --- a/quantum/process_keycode/process_unicode_common.h +++ b/quantum/process_keycode/process_unicode_common.h @@ -64,6 +64,7 @@ enum unicode_input_modes { UC_WIN, // Windows using EnableHexNumpad UC_BSD, // BSD (not implemented) UC_WINC, // Windows using WinCompose (https://github.com/samhocevar/wincompose) + UC_EMACS, // Emacs is an operating system in search of a good text editor UC__COUNT // Number of available input modes (always leave at the end) }; diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index 7228ee9e08..c8f03fa1ce 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -609,6 +609,8 @@ enum quantum_keycodes { MAGIC_UNSWAP_ESCAPE_CAPSLOCK, MAGIC_TOGGLE_ESCAPE_CAPSLOCK, + UNICODE_MODE_EMACS, + // Start of custom keycode range for keyboards and keymaps - always leave at the end SAFE_RANGE }; @@ -894,6 +896,7 @@ enum quantum_keycodes { #define UC_M_WI UNICODE_MODE_WIN #define UC_M_BS UNICODE_MODE_BSD #define UC_M_WC UNICODE_MODE_WINC +#define UC_M_EM UNICODE_MODE_EMACS // Swap Hands #define SH_T(kc) (QK_SWAP_HANDS | (kc)) -- cgit v1.2.3 From 95c43a275984fb57cdf6e5afd02190700e0205bc Mon Sep 17 00:00:00 2001 From: Pascal Getreuer <50221757+getreuer@users.noreply.github.com> Date: Sun, 14 Aug 2022 12:25:32 -0700 Subject: Fix Caps Word to treat mod-taps more consistently. (#17463) * Fix Caps Word to treat mod-taps more consistently. Previously, holding any mod-tap key while Caps Word is active stops Caps Word, and this happens regardless of `caps_word_press_user()`. Yet for regular mod keys, AltGr (KC_RALT) is ignored, Shift keys are passed to `caps_word_press_user()` to determine whether to continue, and similarly, a key `RSFT(KC_RALT)` representing Right Shift + Alt is passed to `caps_word_press_user()` to determine whether to continue. This commit makes held mod-tap keys consistent with regular mod keys: * Holding a `RALT_T` mod-tap is ignored. * When holding a shift mod-tap key, `KC_LSFT` or `KC_RSFT` is passed to `caps_word_press_user()` to determine whether to continue. * When holding a Right Shift + Alt (`RSA_T`) mod-tap, `RSFT(KC_RALT)` is passed to `caps_word_press_user()`. Particularly, with this fix a user may choose to continue Caps Word when a shift mod-tap key is held by adding `KC_LSFT` and `KC_RSFT` cases in `caps_word_press_user()`. For instance as ``` bool caps_word_press_user(uint16_t keycode) { switch (keycode) { // Keycodes that continue Caps Word, with shift applied. case KC_A ... KC_Z: case KC_MINS: add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key. return true; // Keycodes that continue Caps Word, without shifting. case KC_1 ... KC_0: case KC_BSPC: case KC_DEL: case KC_UNDS: case KC_LSFT: // <<< Added here. case KC_RSFT: return true; default: return false; // Deactivate Caps Word. } } ``` * Fix Caps Word to treat mod-taps more consistently. Previously, holding any mod-tap key while Caps Word is active stops Caps Word, and this happens regardless of `caps_word_press_user()`. Yet for regular mod keys, AltGr (KC_RALT) is ignored, Shift keys are passed to `caps_word_press_user()` to determine whether to continue, and similarly, a key `RSFT(KC_RALT)` representing Right Shift + Alt is passed to `caps_word_press_user()` to determine whether to continue. This commit makes held mod-tap keys consistent with regular mod keys: * Holding a `RALT_T` mod-tap is ignored. * When holding a shift mod-tap key, `KC_LSFT` or `KC_RSFT` is passed to `caps_word_press_user()` to determine whether to continue. * When holding a Right Shift + Alt (`RSA_T`) mod-tap, `RSFT(KC_RALT)` is passed to `caps_word_press_user()`. Particularly, with this fix a user may choose to continue Caps Word when a shift mod-tap key is held by adding `KC_LSFT` and `KC_RSFT` cases in `caps_word_press_user()`. For instance as ``` bool caps_word_press_user(uint16_t keycode) { switch (keycode) { // Keycodes that continue Caps Word, with shift applied. case KC_A ... KC_Z: case KC_MINS: add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key. return true; // Keycodes that continue Caps Word, without shifting. case KC_1 ... KC_0: case KC_BSPC: case KC_DEL: case KC_UNDS: case KC_LSFT: // <<< Added here. case KC_RSFT: return true; default: return false; // Deactivate Caps Word. } } ``` * Update quantum/process_keycode/process_caps_word.c Co-authored-by: Joel Challis --- quantum/process_keycode/process_caps_word.c | 32 ++++-- tests/caps_word/test_caps_word.cpp | 159 ++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 6 deletions(-) (limited to 'quantum') diff --git a/quantum/process_keycode/process_caps_word.c b/quantum/process_keycode/process_caps_word.c index bc4369846c..1b9583196d 100644 --- a/quantum/process_keycode/process_caps_word.c +++ b/quantum/process_keycode/process_caps_word.c @@ -101,14 +101,34 @@ bool process_caps_word(uint16_t keycode, keyrecord_t* record) { return true; #ifndef NO_ACTION_TAPPING + // Corresponding to mod keys above, a held mod-tap is handled as: + // * For shift mods, pass KC_LSFT or KC_RSFT to + // caps_word_press_user() to determine whether to continue. + // * For Shift + AltGr (MOD_RSFT | MOD_RALT), pass RSFT(KC_RALT). + // * AltGr (MOD_RALT) is ignored. + // * Otherwise stop Caps Word. case QK_MOD_TAP ... QK_MOD_TAP_MAX: - if (record->tap.count == 0) { - // Deactivate if a mod becomes active through holding - // a mod-tap key. - caps_word_off(); - return true; + if (record->tap.count == 0) { // Mod-tap key is held. + const uint8_t mods = (keycode >> 8) & 0x1f; + switch (mods) { + case MOD_LSFT: + keycode = KC_LSFT; + break; + case MOD_RSFT: + keycode = KC_RSFT; + break; + case MOD_RSFT | MOD_RALT: + keycode = RSFT(KC_RALT); + break; + case MOD_RALT: + return true; + default: + caps_word_off(); + return true; + } + } else { + keycode &= 0xff; } - keycode &= 0xff; break; # ifndef NO_ACTION_LAYER diff --git a/tests/caps_word/test_caps_word.cpp b/tests/caps_word/test_caps_word.cpp index 0af4b0175d..3f59ed3744 100644 --- a/tests/caps_word/test_caps_word.cpp +++ b/tests/caps_word/test_caps_word.cpp @@ -25,10 +25,47 @@ using ::testing::AnyOf; using ::testing::InSequence; using ::testing::TestParamInfo; +namespace { + +bool press_user_default(uint16_t keycode) { + switch (keycode) { + // Keycodes that continue Caps Word, with shift applied. + case KC_A ... KC_Z: + case KC_MINS: + add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key. + return true; + + // Keycodes that continue Caps Word, without shifting. + case KC_1 ... KC_0: + case KC_BSPC: + case KC_DEL: + case KC_UNDS: + return true; + + default: + return false; // Deactivate Caps Word. + } +} + +uint16_t passed_keycode; +bool press_user_save_passed_keycode(uint16_t keycode) { + passed_keycode = keycode; + return true; +} + +bool (*press_user_fun)(uint16_t) = press_user_default; + +extern "C" { +bool caps_word_press_user(uint16_t keycode) { + return press_user_fun(keycode); +} +} // extern "C" + class CapsWord : public TestFixture { public: void SetUp() override { caps_word_off(); + press_user_fun = press_user_default; } }; @@ -226,6 +263,126 @@ TEST_F(CapsWord, ShiftsAltGrSymbols) { testing::Mock::VerifyAndClearExpectations(&driver); } +// Tests typing "AltGr + A" using a mod-tap key. +TEST_F(CapsWord, ShiftsModTapAltGrSymbols) { + TestDriver driver; + KeymapKey key_a(0, 0, 0, KC_A); + KeymapKey key_altgr_t(0, 1, 0, RALT_T(KC_B)); + set_keymap({key_a, key_altgr_t}); + + // Allow any number of reports with no keys or only modifiers. + // clang-format off + EXPECT_CALL(driver, send_keyboard_mock(AnyOf( + KeyboardReport(), + KeyboardReport(KC_RALT), + KeyboardReport(KC_LSFT, KC_RALT)))) + .Times(AnyNumber()); + // Expect "Shift + AltGr + A". + EXPECT_REPORT(driver, (KC_LSFT, KC_RALT, KC_A)); + // clang-format on + + // Turn on Caps Word and type "AltGr + A". + caps_word_on(); + + key_altgr_t.press(); + idle_for(TAPPING_TERM + 1); + tap_key(key_a); + run_one_scan_loop(); + key_altgr_t.release(); + + EXPECT_TRUE(is_caps_word_on()); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +struct CapsWordPressUserParams { + std::string name; + uint16_t keycode; + uint16_t delay_ms; + uint16_t expected_passed_keycode; + bool continues_caps_word; + + static const std::string& GetName(const TestParamInfo& info) { + return info.param.name; + } +}; + +class CapsWordPressUser : public ::testing::WithParamInterface, public CapsWord { + void SetUp() override { + caps_word_on(); + passed_keycode = KC_NO; + press_user_fun = press_user_save_passed_keycode; + } +}; + +// Tests keycodes passed to caps_word_press_user() function for various keys. +TEST_P(CapsWordPressUser, KeyCode) { + TestDriver driver; + KeymapKey key(0, 0, 0, GetParam().keycode); + set_keymap({key}); + + EXPECT_ANY_REPORT(driver).Times(AnyNumber()); + tap_key(key, GetParam().delay_ms); + + EXPECT_EQ(passed_keycode, GetParam().expected_passed_keycode); + EXPECT_EQ(is_caps_word_on(), GetParam().continues_caps_word); + clear_oneshot_mods(); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +const uint16_t LT_1_KC_A = LT(1, KC_A); +// clang-format off +INSTANTIATE_TEST_CASE_P( + PressUser, + CapsWordPressUser, + ::testing::Values( + CapsWordPressUserParams{ + "KC_A", KC_A, 1, KC_A, true}, + CapsWordPressUserParams{ + "KC_HASH", KC_HASH, 1, KC_HASH, true}, + CapsWordPressUserParams{ + "KC_LSFT", KC_LSFT, 1, KC_LSFT, true}, + CapsWordPressUserParams{ + "KC_RSFT", KC_RSFT, 1, KC_RSFT, true}, + CapsWordPressUserParams{ + "LSFT_T_tapped", LSFT_T(KC_A), 1, KC_A, true}, + CapsWordPressUserParams{ + "LSFT_T_held", LSFT_T(KC_A), TAPPING_TERM + 1, KC_LSFT, true}, + CapsWordPressUserParams{ + "RSFT_T_held", RSFT_T(KC_A), TAPPING_TERM + 1, KC_RSFT, true}, + CapsWordPressUserParams{ + "RSA_T_held", RSA_T(KC_A), TAPPING_TERM + 1, RSFT(KC_RALT), true}, + // Holding a mod-tap other than Shift or AltGr stops Caps Word. + CapsWordPressUserParams{ + "LCTL_T_held", LCTL_T(KC_A), TAPPING_TERM + 1, KC_NO, false}, + CapsWordPressUserParams{ + "LALT_T_held", LALT_T(KC_A), TAPPING_TERM + 1, KC_NO, false}, + CapsWordPressUserParams{ + "LGUI_T_held", LGUI_T(KC_A), TAPPING_TERM + 1, KC_NO, false}, + // Layer keys are ignored and continue Caps Word. + CapsWordPressUserParams{ + "MO", MO(1), 1, KC_NO, true}, + CapsWordPressUserParams{ + "TO", TO(1), 1, KC_NO, true}, + CapsWordPressUserParams{ + "TG", TG(1), 1, KC_NO, true}, + CapsWordPressUserParams{ + "TT", TT(1), 1, KC_NO, true}, + CapsWordPressUserParams{ + "OSL", OSL(1), 1, KC_NO, true}, + CapsWordPressUserParams{ + "LT_held", LT_1_KC_A, TAPPING_TERM + 1, KC_NO, true}, + // AltGr keys are ignored and continue Caps Word. + CapsWordPressUserParams{ + "KC_RALT", KC_RALT, 1, KC_NO, true}, + CapsWordPressUserParams{ + "OSM_MOD_RALT", OSM(MOD_RALT), 1, KC_NO, true}, + CapsWordPressUserParams{ + "RALT_T_held", RALT_T(KC_A), TAPPING_TERM + 1, KC_NO, true} + ), + CapsWordPressUserParams::GetName + ); +// clang-format on + struct CapsWordBothShiftsParams { std::string name; uint16_t left_shift_keycode; @@ -435,3 +592,5 @@ INSTANTIATE_TEST_CASE_P( CapsWordDoubleTapShiftParams::GetName ); // clang-format on + +} // namespace -- cgit v1.2.3 From 8e9ee29fe352b98ee1380213fc2e2b0e945cdf3f Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Mon, 15 Aug 2022 07:25:37 +0200 Subject: Remove duplicate COMBINING HORN in keymap_us_extended.h (#18045) --- quantum/keymap_extras/keymap_us_extended.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_us_extended.h b/quantum/keymap_extras/keymap_us_extended.h index fb3e9c7d36..8e71a8de25 100644 --- a/quantum/keymap_extras/keymap_us_extended.h +++ b/quantum/keymap_extras/keymap_us_extended.h @@ -145,7 +145,7 @@ #define US_CURR ALGR(US_4) // ¤ #define US_EURO ALGR(US_5) // € #define US_DCIR ALGR(US_6) // ^ (dead) -#define US_HORN ALGR(US_7) // ̛̛ (dead) +#define US_HORN ALGR(US_7) // ̛ (dead) #define US_OGON ALGR(US_8) // ˛ (dead) #define US_LSQU ALGR(US_9) // ‘ #define US_RSQU ALGR(US_0) // ’ -- cgit v1.2.3 From 8ce946b5c8e7026b5d7337becf4719e2795af9bb Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Mon, 15 Aug 2022 16:40:51 +0200 Subject: [Bug] Add key event check to `is_tap_record` and remove `is_tap_key` (#18063) --- quantum/action.c | 13 ++++--------- quantum/action.h | 1 - .../default_mod_tap/test_tap_hold.cpp | 4 ---- 3 files changed, 4 insertions(+), 14 deletions(-) (limited to 'quantum') diff --git a/quantum/action.c b/quantum/action.c index 83f6e2a970..6b2e9104e0 100644 --- a/quantum/action.c +++ b/quantum/action.c @@ -1085,20 +1085,15 @@ void clear_keyboard_but_mods_and_keys() { #endif } -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -bool is_tap_key(keypos_t key) { - action_t action = layer_switch_get_action(key); - return is_tap_action(action); -} - /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ bool is_tap_record(keyrecord_t *record) { + if (IS_NOEVENT(record->event)) { + return false; + } + #ifdef COMBO_ENABLE action_t action; if (record->keycode) { diff --git a/quantum/action.h b/quantum/action.h index 08e1f6ac29..2bc46429b2 100644 --- a/quantum/action.h +++ b/quantum/action.h @@ -105,7 +105,6 @@ void clear_keyboard(void); void clear_keyboard_but_mods(void); void clear_keyboard_but_mods_and_keys(void); void layer_switch(uint8_t new_layer); -bool is_tap_key(keypos_t key); bool is_tap_record(keyrecord_t *record); bool is_tap_action(action_t action); diff --git a/tests/tap_hold_configurations/default_mod_tap/test_tap_hold.cpp b/tests/tap_hold_configurations/default_mod_tap/test_tap_hold.cpp index 687a4e0318..e798265623 100644 --- a/tests/tap_hold_configurations/default_mod_tap/test_tap_hold.cpp +++ b/tests/tap_hold_configurations/default_mod_tap/test_tap_hold.cpp @@ -140,8 +140,6 @@ TEST_F(DefaultTapHold, tap_regular_key_while_layer_tap_key_is_held) { } TEST_F(DefaultTapHold, tap_mod_tap_hold_key_two_times) { - GTEST_SKIP() << "TODO:Holding a modtap key results in out of bounds access to the keymap, this is a bug in QMK."; - TestDriver driver; InSequence s; auto mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P)); @@ -175,8 +173,6 @@ TEST_F(DefaultTapHold, tap_mod_tap_hold_key_two_times) { } TEST_F(DefaultTapHold, tap_mod_tap_hold_key_twice_and_hold_on_second_time) { - GTEST_SKIP() << "TODO:Holding a modtap key results in out of bounds access to the keymap, this is a bug in QMK."; - TestDriver driver; InSequence s; auto mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P)); -- cgit v1.2.3 From 5021cf58ade469560fa0fd018f6b35b2b6f6907f Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Mon, 15 Aug 2022 19:41:05 +0200 Subject: Fix DV_SCLN and DV_COLN in keymap_spanish_dvorak.h (#18043) --- quantum/keymap_extras/keymap_spanish_dvorak.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'quantum') diff --git a/quantum/keymap_extras/keymap_spanish_dvorak.h b/quantum/keymap_extras/keymap_spanish_dvorak.h index 29c4f1c44a..ea0c93f86a 100644 --- a/quantum/keymap_extras/keymap_spanish_dvorak.h +++ b/quantum/keymap_extras/keymap_spanish_dvorak.h @@ -114,8 +114,8 @@ #define DV_QUES S(DV_QUOT) // ? #define DV_IQUE S(DV_IEXL) // ¿ // Row 2 -#define DV_COLN S(KC_DOT) // : -#define DV_SCLN S(KC_COMM) // ; +#define DV_COLN S(DV_DOT) // : +#define DV_SCLN S(DV_COMM) // ; #define DV_CIRC S(DV_GRV) // ^ (dead) #define DV_ASTR S(DV_PLUS) // * // Row 3 -- cgit v1.2.3 From a2765bfe1998abdd4571556bff236a3d89b0c16d Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Sat, 27 Aug 2022 00:41:10 +0100 Subject: Add missing SS_LOPT and SS_ROPT defines (#18175) --- quantum/send_string/send_string_keycodes.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'quantum') diff --git a/quantum/send_string/send_string_keycodes.h b/quantum/send_string/send_string_keycodes.h index 7017e03d5a..802d9a8240 100644 --- a/quantum/send_string/send_string_keycodes.h +++ b/quantum/send_string/send_string_keycodes.h @@ -419,6 +419,7 @@ #define SS_LSFT(string) SS_DOWN(X_LSFT) string SS_UP(X_LSFT) #define SS_LALT(string) SS_DOWN(X_LALT) string SS_UP(X_LALT) #define SS_LGUI(string) SS_DOWN(X_LGUI) string SS_UP(X_LGUI) +#define SS_LOPT(string) SS_LALT(string) #define SS_LCMD(string) SS_LGUI(string) #define SS_LWIN(string) SS_LGUI(string) @@ -427,6 +428,7 @@ #define SS_RALT(string) SS_DOWN(X_RALT) string SS_UP(X_RALT) #define SS_RGUI(string) SS_DOWN(X_RGUI) string SS_UP(X_RGUI) #define SS_ALGR(string) SS_RALT(string) +#define SS_ROPT(string) SS_RALT(string) #define SS_RCMD(string) SS_RGUI(string) #define SS_RWIN(string) SS_RGUI(string) -- cgit v1.2.3