summaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
authorDrashna Jael're <drashna@live.com>2021-06-29 12:23:03 -0700
committerDrashna Jael're <drashna@live.com>2021-06-29 12:24:07 -0700
commitacf2c323e2927f6007b17ded577cf49fd86fec6c (patch)
tree8334dc5c71e6ab9bf33c76143eac7bb0e60159b0 /quantum
parentec7a7beeed3046e9144d4c4ce0ef3b2c4f9e4341 (diff)
parentf55e39e8a2246f6f96fd5d4a84a866e2615cde7b (diff)
Merge upstream QMK Firmware at '0.12.52~1'
Diffstat (limited to 'quantum')
-rw-r--r--quantum/api/api_sysex.h2
-rw-r--r--quantum/audio/audio.c539
-rw-r--r--quantum/audio/audio.h281
-rw-r--r--quantum/audio/audio_pwm.c606
-rw-r--r--quantum/audio/driver_avr_pwm.h (renamed from quantum/template/base/template.h)16
-rw-r--r--quantum/audio/driver_avr_pwm_hardware.c332
-rw-r--r--quantum/audio/driver_chibios_dac.h126
-rw-r--r--quantum/audio/driver_chibios_dac_additive.c335
-rw-r--r--quantum/audio/driver_chibios_dac_basic.c245
-rw-r--r--quantum/audio/driver_chibios_pwm.h40
-rw-r--r--quantum/audio/driver_chibios_pwm_hardware.c144
-rw-r--r--quantum/audio/driver_chibios_pwm_software.c164
-rw-r--r--quantum/audio/musical_notes.h76
-rw-r--r--quantum/audio/song_list.h4
-rw-r--r--quantum/audio/voices.c171
-rw-r--r--quantum/audio/voices.h20
-rw-r--r--quantum/audio/wave.h36
-rw-r--r--quantum/backlight/backlight_avr.c6
-rw-r--r--quantum/bitwise.c123
-rw-r--r--quantum/bitwise.h40
-rw-r--r--quantum/color.c1
-rw-r--r--quantum/command.c786
-rw-r--r--quantum/command.h163
-rw-r--r--quantum/config_common.h398
-rw-r--r--quantum/debounce/sym_defer_pk.c6
-rw-r--r--quantum/debounce/sym_eager_pk.c6
-rw-r--r--quantum/debounce/sym_eager_pr.c6
-rw-r--r--quantum/dip_switch.c17
-rw-r--r--quantum/dynamic_keymap.c38
-rw-r--r--quantum/encoder.c22
-rw-r--r--quantum/encoder.h2
-rw-r--r--quantum/fauxclicky.c59
-rw-r--r--quantum/fauxclicky.h97
-rw-r--r--quantum/keymap.h4
-rw-r--r--quantum/keymap_extras/keymap_canadian_multilingual.h60
-rw-r--r--quantum/keymap_extras/keymap_croatian.h163
-rw-r--r--quantum/keymap_extras/keymap_french_afnor.h253
-rw-r--r--quantum/keymap_extras/keymap_neo2.h180
-rw-r--r--quantum/keymap_extras/keymap_nordic.h5
-rw-r--r--quantum/keymap_extras/keymap_norwegian.h197
-rw-r--r--quantum/keymap_extras/keymap_spanish_dvorak.h6
-rw-r--r--quantum/keymap_extras/keymap_us_extended.h227
-rw-r--r--quantum/keymap_extras/keymap_us_international.h20
-rw-r--r--quantum/keymap_extras/keymap_us_international_linux.h224
-rw-r--r--quantum/keymap_extras/sendstring_belgian.h8
-rw-r--r--quantum/keymap_extras/sendstring_bepo.h10
-rw-r--r--quantum/keymap_extras/sendstring_canadian_multilingual.h100
-rw-r--r--quantum/keymap_extras/sendstring_colemak.h14
-rw-r--r--quantum/keymap_extras/sendstring_croatian.h100
-rw-r--r--quantum/keymap_extras/sendstring_dvorak.h39
-rw-r--r--quantum/keymap_extras/sendstring_french.h12
-rw-r--r--quantum/keymap_extras/sendstring_french_afnor.h100
-rw-r--r--quantum/keymap_extras/sendstring_german.h26
-rw-r--r--quantum/keymap_extras/sendstring_jis.h31
-rw-r--r--quantum/keymap_extras/sendstring_norman.h14
-rw-r--r--quantum/keymap_extras/sendstring_spanish.h6
-rw-r--r--quantum/keymap_extras/sendstring_uk.h29
-rw-r--r--quantum/keymap_extras/sendstring_us_international.h100
-rw-r--r--quantum/keymap_extras/sendstring_workman.h14
-rw-r--r--quantum/led.h54
-rw-r--r--quantum/led_matrix.c140
-rw-r--r--quantum/led_matrix.h42
-rw-r--r--quantum/led_matrix_drivers.c2
-rw-r--r--quantum/led_matrix_types.h69
-rw-r--r--quantum/matrix.c14
-rw-r--r--quantum/matrix.h79
-rw-r--r--quantum/matrix_common.c7
-rw-r--r--quantum/mcu_selection.mk93
-rw-r--r--quantum/mousekey.c488
-rw-r--r--quantum/mousekey.h179
-rw-r--r--quantum/pointing_device.c9
-rw-r--r--quantum/pointing_device.h1
-rw-r--r--quantum/process_keycode/process_combo.c6
-rwxr-xr-x[-rw-r--r--]quantum/process_keycode/process_grave_esc.h0
-rw-r--r--quantum/process_keycode/process_magic.c5
-rw-r--r--quantum/process_keycode/process_midi.c23
-rw-r--r--quantum/process_keycode/process_rgb.c14
-rw-r--r--quantum/process_keycode/process_tap_dance.c4
-rw-r--r--quantum/process_keycode/process_tap_dance.h8
-rw-r--r--quantum/process_keycode/process_unicode_common.c6
-rw-r--r--quantum/quantum.c307
-rw-r--r--quantum/quantum.h143
-rw-r--r--quantum/quantum_keycodes.h83
-rw-r--r--quantum/rgb_matrix.c26
-rw-r--r--quantum/rgb_matrix.h2
-rw-r--r--quantum/rgb_matrix_animations/hue_breathing_anim.h22
-rw-r--r--quantum/rgb_matrix_animations/hue_pendulum_anim.h17
-rw-r--r--quantum/rgb_matrix_animations/hue_wave_anim.h17
-rw-r--r--quantum/rgb_matrix_animations/rgb_matrix_effects.inc3
-rw-r--r--quantum/rgb_matrix_animations/typing_heatmap_anim.h4
-rw-r--r--quantum/rgb_matrix_types.h16
-rw-r--r--quantum/rgblight.c152
-rw-r--r--quantum/rgblight.h5
-rw-r--r--quantum/ring_buffer.h44
-rw-r--r--quantum/send_string.c306
-rw-r--r--quantum/send_string.h54
-rw-r--r--quantum/send_string_keycodes.h18
-rw-r--r--quantum/split_common/matrix.c46
-rw-r--r--quantum/split_common/post_config.h2
-rw-r--r--quantum/split_common/split_util.c5
-rw-r--r--quantum/split_common/transport.c142
-rw-r--r--quantum/split_common/transport.h6
-rw-r--r--quantum/template/avr/config.h9
-rw-r--r--quantum/template/avr/rules.mk2
-rw-r--r--quantum/template/avr/template.c43
-rw-r--r--quantum/template/base/keymaps/default/keymap.c6
-rw-r--r--quantum/template/base/keymaps/default/readme.md2
-rw-r--r--quantum/template/ps2avrgb/config.h1
-rw-r--r--quantum/template/ps2avrgb/i2c.c106
-rw-r--r--quantum/template/ps2avrgb/matrix.c112
-rw-r--r--quantum/template/ps2avrgb/readme.md2
-rw-r--r--quantum/template/ps2avrgb/rules.mk2
-rw-r--r--quantum/template/ps2avrgb/template.c44
-rw-r--r--quantum/template/ps2avrgb/usbconfig.h346
-rw-r--r--quantum/util.h (renamed from quantum/template/ps2avrgb/i2c.h)19
-rw-r--r--quantum/via.c18
-rw-r--r--quantum/via.h8
-rw-r--r--quantum/via_ensure_keycode.h366
-rw-r--r--quantum/wpm.c39
-rw-r--r--quantum/wpm.h4
120 files changed, 7510 insertions, 3131 deletions
diff --git a/quantum/api/api_sysex.h b/quantum/api/api_sysex.h
index 382f4bea44..eb0a18848d 100644
--- a/quantum/api/api_sysex.h
+++ b/quantum/api/api_sysex.h
@@ -18,6 +18,8 @@
#include "api.h"
+#define API_SYSEX_MAX_SIZE 32
+
void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t* bytes, uint16_t length);
#define SEND_BYTES(mt, dt, b, l) send_bytes_sysex(mt, dt, b, l)
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
new file mode 100644
index 0000000000..46277dd70b
--- /dev/null
+++ b/quantum/audio/audio.c
@@ -0,0 +1,539 @@
+/* Copyright 2016-2020 Jack Humbert
+ * Copyright 2020 JohSchneider
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "audio.h"
+#include "eeconfig.h"
+#include "timer.h"
+#include "wait.h"
+
+/* audio system:
+ *
+ * audio.[ch] takes care of all overall state, tracking the actively playing
+ * notes/tones; the notes a SONG consists of;
+ * ...
+ * = everything audio-related that is platform agnostic
+ *
+ * driver_[avr|chibios]_[dac|pwm] take care of the lower hardware dependent parts,
+ * specific to each platform and the used subsystem/driver to drive
+ * the output pins/channels with the calculated frequencies for each
+ * active tone
+ * as part of this, the driver has to trigger regular state updates by
+ * calling 'audio_update_state' through some sort of timer - be it a
+ * dedicated one or piggybacking on for example the timer used to
+ * generate a pwm signal/clock.
+ *
+ *
+ * A Note on terminology:
+ * tone, pitch and frequency are used somewhat interchangeably, in a strict Wikipedia-sense:
+ * "(Musical) tone, a sound characterized by its duration, pitch (=frequency),
+ * intensity (=volume), and timbre"
+ * - intensity/volume is currently not handled at all, although the 'dac_additive' driver could do so
+ * - timbre is handled globally (TODO: only used with the pwm drivers at the moment)
+ *
+ * in musical_note.h a 'note' is the combination of a pitch and a duration
+ * these are used to create SONG arrays; during playback their frequencies
+ * are handled as single successive tones, while the durations are
+ * kept track of in 'audio_update_state'
+ *
+ * 'voice' as it is used here, equates to a sort of instrument with its own
+ * characteristics sound and effects
+ * the audio system as-is deals only with (possibly multiple) tones of one
+ * instrument/voice at a time (think: chords). since the number of tones that
+ * can be reproduced depends on the hardware/driver in use: pwm can only
+ * reproduce one tone per output/speaker; DACs can reproduce/mix multiple
+ * when doing additive synthesis.
+ *
+ * 'duration' can either be in the beats-per-minute related unit found in
+ * musical_notes.h, OR in ms; keyboards create SONGs with the former, while
+ * the internal state of the audio system does its calculations with the later - ms
+ */
+
+#ifndef AUDIO_TONE_STACKSIZE
+# define AUDIO_TONE_STACKSIZE 8
+#endif
+uint8_t active_tones = 0; // number of tones pushed onto the stack by audio_play_tone - might be more than the hardware is able to reproduce at any single time
+musical_tone_t tones[AUDIO_TONE_STACKSIZE]; // stack of currently active tones
+
+bool playing_melody = false; // playing a SONG?
+bool playing_note = false; // or (possibly multiple simultaneous) tones
+bool state_changed = false; // global flag, which is set if anything changes with the active_tones
+
+// melody/SONG related state variables
+float (*notes_pointer)[][2]; // SONG, an array of MUSICAL_NOTEs
+uint16_t notes_count; // length of the notes_pointer array
+bool notes_repeat; // PLAY_SONG or PLAY_LOOP?
+uint16_t melody_current_note_duration = 0; // duration of the currently playing note from the active melody, in ms
+uint8_t note_tempo = TEMPO_DEFAULT; // beats-per-minute
+uint16_t current_note = 0; // index into the array at notes_pointer
+bool note_resting = false; // if a short pause was introduced between two notes with the same frequency while playing a melody
+uint16_t last_timestamp = 0;
+
+#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
+# ifndef AUDIO_MAX_SIMULTANEOUS_TONES
+# define AUDIO_MAX_SIMULTANEOUS_TONES 3
+# endif
+uint16_t tone_multiplexing_rate = AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT;
+uint8_t tone_multiplexing_index_shift = 0; // offset used on active-tone array access
+#endif
+
+// provided and used by voices.c
+extern uint8_t note_timbre;
+extern bool glissando;
+extern bool vibrato;
+extern uint16_t voices_timer;
+
+#ifndef STARTUP_SONG
+# define STARTUP_SONG SONG(STARTUP_SOUND)
+#endif
+#ifndef AUDIO_ON_SONG
+# define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND)
+#endif
+#ifndef AUDIO_OFF_SONG
+# define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND)
+#endif
+float startup_song[][2] = STARTUP_SONG;
+float audio_on_song[][2] = AUDIO_ON_SONG;
+float audio_off_song[][2] = AUDIO_OFF_SONG;
+
+static bool audio_initialized = false;
+static bool audio_driver_stopped = true;
+audio_config_t audio_config;
+
+void audio_init() {
+ if (audio_initialized) {
+ return;
+ }
+
+ // Check EEPROM
+#ifdef EEPROM_ENABLE
+ if (!eeconfig_is_enabled()) {
+ eeconfig_init();
+ }
+ audio_config.raw = eeconfig_read_audio();
+#else // EEPROM settings
+ audio_config.enable = true;
+# ifdef AUDIO_CLICKY_ON
+ audio_config.clicky_enable = true;
+# endif
+#endif // EEPROM settings
+
+ for (uint8_t i = 0; i < AUDIO_TONE_STACKSIZE; i++) {
+ tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
+ }
+
+ if (!audio_initialized) {
+ audio_driver_initialize();
+ audio_initialized = true;
+ }
+ stop_all_notes();
+}
+
+void audio_startup(void) {
+ if (audio_config.enable) {
+ PLAY_SONG(startup_song);
+ }
+
+ last_timestamp = timer_read();
+}
+
+void audio_toggle(void) {
+ if (audio_config.enable) {
+ stop_all_notes();
+ }
+ audio_config.enable ^= 1;
+ eeconfig_update_audio(audio_config.raw);
+ if (audio_config.enable) {
+ audio_on_user();
+ }
+}
+
+void audio_on(void) {
+ audio_config.enable = 1;
+ eeconfig_update_audio(audio_config.raw);
+ audio_on_user();
+ PLAY_SONG(audio_on_song);
+}
+
+void audio_off(void) {
+ PLAY_SONG(audio_off_song);
+ wait_ms(100);
+ audio_stop_all();
+ audio_config.enable = 0;
+ eeconfig_update_audio(audio_config.raw);
+}
+
+bool audio_is_on(void) { return (audio_config.enable != 0); }
+
+void audio_stop_all() {
+ if (audio_driver_stopped) {
+ return;
+ }
+
+ active_tones = 0;
+
+ audio_driver_stop();
+
+ playing_melody = false;
+ playing_note = false;
+
+ melody_current_note_duration = 0;
+
+ for (uint8_t i = 0; i < AUDIO_TONE_STACKSIZE; i++) {
+ tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
+ }
+
+ audio_driver_stopped = true;
+}
+
+void audio_stop_tone(float pitch) {
+ if (pitch < 0.0f) {
+ pitch = -1 * pitch;
+ }
+
+ if (playing_note) {
+ if (!audio_initialized) {
+ audio_init();
+ }
+ bool found = false;
+ for (int i = AUDIO_TONE_STACKSIZE - 1; i >= 0; i--) {
+ found = (tones[i].pitch == pitch);
+ if (found) {
+ tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
+ for (int j = i; (j < AUDIO_TONE_STACKSIZE - 1); j++) {
+ tones[j] = tones[j + 1];
+ tones[j + 1] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
+ }
+ break;
+ }
+ }
+ if (!found) {
+ return;
+ }
+
+ state_changed = true;
+ active_tones--;
+ if (active_tones < 0) active_tones = 0;
+#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
+ if (tone_multiplexing_index_shift >= active_tones) {
+ tone_multiplexing_index_shift = 0;
+ }
+#endif
+ if (active_tones == 0) {
+ audio_driver_stop();
+ audio_driver_stopped = true;
+ playing_note = false;
+ }
+ }
+}
+
+void audio_play_note(float pitch, uint16_t duration) {
+ if (!audio_config.enable) {
+ return;
+ }
+
+ if (!audio_initialized) {
+ audio_init();
+ }
+
+ if (pitch < 0.0f) {
+ pitch = -1 * pitch;
+ }
+
+ // round-robin: shifting out old tones, keeping only unique ones
+ // if the new frequency is already amongst the active tones, shift it to the top of the stack
+ bool found = false;
+ for (int i = active_tones - 1; i >= 0; i--) {
+ found = (tones[i].pitch == pitch);
+ if (found) {
+ for (int j = i; (j < active_tones - 1); j++) {
+ tones[j] = tones[j + 1];
+ tones[j + 1] = (musical_tone_t){.time_started = timer_read(), .pitch = pitch, .duration = duration};
+ }
+ return; // since this frequency played already, the hardware was already started
+ }
+ }
+
+ // frequency/tone is actually new, so we put it on the top of the stack
+ active_tones++;
+ if (active_tones > AUDIO_TONE_STACKSIZE) {
+ active_tones = AUDIO_TONE_STACKSIZE;
+ // shift out the oldest tone to make room
+ for (int i = 0; i < active_tones - 1; i++) {
+ tones[i] = tones[i + 1];
+ }
+ }
+ state_changed = true;
+ playing_note = true;
+ tones[active_tones - 1] = (musical_tone_t){.time_started = timer_read(), .pitch = pitch, .duration = duration};
+
+ // TODO: needs to be handled per note/tone -> use its timestamp instead?
+ voices_timer = timer_read(); // reset to zero, for the effects added by voices.c
+
+ if (audio_driver_stopped) {
+ audio_driver_start();
+ audio_driver_stopped = false;
+ }
+}
+
+void audio_play_tone(float pitch) { audio_play_note(pitch, 0xffff); }
+
+void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat) {
+ if (!audio_config.enable) {
+ audio_stop_all();
+ return;
+ }
+
+ if (!audio_initialized) {
+ audio_init();
+ }
+
+ // Cancel note if a note is playing
+ if (playing_note) audio_stop_all();
+
+ playing_melody = true;
+ note_resting = false;
+
+ notes_pointer = np;
+ notes_count = n_count;
+ notes_repeat = n_repeat;
+
+ current_note = 0; // note in the melody-array/list at note_pointer
+
+ // start first note manually, which also starts the audio_driver
+ // all following/remaining notes are played by 'audio_update_state'
+ audio_play_note((*notes_pointer)[current_note][0], audio_duration_to_ms((*notes_pointer)[current_note][1]));
+ last_timestamp = timer_read();
+ melody_current_note_duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
+}
+
+float click[2][2];
+void audio_play_click(uint16_t delay, float pitch, uint16_t duration) {
+ uint16_t duration_tone = audio_ms_to_duration(duration);
+ uint16_t duration_delay = audio_ms_to_duration(delay);
+
+ if (delay <= 0.0f) {
+ click[0][0] = pitch;
+ click[0][1] = duration_tone;
+ click[1][0] = 0.0f;
+ click[1][1] = 0.0f;
+ audio_play_melody(&click, 1, false);
+ } else {
+ // first note is a rest/pause
+ click[0][0] = 0.0f;
+ click[0][1] = duration_delay;
+ // second note is the actual click
+ click[1][0] = pitch;
+ click[1][1] = duration_tone;
+ audio_play_melody(&click, 2, false);
+ }
+}
+
+bool audio_is_playing_note(void) { return playing_note; }
+
+bool audio_is_playing_melody(void) { return playing_melody; }
+
+uint8_t audio_get_number_of_active_tones(void) { return active_tones; }
+
+float audio_get_frequency(uint8_t tone_index) {
+ if (tone_index >= active_tones) {
+ return 0.0f;
+ }
+ return tones[active_tones - tone_index - 1].pitch;
+}
+
+float audio_get_processed_frequency(uint8_t tone_index) {
+ if (tone_index >= active_tones) {
+ return 0.0f;
+ }
+
+ int8_t index = active_tones - tone_index - 1;
+ // new tones are stacked on top (= appended at the end), so the most recent/current is MAX-1
+
+#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
+ index = index - tone_multiplexing_index_shift;
+ if (index < 0) // wrap around
+ index += active_tones;
+#endif
+
+ if (tones[index].pitch <= 0.0f) {
+ return 0.0f;
+ }
+
+ return voice_envelope(tones[index].pitch);
+}
+
+bool audio_update_state(void) {
+ if (!playing_note && !playing_melody) {
+ return false;
+ }
+
+ bool goto_next_note = false;
+ uint16_t current_time = timer_read();
+
+ if (playing_melody) {
+ goto_next_note = timer_elapsed(last_timestamp) >= melody_current_note_duration;
+ if (goto_next_note) {
+ uint16_t delta = timer_elapsed(last_timestamp) - melody_current_note_duration;
+ last_timestamp = current_time;
+ uint16_t previous_note = current_note;
+ current_note++;
+ voices_timer = timer_read(); // reset to zero, for the effects added by voices.c
+
+ if (current_note >= notes_count) {
+ if (notes_repeat) {
+ current_note = 0;
+ } else {
+ audio_stop_all();
+ return false;
+ }
+ }
+
+ if (!note_resting && (*notes_pointer)[previous_note][0] == (*notes_pointer)[current_note][0]) {
+ note_resting = true;
+
+ // special handling for successive notes of the same frequency:
+ // insert a short pause to separate them audibly
+ audio_play_note(0.0f, audio_duration_to_ms(2));
+ current_note = previous_note;
+ melody_current_note_duration = audio_duration_to_ms(2);
+
+ } else {
+ note_resting = false;
+
+ // TODO: handle glissando here (or remember previous and current tone)
+ /* there would need to be a freq(here we are) -> freq(next note)
+ * and do slide/glissando in between problem here is to know which
+ * frequency on the stack relates to what other? e.g. a melody starts
+ * tones in a sequence, and stops expiring one, so the most recently
+ * stopped is the starting point for a glissando to the most recently started?
+ * how to detect and preserve this relation?
+ * and what about user input, chords, ...?
+ */
+
+ // '- delta': Skip forward in the next note's length if we've over shot
+ // the last, so the overall length of the song is the same
+ uint16_t duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
+
+ // Skip forward past any completely missed notes
+ while (delta > duration && current_note < notes_count - 1) {
+ delta -= duration;
+ current_note++;
+ duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
+ }
+
+ if (delta < duration) {
+ duration -= delta;
+ } else {
+ // Only way to get here is if it is the last note and
+ // we have completely missed it. Play it for 1ms...
+ duration = 1;
+ }
+
+ audio_play_note((*notes_pointer)[current_note][0], duration);
+ melody_current_note_duration = duration;
+ }
+ }
+ }
+
+ if (playing_note) {
+#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
+ tone_multiplexing_index_shift = (int)(current_time / tone_multiplexing_rate) % MIN(AUDIO_MAX_SIMULTANEOUS_TONES, active_tones);
+ goto_next_note = true;
+#endif
+ if (vibrato || glissando) {
+ // force update on each cycle, since vibrato shifts the frequency slightly
+ goto_next_note = true;
+ }
+
+ // housekeeping: stop notes that have no playtime left
+ for (int i = 0; i < active_tones; i++) {
+ if ((tones[i].duration != 0xffff) // indefinitely playing notes, started by 'audio_play_tone'
+ && (tones[i].duration != 0) // 'uninitialized'
+ ) {
+ if (timer_elapsed(tones[i].time_started) >= tones[i].duration) {
+ audio_stop_tone(tones[i].pitch); // also sets 'state_changed=true'
+ }
+ }
+ }
+ }
+
+ // state-changes have a higher priority, always triggering the hardware to update
+ if (state_changed) {
+ state_changed = false;
+ return true;
+ }
+
+ return goto_next_note;
+}
+
+// Tone-multiplexing functions
+#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
+void audio_set_tone_multiplexing_rate(uint16_t rate) { tone_multiplexing_rate = rate; }
+void audio_enable_tone_multiplexing(void) { tone_multiplexing_rate = AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT; }
+void audio_disable_tone_multiplexing(void) { tone_multiplexing_rate = 0; }
+void audio_increase_tone_multiplexing_rate(uint16_t change) {
+ if ((0xffff - change) > tone_multiplexing_rate) {
+ tone_multiplexing_rate += change;
+ }
+}
+void audio_decrease_tone_multiplexing_rate(uint16_t change) {
+ if (change <= tone_multiplexing_rate) {
+ tone_multiplexing_rate -= change;
+ }
+}
+#endif
+
+// Tempo functions
+
+void audio_set_tempo(uint8_t tempo) {
+ if (tempo < 10) note_tempo = 10;
+ // else if (tempo > 250)
+ // note_tempo = 250;
+ else
+ note_tempo = tempo;
+}
+
+void audio_increase_tempo(uint8_t tempo_change) {
+ if (tempo_change > 255 - note_tempo)
+ note_tempo = 255;
+ else
+ note_tempo += tempo_change;
+}
+
+void audio_decrease_tempo(uint8_t tempo_change) {
+ if (tempo_change >= note_tempo - 10)
+ note_tempo = 10;
+ else
+ note_tempo -= tempo_change;
+}
+
+// TODO in the int-math version are some bugs; songs sometimes abruptly end - maybe an issue with the timer/system-tick wrapping around?
+uint16_t audio_duration_to_ms(uint16_t duration_bpm) {
+#if defined(__AVR__)
+ // doing int-math saves us some bytes in the overall firmware size, but the intermediate result is less accurate before being cast to/returned as uint
+ return ((uint32_t)duration_bpm * 60 * 1000) / (64 * note_tempo);
+ // NOTE: beware of uint16_t overflows when note_tempo is low and/or the duration is long
+#else
+ return ((float)duration_bpm * 60) / (64 * note_tempo) * 1000;
+#endif
+}
+uint16_t audio_ms_to_duration(uint16_t duration_ms) {
+#if defined(__AVR__)
+ return ((uint32_t)duration_ms * 64 * note_tempo) / 60 / 1000;
+#else
+ return ((float)duration_ms * 64 * note_tempo) / 60 / 1000;
+#endif
+}
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
index dccf03d5f6..56b9158a1a 100644
--- a/quantum/audio/audio.h
+++ b/quantum/audio/audio.h
@@ -1,4 +1,5 @@
-/* Copyright 2016 Jack Humbert
+/* Copyright 2016-2020 Jack Humbert
+ * Copyright 2020 JohSchneider
*
* 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
@@ -13,28 +14,30 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
#pragma once
#include <stdint.h>
#include <stdbool.h>
-#if defined(__AVR__)
-# include <avr/io.h>
-#endif
-#include "wait.h"
#include "musical_notes.h"
#include "song_list.h"
#include "voices.h"
#include "quantum.h"
#include <math.h>
-// Largely untested PWM audio mode (doesn't sound as good)
-// #define PWM_AUDIO
-
-// #define VIBRATO_ENABLE
+#if defined(__AVR__)
+# include <avr/io.h>
+# if defined(AUDIO_DRIVER_PWM)
+# include "driver_avr_pwm.h"
+# endif
+#endif
-// Enable vibrato strength/amplitude - slows down ISR too much
-// #define VIBRATO_STRENGTH_ENABLE
+#if defined(PROTOCOL_CHIBIOS)
+# if defined(AUDIO_DRIVER_PWM)
+# include "driver_chibios_pwm.h"
+# elif defined(AUDIO_DRIVER_DAC)
+# include "driver_chibios_dac.h"
+# endif
+#endif
typedef union {
uint8_t raw;
@@ -45,62 +48,238 @@ typedef union {
};
} audio_config_t;
-bool is_audio_on(void);
+// AVR/LUFA has a MIN, arm/chibios does not
+#ifndef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/*
+ * a 'musical note' is represented by pitch and duration; a 'musical tone' adds intensity and timbre
+ * https://en.wikipedia.org/wiki/Musical_tone
+ * "A musical tone is characterized by its duration, pitch, intensity (or loudness), and timbre (or quality)"
+ */
+typedef struct {
+ uint16_t time_started; // timestamp the tone/note was started, system time runs with 1ms resolution -> 16bit timer overflows every ~64 seconds, long enough under normal circumstances; but might be too soon for long-duration notes when the note_tempo is set to a very low value
+ float pitch; // aka frequency, in Hz
+ uint16_t duration; // in ms, converted from the musical_notes.h unit which has 64parts to a beat, factoring in the current tempo in beats-per-minute
+ // float intensity; // aka volume [0,1] TODO: not used at the moment; pwm drivers can't handle it
+ // uint8_t timbre; // range: [0,100] TODO: this currently kept track of globally, should we do this per tone instead?
+} musical_tone_t;
+
+// public interface
+
+/**
+ * @brief one-time initialization called by quantum/quantum.c
+ * @details usually done lazy, when some tones are to be played
+ *
+ * @post audio system (and hardware) initialized and ready to play tones
+ */
+void audio_init(void);
+void audio_startup(void);
+
+/**
+ * @brief en-/disable audio output, save this choice to the eeprom
+ */
void audio_toggle(void);
+/**
+ * @brief enable audio output, save this choice to the eeprom
+ */
void audio_on(void);
+/**
+ * @brief disable audio output, save this choice to the eeprom
+ */
void audio_off(void);
+/**
+ * @brief query the if audio output is enabled
+ */
+bool audio_is_on(void);
-// Vibrato rate functions
+/**
+ * @brief start playback of a tone with the given frequency and duration
+ *
+ * @details starts the playback of a given note, which is automatically stopped
+ * at the the end of its duration = fire&forget
+ *
+ * @param[in] pitch frequency of the tone be played
+ * @param[in] duration in milliseconds, use 'audio_duration_to_ms' to convert
+ * from the musical_notes.h unit to ms
+ */
+void audio_play_note(float pitch, uint16_t duration);
+// TODO: audio_play_note(float pitch, uint16_t duration, float intensity, float timbre);
+// audio_play_note_with_instrument ifdef AUDIO_ENABLE_VOICES
-#ifdef VIBRATO_ENABLE
+/**
+ * @brief start playback of a tone with the given frequency
+ *
+ * @details the 'frequency' is put on-top the internal stack of active tones,
+ * as a new tone with indefinite duration. this tone is played by
+ * the hardware until a call to 'audio_stop_tone'.
+ * should a tone with that frequency already be active, its entry
+ * is put on the top of said internal stack - so no duplicate
+ * entries are kept.
+ * 'hardware_start' is called upon the first note.
+ *
+ * @param[in] pitch frequency of the tone be played
+ */
+void audio_play_tone(float pitch);
-void set_vibrato_rate(float rate);
-void increase_vibrato_rate(float change);
-void decrease_vibrato_rate(float change);
+/**
+ * @brief stop a given tone/frequency
+ *
+ * @details removes a tone matching the given frequency from the internal
+ * playback stack
+ * the hardware is stopped in case this was the last/only frequency
+ * being played.
+ *
+ * @param[in] pitch tone/frequency to be stopped
+ */
+void audio_stop_tone(float pitch);
-# ifdef VIBRATO_STRENGTH_ENABLE
+/**
+ * @brief play a melody
+ *
+ * @details starts playback of a melody passed in from a SONG definition - an
+ * array of {pitch, duration} float-tuples
+ *
+ * @param[in] np note-pointer to the SONG array
+ * @param[in] n_count number of MUSICAL_NOTES of the SONG
+ * @param[in] n_repeat false for onetime, true for looped playback
+ */
+void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat);
-void set_vibrato_strength(float strength);
-void increase_vibrato_strength(float change);
-void decrease_vibrato_strength(float change);
+/**
+ * @brief play a short tone of a specific frequency to emulate a 'click'
+ *
+ * @details constructs a two-note melody (one pause plus a note) and plays it through
+ * audio_play_melody. very short durations might not quite work due to
+ * hardware limitations (DAC: added pulses from zero-crossing feature;...)
+ *
+ * @param[in] delay in milliseconds, length for the pause before the pulses, can be zero
+ * @param[in] pitch
+ * @param[in] duration in milliseconds, length of the 'click'
+ */
+void audio_play_click(uint16_t delay, float pitch, uint16_t duration);
-# endif
+/**
+ * @brief stops all playback
+ *
+ * @details stops playback of both a melody as well as single tones, resetting
+ * the internal state
+ */
+void audio_stop_all(void);
-#endif
+/**
+ * @brief query if one/multiple tones are playing
+ */
+bool audio_is_playing_note(void);
-// Polyphony functions
+/**
+ * @brief query if a melody/SONG is playing
+ */
+bool audio_is_playing_melody(void);
-void set_polyphony_rate(float rate);
-void enable_polyphony(void);
-void disable_polyphony(void);
-void increase_polyphony_rate(float change);
-void decrease_polyphony_rate(float change);
+// These macros are used to allow audio_play_melody to play an array of indeterminate
+// length. This works around the limitation of C's sizeof operation on pointers.
+// The global float array for the song must be used here.
+#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
-void set_timbre(float timbre);
-void set_tempo(uint8_t tempo);
+/**
+ * @brief convenience macro, to play a melody/SONG once
+ */
+#define PLAY_SONG(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), false)
+// TODO: a 'song' is a melody plus singing/vocals -> PLAY_MELODY
+/**
+ * @brief convenience macro, to play a melody/SONG in a loop, until stopped by 'audio_stop_all'
+ */
+#define PLAY_LOOP(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), true)
-void increase_tempo(uint8_t tempo_change);
-void decrease_tempo(uint8_t tempo_change);
+// Tone-Multiplexing functions
+// this feature only makes sense for hardware setups which can't do proper
+// audio-wave synthesis = have no DAC and need to use PWM for tone generation
+#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
+# ifndef AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT
+# define AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 0
+// 0=off, good starting value is 4; the lower the value the higher the cpu-load
+# endif
+void audio_set_tone_multiplexing_rate(uint16_t rate);
+void audio_enable_tone_multiplexing(void);
+void audio_disable_tone_multiplexing(void);
+void audio_increase_tone_multiplexing_rate(uint16_t change);
+void audio_decrease_tone_multiplexing_rate(uint16_t change);
+#endif
+
+// Tempo functions
+
+void audio_set_tempo(uint8_t tempo);
+void audio_increase_tempo(uint8_t tempo_change);
+void audio_decrease_tempo(uint8_t tempo_change);
+
+// conversion macros, from 64parts-to-a-beat to milliseconds and back
+uint16_t audio_duration_to_ms(uint16_t duration_bpm);
+uint16_t audio_ms_to_duration(uint16_t duration_ms);
-void audio_init(void);
void audio_startup(void);
-#ifdef PWM_AUDIO
-void play_sample(uint8_t* s, uint16_t l, bool r);
-#endif
-void play_note(float freq, int vol);
-void stop_note(float freq);
-void stop_all_notes(void);
-void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat);
+// hardware interface
-#define SCALE \
- (int8_t[]) { 0 + (12 * 0), 2 + (12 * 0), 4 + (12 * 0), 5 + (12 * 0), 7 + (12 * 0), 9 + (12 * 0), 11 + (12 * 0), 0 + (12 * 1), 2 + (12 * 1), 4 + (12 * 1), 5 + (12 * 1), 7 + (12 * 1), 9 + (12 * 1), 11 + (12 * 1), 0 + (12 * 2), 2 + (12 * 2), 4 + (12 * 2), 5 + (12 * 2), 7 + (12 * 2), 9 + (12 * 2), 11 + (12 * 2), 0 + (12 * 3), 2 + (12 * 3), 4 + (12 * 3), 5 + (12 * 3), 7 + (12 * 3), 9 + (12 * 3), 11 + (12 * 3), 0 + (12 * 4), 2 + (12 * 4), 4 + (12 * 4), 5 + (12 * 4), 7 + (12 * 4), 9 + (12 * 4), 11 + (12 * 4), }
+// implementation in the driver_avr/arm_* respective parts
+void audio_driver_initialize(void);
+void audio_driver_start(void);
+void audio_driver_stop(void);
-// These macros are used to allow play_notes to play an array of indeterminate
-// length. This works around the limitation of C's sizeof operation on pointers.
-// The global float array for the song must be used here.
-#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
-#define PLAY_SONG(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), false)
-#define PLAY_LOOP(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), true)
+/**
+ * @brief get the number of currently active tones
+ * @return number, 0=none active
+ */
+uint8_t audio_get_number_of_active_tones(void);
+
+/**
+ * @brief access to the raw/unprocessed frequency for a specific tone
+ * @details each active tone has a frequency associated with it, which
+ * the internal state keeps track of, and is usually influenced
+ * by various effects
+ * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
+ * first being the most recent and each increment yielding the next
+ * older one
+ * @return a positive frequency, in Hz; or zero if the tone is a pause
+ */
+float audio_get_frequency(uint8_t tone_index);
+
+/**
+ * @brief calculate and return the frequency for the requested tone
+ * @details effects like glissando, vibrato, ... are post-processed onto the
+ * each active tones 'base'-frequency; this function returns the
+ * post-processed result.
+ * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
+ * first being the most recent and each increment yielding the next
+ * older one
+ * @return a positive frequency, in Hz; or zero if the tone is a pause
+ */
+float audio_get_processed_frequency(uint8_t tone_index);
+
+/**
+ * @brief update audio internal state: currently playing and active tones,...
+ * @details This function is intended to be called by the audio-hardware
+ * specific implementation on a somewhat regular basis while a SONG
+ * or notes (pitch+duration) are playing to 'advance' the internal
+ * state (current playing notes, position in the melody, ...)
+ *
+ * @return true if something changed in the currently active tones, which the
+ * hardware might need to react to
+ */
+bool audio_update_state(void);
+
+// legacy and back-warts compatibility stuff
+
+#define is_audio_on() audio_is_on()
+#define is_playing_notes() audio_is_playing_melody()
+#define is_playing_note() audio_is_playing_note()
+#define stop_all_notes() audio_stop_all()
+#define stop_note(f) audio_stop_tone(f)
+#define play_note(f, v) audio_play_tone(f)
-bool is_playing_notes(void);
+#define set_timbre(t) voice_set_timbre(t)
+#define set_tempo(t) audio_set_tempo(t)
+#define increase_tempo(t) audio_increase_tempo(t)
+#define decrease_tempo(t) audio_decrease_tempo(t)
+// vibrato functions are not used in any keyboards
diff --git a/quantum/audio/audio_pwm.c b/quantum/audio/audio_pwm.c
deleted file mode 100644
index d93ac4bb40..0000000000
--- a/quantum/audio/audio_pwm.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/* Copyright 2016 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 <http://www.gnu.org/licenses/>.
- */
-#include <stdio.h>
-#include <string.h>
-//#include <math.h>
-#include <avr/pgmspace.h>
-#include <avr/interrupt.h>
-#include <avr/io.h>
-#include "print.h"
-#include "audio.h"
-#include "keymap.h"
-
-#include "eeconfig.h"
-
-#define PI 3.14159265
-
-#define CPU_PRESCALER 8
-
-#ifndef STARTUP_SONG
-# define STARTUP_SONG SONG(STARTUP_SOUND)
-#endif
-float startup_song[][2] = STARTUP_SONG;
-
-// Timer Abstractions
-
-// TIMSK3 - Timer/Counter #3 Interrupt Mask Register
-// Turn on/off 3A interputs, stopping/enabling the ISR calls
-#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
-#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
-
-// TCCR3A: Timer/Counter #3 Control Register
-// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
-#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
-#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
-
-#define NOTE_PERIOD ICR3
-#define NOTE_DUTY_CYCLE OCR3A
-
-#ifdef PWM_AUDIO
-# include "wave.h"
-# define SAMPLE_DIVIDER 39
-# define SAMPLE_RATE (2000000.0 / SAMPLE_DIVIDER / 2048)
-// Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
-
-float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
-uint16_t place_int = 0;
-bool repeat = true;
-#endif
-
-void delay_us(int count) {
- while (count--) {
- _delay_us(1);
- }
-}
-
-int voices = 0;
-int voice_place = 0;
-float frequency = 0;
-int volume = 0;
-long position = 0;
-
-float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
-int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
-bool sliding = false;
-
-float place = 0;
-
-uint8_t* sample;
-uint16_t sample_length = 0;
-// float freq = 0;
-
-bool playing_notes = false;
-bool playing_note = false;
-float note_frequency = 0;
-float note_length = 0;
-uint8_t note_tempo = TEMPO_DEFAULT;
-float note_timbre = TIMBRE_DEFAULT;
-uint16_t note_position = 0;
-float (*notes_pointer)[][2];
-uint16_t notes_count;
-bool notes_repeat;
-float notes_rest;
-bool note_resting = false;
-
-uint16_t current_note = 0;
-uint8_t rest_counter = 0;
-
-#ifdef VIBRATO_ENABLE
-float vibrato_counter = 0;
-float vibrato_strength = .5;
-float vibrato_rate = 0.125;
-#endif
-
-float polyphony_rate = 0;
-
-static bool audio_initialized = false;
-
-audio_config_t audio_config;
-
-uint16_t envelope_index = 0;
-
-void audio_init() {
- // Check EEPROM
- if (!eeconfig_is_enabled()) {
- eeconfig_init();
- }
- audio_config.raw = eeconfig_read_audio();
-
-#ifdef PWM_AUDIO
-
- PLLFRQ = _BV(PDIV2);
- PLLCSR = _BV(PLLE);
- while (!(PLLCSR & _BV(PLOCK)))
- ;
- PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
-
- /* Init a fast PWM on Timer4 */
- TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
- TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
- OCR4A = 0;
-
- /* Enable the OC4A output */
- DDRC |= _BV(PORTC6);
-
- DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs
-
- TCCR3A = 0x0; // Options not needed
- TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
- OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
-
-#else
-
- // Set port PC6 (OC3A and /OC4A) as output
- DDRC |= _BV(PORTC6);
-
- DISABLE_AUDIO_COUNTER_3_ISR;
-
- // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
- // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
- // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
- // Clock Select (CS3n) = 0b010 = Clock / 8
- TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
- TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
-
-#endif
-
- audio_initialized = true;
-}
-
-void audio_startup() {
- if (audio_config.enable) {
- PLAY_SONG(startup_song);
- }
-}
-
-void stop_all_notes() {
- if (!audio_initialized) {
- audio_init();
- }
- voices = 0;
-#ifdef PWM_AUDIO
- DISABLE_AUDIO_COUNTER_3_ISR;
-#else
- DISABLE_AUDIO_COUNTER_3_ISR;
- DISABLE_AUDIO_COUNTER_3_OUTPUT;
-#endif
-
- playing_notes = false;
- playing_note = false;
- frequency = 0;
- volume = 0;
-
- for (uint8_t i = 0; i < 8; i++) {
- frequencies[i] = 0;
- volumes[i] = 0;
- }
-}
-
-void stop_note(float freq) {
- if (playing_note) {
- if (!audio_initialized) {
- audio_init();
- }
-#ifdef PWM_AUDIO
- freq = freq / SAMPLE_RATE;
-#endif
- for (int i = 7; i >= 0; i--) {
- if (frequencies[i] == freq) {
- frequencies[i] = 0;
- volumes[i] = 0;
- for (int j = i; (j < 7); j++) {
- frequencies[j] = frequencies[j + 1];
- frequencies[j + 1] = 0;
- volumes[j] = volumes[j + 1];
- volumes[j + 1] = 0;
- }
- break;
- }
- }
- voices--;
- if (voices < 0) voices = 0;
- if (voice_place >= voices) {
- voice_place = 0;
- }
- if (voices == 0) {
-#ifdef PWM_AUDIO
- DISABLE_AUDIO_COUNTER_3_ISR;
-#else
- DISABLE_AUDIO_COUNTER_3_ISR;
- DISABLE_AUDIO_COUNTER_3_OUTPUT;
-#endif
- frequency = 0;
- volume = 0;
- playing_note = false;
- }
- }
-}
-
-#ifdef VIBRATO_ENABLE
-
-float mod(float a, int b) {
- float r = fmod(a, b);
- return r < 0 ? r + b : r;
-}
-
-float vibrato(float average_freq) {
-# ifdef VIBRATO_STRENGTH_ENABLE
- float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
-# else
- float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
-# endif
- vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
- return vibrated_freq;
-}
-
-#endif
-
-ISR(TIMER3_COMPA_vect) {
- if (playing_note) {
-#ifdef PWM_AUDIO
- if (voices == 1) {
- // SINE
- OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
-
- // SQUARE
- // if (((int)place) >= 1024){
- // OCR4A = 0xFF >> 2;
- // } else {
- // OCR4A = 0x00;
- // }
-
- // SAWTOOTH
- // OCR4A = (int)place / 4;
-
- // TRIANGLE
- // if (((int)place) >= 1024) {
- // OCR4A = (int)place / 2;
- // } else {
- // OCR4A = 2048 - (int)place / 2;
- // }
-
- place += frequency;
-
- if (place >= SINE_LENGTH) place -= SINE_LENGTH;
-
- } else {
- int sum = 0;
- for (int i = 0; i < voices; i++) {
- // SINE
- sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
-
- // SQUARE
- // if (((int)places[i]) >= 1024){
- // sum += 0xFF >> 2;
- // } else {
- // sum += 0x00;
- // }
-
- places[i] += frequencies[i];
-
- if (places[i] >= SINE_LENGTH) places[i] -= SINE_LENGTH;
- }
- OCR4A = sum;
- }
-#else
- if (voices > 0) {
- float freq;
- if (polyphony_rate > 0) {
- if (voices > 1) {
- voice_place %= voices;
- if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
- voice_place = (voice_place + 1) % voices;
- place = 0.0;
- }
- }
-# ifdef VIBRATO_ENABLE
- if (vibrato_strength > 0) {
- freq = vibrato(frequencies[voice_place]);
- } else {
-# else
- {
-# endif
- freq = frequencies[voice_place];
- }
- } else {
- if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
- frequency = frequency * pow(2, 440 / frequency / 12 / 2);
- } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
- frequency = frequency * pow(2, -440 / frequency / 12 / 2);
- } else {
- frequency = frequencies[voices - 1];
- }
-
-# ifdef VIBRATO_ENABLE
- if (vibrato_strength > 0) {
- freq = vibrato(frequency);
- } else {
-# else
- {
-# endif
- freq = frequency;
- }
- }
-
- if (envelope_index < 65535) {
- envelope_index++;
- }
- freq = voice_envelope(freq);
-
- if (freq < 30.517578125) freq = 30.52;
- NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
- NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
- }
-#endif
- }
-
- // SAMPLE
- // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
-
- // place_int++;
-
- // if (place_int >= sample_length)
- // if (repeat)
- // place_int -= sample_length;
- // else
- // DISABLE_AUDIO_COUNTER_3_ISR;
-
- if (playing_notes) {
-#ifdef PWM_AUDIO
- OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
-
- place += note_frequency;
- if (place >= SINE_LENGTH) place -= SINE_LENGTH;
-#else
- if (note_frequency > 0) {
- float freq;
-
-# ifdef VIBRATO_ENABLE
- if (vibrato_strength > 0) {
- freq = vibrato(note_frequency);
- } else {
-# else
- {
-# endif
- freq = note_frequency;
- }
-
- if (envelope_index < 65535) {
- envelope_index++;
- }
- freq = voice_envelope(freq);
-
- NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
- NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
- } else {
- NOTE_PERIOD = 0;
- NOTE_DUTY_CYCLE = 0;
- }
-#endif
-
- note_position++;
- bool end_of_note = false;
- if (NOTE_PERIOD > 0)
- end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF));
- else
- end_of_note = (note_position >= (note_length * 0x7FF));
- if (end_of_note) {
- current_note++;
- if (current_note >= notes_count) {
- if (notes_repeat) {
- current_note = 0;
- } else {
-#ifdef PWM_AUDIO
- DISABLE_AUDIO_COUNTER_3_ISR;
-#else
- DISABLE_AUDIO_COUNTER_3_ISR;
- DISABLE_AUDIO_COUNTER_3_OUTPUT;
-#endif
- playing_notes = false;
- return;
- }
- }
- if (!note_resting && (notes_rest > 0)) {
- note_resting = true;
- note_frequency = 0;
- note_length = notes_rest;
- current_note--;
- } else {
- note_resting = false;
-#ifdef PWM_AUDIO
- note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
- note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
-#else
- envelope_index = 0;
- note_frequency = (*notes_pointer)[current_note][0];
- note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
-#endif
- }
- note_position = 0;
- }
- }
-
- if (!audio_config.enable) {
- playing_notes = false;
- playing_note = false;
- }
-}
-
-void play_note(float freq, int vol) {
- if (!audio_initialized) {
- audio_init();
- }
-
- if (audio_config.enable && voices < 8) {
- DISABLE_AUDIO_COUNTER_3_ISR;
-
- // Cancel notes if notes are playing
- if (playing_notes) stop_all_notes();
-
- playing_note = true;
-
- envelope_index = 0;
-
-#ifdef PWM_AUDIO
- freq = freq / SAMPLE_RATE;
-#endif
- if (freq > 0) {
- frequencies[voices] = freq;
- volumes[voices] = vol;
- voices++;
- }
-
-#ifdef PWM_AUDIO
- ENABLE_AUDIO_COUNTER_3_ISR;
-#else
- ENABLE_AUDIO_COUNTER_3_ISR;
- ENABLE_AUDIO_COUNTER_3_OUTPUT;
-#endif
- }
-}
-
-void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) {
- if (!audio_initialized) {
- audio_init();
- }
-
- if (audio_config.enable) {
- DISABLE_AUDIO_COUNTER_3_ISR;
-
- // Cancel note if a note is playing
- if (playing_note) stop_all_notes();
-
- playing_notes = true;
-
- notes_pointer = np;
- notes_count = n_count;
- notes_repeat = n_repeat;
- notes_rest = n_rest;
-
- place = 0;
- current_note = 0;
-
-#ifdef PWM_AUDIO
- note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
- note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
-#else
- note_frequency = (*notes_pointer)[current_note][0];
- note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
-#endif
- note_position = 0;
-
-#ifdef PWM_AUDIO
- ENABLE_AUDIO_COUNTER_3_ISR;
-#else
- ENABLE_AUDIO_COUNTER_3_ISR;
- ENABLE_AUDIO_COUNTER_3_OUTPUT;
-#endif
- }
-}
-
-#ifdef PWM_AUDIO
-void play_sample(uint8_t* s, uint16_t l, bool r) {
- if (!audio_initialized) {
- audio_init();
- }
-
- if (audio_config.enable) {
- DISABLE_AUDIO_COUNTER_3_ISR;
- stop_all_notes();
- place_int = 0;
- sample = s;
- sample_length = l;
- repeat = r;
-
- ENABLE_AUDIO_COUNTER_3_ISR;
- }
-}
-#endif
-
-void audio_toggle(void) {
- audio_config.enable ^= 1;
- eeconfig_update_audio(audio_config.raw);
-}
-
-void audio_on(void) {
- audio_config.enable = 1;
- eeconfig_update_audio(audio_config.raw);
-}
-
-void audio_off(void) {
- audio_config.enable = 0;
- eeconfig_update_audio(audio_config.raw);
-}
-
-#ifdef VIBRATO_ENABLE
-
-// Vibrato rate functions
-
-void set_vibrato_rate(float rate) { vibrato_rate = rate; }
-
-void increase_vibrato_rate(float change) { vibrato_rate *= change; }
-
-void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
-
-# ifdef VIBRATO_STRENGTH_ENABLE
-
-void set_vibrato_strength(float strength) { vibrato_strength = strength; }
-
-void increase_vibrato_strength(float change) { vibrato_strength *= change; }
-
-void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
-
-# endif /* VIBRATO_STRENGTH_ENABLE */
-
-#endif /* VIBRATO_ENABLE */
-
-// Polyphony functions
-
-void set_polyphony_rate(float rate) { polyphony_rate = rate; }
-
-void enable_polyphony() { polyphony_rate = 5; }
-
-void disable_polyphony() { polyphony_rate = 0; }
-
-void increase_polyphony_rate(float change) { polyphony_rate *= change; }
-
-void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
-
-// Timbre function
-
-void set_timbre(float timbre) { note_timbre = timbre; }
-
-// Tempo functions
-
-void set_tempo(uint8_t tempo) { note_tempo = tempo; }
-
-void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
-
-void increase_tempo(uint8_t tempo_change) {
- if (note_tempo - tempo_change < 10) {
- note_tempo = 10;
- } else {
- note_tempo -= tempo_change;
- }
-}
-
-//------------------------------------------------------------------------------
-// Override these functions in your keymap file to play different tunes on
-// startup and bootloader jump
-__attribute__((weak)) void play_startup_tone() {}
-
-__attribute__((weak)) void play_goodbye_tone() {}
-//------------------------------------------------------------------------------
diff --git a/quantum/template/base/template.h b/quantum/audio/driver_avr_pwm.h
index 595da73c60..d6eb3571da 100644
--- a/quantum/template/base/template.h
+++ b/quantum/audio/driver_avr_pwm.h
@@ -1,4 +1,5 @@
-/* Copyright %YEAR% %YOUR_NAME%
+/* Copyright 2020 Jack Humbert
+ * Copyright 2020 JohSchneider
*
* 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
@@ -14,16 +15,3 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
-
-#include "quantum.h"
-
-/* This a shortcut to help you visually see your layout.
- *
- * The first section contains all of the arguments representing the physical
- * layout of the board and position of the keys.
- *
- * The second converts the arguments into a two-dimensional array which
- * represents the switch matrix.
- */
-#define LAYOUT(k00, k01, k02, k10, k11) \
- { {k00, k01, k02}, {k10, KC_NO, k11}, }
diff --git a/quantum/audio/driver_avr_pwm_hardware.c b/quantum/audio/driver_avr_pwm_hardware.c
new file mode 100644
index 0000000000..df03a4558c
--- /dev/null
+++ b/quantum/audio/driver_avr_pwm_hardware.c
@@ -0,0 +1,332 @@
+/* Copyright 2016 Jack Humbert
+ * Copyright 2020 JohSchneider
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if defined(__AVR__)
+# include <avr/pgmspace.h>
+# include <avr/interrupt.h>
+# include <avr/io.h>
+#endif
+
+#include "audio.h"
+
+extern bool playing_note;
+extern bool playing_melody;
+extern uint8_t note_timbre;
+
+#define CPU_PRESCALER 8
+
+/*
+ Audio Driver: PWM
+
+ drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4.
+
+ the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3
+ and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1
+
+ alternatively, the PWM pins on PORTB can be used as only/primary speaker
+*/
+
+#if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN != D5)
+# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options."
+#endif
+
+#if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6)
+# define AUDIO1_PIN_SET
+# define AUDIO1_TIMSKx TIMSK3
+# define AUDIO1_TCCRxA TCCR3A
+# define AUDIO1_TCCRxB TCCR3B
+# define AUDIO1_ICRx ICR3
+# define AUDIO1_WGMx0 WGM30
+# define AUDIO1_WGMx1 WGM31
+# define AUDIO1_WGMx2 WGM32
+# define AUDIO1_WGMx3 WGM33
+# define AUDIO1_CSx0 CS30
+# define AUDIO1_CSx1 CS31
+# define AUDIO1_CSx2 CS32
+
+# if (AUDIO_PIN == C6)
+# define AUDIO1_COMxy0 COM3A0
+# define AUDIO1_COMxy1 COM3A1
+# define AUDIO1_OCIExy OCIE3A
+# define AUDIO1_OCRxy OCR3A
+# define AUDIO1_PIN C6
+# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect
+# elif (AUDIO_PIN == C5)
+# define AUDIO1_COMxy0 COM3B0
+# define AUDIO1_COMxy1 COM3B1
+# define AUDIO1_OCIExy OCIE3B
+# define AUDIO1_OCRxy OCR3B
+# define AUDIO1_PIN C5
+# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect
+# elif (AUDIO_PIN == C4)
+# define AUDIO1_COMxy0 COM3C0
+# define AUDIO1_COMxy1 COM3C1
+# define AUDIO1_OCIExy OCIE3C
+# define AUDIO1_OCRxy OCR3C
+# define AUDIO1_PIN C4
+# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect
+# endif
+#endif
+
+#if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT)
+# error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense."
+#endif
+
+#if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6)))
+# error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported."
+#endif
+
+#if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
+# error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported."
+#endif
+
+#if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7) || (AUDIO_PIN == D5)
+# define AUDIO2_PIN_SET
+# define AUDIO2_TIMSKx TIMSK1
+# define AUDIO2_TCCRxA TCCR1A
+# define AUDIO2_TCCRxB TCCR1B
+# define AUDIO2_ICRx ICR1
+# define AUDIO2_WGMx0 WGM10
+# define AUDIO2_WGMx1 WGM11
+# define AUDIO2_WGMx2 WGM12
+# define AUDIO2_WGMx3 WGM13
+# define AUDIO2_CSx0 CS10
+# define AUDIO2_CSx1 CS11
+# define AUDIO2_CSx2 CS12
+
+# if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5)
+# define AUDIO2_COMxy0 COM1A0
+# define AUDIO2_COMxy1 COM1A1
+# define AUDIO2_OCIExy OCIE1A
+# define AUDIO2_OCRxy OCR1A
+# define AUDIO2_PIN B5
+# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
+# elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6)
+# define AUDIO2_COMxy0 COM1B0
+# define AUDIO2_COMxy1 COM1B1
+# define AUDIO2_OCIExy OCIE1B
+# define AUDIO2_OCRxy OCR1B
+# define AUDIO2_PIN B6
+# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect
+# elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7)
+# define AUDIO2_COMxy0 COM1C0
+# define AUDIO2_COMxy1 COM1C1
+# define AUDIO2_OCIExy OCIE1C
+# define AUDIO2_OCRxy OCR1C
+# define AUDIO2_PIN B7
+# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect
+# elif (AUDIO_PIN == D5) && defined(__AVR_ATmega32A__)
+# pragma message "Audio support for ATmega32A is experimental and can cause crashes."
+# undef AUDIO2_TIMSKx
+# define AUDIO2_TIMSKx TIMSK
+# define AUDIO2_COMxy0 COM1A0
+# define AUDIO2_COMxy1 COM1A1
+# define AUDIO2_OCIExy OCIE1A
+# define AUDIO2_OCRxy OCR1A
+# define AUDIO2_PIN D5
+# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
+# endif
+#endif
+
+// C6 seems to be the assumed default by many existing keyboard - but sill warn the user
+#if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET)
+# pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)"
+// TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define
+#endif
+// -----------------------------------------------------------------------------
+
+#ifdef AUDIO1_PIN_SET
+static float channel_1_frequency = 0.0f;
+void channel_1_set_frequency(float freq) {
+ if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0
+ {
+ // disable the output, but keep the pwm-ISR going (with the previous
+ // frequency) so the audio-state keeps getting updated
+ // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet
+ AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
+ return;
+ } else {
+ AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode
+ }
+
+ channel_1_frequency = freq;
+
+ // set pwm period
+ AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
+ // and duty cycle
+ AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
+}
+
+void channel_1_start(void) {
+ // enable timer-counter ISR
+ AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy);
+ // enable timer-counter output
+ AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1);
+}
+
+void channel_1_stop(void) {
+ // disable timer-counter ISR
+ AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy);
+ // disable timer-counter output
+ AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
+}
+#endif
+
+#ifdef AUDIO2_PIN_SET
+static float channel_2_frequency = 0.0f;
+void channel_2_set_frequency(float freq) {
+ if (freq == 0.0f) {
+ AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
+ return;
+ } else {
+ AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
+ }
+
+ channel_2_frequency = freq;
+
+ AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
+ AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
+}
+
+float channel_2_get_frequency(void) { return channel_2_frequency; }
+
+void channel_2_start(void) {
+ AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);
+ AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
+}
+
+void channel_2_stop(void) {
+ AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy);
+ AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
+}
+#endif
+
+void audio_driver_initialize() {
+#ifdef AUDIO1_PIN_SET
+ channel_1_stop();
+ setPinOutput(AUDIO1_PIN);
+#endif
+
+#ifdef AUDIO2_PIN_SET
+ channel_2_stop();
+ setPinOutput(AUDIO2_PIN);
+#endif
+
+ // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
+ // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
+ // OC3A -- PC6
+ // OC3B -- PC5
+ // OC3C -- PC4
+ // OC1A -- PB5
+ // OC1B -- PB6
+ // OC1C -- PB7
+
+ // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
+ // OCR3A - PC6
+ // OCR3B - PC5
+ // OCR3C - PC4
+ // OCR1A - PB5
+ // OCR1B - PB6
+ // OCR1C - PB7
+
+ // Clock Select (CS3n) = 0b010 = Clock / 8
+#ifdef AUDIO1_PIN_SET
+ // initialize timer-counter
+ AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0);
+ AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0);
+#endif
+
+#ifdef AUDIO2_PIN_SET
+ AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0);
+ AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0);
+#endif
+}
+
+void audio_driver_stop() {
+#ifdef AUDIO1_PIN_SET
+ channel_1_stop();
+#endif
+
+#ifdef AUDIO2_PIN_SET
+ channel_2_stop();
+#endif
+}
+
+void audio_driver_start(void) {
+#ifdef AUDIO1_PIN_SET
+ channel_1_start();
+ if (playing_note) {
+ channel_1_set_frequency(audio_get_processed_frequency(0));
+ }
+#endif
+
+#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
+ channel_2_start();
+ if (playing_note) {
+ channel_2_set_frequency(audio_get_processed_frequency(0));
+ }
+#endif
+}
+
+static volatile uint32_t isr_counter = 0;
+#ifdef AUDIO1_PIN_SET
+ISR(AUDIO1_TIMERx_COMPy_vect) {
+ isr_counter++;
+ if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return;
+
+ isr_counter = 0;
+ bool state_changed = audio_update_state();
+
+ if (!playing_note && !playing_melody) {
+ channel_1_stop();
+# ifdef AUDIO2_PIN_SET
+ channel_2_stop();
+# endif
+ return;
+ }
+
+ if (state_changed) {
+ channel_1_set_frequency(audio_get_processed_frequency(0));
+# ifdef AUDIO2_PIN_SET
+ if (audio_get_number_of_active_tones() > 1) {
+ channel_2_set_frequency(audio_get_processed_frequency(1));
+ } else {
+ channel_2_stop();
+ }
+# endif
+ }
+}
+#endif
+
+#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
+ISR(AUDIO2_TIMERx_COMPy_vect) {
+ isr_counter++;
+ if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return;
+
+ isr_counter = 0;
+ bool state_changed = audio_update_state();
+
+ if (!playing_note && !playing_melody) {
+ channel_2_stop();
+ return;
+ }
+
+ if (state_changed) {
+ channel_2_set_frequency(audio_get_processed_frequency(0));
+ }
+}
+#endif
diff --git a/quantum/audio/driver_chibios_dac.h b/quantum/audio/driver_chibios_dac.h
new file mode 100644
index 0000000000..07cd622ead
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac.h
@@ -0,0 +1,126 @@
+/* Copyright 2019 Jack Humbert
+ * Copyright 2020 JohSchneider
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#ifndef A4
+# define A4 PAL_LINE(GPIOA, 4)
+#endif
+#ifndef A5
+# define A5 PAL_LINE(GPIOA, 5)
+#endif
+
+/**
+ * Size of the dac_buffer arrays. All must be the same size.
+ */
+#define AUDIO_DAC_BUFFER_SIZE 256U
+
+/**
+ * Highest value allowed sample value.
+
+ * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U;
+ * lower values adjust the peak-voltage aka volume down.
+ * adjusting this value has only an effect on a sample-buffer whose values are
+ * are NOT pregenerated - see square-wave
+ */
+#ifndef AUDIO_DAC_SAMPLE_MAX
+# define AUDIO_DAC_SAMPLE_MAX 4095U
+#endif
+
+#if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH)
+# define AUDIO_DAC_QUALITY_SANE_MINIMUM
+#endif
+
+/**
+ * These presets allow you to quickly switch between quality settings for
+ * the DAC. The sample rate and maximum number of simultaneous tones roughly
+ * has an inverse relationship - slightly higher sample rates may be possible.
+ *
+ * NOTE: a high sample-rate results in a higher cpu-load, which might lead to
+ * (audible) discontinuities and/or starve other processes of cpu-time
+ * (like RGB-led back-lighting, ...)
+ */
+#ifdef AUDIO_DAC_QUALITY_VERY_LOW
+# define AUDIO_DAC_SAMPLE_RATE 11025U
+# define AUDIO_MAX_SIMULTANEOUS_TONES 8
+#endif
+
+#ifdef AUDIO_DAC_QUALITY_LOW
+# define AUDIO_DAC_SAMPLE_RATE 22050U
+# define AUDIO_MAX_SIMULTANEOUS_TONES 4
+#endif
+
+#ifdef AUDIO_DAC_QUALITY_HIGH
+# define AUDIO_DAC_SAMPLE_RATE 44100U
+# define AUDIO_MAX_SIMULTANEOUS_TONES 2
+#endif
+
+#ifdef AUDIO_DAC_QUALITY_VERY_HIGH
+# define AUDIO_DAC_SAMPLE_RATE 88200U
+# define AUDIO_MAX_SIMULTANEOUS_TONES 1
+#endif
+
+#ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM
+/* a sane-minimum config: with a trade-off between cpu-load and tone-range
+ *
+ * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now
+ * aim for an even even multiple of the buffer-size, we end up with:
+ * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE)
+ * 7902/256 = 30.867 * 2 * 256 ~= 16384
+ * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P)
+ */
+# define AUDIO_DAC_SAMPLE_RATE 16384U
+# define AUDIO_MAX_SIMULTANEOUS_TONES 8
+#endif
+
+/**
+ * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any
+ * lower will sacrifice perceptible audio quality. Any higher will limit the
+ * number of simultaneous tones. In most situations, a tenth (1/10) of the
+ * sample rate is where notes become unbearable.
+ */
+#ifndef AUDIO_DAC_SAMPLE_RATE
+# define AUDIO_DAC_SAMPLE_RATE 44100U
+#endif
+
+/**
+ * The number of tones that can be played simultaneously. If too high a value
+ * is used here, the keyboard will freeze and glitch-out when that many tones
+ * are being played.
+ */
+#ifndef AUDIO_MAX_SIMULTANEOUS_TONES
+# define AUDIO_MAX_SIMULTANEOUS_TONES 2
+#endif
+
+/**
+ * The default value of the DAC when not playing anything. Certain hardware
+ * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here.
+ * Since multiple added sine waves tend to oscillate around the midpoint,
+ * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a
+ * reasonable default value.
+ */
+#ifndef AUDIO_DAC_OFF_VALUE
+# define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2
+#endif
+
+#if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX
+# error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX"
+#endif
+
+/**
+ *user overridable sample generation/processing
+ */
+uint16_t dac_value_generate(void);
diff --git a/quantum/audio/driver_chibios_dac_additive.c b/quantum/audio/driver_chibios_dac_additive.c
new file mode 100644
index 0000000000..db304adb87
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac_additive.c
@@ -0,0 +1,335 @@
+/* Copyright 2016-2019 Jack Humbert
+ * Copyright 2020 JohSchneider
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "audio.h"
+#include <ch.h>
+#include <hal.h>
+
+/*
+ Audio Driver: DAC
+
+ which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA
+
+ it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate'
+
+ this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis
+*/
+
+#if !defined(AUDIO_PIN)
+# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options."
+#endif
+#if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE)
+# pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though."
+#endif
+
+#if !defined(AUDIO_PIN_ALT)
+// no ALT pin defined is valid, but the c-ifs below need some value set
+# define AUDIO_PIN_ALT PAL_NOLINE
+#endif
+
+#if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
+# define AUDIO_DAC_SAMPLE_WAVEFORM_SINE
+#endif
+
+#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE
+/* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0
+ */
+static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = {
+ // 256 values, max 4095
+ 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe,
+ 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1};
+#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE
+#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
+static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = {
+ // 256 values, max 4095
+ 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf,
+ 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
+#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
+#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
+static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = {
+ [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and
+ [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half
+};
+#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
+/*
+// four steps: 0, 1/3, 2/3 and 1
+static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = {
+ [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0,
+ [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3,
+ [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3,
+ [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX,
+}
+*/
+#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
+static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
+
+static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE};
+
+/* keep track of the sample position for for each frequency */
+static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0};
+
+static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0};
+static uint8_t active_tones_snapshot_length = 0;
+
+typedef enum {
+ OUTPUT_SHOULD_START,
+ OUTPUT_RUN_NORMALLY,
+ // path 1: wait for zero, then change/update active tones
+ OUTPUT_TONES_CHANGED,
+ OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE,
+ // path 2: hardware should stop, wait for zero then turn output off = stop the timer
+ OUTPUT_SHOULD_STOP,
+ OUTPUT_REACHED_ZERO_BEFORE_OFF,
+ OUTPUT_OFF,
+ OUTPUT_OFF_1,
+ OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level
+ number_of_output_states
+} output_states_t;
+output_states_t state = OUTPUT_OFF_2;
+
+/**
+ * Generation of the waveform being passed to the callback. Declared weak so users
+ * can override it with their own wave-forms/noises.
+ */
+__attribute__((weak)) uint16_t dac_value_generate(void) {
+ // DAC is running/asking for values but snapshot length is zero -> must be playing a pause
+ if (active_tones_snapshot_length == 0) {
+ return AUDIO_DAC_OFF_VALUE;
+ }
+
+ /* doing additive wave synthesis over all currently playing tones = adding up
+ * sine-wave-samples for each frequency, scaled by the number of active tones
+ */
+ uint16_t value = 0;
+ float frequency = 0.0f;
+
+ for (uint8_t i = 0; i < active_tones_snapshot_length; i++) {
+ /* Note: a user implementation does not have to rely on the active_tones_snapshot, but
+ * could directly query the active frequencies through audio_get_processed_frequency */
+ frequency = active_tones_snapshot[i];
+
+ dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3;
+ /*Note: the 2/3 are necessary to get the correct frequencies on the
+ * DAC output (as measured with an oscilloscope), since the gpt
+ * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback
+ * is called twice per conversion.*/
+
+ dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE);
+
+ // Wavetable generation/lookup
+ uint16_t dac_i = (uint16_t)dac_if[i];
+
+#if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE)
+ value += dac_buffer_sine[dac_i] / active_tones_snapshot_length;
+#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE)
+ value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length;
+#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
+ value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length;
+#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE)
+ value += dac_buffer_square[dac_i] / active_tones_snapshot_length;
+#endif
+ /*
+ // SINE
+ value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3;
+ // TRIANGLE
+ value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3;
+ // SQUARE
+ value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3;
+ //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P
+ */
+
+ // STAIRS (mostly usefully as test-pattern)
+ // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length;
+ }
+
+ return value;
+}
+
+/**
+ * DAC streaming callback. Does all of the main computing for playing songs.
+ *
+ * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'.
+ */
+static void dac_end(DACDriver *dacp) {
+ dacsample_t *sample_p = (dacp)->samples;
+
+ // work on the other half of the buffer
+ if (dacIsBufferComplete(dacp)) {
+ sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index'
+ }
+
+ for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) {
+ if (OUTPUT_OFF <= state) {
+ sample_p[s] = AUDIO_DAC_OFF_VALUE;
+ continue;
+ } else {
+ sample_p[s] = dac_value_generate();
+ }
+
+ /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX)
+ * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX
+ * * *
+ * * *
+ * ---------------------------------------------------------
+ * * * } AUDIO_DAC_SAMPLE_MAX/100
+ * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE
+ * * * } AUDIO_DAC_SAMPLE_MAX/100
+ * ---------------------------------------------------------
+ * *
+ * * *
+ * * *
+ * =====*=*================================================= 0x0
+ */
+ if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below
+ (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above
+ ) {
+ if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) {
+ state = OUTPUT_RUN_NORMALLY;
+ } else if (OUTPUT_TONES_CHANGED == state) {
+ state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE;
+ } else if (OUTPUT_SHOULD_STOP == state) {
+ state = OUTPUT_REACHED_ZERO_BEFORE_OFF;
+ }
+ }
+
+ // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover
+ if (OUTPUT_SHOULD_START == state) {
+ sample_p[s] = AUDIO_DAC_OFF_VALUE;
+ }
+
+ if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) {
+ uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones());
+ active_tones_snapshot_length = 0;
+ // update the snapshot - once, and only on occasion that something changed;
+ // -> saves cpu cycles (?)
+ for (uint8_t i = 0; i < active_tones; i++) {
+ float freq = audio_get_processed_frequency(i);
+ if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step
+ active_tones_snapshot[active_tones_snapshot_length++] = freq;
+ }
+ }
+
+ if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) {
+ state = OUTPUT_OFF;
+ }
+ if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) {
+ state = OUTPUT_RUN_NORMALLY;
+ }
+ }
+ }
+
+ // update audio internal state (note position, current_note, ...)
+ if (audio_update_state()) {
+ if (OUTPUT_SHOULD_STOP != state) {
+ state = OUTPUT_TONES_CHANGED;
+ }
+ }
+
+ if (OUTPUT_OFF <= state) {
+ if (OUTPUT_OFF_2 == state) {
+ // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE
+ gptStopTimer(&GPTD6);
+ } else {
+ state++;
+ }
+ }
+}
+
+static void dac_error(DACDriver *dacp, dacerror_t err) {
+ (void)dacp;
+ (void)err;
+
+ chSysHalt("DAC failure. halp");
+}
+
+static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3,
+ .callback = NULL,
+ .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
+ .dier = 0U};
+
+static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
+
+/**
+ * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
+ * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
+ * to be a third of what we expect.
+ *
+ * Here are all the values for DAC_TRG (TSEL in the ref manual)
+ * TIM15_TRGO 0b011
+ * TIM2_TRGO 0b100
+ * TIM3_TRGO 0b001
+ * TIM6_TRGO 0b000
+ * TIM7_TRGO 0b010
+ * EXTI9 0b110
+ * SWTRIG 0b111
+ */
+static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};
+
+void audio_driver_initialize() {
+ if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
+ palSetLineMode(A4, PAL_MODE_INPUT_ANALOG);
+ dacStart(&DACD1, &dac_conf);
+ }
+ if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
+ palSetLineMode(A5, PAL_MODE_INPUT_ANALOG);
+ dacStart(&DACD2, &dac_conf);
+ }
+
+ /* enable the output buffer, to directly drive external loads with no additional circuitry
+ *
+ * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
+ * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
+ * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
+ *
+ * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
+ * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
+ */
+ DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
+ DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
+
+ if (AUDIO_PIN == A4) {
+ dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
+ } else if (AUDIO_PIN == A5) {
+ dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
+ }
+
+ // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE
+#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
+ if (AUDIO_PIN_ALT == A4) {
+ dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
+ } else if (AUDIO_PIN_ALT == A5) {
+ dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
+ }
+#endif
+
+ gptStart(&GPTD6, &gpt6cfg1);
+}
+
+void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; }
+
+void audio_driver_start(void) {
+ gptStartContinuous(&GPTD6, 2U);
+
+ for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) {
+ dac_if[i] = 0.0f;
+ active_tones_snapshot[i] = 0.0f;
+ }
+ active_tones_snapshot_length = 0;
+ state = OUTPUT_SHOULD_START;
+}
diff --git a/quantum/audio/driver_chibios_dac_basic.c b/quantum/audio/driver_chibios_dac_basic.c
new file mode 100644
index 0000000000..fac6513506
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac_basic.c
@@ -0,0 +1,245 @@
+/* Copyright 2016-2020 Jack Humbert
+ * Copyright 2020 JohSchneider
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "audio.h"
+#include "ch.h"
+#include "hal.h"
+
+/*
+ Audio Driver: DAC
+
+ which utilizes both channels of the DAC unit many STM32 are equipped with to output a modulated square-wave, from precomputed samples stored in a buffer, which is passed to the hardware through DMA
+
+ this driver can either be used to drive to separate speakers, wired to A4+Gnd and A5+Gnd, which allows two tones to be played simultaneously
+ OR
+ one speaker wired to A4+A5 with the AUDIO_PIN_ALT_AS_NEGATIVE define set - see docs/feature_audio
+
+*/
+
+#if !defined(AUDIO_PIN)
+# pragma message "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC basic)' for available options."
+// TODO: make this an 'error' instead; go through a breaking change, and add AUDIO_PIN A5 to all keyboards currently using AUDIO on STM32 based boards? - for now: set the define here
+# define AUDIO_PIN A5
+#endif
+// check configuration for ONE speaker, connected to both DAC pins
+#if defined(AUDIO_PIN_ALT_AS_NEGATIVE) && !defined(AUDIO_PIN_ALT)
+# error "Audio feature: AUDIO_PIN_ALT_AS_NEGATIVE set, but no pin configured as AUDIO_PIN_ALT"
+#endif
+
+#ifndef AUDIO_PIN_ALT
+// no ALT pin defined is valid, but the c-ifs below need some value set
+# define AUDIO_PIN_ALT -1
+#endif
+
+#if !defined(AUDIO_STATE_TIMER)
+# define AUDIO_STATE_TIMER GPTD8
+#endif
+
+// square-wave
+static const dacsample_t dac_buffer_1[AUDIO_DAC_BUFFER_SIZE] = {
+ // First half is max, second half is 0
+ [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = AUDIO_DAC_SAMPLE_MAX,
+ [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = 0,
+};
+
+// square-wave
+static const dacsample_t dac_buffer_2[AUDIO_DAC_BUFFER_SIZE] = {
+ // opposite of dac_buffer above
+ [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0,
+ [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX,
+};
+
+GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
+ .callback = NULL,
+ .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
+ .dier = 0U};
+GPTConfig gpt7cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
+ .callback = NULL,
+ .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
+ .dier = 0U};
+
+static void gpt_audio_state_cb(GPTDriver *gptp);
+GPTConfig gptStateUpdateCfg = {.frequency = 10,
+ .callback = gpt_audio_state_cb,
+ .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
+ .dier = 0U};
+
+static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
+static const DACConfig dac_conf_ch2 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
+
+/**
+ * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
+ * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
+ * to be a third of what we expect.
+ *
+ * Here are all the values for DAC_TRG (TSEL in the ref manual)
+ * TIM15_TRGO 0b011
+ * TIM2_TRGO 0b100
+ * TIM3_TRGO 0b001
+ * TIM6_TRGO 0b000
+ * TIM7_TRGO 0b010
+ * EXTI9 0b110
+ * SWTRIG 0b111
+ */
+static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)};
+static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)};
+
+void channel_1_start(void) {
+ gptStart(&GPTD6, &gpt6cfg1);
+ gptStartContinuous(&GPTD6, 2U);
+ palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
+}
+
+void channel_1_stop(void) {
+ gptStopTimer(&GPTD6);
+ palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);
+ palSetPad(GPIOA, 4);
+}
+
+static float channel_1_frequency = 0.0f;
+void channel_1_set_frequency(float freq) {
+ channel_1_frequency = freq;
+
+ channel_1_stop();
+ if (freq <= 0.0) // a pause/rest has freq=0
+ return;
+
+ gpt6cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
+ channel_1_start();
+}
+float channel_1_get_frequency(void) { return channel_1_frequency; }
+
+void channel_2_start(void) {
+ gptStart(&GPTD7, &gpt7cfg1);
+ gptStartContinuous(&GPTD7, 2U);
+ palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
+}
+
+void channel_2_stop(void) {
+ gptStopTimer(&GPTD7);
+ palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL);
+ palSetPad(GPIOA, 5);
+}
+
+static float channel_2_frequency = 0.0f;
+void channel_2_set_frequency(float freq) {
+ channel_2_frequency = freq;
+
+ channel_2_stop();
+ if (freq <= 0.0) // a pause/rest has freq=0
+ return;
+
+ gpt7cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
+ channel_2_start();
+}
+float channel_2_get_frequency(void) { return channel_2_frequency; }
+
+static void gpt_audio_state_cb(GPTDriver *gptp) {
+ if (audio_update_state()) {
+#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
+ // one piezo/speaker connected to both audio pins, the generated square-waves are inverted
+ channel_1_set_frequency(audio_get_processed_frequency(0));
+ channel_2_set_frequency(audio_get_processed_frequency(0));
+
+#else // two separate audio outputs/speakers
+ // primary speaker on A4, optional secondary on A5
+ if (AUDIO_PIN == A4) {
+ channel_1_set_frequency(audio_get_processed_frequency(0));
+ if (AUDIO_PIN_ALT == A5) {
+ if (audio_get_number_of_active_tones() > 1) {
+ channel_2_set_frequency(audio_get_processed_frequency(1));
+ } else {
+ channel_2_stop();
+ }
+ }
+ }
+
+ // primary speaker on A5, optional secondary on A4
+ if (AUDIO_PIN == A5) {
+ channel_2_set_frequency(audio_get_processed_frequency(0));
+ if (AUDIO_PIN_ALT == A4) {
+ if (audio_get_number_of_active_tones() > 1) {
+ channel_1_set_frequency(audio_get_processed_frequency(1));
+ } else {
+ channel_1_stop();
+ }
+ }
+ }
+#endif
+ }
+}
+
+void audio_driver_initialize() {
+ if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
+ palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
+ dacStart(&DACD1, &dac_conf_ch1);
+
+ // initial setup of the dac-triggering timer is still required, even
+ // though it gets reconfigured and restarted later on
+ gptStart(&GPTD6, &gpt6cfg1);
+ }
+
+ if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
+ palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
+ dacStart(&DACD2, &dac_conf_ch2);
+
+ gptStart(&GPTD7, &gpt7cfg1);
+ }
+
+ /* enable the output buffer, to directly drive external loads with no additional circuitry
+ *
+ * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
+ * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
+ * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
+ *
+ * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
+ * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
+ */
+ DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
+ DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
+
+ // start state-updater
+ gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg);
+}
+
+void audio_driver_stop(void) {
+ if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
+ gptStopTimer(&GPTD6);
+
+ // stop the ongoing conversion and put the output in a known state
+ dacStopConversion(&DACD1);
+ dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
+ }
+
+ if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
+ gptStopTimer(&GPTD7);
+
+ dacStopConversion(&DACD2);
+ dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
+ }
+ gptStopTimer(&AUDIO_STATE_TIMER);
+}
+
+void audio_driver_start(void) {
+ if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
+ dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE);
+ }
+ if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
+ dacStartConversion(&DACD2, &dac_conv_grp_ch2, (dacsample_t *)dac_buffer_2, AUDIO_DAC_BUFFER_SIZE);
+ }
+ gptStartContinuous(&AUDIO_STATE_TIMER, 2U);
+}
diff --git a/quantum/audio/driver_chibios_pwm.h b/quantum/audio/driver_chibios_pwm.h
new file mode 100644
index 0000000000..86cab916e1
--- /dev/null
+++ b/quantum/audio/driver_chibios_pwm.h
@@ -0,0 +1,40 @@
+/* Copyright 2020 Jack Humbert
+ * Copyright 2020 JohSchneider
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#if !defined(AUDIO_PWM_DRIVER)
+// NOTE: Timer2 seems to be used otherwise in QMK, otherwise we could default to A5 (= TIM2_CH1, with PWMD2 and alternate-function(1))
+# define AUDIO_PWM_DRIVER PWMD1
+#endif
+
+#if !defined(AUDIO_PWM_CHANNEL)
+// NOTE: sticking to the STM data-sheet numbering: TIMxCH1 to TIMxCH4
+// default: STM32F303CC PA8+TIM1_CH1 -> 1
+# define AUDIO_PWM_CHANNEL 1
+#endif
+
+#if !defined(AUDIO_PWM_PAL_MODE)
+// pin-alternate function: see the data-sheet for which pin needs what AF to connect to TIMx_CHy
+// default: STM32F303CC PA8+TIM1_CH1 -> 6
+# define AUDIO_PWM_PAL_MODE 6
+#endif
+
+#if !defined(AUDIO_STATE_TIMER)
+// timer used to trigger updates in the audio-system, configured/enabled in chibios mcuconf.
+// Tim6 is the default for "larger" STMs, smaller ones might not have this one (enabled) and need to switch to a different one (e.g.: STM32F103 has only Tim1-Tim4)
+# define AUDIO_STATE_TIMER GPTD6
+#endif
diff --git a/quantum/audio/driver_chibios_pwm_hardware.c b/quantum/audio/driver_chibios_pwm_hardware.c
new file mode 100644
index 0000000000..3c7d89b290
--- /dev/null
+++ b/quantum/audio/driver_chibios_pwm_hardware.c
@@ -0,0 +1,144 @@
+/* Copyright 2020 Jack Humbert
+ * Copyright 2020 JohSchneider
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+Audio Driver: PWM
+
+the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
+
+this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware.
+The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function.
+
+ */
+
+#include "audio.h"
+#include "ch.h"
+#include "hal.h"
+
+#if !defined(AUDIO_PIN)
+# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
+#endif
+
+extern bool playing_note;
+extern bool playing_melody;
+extern uint8_t note_timbre;
+
+static PWMConfig pwmCFG = {
+ .frequency = 100000, /* PWM clock frequency */
+ // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
+ .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
+ .callback = NULL, /* no callback, the hardware directly toggles the pin */
+ .channels =
+ {
+#if AUDIO_PWM_CHANNEL == 4
+ {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIMx_CH1 */
+ {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
+ {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
+ {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */
+#elif AUDIO_PWM_CHANNEL == 3
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */
+ {PWM_OUTPUT_DISABLED, NULL}
+#elif AUDIO_PWM_CHANNEL == 2
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_DISABLED, NULL}
+#else /*fallback to CH1 */
+ {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_DISABLED, NULL}
+#endif
+ },
+};
+
+static float channel_1_frequency = 0.0f;
+void channel_1_set_frequency(float freq) {
+ channel_1_frequency = freq;
+
+ if (freq <= 0.0) // a pause/rest has freq=0
+ return;
+
+ pwmcnt_t period = (pwmCFG.frequency / freq);
+ pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
+ pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
+ // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
+ PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
+}
+
+float channel_1_get_frequency(void) { return channel_1_frequency; }
+
+void channel_1_start(void) {
+ pwmStop(&AUDIO_PWM_DRIVER);
+ pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
+}
+
+void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); }
+
+static void gpt_callback(GPTDriver *gptp);
+GPTConfig gptCFG = {
+ /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
+ the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
+ the tempo (which might vary!) is in bpm (beats per minute)
+ therefore: if the timer ticks away at .frequency = (60*64)Hz,
+ and the .interval counts from 64 downwards - audio_update_state is
+ called just often enough to not miss any notes
+ */
+ .frequency = 60 * 64,
+ .callback = gpt_callback,
+};
+
+void audio_driver_initialize(void) {
+ pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
+
+ // connect the AUDIO_PIN to the PWM hardware
+#if defined(USE_GPIOV1) // STM32F103C8
+ palSetLineMode(AUDIO_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
+#else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
+ palSetLineMode(AUDIO_PIN, PAL_STM32_MODE_ALTERNATE | PAL_STM32_ALTERNATE(AUDIO_PWM_PAL_MODE));
+#endif
+
+ gptStart(&AUDIO_STATE_TIMER, &gptCFG);
+}
+
+void audio_driver_start(void) {
+ channel_1_stop();
+ channel_1_start();
+
+ if (playing_note || playing_melody) {
+ gptStartContinuous(&AUDIO_STATE_TIMER, 64);
+ }
+}
+
+void audio_driver_stop(void) {
+ channel_1_stop();
+ gptStopTimer(&AUDIO_STATE_TIMER);
+}
+
+/* a regular timer task, that checks the note to be currently played
+ * and updates the pwm to output that frequency
+ */
+static void gpt_callback(GPTDriver *gptp) {
+ float freq; // TODO: freq_alt
+
+ if (audio_update_state()) {
+ freq = audio_get_processed_frequency(0); // freq_alt would be index=1
+ channel_1_set_frequency(freq);
+ }
+}
diff --git a/quantum/audio/driver_chibios_pwm_software.c b/quantum/audio/driver_chibios_pwm_software.c
new file mode 100644
index 0000000000..15c3e98b6a
--- /dev/null
+++ b/quantum/audio/driver_chibios_pwm_software.c
@@ -0,0 +1,164 @@
+/* Copyright 2020 Jack Humbert
+ * Copyright 2020 JohSchneider
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+Audio Driver: PWM
+
+the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
+
+this driver uses the chibios-PWM system to produce a square-wave on any given output pin in software
+- a pwm callback is used to set/clear the configured pin.
+
+ */
+#include "audio.h"
+#include "ch.h"
+#include "hal.h"
+
+#if !defined(AUDIO_PIN)
+# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
+#endif
+extern bool playing_note;
+extern bool playing_melody;
+extern uint8_t note_timbre;
+
+static void pwm_audio_period_callback(PWMDriver *pwmp);
+static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp);
+
+static PWMConfig pwmCFG = {
+ .frequency = 100000, /* PWM clock frequency */
+ // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
+ .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
+ .callback = pwm_audio_period_callback,
+ .channels =
+ {
+ // software-PWM just needs another callback on any channel
+ {PWM_OUTPUT_ACTIVE_HIGH, pwm_audio_channel_interrupt_callback}, /* channel 0 -> TIMx_CH1 */
+ {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
+ {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
+ {PWM_OUTPUT_DISABLED, NULL} /* channel 3 -> TIMx_CH4 */
+ },
+};
+
+static float channel_1_frequency = 0.0f;
+void channel_1_set_frequency(float freq) {
+ channel_1_frequency = freq;
+
+ if (freq <= 0.0) // a pause/rest has freq=0
+ return;
+
+ pwmcnt_t period = (pwmCFG.frequency / freq);
+ pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
+
+ pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
+ // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
+ PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
+}
+
+float channel_1_get_frequency(void) { return channel_1_frequency; }
+
+void channel_1_start(void) {
+ pwmStop(&AUDIO_PWM_DRIVER);
+ pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
+
+ pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER);
+ pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
+}
+
+void channel_1_stop(void) {
+ pwmStop(&AUDIO_PWM_DRIVER);
+
+ palClearLine(AUDIO_PIN); // leave the line low, after last note was played
+
+#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
+ palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played
+#endif
+}
+
+// generate a PWM signal on any pin, not necessarily the one connected to the timer
+static void pwm_audio_period_callback(PWMDriver *pwmp) {
+ (void)pwmp;
+ palClearLine(AUDIO_PIN);
+
+#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
+ palSetLine(AUDIO_PIN_ALT);
+#endif
+}
+static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp) {
+ (void)pwmp;
+ if (channel_1_frequency > 0) {
+ palSetLine(AUDIO_PIN); // generate a PWM signal on any pin, not necessarily the one connected to the timer
+#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
+ palClearLine(AUDIO_PIN_ALT);
+#endif
+ }
+}
+
+static void gpt_callback(GPTDriver *gptp);
+GPTConfig gptCFG = {
+ /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
+ the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
+ the tempo (which might vary!) is in bpm (beats per minute)
+ therefore: if the timer ticks away at .frequency = (60*64)Hz,
+ and the .interval counts from 64 downwards - audio_update_state is
+ called just often enough to not miss anything
+ */
+ .frequency = 60 * 64,
+ .callback = gpt_callback,
+};
+
+void audio_driver_initialize(void) {
+ pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
+
+ palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL);
+ palClearLine(AUDIO_PIN);
+
+#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
+ palSetLineMode(AUDIO_PIN_ALT, PAL_MODE_OUTPUT_PUSHPULL);
+ palClearLine(AUDIO_PIN_ALT);
+#endif
+
+ pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks
+ pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
+
+ gptStart(&AUDIO_STATE_TIMER, &gptCFG);
+}
+
+void audio_driver_start(void) {
+ channel_1_stop();
+ channel_1_start();
+
+ if (playing_note || playing_melody) {
+ gptStartContinuous(&AUDIO_STATE_TIMER, 64);
+ }
+}
+
+void audio_driver_stop(void) {
+ channel_1_stop();
+ gptStopTimer(&AUDIO_STATE_TIMER);
+}
+
+/* a regular timer task, that checks the note to be currently played
+ * and updates the pwm to output that frequency
+ */
+static void gpt_callback(GPTDriver *gptp) {
+ float freq; // TODO: freq_alt
+
+ if (audio_update_state()) {
+ freq = audio_get_processed_frequency(0); // freq_alt would be index=1
+ channel_1_set_frequency(freq);
+ }
+}
diff --git a/quantum/audio/musical_notes.h b/quantum/audio/musical_notes.h
index 66aafd27c7..ddd7d374f5 100644
--- a/quantum/audio/musical_notes.h
+++ b/quantum/audio/musical_notes.h
@@ -1,4 +1,5 @@
/* Copyright 2016 Jack Humbert
+ * Copyright 2020 JohSchneider
*
* 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
@@ -13,12 +14,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
#pragma once
-// Tempo Placeholder
#ifndef TEMPO_DEFAULT
-# define TEMPO_DEFAULT 100
+# define TEMPO_DEFAULT 120
+// in beats-per-minute
#endif
#define SONG(notes...) \
@@ -27,12 +27,14 @@
// Note Types
#define MUSICAL_NOTE(note, duration) \
{ (NOTE##note), duration }
+
#define BREVE_NOTE(note) MUSICAL_NOTE(note, 128)
#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64)
#define HALF_NOTE(note) MUSICAL_NOTE(note, 32)
#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16)
#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8)
#define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4)
+#define THIRTYSECOND_NOTE(note) MUSICAL_NOTE(note, 2)
#define BREVE_DOT_NOTE(note) MUSICAL_NOTE(note, 128 + 64)
#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64 + 32)
@@ -40,6 +42,9 @@
#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16 + 8)
#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8 + 4)
#define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4 + 2)
+#define THIRTYSECOND_DOT_NOTE(note) MUSICAL_NOTE(note, 2 + 1)
+// duration of 64 units == one beat == one whole note
+// with a tempo of 60bpm this comes to a length of one second
// Note Type Shortcuts
#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration)
@@ -49,57 +54,52 @@
#define Q__NOTE(n) QUARTER_NOTE(n)
#define E__NOTE(n) EIGHTH_NOTE(n)
#define S__NOTE(n) SIXTEENTH_NOTE(n)
+#define T__NOTE(n) THIRTYSECOND_NOTE(n)
#define BD_NOTE(n) BREVE_DOT_NOTE(n)
#define WD_NOTE(n) WHOLE_DOT_NOTE(n)
#define HD_NOTE(n) HALF_DOT_NOTE(n)
#define QD_NOTE(n) QUARTER_DOT_NOTE(n)
#define ED_NOTE(n) EIGHTH_DOT_NOTE(n)
#define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n)
+#define TD_NOTE(n) THIRTYSECOND_DOT_NOTE(n)
// Note Timbre
// Changes how the notes sound
-#define TIMBRE_12 0.125f
-#define TIMBRE_25 0.250f
-#define TIMBRE_50 0.500f
-#define TIMBRE_75 0.750f
+#define TIMBRE_12 12
+#define TIMBRE_25 25
+#define TIMBRE_50 50
+#define TIMBRE_75 75
#ifndef TIMBRE_DEFAULT
# define TIMBRE_DEFAULT TIMBRE_50
#endif
// Notes - # = Octave
-#ifdef __arm__
-# define NOTE_REST 1.00f
-#else
-# define NOTE_REST 0.00f
-#endif
-
-/* These notes are currently bugged
-#define NOTE_C0 16.35f
-#define NOTE_CS0 17.32f
-#define NOTE_D0 18.35f
-#define NOTE_DS0 19.45f
-#define NOTE_E0 20.60f
-#define NOTE_F0 21.83f
-#define NOTE_FS0 23.12f
-#define NOTE_G0 24.50f
-#define NOTE_GS0 25.96f
-#define NOTE_A0 27.50f
-#define NOTE_AS0 29.14f
-#define NOTE_B0 30.87f
-#define NOTE_C1 32.70f
-#define NOTE_CS1 34.65f
-#define NOTE_D1 36.71f
-#define NOTE_DS1 38.89f
-#define NOTE_E1 41.20f
-#define NOTE_F1 43.65f
-#define NOTE_FS1 46.25f
-#define NOTE_G1 49.00f
-#define NOTE_GS1 51.91f
-#define NOTE_A1 55.00f
-#define NOTE_AS1 58.27f
-*/
+#define NOTE_REST 0.00f
+#define NOTE_C0 16.35f
+#define NOTE_CS0 17.32f
+#define NOTE_D0 18.35f
+#define NOTE_DS0 19.45f
+#define NOTE_E0 20.60f
+#define NOTE_F0 21.83f
+#define NOTE_FS0 23.12f
+#define NOTE_G0 24.50f
+#define NOTE_GS0 25.96f
+#define NOTE_A0 27.50f
+#define NOTE_AS0 29.14f
+#define NOTE_B0 30.87f
+#define NOTE_C1 32.70f
+#define NOTE_CS1 34.65f
+#define NOTE_D1 36.71f
+#define NOTE_DS1 38.89f
+#define NOTE_E1 41.20f
+#define NOTE_F1 43.65f
+#define NOTE_FS1 46.25f
+#define NOTE_G1 49.00f
+#define NOTE_GS1 51.91f
+#define NOTE_A1 55.00f
+#define NOTE_AS1 58.27f
#define NOTE_B1 61.74f
#define NOTE_C2 65.41f
#define NOTE_CS2 69.30f
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h
index d48c11b7d1..b54b397e1c 100644
--- a/quantum/audio/song_list.h
+++ b/quantum/audio/song_list.h
@@ -140,13 +140,11 @@
H__NOTE(_BF5), H__NOTE(_C6), H__NOTE(_DF6), H__NOTE(_A5), H__NOTE(_BF5), H__NOTE(_GF5), W__NOTE(_F5), W__NOTE(_F5), W__NOTE(_F5), W__NOTE(_F5), H__NOTE(_GF5), H__NOTE(_F5), H__NOTE(_EF5), H__NOTE(_C5), B__NOTE(_DF5), W__NOTE(_BF4), Q__NOTE(_BF5), Q__NOTE(_C6), Q__NOTE(_DF6), Q__NOTE(_A5), Q__NOTE(_BF5), Q__NOTE(_A5), Q__NOTE(_GS5), Q__NOTE(_A5), Q__NOTE(_C6), Q__NOTE(_BF5), Q__NOTE(_GF5), Q__NOTE(_F5), Q__NOTE(_GF5), Q__NOTE(_E5), Q__NOTE(_F5), Q__NOTE(_BF5), Q__NOTE(_A5), Q__NOTE(_AF5), Q__NOTE(_G5), Q__NOTE(_GF5), Q__NOTE(_F5), Q__NOTE(_E5), Q__NOTE(_EF5), Q__NOTE(_D5), Q__NOTE(_DF5), Q__NOTE(_C5), Q__NOTE(_DF5), Q__NOTE(_C5), Q__NOTE(_B4), Q__NOTE(_C5), Q__NOTE(_F5), Q__NOTE(_E5), Q__NOTE(_EF5), B__NOTE(_DF5), W__NOTE(_BF4), W__NOTE(_BF5), W__NOTE(_BF5), W__NOTE(_BF5), BD_NOTE(_AF5), W__NOTE(_DF5), H__NOTE(_BF4), H__NOTE(_C5), H__NOTE(_DF5), H__NOTE(_GF5), H__NOTE(_GF5), BD_NOTE(_F5), W__NOTE(_EF5), H__NOTE(_F5), H__NOTE(_EF5), H__NOTE(_DF5), H__NOTE(_A4), B__NOTE(_AF4), \
W__NOTE(_DF5), W__NOTE(_EF5), H__NOTE(_F5), H__NOTE(_EF5), H__NOTE(_DF5), H__NOTE(_EF5), BD_NOTE(_F5),
-
/* Title: State Anthem of the Soviet Union
* Author/Composer: Alexander Alexandrov
* License: Public Domain
*/
-#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),
+#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),
/* Removed sounds
+ This list is here solely for compatibility, so that removed songs don't just break things
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c
index 1592618be4..d43fb8d169 100644
--- a/quantum/audio/voices.c
+++ b/quantum/audio/voices.c
@@ -1,4 +1,5 @@
/* Copyright 2016 Jack Humbert
+ * Copyright 2020 JohSchneider
*
* 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
@@ -17,36 +18,73 @@
#include "audio.h"
#include <stdlib.h>
-// these are imported from audio.c
-extern uint16_t envelope_index;
-extern float note_timbre;
-extern float polyphony_rate;
-extern bool glissando;
+uint8_t note_timbre = TIMBRE_DEFAULT;
+bool glissando = false;
+bool vibrato = false;
+float vibrato_strength = 0.5;
+float vibrato_rate = 0.125;
+uint16_t voices_timer = 0;
+
+#ifdef AUDIO_VOICE_DEFAULT
+voice_type voice = AUDIO_VOICE_DEFAULT;
+#else
voice_type voice = default_voice;
+#endif
void set_voice(voice_type v) { voice = v; }
void voice_iterate() { voice = (voice + 1) % number_of_voices; }
-
void voice_deiterate() { voice = (voice - 1 + number_of_voices) % number_of_voices; }
+#ifdef AUDIO_VOICES
+float mod(float a, int b) {
+ float r = fmod(a, b);
+ return r < 0 ? r + b : r;
+}
+
+// Effect: 'vibrate' a given target frequency slightly above/below its initial value
+float voice_add_vibrato(float average_freq) {
+ float vibrato_counter = mod(timer_read() / (100 * vibrato_rate), VIBRATO_LUT_LENGTH);
+
+ return average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
+}
+
+// Effect: 'slides' the 'frequency' from the starting-point, to the target frequency
+float voice_add_glissando(float from_freq, float to_freq) {
+ if (to_freq != 0 && from_freq < to_freq && from_freq < to_freq * pow(2, -440 / to_freq / 12 / 2)) {
+ return from_freq * pow(2, 440 / from_freq / 12 / 2);
+ } else if (to_freq != 0 && from_freq > to_freq && from_freq > to_freq * pow(2, 440 / to_freq / 12 / 2)) {
+ return from_freq * pow(2, -440 / from_freq / 12 / 2);
+ } else {
+ return to_freq;
+ }
+}
+#endif
+
float voice_envelope(float frequency) {
// envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz
- __attribute__((unused)) uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency));
+// __attribute__((unused)) uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency));
+#ifdef AUDIO_VOICES
+ uint16_t envelope_index = timer_elapsed(voices_timer); // TODO: multiply in some factor?
+ uint16_t compensated_index = envelope_index / 100; // TODO: correct factor would be?
+#endif
switch (voice) {
case default_voice:
- glissando = false;
- note_timbre = TIMBRE_50;
- polyphony_rate = 0;
+ glissando = false;
+ // note_timbre = TIMBRE_50; //Note: leave the user the possibility to adjust the timbre with 'audio_set_timbre'
break;
#ifdef AUDIO_VOICES
+ case vibrating:
+ glissando = false;
+ vibrato = true;
+ break;
+
case something:
- glissando = false;
- polyphony_rate = 0;
+ glissando = false;
switch (compensated_index) {
case 0 ... 9:
note_timbre = TIMBRE_12;
@@ -57,24 +95,23 @@ float voice_envelope(float frequency) {
break;
case 20 ... 200:
- note_timbre = .125 + .125;
+ note_timbre = 12 + 12;
break;
default:
- note_timbre = .125;
+ note_timbre = 12;
break;
}
break;
case drums:
- glissando = false;
- polyphony_rate = 0;
+ glissando = false;
// switch (compensated_index) {
// case 0 ... 10:
- // note_timbre = 0.5;
+ // note_timbre = 50;
// break;
// case 11 ... 20:
- // note_timbre = 0.5 * (21 - compensated_index) / 10;
+ // note_timbre = 50 * (21 - compensated_index) / 10;
// break;
// default:
// note_timbre = 0;
@@ -88,10 +125,10 @@ float voice_envelope(float frequency) {
frequency = (rand() % (int)(40)) + 60;
switch (envelope_index) {
case 0 ... 10:
- note_timbre = 0.5;
+ note_timbre = 50;
break;
case 11 ... 20:
- note_timbre = 0.5 * (21 - envelope_index) / 10;
+ note_timbre = 50 * (21 - envelope_index) / 10;
break;
default:
note_timbre = 0;
@@ -103,10 +140,10 @@ float voice_envelope(float frequency) {
frequency = (rand() % (int)(1000)) + 1000;
switch (envelope_index) {
case 0 ... 5:
- note_timbre = 0.5;
+ note_timbre = 50;
break;
case 6 ... 20:
- note_timbre = 0.5 * (21 - envelope_index) / 15;
+ note_timbre = 50 * (21 - envelope_index) / 15;
break;
default:
note_timbre = 0;
@@ -118,10 +155,10 @@ float voice_envelope(float frequency) {
frequency = (rand() % (int)(2000)) + 3000;
switch (envelope_index) {
case 0 ... 15:
- note_timbre = 0.5;
+ note_timbre = 50;
break;
case 16 ... 20:
- note_timbre = 0.5 * (21 - envelope_index) / 5;
+ note_timbre = 50 * (21 - envelope_index) / 5;
break;
default:
note_timbre = 0;
@@ -133,10 +170,10 @@ float voice_envelope(float frequency) {
frequency = (rand() % (int)(2000)) + 3000;
switch (envelope_index) {
case 0 ... 35:
- note_timbre = 0.5;
+ note_timbre = 50;
break;
case 36 ... 50:
- note_timbre = 0.5 * (51 - envelope_index) / 15;
+ note_timbre = 50 * (51 - envelope_index) / 15;
break;
default:
note_timbre = 0;
@@ -145,8 +182,7 @@ float voice_envelope(float frequency) {
}
break;
case butts_fader:
- glissando = true;
- polyphony_rate = 0;
+ glissando = true;
switch (compensated_index) {
case 0 ... 9:
frequency = frequency / 4;
@@ -159,7 +195,7 @@ float voice_envelope(float frequency) {
break;
case 20 ... 200:
- note_timbre = .125 - pow(((float)compensated_index - 20) / (200 - 20), 2) * .125;
+ note_timbre = 12 - (uint8_t)(pow(((float)compensated_index - 20) / (200 - 20), 2) * 12.5);
break;
default:
@@ -169,7 +205,6 @@ float voice_envelope(float frequency) {
break;
// case octave_crunch:
- // polyphony_rate = 0;
// switch (compensated_index) {
// case 0 ... 9:
// case 20 ... 24:
@@ -187,14 +222,13 @@ float voice_envelope(float frequency) {
// default:
// note_timbre = TIMBRE_12;
- // break;
+ // break;
// }
// break;
case duty_osc:
// This slows the loop down a substantial amount, so higher notes may freeze
- glissando = true;
- polyphony_rate = 0;
+ glissando = true;
switch (compensated_index) {
default:
# define OCS_SPEED 10
@@ -202,38 +236,36 @@ float voice_envelope(float frequency) {
// sine wave is slow
// note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5;
// triangle wave is a bit faster
- note_timbre = (float)abs((compensated_index * OCS_SPEED % 3000) - 1500) * (OCS_AMP / 1500) + (1 - OCS_AMP) / 2;
+ note_timbre = (uint8_t)abs((compensated_index * OCS_SPEED % 3000) - 1500) * (OCS_AMP / 1500) + (1 - OCS_AMP) / 2;
break;
}
break;
case duty_octave_down:
- glissando = true;
- polyphony_rate = 0;
- note_timbre = (envelope_index % 2) * .125 + .375 * 2;
- if ((envelope_index % 4) == 0) note_timbre = 0.5;
+ glissando = true;
+ note_timbre = (uint8_t)(100 * (envelope_index % 2) * .125 + .375 * 2);
+ if ((envelope_index % 4) == 0) note_timbre = 50;
if ((envelope_index % 8) == 0) note_timbre = 0;
break;
case delayed_vibrato:
- glissando = true;
- polyphony_rate = 0;
- note_timbre = TIMBRE_50;
+ glissando = true;
+ note_timbre = TIMBRE_50;
# define VOICE_VIBRATO_DELAY 150
# define VOICE_VIBRATO_SPEED 50
switch (compensated_index) {
case 0 ... VOICE_VIBRATO_DELAY:
break;
default:
+
frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1)) / 1000 * VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)];
break;
}
break;
// case delayed_vibrato_octave:
- // polyphony_rate = 0;
// if ((envelope_index % 2) == 1) {
- // note_timbre = 0.55;
+ // note_timbre = 55;
// } else {
- // note_timbre = 0.45;
+ // note_timbre = 45;
// }
// #define VOICE_VIBRATO_DELAY 150
// #define VOICE_VIBRATO_SPEED 50
@@ -246,35 +278,64 @@ float voice_envelope(float frequency) {
// }
// break;
// case duty_fifth_down:
- // note_timbre = 0.5;
+ // note_timbre = TIMBRE_50;
// if ((envelope_index % 3) == 0)
- // note_timbre = 0.75;
+ // note_timbre = TIMBRE_75;
// break;
// case duty_fourth_down:
- // note_timbre = 0.0;
+ // note_timbre = 0;
// if ((envelope_index % 12) == 0)
- // note_timbre = 0.75;
+ // note_timbre = TIMBRE_75;
// if (((envelope_index % 12) % 4) != 1)
- // note_timbre = 0.75;
+ // note_timbre = TIMBRE_75;
// break;
// case duty_third_down:
- // note_timbre = 0.5;
+ // note_timbre = TIMBRE_50;
// if ((envelope_index % 5) == 0)
- // note_timbre = 0.75;
+ // note_timbre = TIMBRE_75;
// break;
// case duty_fifth_third_down:
- // note_timbre = 0.5;
+ // note_timbre = TIMBRE_50;
// if ((envelope_index % 5) == 0)
- // note_timbre = 0.75;
+ // note_timbre = TIMBRE_75;
// if ((envelope_index % 3) == 0)
- // note_timbre = 0.25;
+ // note_timbre = TIMBRE_25;
// break;
-#endif
+#endif // AUDIO_VOICES
default:
break;
}
+#ifdef AUDIO_VOICES
+ if (vibrato && (vibrato_strength > 0)) {
+ frequency = voice_add_vibrato(frequency);
+ }
+
+ if (glissando) {
+ // TODO: where to keep track of the start-frequency?
+ // frequency = voice_add_glissando(??, frequency);
+ }
+#endif // AUDIO_VOICES
+
return frequency;
}
+
+// Vibrato functions
+
+void voice_set_vibrato_rate(float rate) { vibrato_rate = rate; }
+void voice_increase_vibrato_rate(float change) { vibrato_rate *= change; }
+void voice_decrease_vibrato_rate(float change) { vibrato_rate /= change; }
+void voice_set_vibrato_strength(float strength) { vibrato_strength = strength; }
+void voice_increase_vibrato_strength(float change) { vibrato_strength *= change; }
+void voice_decrease_vibrato_strength(float change) { vibrato_strength /= change; }
+
+// Timbre functions
+
+void voice_set_timbre(uint8_t timbre) {
+ if ((timbre > 0) && (timbre < 100)) {
+ note_timbre = timbre;
+ }
+}
+uint8_t voice_get_timbre(void) { return note_timbre; }
diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h
index abafa2b404..7bd26b461f 100644
--- a/quantum/audio/voices.h
+++ b/quantum/audio/voices.h
@@ -1,4 +1,5 @@
/* Copyright 2016 Jack Humbert
+ * Copyright 2020 JohSchneider
*
* 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
@@ -29,6 +30,7 @@ float voice_envelope(float frequency);
typedef enum {
default_voice,
#ifdef AUDIO_VOICES
+ vibrating,
something,
drums,
butts_fader,
@@ -48,3 +50,21 @@ typedef enum {
void set_voice(voice_type v);
void voice_iterate(void);
void voice_deiterate(void);
+
+// Vibrato functions
+void voice_set_vibrato_rate(float rate);
+void voice_increase_vibrato_rate(float change);
+void voice_decrease_vibrato_rate(float change);
+void voice_set_vibrato_strength(float strength);
+void voice_increase_vibrato_strength(float change);
+void voice_decrease_vibrato_strength(float change);
+
+// Timbre functions
+/**
+ * @brief set the global timbre for tones to be played
+ * @note: only applies to pwm implementations - where it adjusts the duty-cycle
+ * @note: using any instrument from voices.[ch] other than 'default' may override the set value
+ * @param[in]: timbre: valid range is (0,100)
+ */
+void voice_set_timbre(uint8_t timbre);
+uint8_t voice_get_timbre(void);
diff --git a/quantum/audio/wave.h b/quantum/audio/wave.h
deleted file mode 100644
index 48210a944e..0000000000
--- a/quantum/audio/wave.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Copyright 2016 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <avr/io.h>
-#include <avr/interrupt.h>
-#include <avr/pgmspace.h>
-
-#define SINE_LENGTH 2048
-
-const uint8_t sinewave[] PROGMEM = // 2048 values
- {0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x93, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xbb,
- 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd5, 0xd5, 0xd5, 0xd5, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8,
- 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
- 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
- 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4,
- 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9d,
- 0x9d, 0x9d, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x94, 0x94, 0x93, 0x93, 0x93, 0x92, 0x92, 0x91, 0x91, 0x91, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x86, 0x86, 0x85, 0x85, 0x85, 0x84, 0x84, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, 0x7a, 0x7a, 0x7a, 0x79, 0x79, 0x78, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x75, 0x75, 0x75, 0x74, 0x74, 0x73, 0x73, 0x73, 0x72, 0x72, 0x71, 0x71, 0x71, 0x70, 0x70, 0x70, 0x6f, 0x6f, 0x6e, 0x6e, 0x6e, 0x6d, 0x6d, 0x6c, 0x6c, 0x6c, 0x6b, 0x6b, 0x6a, 0x6a, 0x6a, 0x69, 0x69, 0x69, 0x68, 0x68, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x62, 0x61, 0x61, 0x61, 0x60,
- 0x60, 0x5f, 0x5f, 0x5f, 0x5e, 0x5e, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5b, 0x5b, 0x5a, 0x5a, 0x5a, 0x59, 0x59, 0x59, 0x58, 0x58, 0x58, 0x57, 0x57, 0x56, 0x56, 0x56, 0x55, 0x55, 0x55, 0x54, 0x54, 0x53, 0x53, 0x53, 0x52, 0x52, 0x52, 0x51, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 0x4f, 0x4e, 0x4e, 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x4a, 0x4a, 0x49, 0x49, 0x49, 0x48, 0x48, 0x48, 0x47, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26, 0x26, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, 0x10, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xe, 0xe, 0xe, 0xe, 0xe, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8,
- 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
- 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xe, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46,
- 0x46, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f};
diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c
index 4d66da80ba..e47192de34 100644
--- a/quantum/backlight/backlight_avr.c
+++ b/quantum/backlight/backlight_avr.c
@@ -68,7 +68,7 @@
# define COMxx1 COM3A1
# define OCRxx OCR3A
# endif
-#elif (defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
+#elif (defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
# define HARDWARE_PWM
# define ICRx ICR1
# define TCCRxA TCCR1A
@@ -126,7 +126,7 @@
# define COMxx1 COM1B1
# define OCRxx OCR1B
# endif
-#elif !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
+#elif (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
// Timer 1 is not in use by Audio feature, Backlight can use it
# pragma message "Using hardware timer 1 with software PWM"
# define HARDWARE_PWM
@@ -145,7 +145,7 @@
# define OCIExA OCIE1A
# define OCRxx OCR1A
-#elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
+#elif (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6)
# pragma message "Using hardware timer 3 with software PWM"
// Timer 3 is not in use by Audio feature, Backlight can use it
# define HARDWARE_PWM
diff --git a/quantum/bitwise.c b/quantum/bitwise.c
new file mode 100644
index 0000000000..861cca0054
--- /dev/null
+++ b/quantum/bitwise.c
@@ -0,0 +1,123 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util.h"
+
+// bit population - return number of on-bit
+__attribute__((noinline)) uint8_t bitpop(uint8_t bits) {
+ uint8_t c;
+ for (c = 0; bits; c++) bits &= bits - 1;
+ return c;
+ /*
+ const uint8_t bit_count[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+ return bit_count[bits>>4] + bit_count[bits&0x0F]
+ */
+}
+
+uint8_t bitpop16(uint16_t bits) {
+ uint8_t c;
+ for (c = 0; bits; c++) bits &= bits - 1;
+ return c;
+}
+
+uint8_t bitpop32(uint32_t bits) {
+ uint8_t c;
+ for (c = 0; bits; c++) bits &= bits - 1;
+ return c;
+}
+
+// most significant on-bit - return highest location of on-bit
+// NOTE: return 0 when bit0 is on or all bits are off
+__attribute__((noinline)) uint8_t biton(uint8_t bits) {
+ uint8_t n = 0;
+ if (bits >> 4) {
+ bits >>= 4;
+ n += 4;
+ }
+ if (bits >> 2) {
+ bits >>= 2;
+ n += 2;
+ }
+ if (bits >> 1) {
+ bits >>= 1;
+ n += 1;
+ }
+ return n;
+}
+
+uint8_t biton16(uint16_t bits) {
+ uint8_t n = 0;
+ if (bits >> 8) {
+ bits >>= 8;
+ n += 8;
+ }
+ if (bits >> 4) {
+ bits >>= 4;
+ n += 4;
+ }
+ if (bits >> 2) {
+ bits >>= 2;
+ n += 2;
+ }
+ if (bits >> 1) {
+ bits >>= 1;
+ n += 1;
+ }
+ return n;
+}
+
+uint8_t biton32(uint32_t bits) {
+ uint8_t n = 0;
+ if (bits >> 16) {
+ bits >>= 16;
+ n += 16;
+ }
+ if (bits >> 8) {
+ bits >>= 8;
+ n += 8;
+ }
+ if (bits >> 4) {
+ bits >>= 4;
+ n += 4;
+ }
+ if (bits >> 2) {
+ bits >>= 2;
+ n += 2;
+ }
+ if (bits >> 1) {
+ bits >>= 1;
+ n += 1;
+ }
+ return n;
+}
+
+__attribute__((noinline)) uint8_t bitrev(uint8_t bits) {
+ bits = (bits & 0x0f) << 4 | (bits & 0xf0) >> 4;
+ bits = (bits & 0b00110011) << 2 | (bits & 0b11001100) >> 2;
+ bits = (bits & 0b01010101) << 1 | (bits & 0b10101010) >> 1;
+ return bits;
+}
+
+uint16_t bitrev16(uint16_t bits) {
+ bits = bitrev(bits & 0x00ff) << 8 | bitrev((bits & 0xff00) >> 8);
+ return bits;
+}
+
+uint32_t bitrev32(uint32_t bits) {
+ bits = (uint32_t)bitrev16(bits & 0x0000ffff) << 16 | bitrev16((bits & 0xffff0000) >> 16);
+ return bits;
+}
diff --git a/quantum/bitwise.h b/quantum/bitwise.h
new file mode 100644
index 0000000000..276bc7437b
--- /dev/null
+++ b/quantum/bitwise.h
@@ -0,0 +1,40 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint8_t bitpop(uint8_t bits);
+uint8_t bitpop16(uint16_t bits);
+uint8_t bitpop32(uint32_t bits);
+
+uint8_t biton(uint8_t bits);
+uint8_t biton16(uint16_t bits);
+uint8_t biton32(uint32_t bits);
+
+uint8_t bitrev(uint8_t bits);
+uint16_t bitrev16(uint16_t bits);
+uint32_t bitrev32(uint32_t bits);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/quantum/color.c b/quantum/color.c
index 3cb8a1a2ca..1c5128e4a2 100644
--- a/quantum/color.c
+++ b/quantum/color.c
@@ -96,7 +96,6 @@ RGB hsv_to_rgb_impl(HSV hsv, bool use_cie) {
return rgb;
}
-
RGB hsv_to_rgb(HSV hsv) {
#ifdef USE_CIE1931_CURVE
return hsv_to_rgb_impl(hsv, true);
diff --git a/quantum/command.c b/quantum/command.c
new file mode 100644
index 0000000000..34c4b36b1c
--- /dev/null
+++ b/quantum/command.c
@@ -0,0 +1,786 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdint.h>
+#include <stdbool.h>
+#include "wait.h"
+#include "keycode.h"
+#include "host.h"
+#include "keymap.h"
+#include "print.h"
+#include "debug.h"
+#include "util.h"
+#include "timer.h"
+#include "keyboard.h"
+#include "bootloader.h"
+#include "action_layer.h"
+#include "action_util.h"
+#include "eeconfig.h"
+#include "sleep_led.h"
+#include "led.h"
+#include "command.h"
+#include "quantum.h"
+#include "version.h"
+
+#ifdef BACKLIGHT_ENABLE
+# include "backlight.h"
+#endif
+
+#if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED)
+# include "mousekey.h"
+#endif
+
+#ifdef AUDIO_ENABLE
+# include "audio.h"
+#endif /* AUDIO_ENABLE */
+
+static bool command_common(uint8_t code);
+static void command_common_help(void);
+static void print_version(void);
+static void print_status(void);
+static bool command_console(uint8_t code);
+static void command_console_help(void);
+#if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED)
+static bool mousekey_console(uint8_t code);
+static void mousekey_console_help(void);
+#endif
+
+static void switch_default_layer(uint8_t layer);
+
+command_state_t command_state = ONESHOT;
+
+bool command_proc(uint8_t code) {
+ switch (command_state) {
+ case ONESHOT:
+ if (!IS_COMMAND()) return false;
+ return (command_extra(code) || command_common(code));
+ break;
+ case CONSOLE:
+ if (IS_COMMAND())
+ return (command_extra(code) || command_common(code));
+ else
+ return (command_console_extra(code) || command_console(code));
+ break;
+#if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED)
+ case MOUSEKEY:
+ mousekey_console(code);
+ break;
+#endif
+ default:
+ command_state = ONESHOT;
+ return false;
+ }
+ return true;
+}
+
+/* TODO: Refactoring is needed. */
+/* This allows to define extra commands. return false when not processed. */
+bool command_extra(uint8_t code) __attribute__((weak));
+bool command_extra(uint8_t code) {
+ (void)code;
+ return false;
+}
+
+bool command_console_extra(uint8_t code) __attribute__((weak));
+bool command_console_extra(uint8_t code) {
+ (void)code;
+ return false;
+}
+
+/***********************************************************
+ * Command common
+ ***********************************************************/
+static void command_common_help(void) {
+ print("\n\t- Magic -\n" STR(MAGIC_KEY_DEBUG) ": Debug Message Toggle\n" STR(MAGIC_KEY_DEBUG_MATRIX) ": Matrix Debug Mode Toggle - Show keypresses in matrix grid\n" STR(MAGIC_KEY_DEBUG_KBD) ": Keyboard Debug Toggle - Show keypress report\n" STR(MAGIC_KEY_DEBUG_MOUSE) ": Debug Mouse Toggle\n" STR(MAGIC_KEY_VERSION) ": Version\n" STR(MAGIC_KEY_STATUS) ": Status\n" STR(MAGIC_KEY_CONSOLE) ": Activate Console Mode\n"
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+ STR(MAGIC_KEY_LAYER0) ": Switch to Layer 0\n" STR(MAGIC_KEY_LAYER1) ": Switch to Layer 1\n" STR(MAGIC_KEY_LAYER2) ": Switch to Layer 2\n" STR(MAGIC_KEY_LAYER3) ": Switch to Layer 3\n" STR(MAGIC_KEY_LAYER4) ": Switch to Layer 4\n" STR(MAGIC_KEY_LAYER5) ": Switch to Layer 5\n" STR(MAGIC_KEY_LAYER6) ": Switch to Layer 6\n" STR(MAGIC_KEY_LAYER7) ": Switch to Layer 7\n" STR(MAGIC_KEY_LAYER8) ": Switch to Layer 8\n" STR(MAGIC_KEY_LAYER9) ": Switch to Layer 9\n"
+#endif
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+ "F1-F10: Switch to Layer 0-9 (F10 = L0)\n"
+#endif
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+ "0-9: Switch to Layer 0-9\n"
+#endif
+
+ STR(MAGIC_KEY_LAYER0_ALT) ": Switch to Layer 0 (alternate)\n"
+
+ STR(MAGIC_KEY_BOOTLOADER) ": Jump to Bootloader\n" STR(MAGIC_KEY_BOOTLOADER_ALT) ": Jump to Bootloader (alternate)\n"
+
+#ifdef KEYBOARD_LOCK_ENABLE
+ STR(MAGIC_KEY_LOCK) ": Lock Keyboard\n"
+#endif
+
+ STR(MAGIC_KEY_EEPROM) ": Print EEPROM Settings\n" STR(MAGIC_KEY_EEPROM_CLEAR) ": Clear EEPROM\n"
+
+#ifdef NKRO_ENABLE
+ STR(MAGIC_KEY_NKRO) ": NKRO Toggle\n"
+#endif
+
+#ifdef SLEEP_LED_ENABLE
+ STR(MAGIC_KEY_SLEEP_LED) ": Sleep LED Test\n"
+#endif
+ );
+}
+
+static void print_version(void) {
+ // print version & information
+ print("\n\t- Version -\n");
+ print("VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") "
+ "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") "
+ "VER: " STR(DEVICE_VER) "\n");
+ print("BUILD: (" __DATE__ ")\n");
+#ifndef SKIP_VERSION
+# ifdef PROTOCOL_CHIBIOS
+ print("CHIBIOS: " STR(CHIBIOS_VERSION) ", CONTRIB: " STR(CHIBIOS_CONTRIB_VERSION) "\n");
+# endif
+#endif
+
+ /* build options */
+ print("OPTIONS:"
+
+#ifdef PROTOCOL_LUFA
+ " LUFA"
+#endif
+#ifdef PROTOCOL_VUSB
+ " VUSB"
+#endif
+#ifdef BOOTMAGIC_ENABLE
+ " BOOTMAGIC"
+#endif
+#ifdef MOUSEKEY_ENABLE
+ " MOUSEKEY"
+#endif
+#ifdef EXTRAKEY_ENABLE
+ " EXTRAKEY"
+#endif
+#ifdef CONSOLE_ENABLE
+ " CONSOLE"
+#endif
+#ifdef COMMAND_ENABLE
+ " COMMAND"
+#endif
+#ifdef NKRO_ENABLE
+ " NKRO"
+#endif
+#ifdef LTO_ENABLE
+ " LTO"
+#endif
+
+ " " STR(BOOTLOADER_SIZE) "\n");
+
+ print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__)
+#if defined(__AVR__)
+ " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__ " AVR_ARCH: avr" STR(__AVR_ARCH__)
+#endif
+ "\n");
+
+ return;
+}
+
+static void print_status(void) {
+ print("\n\t- Status -\n");
+
+ print_val_hex8(host_keyboard_leds());
+#ifndef PROTOCOL_VUSB
+ // these aren't set on the V-USB protocol, so we just ignore them for now
+ print_val_hex8(keyboard_protocol);
+ print_val_hex8(keyboard_idle);
+#endif
+#ifdef NKRO_ENABLE
+ print_val_hex8(keymap_config.nkro);
+#endif
+ print_val_hex32(timer_read32());
+ return;
+}
+
+static void print_eeconfig(void) {
+// Print these variables if NO_PRINT or USER_PRINT are not defined.
+#if !defined(NO_PRINT) && !defined(USER_PRINT)
+
+ print("default_layer: ");
+ print_dec(eeconfig_read_default_layer());
+ print("\n");
+
+ debug_config_t dc;
+ dc.raw = eeconfig_read_debug();
+ print("debug_config.raw: ");
+ print_hex8(dc.raw);
+ print("\n");
+ print(".enable: ");
+ print_dec(dc.enable);
+ print("\n");
+ print(".matrix: ");
+ print_dec(dc.matrix);
+ print("\n");
+ print(".keyboard: ");
+ print_dec(dc.keyboard);
+ print("\n");
+ print(".mouse: ");
+ print_dec(dc.mouse);
+ print("\n");
+
+ keymap_config_t kc;
+ kc.raw = eeconfig_read_keymap();
+ print("keymap_config.raw: ");
+ print_hex8(kc.raw);
+ print("\n");
+ print(".swap_control_capslock: ");
+ print_dec(kc.swap_control_capslock);
+ print("\n");
+ print(".capslock_to_control: ");
+ print_dec(kc.capslock_to_control);
+ print("\n");
+ print(".swap_lctl_lgui: ");
+ print_dec(kc.swap_lctl_lgui);
+ print("\n");
+ print(".swap_rctl_rgui: ");
+ print_dec(kc.swap_rctl_rgui);
+ print("\n");
+ print(".swap_lalt_lgui: ");
+ print_dec(kc.swap_lalt_lgui);
+ print("\n");
+ print(".swap_ralt_rgui: ");
+ print_dec(kc.swap_ralt_rgui);
+ print("\n");
+ print(".no_gui: ");
+ print_dec(kc.no_gui);
+ print("\n");
+ print(".swap_grave_esc: ");
+ print_dec(kc.swap_grave_esc);
+ print("\n");
+ print(".swap_backslash_backspace: ");
+ print_dec(kc.swap_backslash_backspace);
+ print("\n");
+ print(".nkro: ");
+ print_dec(kc.nkro);
+ print("\n");
+
+# ifdef BACKLIGHT_ENABLE
+ backlight_config_t bc;
+ bc.raw = eeconfig_read_backlight();
+ print("backlight_config.raw: ");
+ print_hex8(bc.raw);
+ print("\n");
+ print(".enable: ");
+ print_dec(bc.enable);
+ print("\n");
+ print(".level: ");
+ print_dec(bc.level);
+ print("\n");
+# endif /* BACKLIGHT_ENABLE */
+
+#endif /* !NO_PRINT */
+}
+
+static bool command_common(uint8_t code) {
+#ifdef KEYBOARD_LOCK_ENABLE
+ static host_driver_t *host_driver = 0;
+#endif
+
+ switch (code) {
+#ifdef SLEEP_LED_ENABLE
+
+ // test breathing sleep LED
+ case MAGIC_KC(MAGIC_KEY_SLEEP_LED):
+ print("Sleep LED Test\n");
+ sleep_led_toggle();
+ led_set(host_keyboard_leds());
+ break;
+#endif
+
+ // print stored eeprom config
+ case MAGIC_KC(MAGIC_KEY_EEPROM):
+ print("eeconfig:\n");
+ print_eeconfig();
+ break;
+
+ // clear eeprom
+ case MAGIC_KC(MAGIC_KEY_EEPROM_CLEAR):
+ print("Clearing EEPROM\n");
+ eeconfig_init();
+ break;
+
+#ifdef KEYBOARD_LOCK_ENABLE
+
+ // lock/unlock keyboard
+ case MAGIC_KC(MAGIC_KEY_LOCK):
+ if (host_get_driver()) {
+ host_driver = host_get_driver();
+ clear_keyboard();
+ host_set_driver(0);
+ print("Locked.\n");
+ } else {
+ host_set_driver(host_driver);
+ print("Unlocked.\n");
+ }
+ break;
+#endif
+
+ // print help
+ case MAGIC_KC(MAGIC_KEY_HELP):
+ case MAGIC_KC(MAGIC_KEY_HELP_ALT):
+ command_common_help();
+ break;
+
+ // activate console
+ case MAGIC_KC(MAGIC_KEY_CONSOLE):
+ debug_matrix = false;
+ debug_keyboard = false;
+ debug_mouse = false;
+ debug_enable = false;
+ command_console_help();
+ print("C> ");
+ command_state = CONSOLE;
+ break;
+
+ // jump to bootloader
+ case MAGIC_KC(MAGIC_KEY_BOOTLOADER):
+ case MAGIC_KC(MAGIC_KEY_BOOTLOADER_ALT):
+ print("\n\nJumping to bootloader... ");
+ reset_keyboard();
+ break;
+
+ // debug toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG):
+ debug_enable = !debug_enable;
+ if (debug_enable) {
+ print("\ndebug: on\n");
+ } else {
+ print("\ndebug: off\n");
+ debug_matrix = false;
+ debug_keyboard = false;
+ debug_mouse = false;
+ }
+ break;
+
+ // debug matrix toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG_MATRIX):
+ debug_matrix = !debug_matrix;
+ if (debug_matrix) {
+ print("\nmatrix: on\n");
+ debug_enable = true;
+ } else {
+ print("\nmatrix: off\n");
+ }
+ break;
+
+ // debug keyboard toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG_KBD):
+ debug_keyboard = !debug_keyboard;
+ if (debug_keyboard) {
+ print("\nkeyboard: on\n");
+ debug_enable = true;
+ } else {
+ print("\nkeyboard: off\n");
+ }
+ break;
+
+ // debug mouse toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG_MOUSE):
+ debug_mouse = !debug_mouse;
+ if (debug_mouse) {
+ print("\nmouse: on\n");
+ debug_enable = true;
+ } else {
+ print("\nmouse: off\n");
+ }
+ break;
+
+ // print version
+ case MAGIC_KC(MAGIC_KEY_VERSION):
+ print_version();
+ break;
+
+ // print status
+ case MAGIC_KC(MAGIC_KEY_STATUS):
+ print_status();
+ break;
+
+#ifdef NKRO_ENABLE
+
+ // NKRO toggle
+ case MAGIC_KC(MAGIC_KEY_NKRO):
+ clear_keyboard(); // clear to prevent stuck keys
+ keymap_config.nkro = !keymap_config.nkro;
+ if (keymap_config.nkro) {
+ print("NKRO: on\n");
+ } else {
+ print("NKRO: off\n");
+ }
+ break;
+#endif
+
+ // switch layers
+
+ case MAGIC_KC(MAGIC_KEY_LAYER0_ALT):
+ switch_default_layer(0);
+ break;
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+
+ case MAGIC_KC(MAGIC_KEY_LAYER0):
+ switch_default_layer(0);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER1):
+ switch_default_layer(1);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER2):
+ switch_default_layer(2);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER3):
+ switch_default_layer(3);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER4):
+ switch_default_layer(4);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER5):
+ switch_default_layer(5);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER6):
+ switch_default_layer(6);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER7):
+ switch_default_layer(7);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER8):
+ switch_default_layer(8);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER9):
+ switch_default_layer(9);
+ break;
+#endif
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+
+ case KC_F1 ... KC_F9:
+ switch_default_layer((code - KC_F1) + 1);
+ break;
+ case KC_F10:
+ switch_default_layer(0);
+ break;
+#endif
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+
+ case KC_1 ... KC_9:
+ switch_default_layer((code - KC_1) + 1);
+ break;
+ case KC_0:
+ switch_default_layer(0);
+ break;
+#endif
+
+ default:
+ print("?");
+ return false;
+ }
+ return true;
+}
+
+/***********************************************************
+ * Command console
+ ***********************************************************/
+static void command_console_help(void) {
+ print("\n\t- Console -\n"
+ "ESC/q: quit\n"
+#ifdef MOUSEKEY_ENABLE
+ "m: mousekey\n"
+#endif
+ );
+}
+
+static bool command_console(uint8_t code) {
+ switch (code) {
+ case KC_H:
+ case KC_SLASH: /* ? */
+ command_console_help();
+ break;
+ case KC_Q:
+ case KC_ESC:
+ command_state = ONESHOT;
+ return false;
+#if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED)
+ case KC_M:
+ mousekey_console_help();
+ print("M> ");
+ command_state = MOUSEKEY;
+ return true;
+#endif
+ default:
+ print("?");
+ return false;
+ }
+ print("C> ");
+ return true;
+}
+
+#if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED)
+/***********************************************************
+ * Mousekey console
+ ***********************************************************/
+static uint8_t mousekey_param = 0;
+
+static void mousekey_param_print(void) {
+// Print these variables if NO_PRINT or USER_PRINT are not defined.
+# if !defined(NO_PRINT) && !defined(USER_PRINT)
+ print("\n\t- Values -\n");
+ print("1: delay(*10ms): ");
+ print_dec(mk_delay);
+ print("\n");
+ print("2: interval(ms): ");
+ print_dec(mk_interval);
+ print("\n");
+ print("3: max_speed: ");
+ print_dec(mk_max_speed);
+ print("\n");
+ print("4: time_to_max: ");
+ print_dec(mk_time_to_max);
+ print("\n");
+ print("5: wheel_max_speed: ");
+ print_dec(mk_wheel_max_speed);
+ print("\n");
+ print("6: wheel_time_to_max: ");
+ print_dec(mk_wheel_time_to_max);
+ print("\n");
+# endif /* !NO_PRINT */
+}
+
+//#define PRINT_SET_VAL(v) print(#v " = "); print_dec(v); print("\n");
+# define PRINT_SET_VAL(v) xprintf(# v " = %d\n", (v))
+static void mousekey_param_inc(uint8_t param, uint8_t inc) {
+ switch (param) {
+ case 1:
+ if (mk_delay + inc < UINT8_MAX)
+ mk_delay += inc;
+ else
+ mk_delay = UINT8_MAX;
+ PRINT_SET_VAL(mk_delay);
+ break;
+ case 2:
+ if (mk_interval + inc < UINT8_MAX)
+ mk_interval += inc;
+ else
+ mk_interval = UINT8_MAX;
+ PRINT_SET_VAL(mk_interval);
+ break;
+ case 3:
+ if (mk_max_speed + inc < UINT8_MAX)
+ mk_max_speed += inc;
+ else
+ mk_max_speed = UINT8_MAX;
+ PRINT_SET_VAL(mk_max_speed);
+ break;
+ case 4:
+ if (mk_time_to_max + inc < UINT8_MAX)
+ mk_time_to_max += inc;
+ else
+ mk_time_to_max = UINT8_MAX;
+ PRINT_SET_VAL(mk_time_to_max);
+ break;
+ case 5:
+ if (mk_wheel_max_speed + inc < UINT8_MAX)
+ mk_wheel_max_speed += inc;
+ else
+ mk_wheel_max_speed = UINT8_MAX;
+ PRINT_SET_VAL(mk_wheel_max_speed);
+ break;
+ case 6:
+ if (mk_wheel_time_to_max + inc < UINT8_MAX)
+ mk_wheel_time_to_max += inc;
+ else
+ mk_wheel_time_to_max = UINT8_MAX;
+ PRINT_SET_VAL(mk_wheel_time_to_max);
+ break;
+ }
+}
+
+static void mousekey_param_dec(uint8_t param, uint8_t dec) {
+ switch (param) {
+ case 1:
+ if (mk_delay > dec)
+ mk_delay -= dec;
+ else
+ mk_delay = 0;
+ PRINT_SET_VAL(mk_delay);
+ break;
+ case 2:
+ if (mk_interval > dec)
+ mk_interval -= dec;
+ else
+ mk_interval = 0;
+ PRINT_SET_VAL(mk_interval);
+ break;
+ case 3:
+ if (mk_max_speed > dec)
+ mk_max_speed -= dec;
+ else
+ mk_max_speed = 0;
+ PRINT_SET_VAL(mk_max_speed);
+ break;
+ case 4:
+ if (mk_time_to_max > dec)
+ mk_time_to_max -= dec;
+ else
+ mk_time_to_max = 0;
+ PRINT_SET_VAL(mk_time_to_max);
+ break;
+ case 5:
+ if (mk_wheel_max_speed > dec)
+ mk_wheel_max_speed -= dec;
+ else
+ mk_wheel_max_speed = 0;
+ PRINT_SET_VAL(mk_wheel_max_speed);
+ break;
+ case 6:
+ if (mk_wheel_time_to_max > dec)
+ mk_wheel_time_to_max -= dec;
+ else
+ mk_wheel_time_to_max = 0;
+ PRINT_SET_VAL(mk_wheel_time_to_max);
+ break;
+ }
+}
+
+static void mousekey_console_help(void) {
+ print("\n\t- Mousekey -\n"
+ "ESC/q: quit\n"
+ "1: delay(*10ms)\n"
+ "2: interval(ms)\n"
+ "3: max_speed\n"
+ "4: time_to_max\n"
+ "5: wheel_max_speed\n"
+ "6: wheel_time_to_max\n"
+ "\n"
+ "p: print values\n"
+ "d: set defaults\n"
+ "up: +1\n"
+ "down: -1\n"
+ "pgup: +10\n"
+ "pgdown: -10\n"
+ "\n"
+ "speed = delta * max_speed * (repeat / time_to_max)\n");
+ xprintf("where delta: cursor=%d, wheel=%d\n"
+ "See http://en.wikipedia.org/wiki/Mouse_keys\n",
+ MOUSEKEY_MOVE_DELTA, MOUSEKEY_WHEEL_DELTA);
+}
+
+static bool mousekey_console(uint8_t code) {
+ switch (code) {
+ case KC_H:
+ case KC_SLASH: /* ? */
+ mousekey_console_help();
+ break;
+ case KC_Q:
+ case KC_ESC:
+ if (mousekey_param) {
+ mousekey_param = 0;
+ } else {
+ print("C> ");
+ command_state = CONSOLE;
+ return false;
+ }
+ break;
+ case KC_P:
+ mousekey_param_print();
+ break;
+ case KC_1:
+ case KC_2:
+ case KC_3:
+ case KC_4:
+ case KC_5:
+ case KC_6:
+ mousekey_param = numkey2num(code);
+ break;
+ case KC_UP:
+ mousekey_param_inc(mousekey_param, 1);
+ break;
+ case KC_DOWN:
+ mousekey_param_dec(mousekey_param, 1);
+ break;
+ case KC_PGUP:
+ mousekey_param_inc(mousekey_param, 10);
+ break;
+ case KC_PGDN:
+ mousekey_param_dec(mousekey_param, 10);
+ break;
+ case KC_D:
+ mk_delay = MOUSEKEY_DELAY / 10;
+ mk_interval = MOUSEKEY_INTERVAL;
+ mk_max_speed = MOUSEKEY_MAX_SPEED;
+ mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
+ mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED;
+ mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
+ print("set default\n");
+ break;
+ default:
+ print("?");
+ return false;
+ }
+ if (mousekey_param) {
+ xprintf("M%d> ", mousekey_param);
+ } else {
+ print("M>");
+ }
+ return true;
+}
+#endif
+
+/***********************************************************
+ * Utilities
+ ***********************************************************/
+uint8_t numkey2num(uint8_t code) {
+ switch (code) {
+ case KC_1:
+ return 1;
+ case KC_2:
+ return 2;
+ case KC_3:
+ return 3;
+ case KC_4:
+ return 4;
+ case KC_5:
+ return 5;
+ case KC_6:
+ return 6;
+ case KC_7:
+ return 7;
+ case KC_8:
+ return 8;
+ case KC_9:
+ return 9;
+ case KC_0:
+ return 0;
+ }
+ return 0;
+}
+
+static void switch_default_layer(uint8_t layer) {
+ xprintf("L%d\n", layer);
+ default_layer_set(1UL << layer);
+ clear_keyboard();
+}
diff --git a/quantum/command.h b/quantum/command.h
new file mode 100644
index 0000000000..4f77be085c
--- /dev/null
+++ b/quantum/command.h
@@ -0,0 +1,163 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+/* FIXME: Add doxygen comments for the behavioral defines in here. */
+
+/* TODO: Refactoring */
+typedef enum { ONESHOT, CONSOLE, MOUSEKEY } command_state_t;
+extern command_state_t command_state;
+
+/* This allows to extend commands. Return false when command is not processed. */
+bool command_extra(uint8_t code);
+bool command_console_extra(uint8_t code);
+
+#ifdef COMMAND_ENABLE
+uint8_t numkey2num(uint8_t code);
+bool command_proc(uint8_t code);
+#else
+# define command_proc(code) false
+#endif
+
+#ifndef IS_COMMAND
+# define IS_COMMAND() (get_mods() == MOD_MASK_SHIFT)
+#endif
+
+#ifndef MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+# define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true
+#endif
+
+#ifndef MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+# define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true
+#endif
+
+#ifndef MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+# define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false
+#endif
+
+#ifndef MAGIC_KEY_HELP
+# define MAGIC_KEY_HELP H
+#endif
+
+#ifndef MAGIC_KEY_HELP_ALT
+# define MAGIC_KEY_HELP_ALT SLASH
+#endif
+
+#ifndef MAGIC_KEY_DEBUG
+# define MAGIC_KEY_DEBUG D
+#endif
+
+#ifndef MAGIC_KEY_DEBUG_MATRIX
+# define MAGIC_KEY_DEBUG_MATRIX X
+#endif
+
+#ifndef MAGIC_KEY_DEBUG_KBD
+# define MAGIC_KEY_DEBUG_KBD K
+#endif
+
+#ifndef MAGIC_KEY_DEBUG_MOUSE
+# define MAGIC_KEY_DEBUG_MOUSE M
+#endif
+
+#ifndef MAGIC_KEY_VERSION
+# define MAGIC_KEY_VERSION V
+#endif
+
+#ifndef MAGIC_KEY_STATUS
+# define MAGIC_KEY_STATUS S
+#endif
+
+#ifndef MAGIC_KEY_CONSOLE
+# define MAGIC_KEY_CONSOLE C
+#endif
+
+#ifndef MAGIC_KEY_LAYER0
+# define MAGIC_KEY_LAYER0 0
+#endif
+
+#ifndef MAGIC_KEY_LAYER0_ALT
+# define MAGIC_KEY_LAYER0_ALT GRAVE
+#endif
+
+#ifndef MAGIC_KEY_LAYER1
+# define MAGIC_KEY_LAYER1 1
+#endif
+
+#ifndef MAGIC_KEY_LAYER2
+# define MAGIC_KEY_LAYER2 2
+#endif
+
+#ifndef MAGIC_KEY_LAYER3
+# define MAGIC_KEY_LAYER3 3
+#endif
+
+#ifndef MAGIC_KEY_LAYER4
+# define MAGIC_KEY_LAYER4 4
+#endif
+
+#ifndef MAGIC_KEY_LAYER5
+# define MAGIC_KEY_LAYER5 5
+#endif
+
+#ifndef MAGIC_KEY_LAYER6
+# define MAGIC_KEY_LAYER6 6
+#endif
+
+#ifndef MAGIC_KEY_LAYER7
+# define MAGIC_KEY_LAYER7 7
+#endif
+
+#ifndef MAGIC_KEY_LAYER8
+# define MAGIC_KEY_LAYER8 8
+#endif
+
+#ifndef MAGIC_KEY_LAYER9
+# define MAGIC_KEY_LAYER9 9
+#endif
+
+#ifndef MAGIC_KEY_BOOTLOADER
+# define MAGIC_KEY_BOOTLOADER B
+#endif
+
+#ifndef MAGIC_KEY_BOOTLOADER_ALT
+# define MAGIC_KEY_BOOTLOADER_ALT ESC
+#endif
+
+#ifndef MAGIC_KEY_LOCK
+# define MAGIC_KEY_LOCK CAPS
+#endif
+
+#ifndef MAGIC_KEY_EEPROM
+# define MAGIC_KEY_EEPROM E
+#endif
+
+#ifndef MAGIC_KEY_EEPROM_CLEAR
+# define MAGIC_KEY_EEPROM_CLEAR BSPACE
+#endif
+
+#ifndef MAGIC_KEY_NKRO
+# define MAGIC_KEY_NKRO N
+#endif
+
+#ifndef MAGIC_KEY_SLEEP_LED
+# define MAGIC_KEY_SLEEP_LED Z
+
+#endif
+
+#define XMAGIC_KC(key) KC_##key
+#define MAGIC_KC(key) XMAGIC_KC(key)
diff --git a/quantum/config_common.h b/quantum/config_common.h
index 53377f2b61..d93477b27e 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -16,402 +16,12 @@
#pragma once
+#ifndef __ASSEMBLER__
+# include "pin_defs.h"
+#endif
+
/* diode directions */
#define COL2ROW 0
#define ROW2COL 1
-#define CUSTOM_MATRIX 2 /* Disables built-in matrix scanning code */
-
-// useful for direct pin mapping
-#define NO_PIN (pin_t)(~0)
-
-#ifdef __AVR__
-# ifndef __ASSEMBLER__
-# include <avr/io.h>
-# endif
-# define PORT_SHIFTER 4 // this may be 4 for all AVR chips
-
-// If you want to add more to this list, reference the PINx definitions in these header
-// files: https://github.com/vancegroup-mirrors/avr-libc/tree/master/avr-libc/include/avr
-
-# if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
-# define ADDRESS_BASE 0x00
-# define PINB_ADDRESS 0x3
-# define PINC_ADDRESS 0x6
-# define PIND_ADDRESS 0x9
-# define PINE_ADDRESS 0xC
-# define PINF_ADDRESS 0xF
-# elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
-# define ADDRESS_BASE 0x00
-# define PINB_ADDRESS 0x3
-# define PINC_ADDRESS 0x6
-# define PIND_ADDRESS 0x9
-# elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__)
-# define ADDRESS_BASE 0x00
-# define PINA_ADDRESS 0x0
-# define PINB_ADDRESS 0x3
-# define PINC_ADDRESS 0x6
-# define PIND_ADDRESS 0x9
-# define PINE_ADDRESS 0xC
-# define PINF_ADDRESS 0xF
-# elif defined(__AVR_ATmega32A__)
-# define ADDRESS_BASE 0x10
-# define PIND_ADDRESS 0x0
-# define PINC_ADDRESS 0x3
-# define PINB_ADDRESS 0x6
-# define PINA_ADDRESS 0x9
-# elif defined(__AVR_ATtiny85__)
-# define ADDRESS_BASE 0x10
-# define PINB_ADDRESS 0x6
-# else
-# error "Pins are not defined"
-# endif
-
-/* I/O pins */
-# define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin)
-
-# ifdef PORTA
-# define A0 PINDEF(A, 0)
-# define A1 PINDEF(A, 1)
-# define A2 PINDEF(A, 2)
-# define A3 PINDEF(A, 3)
-# define A4 PINDEF(A, 4)
-# define A5 PINDEF(A, 5)
-# define A6 PINDEF(A, 6)
-# define A7 PINDEF(A, 7)
-# endif
-# ifdef PORTB
-# define B0 PINDEF(B, 0)
-# define B1 PINDEF(B, 1)
-# define B2 PINDEF(B, 2)
-# define B3 PINDEF(B, 3)
-# define B4 PINDEF(B, 4)
-# define B5 PINDEF(B, 5)
-# define B6 PINDEF(B, 6)
-# define B7 PINDEF(B, 7)
-# endif
-# ifdef PORTC
-# define C0 PINDEF(C, 0)
-# define C1 PINDEF(C, 1)
-# define C2 PINDEF(C, 2)
-# define C3 PINDEF(C, 3)
-# define C4 PINDEF(C, 4)
-# define C5 PINDEF(C, 5)
-# define C6 PINDEF(C, 6)
-# define C7 PINDEF(C, 7)
-# endif
-# ifdef PORTD
-# define D0 PINDEF(D, 0)
-# define D1 PINDEF(D, 1)
-# define D2 PINDEF(D, 2)
-# define D3 PINDEF(D, 3)
-# define D4 PINDEF(D, 4)
-# define D5 PINDEF(D, 5)
-# define D6 PINDEF(D, 6)
-# define D7 PINDEF(D, 7)
-# endif
-# ifdef PORTE
-# define E0 PINDEF(E, 0)
-# define E1 PINDEF(E, 1)
-# define E2 PINDEF(E, 2)
-# define E3 PINDEF(E, 3)
-# define E4 PINDEF(E, 4)
-# define E5 PINDEF(E, 5)
-# define E6 PINDEF(E, 6)
-# define E7 PINDEF(E, 7)
-# endif
-# ifdef PORTF
-# define F0 PINDEF(F, 0)
-# define F1 PINDEF(F, 1)
-# define F2 PINDEF(F, 2)
-# define F3 PINDEF(F, 3)
-# define F4 PINDEF(F, 4)
-# define F5 PINDEF(F, 5)
-# define F6 PINDEF(F, 6)
-# define F7 PINDEF(F, 7)
-# endif
-
-# ifndef __ASSEMBLER__
-# define _PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + ((p) >> PORT_SHIFTER) + (offset))
-// Port X Input Pins Address
-# define PINx_ADDRESS(p) _PIN_ADDRESS(p, 0)
-// Port X Data Direction Register, 0:input 1:output
-# define DDRx_ADDRESS(p) _PIN_ADDRESS(p, 1)
-// Port X Data Register
-# define PORTx_ADDRESS(p) _PIN_ADDRESS(p, 2)
-# endif
-
-#elif defined(PROTOCOL_CHIBIOS)
-// Defines mapping for Proton C replacement
-# ifdef CONVERT_TO_PROTON_C
-// Left side (front)
-# define D3 PAL_LINE(GPIOA, 9)
-# define D2 PAL_LINE(GPIOA, 10)
-// GND
-// GND
-# define D1 PAL_LINE(GPIOB, 7)
-# define D0 PAL_LINE(GPIOB, 6)
-# define D4 PAL_LINE(GPIOB, 5)
-# define C6 PAL_LINE(GPIOB, 4)
-# define D7 PAL_LINE(GPIOB, 3)
-# define E6 PAL_LINE(GPIOB, 2)
-# define B4 PAL_LINE(GPIOB, 1)
-# define B5 PAL_LINE(GPIOB, 0)
-
-// Right side (front)
-// RAW
-// GND
-// RESET
-// VCC
-# define F4 PAL_LINE(GPIOA, 2)
-# define F5 PAL_LINE(GPIOA, 1)
-# define F6 PAL_LINE(GPIOA, 0)
-# define F7 PAL_LINE(GPIOB, 8)
-# define B1 PAL_LINE(GPIOB, 13)
-# define B3 PAL_LINE(GPIOB, 14)
-# define B2 PAL_LINE(GPIOB, 15)
-# define B6 PAL_LINE(GPIOB, 9)
-
-// LEDs (only D5/C13 uses an actual LED)
-# ifdef CONVERT_TO_PROTON_C_RXLED
-# define D5 PAL_LINE(GPIOC, 14)
-# define B0 PAL_LINE(GPIOC, 13)
-# else
-# define D5 PAL_LINE(GPIOC, 13)
-# define B0 PAL_LINE(GPIOC, 14)
-# endif
-# else
-# define A0 PAL_LINE(GPIOA, 0)
-# define A1 PAL_LINE(GPIOA, 1)
-# define A2 PAL_LINE(GPIOA, 2)
-# define A3 PAL_LINE(GPIOA, 3)
-# define A4 PAL_LINE(GPIOA, 4)
-# define A5 PAL_LINE(GPIOA, 5)
-# define A6 PAL_LINE(GPIOA, 6)
-# define A7 PAL_LINE(GPIOA, 7)
-# define A8 PAL_LINE(GPIOA, 8)
-# define A9 PAL_LINE(GPIOA, 9)
-# define A10 PAL_LINE(GPIOA, 10)
-# define A11 PAL_LINE(GPIOA, 11)
-# define A12 PAL_LINE(GPIOA, 12)
-# define A13 PAL_LINE(GPIOA, 13)
-# define A14 PAL_LINE(GPIOA, 14)
-# define A15 PAL_LINE(GPIOA, 15)
-# define B0 PAL_LINE(GPIOB, 0)
-# define B1 PAL_LINE(GPIOB, 1)
-# define B2 PAL_LINE(GPIOB, 2)
-# define B3 PAL_LINE(GPIOB, 3)
-# define B4 PAL_LINE(GPIOB, 4)
-# define B5 PAL_LINE(GPIOB, 5)
-# define B6 PAL_LINE(GPIOB, 6)
-# define B7 PAL_LINE(GPIOB, 7)
-# define B8 PAL_LINE(GPIOB, 8)
-# define B9 PAL_LINE(GPIOB, 9)
-# define B10 PAL_LINE(GPIOB, 10)
-# define B11 PAL_LINE(GPIOB, 11)
-# define B12 PAL_LINE(GPIOB, 12)
-# define B13 PAL_LINE(GPIOB, 13)
-# define B14 PAL_LINE(GPIOB, 14)
-# define B15 PAL_LINE(GPIOB, 15)
-# define B16 PAL_LINE(GPIOB, 16)
-# define B17 PAL_LINE(GPIOB, 17)
-# define B18 PAL_LINE(GPIOB, 18)
-# define B19 PAL_LINE(GPIOB, 19)
-# define C0 PAL_LINE(GPIOC, 0)
-# define C1 PAL_LINE(GPIOC, 1)
-# define C2 PAL_LINE(GPIOC, 2)
-# define C3 PAL_LINE(GPIOC, 3)
-# define C4 PAL_LINE(GPIOC, 4)
-# define C5 PAL_LINE(GPIOC, 5)
-# define C6 PAL_LINE(GPIOC, 6)
-# define C7 PAL_LINE(GPIOC, 7)
-# define C8 PAL_LINE(GPIOC, 8)
-# define C9 PAL_LINE(GPIOC, 9)
-# define C10 PAL_LINE(GPIOC, 10)
-# define C11 PAL_LINE(GPIOC, 11)
-# define C12 PAL_LINE(GPIOC, 12)
-# define C13 PAL_LINE(GPIOC, 13)
-# define C14 PAL_LINE(GPIOC, 14)
-# define C15 PAL_LINE(GPIOC, 15)
-# define D0 PAL_LINE(GPIOD, 0)
-# define D1 PAL_LINE(GPIOD, 1)
-# define D2 PAL_LINE(GPIOD, 2)
-# define D3 PAL_LINE(GPIOD, 3)
-# define D4 PAL_LINE(GPIOD, 4)
-# define D5 PAL_LINE(GPIOD, 5)
-# define D6 PAL_LINE(GPIOD, 6)
-# define D7 PAL_LINE(GPIOD, 7)
-# define D8 PAL_LINE(GPIOD, 8)
-# define D9 PAL_LINE(GPIOD, 9)
-# define D10 PAL_LINE(GPIOD, 10)
-# define D11 PAL_LINE(GPIOD, 11)
-# define D12 PAL_LINE(GPIOD, 12)
-# define D13 PAL_LINE(GPIOD, 13)
-# define D14 PAL_LINE(GPIOD, 14)
-# define D15 PAL_LINE(GPIOD, 15)
-# define E0 PAL_LINE(GPIOE, 0)
-# define E1 PAL_LINE(GPIOE, 1)
-# define E2 PAL_LINE(GPIOE, 2)
-# define E3 PAL_LINE(GPIOE, 3)
-# define E4 PAL_LINE(GPIOE, 4)
-# define E5 PAL_LINE(GPIOE, 5)
-# define E6 PAL_LINE(GPIOE, 6)
-# define E7 PAL_LINE(GPIOE, 7)
-# define E8 PAL_LINE(GPIOE, 8)
-# define E9 PAL_LINE(GPIOE, 9)
-# define E10 PAL_LINE(GPIOE, 10)
-# define E11 PAL_LINE(GPIOE, 11)
-# define E12 PAL_LINE(GPIOE, 12)
-# define E13 PAL_LINE(GPIOE, 13)
-# define E14 PAL_LINE(GPIOE, 14)
-# define E15 PAL_LINE(GPIOE, 15)
-# define F0 PAL_LINE(GPIOF, 0)
-# define F1 PAL_LINE(GPIOF, 1)
-# define F2 PAL_LINE(GPIOF, 2)
-# define F3 PAL_LINE(GPIOF, 3)
-# define F4 PAL_LINE(GPIOF, 4)
-# define F5 PAL_LINE(GPIOF, 5)
-# define F6 PAL_LINE(GPIOF, 6)
-# define F7 PAL_LINE(GPIOF, 7)
-# define F8 PAL_LINE(GPIOF, 8)
-# define F9 PAL_LINE(GPIOF, 9)
-# define F10 PAL_LINE(GPIOF, 10)
-# define F11 PAL_LINE(GPIOF, 11)
-# define F12 PAL_LINE(GPIOF, 12)
-# define F13 PAL_LINE(GPIOF, 13)
-# define F14 PAL_LINE(GPIOF, 14)
-# define F15 PAL_LINE(GPIOF, 15)
-# define G0 PAL_LINE(GPIOG, 0)
-# define G1 PAL_LINE(GPIOG, 1)
-# define G2 PAL_LINE(GPIOG, 2)
-# define G3 PAL_LINE(GPIOG, 3)
-# define G4 PAL_LINE(GPIOG, 4)
-# define G5 PAL_LINE(GPIOG, 5)
-# define G6 PAL_LINE(GPIOG, 6)
-# define G7 PAL_LINE(GPIOG, 7)
-# define G8 PAL_LINE(GPIOG, 8)
-# define G9 PAL_LINE(GPIOG, 9)
-# define G10 PAL_LINE(GPIOG, 10)
-# define G11 PAL_LINE(GPIOG, 11)
-# define G12 PAL_LINE(GPIOG, 12)
-# define G13 PAL_LINE(GPIOG, 13)
-# define G14 PAL_LINE(GPIOG, 14)
-# define G15 PAL_LINE(GPIOG, 15)
-# define H0 PAL_LINE(GPIOH, 0)
-# define H1 PAL_LINE(GPIOH, 1)
-# define H2 PAL_LINE(GPIOH, 2)
-# define H3 PAL_LINE(GPIOH, 3)
-# define H4 PAL_LINE(GPIOH, 4)
-# define H5 PAL_LINE(GPIOH, 5)
-# define H6 PAL_LINE(GPIOH, 6)
-# define H7 PAL_LINE(GPIOH, 7)
-# define H8 PAL_LINE(GPIOH, 8)
-# define H9 PAL_LINE(GPIOH, 9)
-# define H10 PAL_LINE(GPIOH, 10)
-# define H11 PAL_LINE(GPIOH, 11)
-# define H12 PAL_LINE(GPIOH, 12)
-# define H13 PAL_LINE(GPIOH, 13)
-# define H14 PAL_LINE(GPIOH, 14)
-# define H15 PAL_LINE(GPIOH, 15)
-# define I0 PAL_LINE(GPIOI, 0)
-# define I1 PAL_LINE(GPIOI, 1)
-# define I2 PAL_LINE(GPIOI, 2)
-# define I3 PAL_LINE(GPIOI, 3)
-# define I4 PAL_LINE(GPIOI, 4)
-# define I5 PAL_LINE(GPIOI, 5)
-# define I6 PAL_LINE(GPIOI, 6)
-# define I7 PAL_LINE(GPIOI, 7)
-# define I8 PAL_LINE(GPIOI, 8)
-# define I9 PAL_LINE(GPIOI, 9)
-# define I10 PAL_LINE(GPIOI, 10)
-# define I11 PAL_LINE(GPIOI, 11)
-# define I12 PAL_LINE(GPIOI, 12)
-# define I13 PAL_LINE(GPIOI, 13)
-# define I14 PAL_LINE(GPIOI, 14)
-# define I15 PAL_LINE(GPIOI, 15)
-# define J0 PAL_LINE(GPIOJ, 0)
-# define J1 PAL_LINE(GPIOJ, 1)
-# define J2 PAL_LINE(GPIOJ, 2)
-# define J3 PAL_LINE(GPIOJ, 3)
-# define J4 PAL_LINE(GPIOJ, 4)
-# define J5 PAL_LINE(GPIOJ, 5)
-# define J6 PAL_LINE(GPIOJ, 6)
-# define J7 PAL_LINE(GPIOJ, 7)
-# define J8 PAL_LINE(GPIOJ, 8)
-# define J9 PAL_LINE(GPIOJ, 9)
-# define J10 PAL_LINE(GPIOJ, 10)
-# define J11 PAL_LINE(GPIOJ, 11)
-# define J12 PAL_LINE(GPIOJ, 12)
-# define J13 PAL_LINE(GPIOJ, 13)
-# define J14 PAL_LINE(GPIOJ, 14)
-# define J15 PAL_LINE(GPIOJ, 15)
-// Keyboards can `#define KEYBOARD_REQUIRES_GPIOK` if they need to access GPIO-K pins. These conflict with a whole
-// bunch of layout definitions, so it's intentionally left out unless absolutely required -- in that case, the
-// keyboard designer should use a different symbol when defining their layout macros.
-# ifdef KEYBOARD_REQUIRES_GPIOK
-# define K0 PAL_LINE(GPIOK, 0)
-# define K1 PAL_LINE(GPIOK, 1)
-# define K2 PAL_LINE(GPIOK, 2)
-# define K3 PAL_LINE(GPIOK, 3)
-# define K4 PAL_LINE(GPIOK, 4)
-# define K5 PAL_LINE(GPIOK, 5)
-# define K6 PAL_LINE(GPIOK, 6)
-# define K7 PAL_LINE(GPIOK, 7)
-# define K8 PAL_LINE(GPIOK, 8)
-# define K9 PAL_LINE(GPIOK, 9)
-# define K10 PAL_LINE(GPIOK, 10)
-# define K11 PAL_LINE(GPIOK, 11)
-# define K12 PAL_LINE(GPIOK, 12)
-# define K13 PAL_LINE(GPIOK, 13)
-# define K14 PAL_LINE(GPIOK, 14)
-# define K15 PAL_LINE(GPIOK, 15)
-# endif
-# endif
-#endif
-
-/* USART configuration */
-#ifdef BLUETOOTH_ENABLE
-# ifdef __AVR_ATmega32U4__
-# define SERIAL_UART_BAUD 9600
-# define SERIAL_UART_DATA UDR1
-# define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1)
-# define SERIAL_UART_RXD_VECT USART1_RX_vect
-# define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1))
-# define SERIAL_UART_INIT() \
- do { \
- /* baud rate */ \
- UBRR1L = SERIAL_UART_UBRR; \
- /* baud rate */ \
- UBRR1H = SERIAL_UART_UBRR >> 8; \
- /* enable TX */ \
- UCSR1B = _BV(TXEN1); \
- /* 8-bit data */ \
- UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \
- sei(); \
- } while (0)
-# elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
-# define SERIAL_UART_BAUD 115200
-# define SERIAL_UART_DATA UDR1
- /* UBRR should result in ~16 and set UCSR1A = _BV(U2X1) as per rn42 documentation. HC05 needs baudrate configured accordingly */
-# define SERIAL_UART_UBRR (F_CPU / (8UL * SERIAL_UART_BAUD) - 1)
-# define SERIAL_UART_RXD_VECT USART1_RX_vect
-# define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1))
-# define SERIAL_UART_INIT() do { \
- UCSR1A = _BV(U2X1); \
- /* baud rate */ \
- UBRR1L = SERIAL_UART_UBRR; \
- /* baud rate */ \
- UBRR1H = SERIAL_UART_UBRR >> 8; \
- /* enable TX */ \
- UCSR1B = _BV(TXEN1); \
- /* 8-bit data */ \
- UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \
- sei(); \
- } while(0)
-# else
-# error "USART configuration is needed."
-# endif
-#endif
-
-#define API_SYSEX_MAX_SIZE 32
#include "song_list.h"
diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c
index 6c0e3bb071..60513f98e1 100644
--- a/quantum/debounce/sym_defer_pk.c
+++ b/quantum/debounce/sym_defer_pk.c
@@ -23,6 +23,12 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
#include "quantum.h"
#include <stdlib.h>
+#ifdef PROTOCOL_CHIBIOS
+# if CH_CFG_USE_MEMCORE == FALSE
+# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
+# endif
+#endif
+
#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c
index 93a40ad441..e66cf92d79 100644
--- a/quantum/debounce/sym_eager_pk.c
+++ b/quantum/debounce/sym_eager_pk.c
@@ -23,6 +23,12 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
#include "quantum.h"
#include <stdlib.h>
+#ifdef PROTOCOL_CHIBIOS
+# if CH_CFG_USE_MEMCORE == FALSE
+# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
+# endif
+#endif
+
#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c
index d12931fddb..20ccb46f1d 100644
--- a/quantum/debounce/sym_eager_pr.c
+++ b/quantum/debounce/sym_eager_pr.c
@@ -23,6 +23,12 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
#include "quantum.h"
#include <stdlib.h>
+#ifdef PROTOCOL_CHIBIOS
+# if CH_CFG_USE_MEMCORE == FALSE
+# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
+# endif
+#endif
+
#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
diff --git a/quantum/dip_switch.c b/quantum/dip_switch.c
index b1edd7d9cc..cda69bd0ef 100644
--- a/quantum/dip_switch.c
+++ b/quantum/dip_switch.c
@@ -49,17 +49,13 @@ static uint16_t scan_count;
static bool dip_switch_state[NUMBER_OF_DIP_SWITCHES] = {0};
static bool last_dip_switch_state[NUMBER_OF_DIP_SWITCHES] = {0};
-__attribute__((weak))
-void dip_switch_update_user(uint8_t index, bool active) {}
+__attribute__((weak)) void dip_switch_update_user(uint8_t index, bool active) {}
-__attribute__((weak))
-void dip_switch_update_kb(uint8_t index, bool active) { dip_switch_update_user(index, active); }
+__attribute__((weak)) void dip_switch_update_kb(uint8_t index, bool active) { dip_switch_update_user(index, active); }
-__attribute__((weak))
-void dip_switch_update_mask_user(uint32_t state) {}
+__attribute__((weak)) void dip_switch_update_mask_user(uint32_t state) {}
-__attribute__((weak))
-void dip_switch_update_mask_kb(uint32_t state) { dip_switch_update_mask_user(state); }
+__attribute__((weak)) void dip_switch_update_mask_kb(uint32_t state) { dip_switch_update_mask_user(state); }
void dip_switch_init(void) {
#ifdef DIP_SWITCH_PINS
@@ -73,10 +69,9 @@ void dip_switch_init(void) {
#endif
}
-
void dip_switch_read(bool forced) {
- bool has_dip_state_changed = false;
- uint32_t dip_switch_mask = 0;
+ bool has_dip_state_changed = false;
+ uint32_t dip_switch_mask = 0;
#ifdef DIP_SWITCH_MATRIX_GRID
bool read_raw = false;
diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c
index 688379c9af..f76f37f997 100644
--- a/quantum/dynamic_keymap.c
+++ b/quantum/dynamic_keymap.c
@@ -14,16 +14,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "keymap.h" // to get keymaps[][][]
-#include "eeprom.h"
-#include "progmem.h" // to read default from flash
+
+#include "tmk_core/common/eeprom.h"
#include "quantum.h" // for send_string()
-#include "dynamic_keymap.h"
-#ifdef VIA_ENABLE
-# include "via.h" // for default VIA_EEPROM_ADDR_END
-#else
-# include "eeconfig.h"
-#endif
+#include "eeconfig.h"
#ifndef DYNAMIC_KEYMAP_LAYER_COUNT
# define DYNAMIC_KEYMAP_LAYER_COUNT 4
@@ -35,10 +29,18 @@
// This is the default EEPROM max address to use for dynamic keymaps.
// The default is the ATmega32u4 EEPROM max address.
-// Explicitly override it if the keyboard uses a microcontroller with
+// Explicitly override it if the keyboard uses a microcontroller with
// more EEPROM *and* it makes sense to increase it.
#ifndef DYNAMIC_KEYMAP_EEPROM_MAX_ADDR
-# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 1023
+# if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)
+# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 2047
+# elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
+# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 4095
+# elif defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATtiny85__)
+# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 511
+# else
+# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 1023
+# endif
#endif
// Due to usage of uint16_t check for max 65535
@@ -222,9 +224,9 @@ void dynamic_keymap_macro_send(uint8_t id) {
++p;
}
- // Send the macro string one or two chars at a time
- // by making temporary 1 or 2 char strings
- char data[3] = {0, 0, 0};
+ // Send the macro string one or three chars at a time
+ // by making temporary 1 or 3 char strings
+ char data[4] = {0, 0, 0, 0};
// We already checked there was a null at the end of
// the buffer, so this cannot go past the end
while (1) {
@@ -235,10 +237,12 @@ void dynamic_keymap_macro_send(uint8_t id) {
break;
}
// If the char is magic (tap, down, up),
- // add the next char (key to use) and send a 2 char string.
+ // add the next char (key to use) and send a 3 char string.
if (data[0] == SS_TAP_CODE || data[0] == SS_DOWN_CODE || data[0] == SS_UP_CODE) {
- data[1] = eeprom_read_byte(p++);
- if (data[1] == 0) {
+ data[1] = data[0];
+ data[0] = SS_QMK_PREFIX;
+ data[2] = eeprom_read_byte(p++);
+ if (data[2] == 0) {
break;
}
}
diff --git a/quantum/encoder.c b/quantum/encoder.c
index 7ca31afedc..2ed64c1e30 100644
--- a/quantum/encoder.c
+++ b/quantum/encoder.c
@@ -94,8 +94,9 @@ void encoder_init(void) {
#endif
}
-static void encoder_update(int8_t index, uint8_t state) {
- uint8_t i = index;
+static bool encoder_update(int8_t index, uint8_t state) {
+ bool changed = false;
+ uint8_t i = index;
#ifdef ENCODER_RESOLUTIONS
int8_t resolution = encoder_resolutions[i];
@@ -109,40 +110,53 @@ static void encoder_update(int8_t index, uint8_t state) {
encoder_pulses[i] += encoder_LUT[state & 0xF];
if (encoder_pulses[i] >= resolution) {
encoder_value[index]++;
+ changed = true;
encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
}
if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise
encoder_value[index]--;
+ changed = true;
encoder_update_kb(index, ENCODER_CLOCKWISE);
}
encoder_pulses[i] %= resolution;
+ return changed;
}
-void encoder_read(void) {
+bool encoder_read(void) {
+ bool changed = false;
for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) {
encoder_state[i] <<= 2;
encoder_state[i] |= (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1);
- encoder_update(i, encoder_state[i]);
+ changed |= encoder_update(i, encoder_state[i]);
}
+ return changed;
}
#ifdef SPLIT_KEYBOARD
+void last_encoder_activity_trigger(void);
+
void encoder_state_raw(uint8_t* slave_state) { memcpy(slave_state, &encoder_value[thisHand], sizeof(uint8_t) * NUMBER_OF_ENCODERS); }
void encoder_update_raw(uint8_t* slave_state) {
+ bool changed = false;
for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) {
uint8_t index = i + thatHand;
int8_t delta = slave_state[i] - encoder_value[index];
while (delta > 0) {
delta--;
encoder_value[index]++;
+ changed = true;
encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
}
while (delta < 0) {
delta++;
encoder_value[index]--;
+ changed = true;
encoder_update_kb(index, ENCODER_CLOCKWISE);
}
}
+
+ // Update the last encoder input time -- handled external to encoder_read() when we're running a split
+ if (changed) last_encoder_activity_trigger();
}
#endif
diff --git a/quantum/encoder.h b/quantum/encoder.h
index ec09a8cc47..db6f220da4 100644
--- a/quantum/encoder.h
+++ b/quantum/encoder.h
@@ -20,7 +20,7 @@
#include "quantum.h"
void encoder_init(void);
-void encoder_read(void);
+bool encoder_read(void);
void encoder_update_kb(int8_t index, bool clockwise);
void encoder_update_user(int8_t index, bool clockwise);
diff --git a/quantum/fauxclicky.c b/quantum/fauxclicky.c
deleted file mode 100644
index 53499c9c1e..0000000000
--- a/quantum/fauxclicky.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-Copyright 2017 Priyadi Iman Nurcahyo
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <avr/interrupt.h>
-#include <avr/io.h>
-#include "timer.h"
-#include "fauxclicky.h"
-#include <stdbool.h>
-#include "musical_notes.h"
-
-bool fauxclicky_enabled = true;
-uint16_t note_start = 0;
-bool note_playing = false;
-uint16_t note_period = 0;
-
-void fauxclicky_init() {
- // Set port PC6 (OC3A and /OC4A) as output
- DDRC |= _BV(PORTC6);
-
- // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
- TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
- TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
-}
-
-void fauxclicky_stop() {
- FAUXCLICKY_DISABLE_OUTPUT;
- note_playing = false;
-}
-
-void fauxclicky_play(float note[]) {
- if (!fauxclicky_enabled) return;
- if (note_playing) fauxclicky_stop();
- FAUXCLICKY_TIMER_PERIOD = (uint16_t)(((float)F_CPU) / (note[0] * (float)FAUXCLICKY_CPU_PRESCALER));
- FAUXCLICKY_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (note[0] * (float)FAUXCLICKY_CPU_PRESCALER)) / (float)2);
- note_playing = true;
- note_period = (note[1] / (float)16) * ((float)60 / (float)FAUXCLICKY_TEMPO) * 1000;
- note_start = timer_read();
- FAUXCLICKY_ENABLE_OUTPUT;
-}
-
-void fauxclicky_check() {
- if (!note_playing) return;
-
- if (timer_elapsed(note_start) > note_period) {
- fauxclicky_stop();
- }
-}
diff --git a/quantum/fauxclicky.h b/quantum/fauxclicky.h
deleted file mode 100644
index ed54d0edcf..0000000000
--- a/quantum/fauxclicky.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-Copyright 2017 Priyadi Iman Nurcahyo
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef AUDIO_ENABLE
-# error "AUDIO_ENABLE and FAUXCLICKY_ENABLE cannot be both enabled"
-#endif
-
-#include "musical_notes.h"
-#include <stdbool.h>
-
-__attribute__((weak)) float fauxclicky_pressed_note[2] = MUSICAL_NOTE(_D4, 0.25);
-__attribute__((weak)) float fauxclicky_released_note[2] = MUSICAL_NOTE(_C4, 0.125);
-__attribute__((weak)) float fauxclicky_beep_note[2] = MUSICAL_NOTE(_C4, 0.25);
-
-extern bool fauxclicky_enabled;
-
-//
-// tempo in BPM
-//
-
-#ifndef FAUXCLICKY_TEMPO
-# define FAUXCLICKY_TEMPO TEMPO_DEFAULT
-#endif
-
-// beep on press
-#define FAUXCLICKY_ACTION_PRESS fauxclicky_play(fauxclicky_pressed_note)
-
-// beep on release
-#define FAUXCLICKY_ACTION_RELEASE fauxclicky_play(fauxclicky_released_note)
-
-// general purpose beep
-#define FAUXCLICKY_BEEP fauxclicky_play(fauxclicky_beep_note)
-
-// enable
-#define FAUXCLICKY_ON fauxclicky_enabled = true
-
-// disable
-#define FAUXCLICKY_OFF \
- do { \
- fauxclicky_enabled = false; \
- fauxclicky_stop(); \
- } while (0)
-
-// toggle
-#define FAUXCLICKY_TOGGLE \
- do { \
- if (fauxclicky_enabled) { \
- FAUXCLICKY_OFF; \
- } else { \
- FAUXCLICKY_ON; \
- } \
- } while (0)
-
-//
-// pin configuration
-//
-
-#ifndef FAUXCLICKY_CPU_PRESCALER
-# define FAUXCLICKY_CPU_PRESCALER 8
-#endif
-
-#ifndef FAUXCLICKY_ENABLE_OUTPUT
-# define FAUXCLICKY_ENABLE_OUTPUT TCCR3A |= _BV(COM3A1)
-#endif
-
-#ifndef FAUXCLICKY_DISABLE_OUTPUT
-# define FAUXCLICKY_DISABLE_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0))
-#endif
-
-#ifndef FAUXCLICKY_TIMER_PERIOD
-# define FAUXCLICKY_TIMER_PERIOD ICR3
-#endif
-
-#ifndef FAUXCLICKY_DUTY_CYCLE
-# define FAUXCLICKY_DUTY_CYCLE OCR3A
-#endif
-
-//
-// definitions
-//
-
-void fauxclicky_init(void);
-void fauxclicky_stop(void);
-void fauxclicky_play(float note[2]);
-void fauxclicky_check(void);
diff --git a/quantum/keymap.h b/quantum/keymap.h
index 00d21e084b..191e813977 100644
--- a/quantum/keymap.h
+++ b/quantum/keymap.h
@@ -39,6 +39,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#if defined(PROTOCOL_CHIBIOS)
# define RESET QK_RESET
#endif
+// Gross hack, remove me and change RESET keycode to QK_BOOT
+#if defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1287__)
+# undef RESET
+#endif
#include "quantum_keycodes.h"
diff --git a/quantum/keymap_extras/keymap_canadian_multilingual.h b/quantum/keymap_extras/keymap_canadian_multilingual.h
index d86a96086c..bb8e44d546 100644
--- a/quantum/keymap_extras/keymap_canadian_multilingual.h
+++ b/quantum/keymap_extras/keymap_canadian_multilingual.h
@@ -22,15 +22,15 @@
/*
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
- * │ / │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │ │
+ * │ / │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 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 │ , │ . │ É │ │
+ * │    │ Ù │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ É │          │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
- * │ │ │ │ │ │ │ │ │
+ * │    │    │    │                        │    │    │    │    │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
@@ -88,15 +88,15 @@
/* Shifted symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
- * │ \ │ ! │ @ │ # │ $ │ % │ ? │ & │ * │ ( │ ) │ _ │ + │ │
+ * │ \ │ ! │ @ │ # │ $ │ % │ ? │ & │ * │ ( │ ) │ _ │ + │       │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
- * │ │ │ │ │ │ │ │ │ │ │ │ ¨ │ │ │
- * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │
- * │ │ │ │ │ │ │ │ │ │ │ : │ │ │ │
+ * │     │   │   │   │   │   │   │   │   │   │   │ ¨ │   │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │   │   │   │   │   │   │   │   │   │ : │   │   │    │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
- * │ │ │ │ │ │ │ │ │ │ ' │ " │ │ │
+ * │    │   │   │   │   │   │   │   │   │ ' │ " │   │          │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
- * │ │ │ │ │ │ │ │ │
+ * │    │    │    │                        │    │    │    │    │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
@@ -123,15 +123,15 @@
/* AltGr symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
- * │ | │ │ │ │ ¤ │ │ │ { │ } │ [ │ ] │ │ ¬ │ │
+ * │ | │   │   │   │ ¤ │   │   │ { │ } │ [ │ ] │   │ ¬ │       │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
- * │ │ │ │ € │ │ │ │ │ │ │ │ ` │ ~ │ │
- * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │
- * │ │ │ │ │ │ │ │ │ │ │ ° │ │ │ │
+ * │     │   │   │ € │   │   │   │   │   │   │   │ ` │ ~ │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │   │   │   │   │   │   │   │   │   │ ° │   │   │    │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
- * │ │ │ « │ » │ │ │ │ │ │ < │ > │ │ │
+ * │    │   │ « │ » │   │   │   │   │   │ < │ > │   │          │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
- * │ │ │ │ │ │ │ │ │
+ * │    │    │    │                        │    │    │    │    │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
@@ -156,15 +156,15 @@
/* Right Ctrl symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
- * │ │ ¹ │ ² │ ³ │ ¼ │ ½ │ ¾ │ │ │ │ │ │ ¸ │ │
+ * │   │ ¹ │ ² │ ³ │ ¼ │ ½ │ ¾ │   │   │   │   │   │ ¸ │       │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
- * │ │ Ω │ Ł │ Œ │ ¶ │ Ŧ │ ← │ ↓ │ → │ Ø │ Þ │ │ ~ │ │
- * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │
- * │ │ Æ │ ß │ Ð │ │ Ŋ │ Ħ │ IJ │ ĸ │ Ŀ │ ´ │ │ │ │
+ * │     │ Ω │ Ł │ Œ │ ¶ │ Ŧ │ ← │ ↓ │ → │ Ø │ Þ │   │ ~ │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │ Æ │ ß │ Ð │   │ Ŋ │ Ħ │ IJ │ ĸ │ Ŀ │ ´ │   │   │    │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
- * │ │ │ │ │ ¢ │ “ │ ” │ ʼn │ μ │ ― │ ˙ │ │ │
+ * │    │   │   │   │ ¢ │ “ │ ” │ ʼn │ μ │ ― │ ˙ │   │          │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
- * │ │ │ │ │ │ │ │ │
+ * │    │    │    │                        │    │    │    │    │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
@@ -208,15 +208,15 @@
/* Shift+Right Ctrl symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
- * │ - │ ¡ │ │ £ │ │ ⅜ │ ⅝ │ ⅞ │ ™ │ ± │ │ ¿ │ ˛ │ │
+ * │ - │ ¡ │   │ £ │   │ ⅜ │ ⅝ │ ⅞ │ ™ │ ± │   │ ¿ │ ˛ │       │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
- * │ │ │ │ │ ® │ │ ¥ │ ↑ │ ı │ │ │ ° │ ¯ │ │
- * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │
- * │ │ │ § │ │ ª │ │ │ │ │ │ ˝ │ ˇ │ ˘ │ │
+ * │     │   │   │   │ ® │   │ ¥ │ ↑ │ ı │   │   │ ° │ ¯ │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │   │ § │   │ ª │   │   │   │   │   │ ˝ │ ˇ │ ˘ │    │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
- * │ │ ¦ │ │ │ © │ ‘ │ ’ │ ♪ │ º │ × │ ÷ │ │ │
+ * │    │ ¦ │   │   │ © │ ‘ │ ’ │ ♪ │ º │ × │ ÷ │   │          │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
- * │ │ │ │ │ │ │ │ │
+ * │    │    │    │                        │    │    │    │    │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
diff --git a/quantum/keymap_extras/keymap_croatian.h b/quantum/keymap_extras/keymap_croatian.h
new file mode 100644
index 0000000000..4af5dc5875
--- /dev/null
+++ b/quantum/keymap_extras/keymap_croatian.h
@@ -0,0 +1,163 @@
+/* Copyright 2020
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "keymap.h"
+
+// clang-format off
+
+/*
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ¸ │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ ' │ + │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ Q │ W │ E │ R │ T │ Z │ U │ I │ O │ P │ Š │ Đ │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ Č │ Ć │ Ž │    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │ < │ Y │ X │ C │ V │ B │ N │ M │ , │ . │ - │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define HR_CEDL KC_GRV // ¸ (dead)
+#define HR_1 KC_1 // 1
+#define HR_2 KC_2 // 2
+#define HR_3 KC_3 // 3
+#define HR_4 KC_4 // 4
+#define HR_5 KC_5 // 5
+#define HR_6 KC_6 // 6
+#define HR_7 KC_7 // 7
+#define HR_8 KC_8 // 8
+#define HR_9 KC_9 // 9
+#define HR_0 KC_0 // 0
+#define HR_QUOT KC_MINS // '
+#define HR_PLUS KC_EQL // +
+// Row 2
+#define HR_Q KC_Q // Q
+#define HR_W KC_W // W
+#define HR_E KC_E // E
+#define HR_R KC_R // R
+#define HR_T KC_T // T
+#define HR_Z KC_Y // Z
+#define HR_U KC_U // U
+#define HR_I KC_I // I
+#define HR_O KC_O // O
+#define HR_P KC_P // P
+#define HR_SCAR KC_LBRC // Š
+#define HR_DSTR KC_RBRC // Đ
+// Row 3
+#define HR_A KC_A // A
+#define HR_S KC_S // S
+#define HR_D KC_D // D
+#define HR_F KC_F // F
+#define HR_G KC_G // G
+#define HR_H KC_H // H
+#define HR_J KC_J // J
+#define HR_K KC_K // K
+#define HR_L KC_L // L
+#define HR_CCAR KC_SCLN // Č
+#define HR_CACU KC_QUOT // Ć
+#define HR_ZCAR KC_NUHS // Ž
+// Row 4
+#define HR_LABK KC_NUBS // <
+#define HR_Y KC_Z // Y
+#define HR_X KC_X // X
+#define HR_C KC_C // C
+#define HR_V KC_V // V
+#define HR_B KC_B // B
+#define HR_N KC_N // N
+#define HR_M KC_M // M
+#define HR_COMM KC_COMM // ,
+#define HR_DOT KC_DOT // .
+#define HR_MINS KC_SLSH // -
+
+/* Shifted symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ¨ │ ! │ " │ # │ $ │ % │ & │ / │ ( │ ) │ = │ ? │ * │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │   │   │   │   │   │   │   │   │   │   │   │   │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │   │   │   │   │   │   │   │   │   │   │   │   │    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │ > │   │   │   │   │   │   │   │ ; │ : │ _ │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define HR_DIAE S(HR_CEDL) // ¨ (dead)
+#define HR_EXLM S(HR_1) // !
+#define HR_DQUO S(HR_2) // "
+#define HR_HASH S(HR_3) // #
+#define HR_DLR S(HR_4) // $
+#define HR_PERC S(HR_5) // %
+#define HR_AMPR S(HR_6) // &
+#define HR_SLSH S(HR_7) // /
+#define HR_LPRN S(HR_8) // (
+#define HR_RPRN S(HR_9) // )
+#define HR_EQL S(HR_0) // =
+#define HR_QUES S(HR_QUOT) // ?
+#define HR_ASTR S(HR_PLUS) // *
+// Row 4
+#define HR_RABK S(HR_LABK) // >
+#define HR_SCLN S(HR_COMM) // ;
+#define HR_COLN S(HR_DOT) // :
+#define HR_UNDS S(HR_MINS) // _
+
+/* AltGr symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │   │ ~ │ ˇ │ ^ │ ˘ │ ° │ ˛ │ ` │ ˙ │ ´ │ ˝ │   │   │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ \ │ | │ € │   │   │   │   │   │   │   │ ÷ │ × │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │   │   │   │ [ │ ] │   │   │ ł │ Ł │   │ ß │ ¤ │    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │   │   │   │   │ @ │ { │ } │ § │   │   │   │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define HR_TILD ALGR(HR_1) // ~
+#define HR_CARN ALGR(HR_2) // ˇ (dead)
+#define HR_CIRC ALGR(HR_3) // ^ (dead)
+#define HR_BREV ALGR(HR_4) // ˘ (dead)
+#define HR_RNGA ALGR(HR_5) // ° (dead)
+#define HR_OGON ALGR(HR_6) // ˛ (dead)
+#define HR_GRV ALGR(HR_7) // `
+#define HR_DOTA ALGR(HR_8) // ˙ (dead)
+#define HR_ACUT ALGR(HR_9) // ´ (dead)
+#define HR_DACU ALGR(HR_0) // ˝ (dead)
+// Row 2
+#define HR_BSLS ALGR(HR_Q) // (backslash)
+#define HR_PIPE ALGR(HR_W) // |
+#define HR_EURO ALGR(HR_E) // €
+#define HR_DIV ALGR(HR_SCAR) // ÷
+#define HR_MUL ALGR(HR_DSTR) // ×
+// Row 3
+#define HR_LBRC ALGR(HR_F) // [
+#define HR_RBRC ALGR(HR_G) // ]
+#define HR_LLST ALGR(HR_K) // ł
+#define HR_CLST ALGR(HR_L) // Ł
+#define HR_SS ALGR(HR_CACU) // ß
+#define HR_CURR ALGR(HR_ZCAR) // ¤
+// Row 4
+#define HR_AT ALGR(HR_V) // @
+#define HR_LCBR ALGR(HR_B) // {
+#define HR_RCBR ALGR(HR_N) // }
+#define HR_SECT ALGR(HR_M) // §
diff --git a/quantum/keymap_extras/keymap_french_afnor.h b/quantum/keymap_extras/keymap_french_afnor.h
new file mode 100644
index 0000000000..be67fdc952
--- /dev/null
+++ b/quantum/keymap_extras/keymap_french_afnor.h
@@ -0,0 +1,253 @@
+/* Copyright 2020 Guillaume Gérard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* French AZERTY - AFNOR NF Z71-300
+ *
+ * A standard for the French keyboard
+ *
+ * The project was launched at the end of 2015 on the proposal of the General
+ * Delegation for the French language and the languages ​​of France (Ministry
+ * of Culture), starting from the observation that the current "azerty"
+ * keyboards constrain the writing of French, languages regional and European
+ * languages ​​with Latin alphabet.
+ *
+ * For the first time, a standard (NF Z71-300) defines the placement of
+ * characters on the French keyboard. It offers two layouts, one of which
+ * closely follows the QWERTY keyboard used by most people who write in French.
+ *
+ * However, it is in many ways superior to the old keyboard:
+ *
+ * - it contains all the characters required to enter text in French (for example É, œ and ")
+ * - it is designed to be more ergonomic and allow faster typing
+ * - it includes almost 60 additional characters for entering foreign languages, technical content, etc
+ * - however, the characters remain easy to locate thanks to intuitive groupings
+ *
+ * Source: https://norme-azerty.fr
+ */
+
+#pragma once
+
+#include "keymap.h"
+
+// clang-format off
+
+/*
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ @ │ à │ é │ è │ ê │ ( │ ) │ ‘ │ ’ │ « │ » │ ' │ ^ │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ A │ Z │ E │ R │ T │ Y │ U │ I │ O │ P │ - │ + │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │ Q │ S │ D │ F │ G │ H │ J │ K │ L │ M │ / │ * │    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │ < │ W │ X │ C │ V │ B │ N │ . │ , │ : │ ; │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define FR_AT KC_GRV // @
+#define FR_AGRV KC_1 // à
+#define FR_EACU KC_2 // é
+#define FR_EGRV KC_3 // è
+#define FR_ECIR KC_4 // ê
+#define FR_LPRN KC_5 // (
+#define FR_RPRN KC_6 // )
+#define FR_LSQU KC_7 // ‘
+#define FR_RSQU KC_8 // ’
+#define FR_LDAQ KC_9 // «
+#define FR_RDAQ KC_0 // »
+#define FR_QUOT KC_MINS // '
+#define FR_DCIR KC_EQL // ^ (dead)
+// Row 2
+#define FR_A KC_Q // A
+#define FR_Z KC_W // Z
+#define FR_E KC_E // E
+#define FR_R KC_R // R
+#define FR_T KC_T // T
+#define FR_Y KC_Y // Y
+#define FR_U KC_U // U
+#define FR_I KC_I // I
+#define FR_O KC_O // O
+#define FR_P KC_P // P
+#define FR_MINS KC_LBRC // -
+#define FR_PLUS KC_RBRC // +
+// Row 3
+#define FR_Q KC_A // Q
+#define FR_S KC_S // S
+#define FR_D KC_D // D
+#define FR_F KC_F // F
+#define FR_G KC_G // G
+#define FR_H KC_H // H
+#define FR_J KC_J // J
+#define FR_K KC_K // K
+#define FR_L KC_L // L
+#define FR_M KC_SCLN // M
+#define FR_SLSH KC_QUOT // /
+#define FR_ASTR KC_NUHS // *
+// Row 4
+#define FR_LABK KC_NUBS // <
+#define FR_W KC_Z // W
+#define FR_X KC_X // X
+#define FR_C KC_C // C
+#define FR_V KC_V // V
+#define FR_B KC_B // B
+#define FR_N KC_N // N
+#define FR_DOT KC_M // .
+#define FR_COMM KC_COMM // ,
+#define FR_COLN KC_DOT // :
+#define FR_SCLN KC_SLSH // ;
+
+/* Shifted symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ # │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ " │ ¨ │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │   │   │   │   │   │   │   │   │   │   │ – │ ± │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │   │   │   │   │   │   │   │   │   │   │ \ │ ½ │    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │ > │   │   │   │   │   │   │ ? │ ! │ … │ = │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define FR_HASH S(FR_AT) // #
+#define FR_1 S(FR_AGRV) // 1
+#define FR_2 S(FR_EACU) // 2
+#define FR_3 S(FR_EGRV) // 3
+#define FR_4 S(FR_ECIR) // 4
+#define FR_5 S(FR_LPRN) // 5
+#define FR_6 S(FR_RPRN) // 6
+#define FR_7 S(FR_LSQU) // 7
+#define FR_8 S(FR_RSQU) // 8
+#define FR_9 S(FR_LDAQ) // 9
+#define FR_0 S(FR_RDAQ) // 0
+#define FR_DQUO S(FR_QUOT) // "
+#define FR_DIAE S(FR_DCIR) // ¨ (dead)
+// Row 2
+#define FR_NDSH S(FR_MINS) // –
+#define FR_PLMN S(FR_PLUS) // ±
+// Row 3
+#define FR_BSLS S(FR_SLSH) // (backslash)
+#define FR_HALF S(FR_ASTR) // ½
+// Row 4
+#define FR_RABK S(FR_LABK) // >
+#define FR_QUES S(FR_DOT) // ?
+#define FR_EXLM S(FR_COMM) // !
+#define FR_ELLP S(FR_COLN) // …
+#define FR_EQL S(FR_SCLN) // =
+
+/* AltGr symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ˘ │ § │ ´ │ ` │ & │ [ │ ] │ ¯ │ _ │ “ │ ” │ ° │ ˇ │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ æ │ £ │ € │ ® │ { │ } │ ù │ ˙ │ œ │ % │ − │ † │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │ θ │ ß │ $ │ ¤ │ µ │ Eu│   │ ∕ │ | │ ∞ │ ÷ │ × │    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │ ≤ │ ʒ │ © │ ç │ ¸ │ − │ ~ │ ¿ │ ¡ │ · │ ≃ │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define FR_BREV ALGR(FR_AT) // ˘ (dead)
+#define FR_SECT ALGR(FR_AGRV) // §
+#define FR_ACUT ALGR(FR_EACU) // ´ (dead)
+#define FR_GRV ALGR(FR_EGRV) // ` (dead)
+#define FR_AMPR ALGR(FR_ECIR) // &
+#define FR_LBRC ALGR(FR_LPRN) // [
+#define FR_RBRC ALGR(FR_RPRN) // ]
+#define FR_MACR ALGR(FR_LSQU) // ¯ (dead)
+#define FR_UNDS ALGR(FR_RSQU) // _
+#define FR_LDQU ALGR(FR_LDAQ) // “
+#define FR_RDQU ALGR(FR_RDAQ) // ”
+#define FR_DEG ALGR(FR_QUOT) // °
+#define FR_CARN ALGR(FR_DCIR) // ˇ (dead)
+// Row 2
+#define FR_AE ALGR(FR_A) // æ
+#define FR_PND ALGR(FR_Z) // £
+#define FR_EURO ALGR(FR_E) // €
+#define FR_REGD ALGR(FR_R) // ®
+#define FR_LCBR ALGR(FR_T) // {
+#define FR_RCBR ALGR(FR_Y) // }
+#define FR_UGRV ALGR(FR_U) // ù
+#define FR_DOTA ALGR(FR_I) // ˙ (dead)
+#define FR_OE ALGR(FR_O) // œ
+#define FR_PERC ALGR(FR_P) // %
+#define FR_MMNS ALGR(FR_MINS) // −
+#define FR_DAGG ALGR(FR_PLUS) // †
+// Row 3
+#define FR_THET ALGR(FR_Q) // θ
+#define FR_SS ALGR(FR_S) // ß
+#define FR_DLR ALGR(FR_D) // $
+#define FR_CURR ALGR(FR_F) // ¤ (dead monetary key)
+#define FR_DGRK ALGR(FR_G) // µ (dead Greek key)
+#define FR_EU ALGR(FR_H) // Eu (dead European symbol key)
+#define FR_DSLS ALGR(FR_K) // ∕ (dead)
+#define FR_PIPE ALGR(FR_L) // |
+#define FR_INFN ALGR(FR_M) // ∞
+#define FR_DIV ALGR(FR_SLSH) // ÷
+#define FR_MUL ALGR(FR_ASTR) // ×
+// Row 4
+#define FR_LEQL ALGR(FR_LABK) // ≤
+#define FR_EZH ALGR(FR_W) // ʒ
+#define FR_COPY ALGR(FR_X) // ©
+#define FR_CCED ALGR(FR_C) // ç
+#define FR_CEDL ALGR(FR_V) // ¸ (dead)
+#define FR_DMNS ALGR(FR_B) // − (dead)
+#define FR_DTIL ALGR(FR_N) // ~ (dead)
+#define FR_IQUE ALGR(FR_DOT) // ¿
+#define FR_IEXL ALGR(FR_COMM) // ¡
+#define FR_MDDT ALGR(FR_COLN) // ·
+#define FR_AEQL ALGR(FR_SCLN) // ≃
+
+/* Shift+AltGr symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │  ̑ │   │   │   │   │ ˝ │  ̏ │   │ — │ ‹ │ › │ ˚ │   │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │   │   │   │   │ ™ │   │   │  ̣ │   │ ‰ │ ‑ │ ‡ │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │      │   │   │   │   │   │ ˍ │   │   │   │   │ √ │ ¼ │    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │ ≥ │   │   │   │ ˛ │   │   │   │  ̦ │   │ ≠ │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define FR_IBRV S(ALGR(FR_AT)) //  ̑ (dead)
+#define FR_DACU S(ALGR(FR_LPRN)) // ˝ (dead)
+#define FR_DGRV S(ALGR(FR_RPRN)) //  ̏ (dead)
+#define FR_MDSH S(ALGR(FR_RSQU)) // —
+#define FR_LSAQ S(ALGR(FR_LDAQ)) // ‹
+#define FR_RSAQ S(ALGR(FR_RDAQ)) // ›
+#define FR_RNGA S(ALGR(FR_QUOT)) // ˚ (dead)
+// Row 2
+#define FR_TM S(ALGR(FR_T)) // ™
+#define FR_DOTB S(ALGR(FR_I)) //  ̣ (dead)
+#define FR_PERM S(ALGR(FR_P)) // ‰
+#define FR_NBHY S(ALGR(FR_MINS)) // ‑ (non-breaking hyphen)
+#define FR_DDAG S(ALGR(FR_PLUS)) // ‡
+// Row 3
+#define FR_MACB S(ALGR(FR_H)) // ˍ (dead)
+#define FR_SQRT S(ALGR(FR_SLSH)) // √
+#define FR_QRTR S(ALGR(FR_ASTR)) // ¼
+// Row 4
+#define FR_GEQL S(ALGR(FR_LABK)) // ≥
+#define FR_OGON S(ALGR(FR_V)) // ˛ (dead)
+#define FR_DCMM S(ALGR(FR_COMM)) //  ̦ (dead)
+#define FR_NEQL S(ALGR(FR_SCLN)) // ≠
diff --git a/quantum/keymap_extras/keymap_neo2.h b/quantum/keymap_extras/keymap_neo2.h
index 818a739c76..c34e9116bb 100644
--- a/quantum/keymap_extras/keymap_neo2.h
+++ b/quantum/keymap_extras/keymap_neo2.h
@@ -13,66 +13,130 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef KEYMAP_NEO2
-#define KEYMAP_NEO2
-#include "keymap.h"
-#include "keymap_german.h"
-
-#define NEO_A KC_D
-#define NEO_B KC_N
-#define NEO_C KC_R
-#define NEO_D DE_OE
-#define NEO_E KC_F
-#define NEO_F KC_O
-#define NEO_G KC_I
-#define NEO_H KC_U
-#define NEO_I KC_S
-#define NEO_J DE_MINS
-#define NEO_K DE_Z
-#define NEO_L KC_E
-#define NEO_M KC_M
-#define NEO_N KC_J
-#define NEO_O KC_G
-#define NEO_P KC_V
-#define NEO_Q KC_P
-#define NEO_R KC_K
-#define NEO_S KC_H
-#define NEO_T KC_L
-#define NEO_U KC_A
-#define NEO_V KC_W
-#define NEO_W KC_T
-#define NEO_X KC_Q
-#define NEO_Y DE_AE
-#define NEO_Z KC_B
-#define NEO_AE KC_C
-#define NEO_OE KC_X
-#define NEO_UE DE_Y
-#define NEO_SS DE_UE
-
-#define NEO_DOT DE_DOT
-#define NEO_COMM DE_COMM
+#pragma once
-#define NEO_1 DE_1
-#define NEO_2 DE_2
-#define NEO_3 DE_3
-#define NEO_4 DE_4
-#define NEO_5 DE_5
-#define NEO_6 DE_6
-#define NEO_7 DE_7
-#define NEO_8 DE_8
-#define NEO_9 DE_9
-#define NEO_0 DE_0
-#define NEO_MINS DE_SS
-
-#define NEO_ACUT DE_PLUS
-#define NEO_GRV DE_ACUT
-#define NEO_CIRC DE_CIRC
+#include "keymap.h"
-#define NEO_L1_L KC_CAPS
-#define NEO_L1_R DE_HASH
+// clang-format off
-#define NEO_L2_L DE_LESS
-#define NEO_L2_R KC_ALGR
+/*
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ^ │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ ` │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ X │ V │ L │ C │ W │ K │ H │ G │ F │ Q │ ß │ ´ │     │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
+ * │  L3  │ U │ I │ A │ E │ O │ S │ N │ R │ T │ D │ Y │ L3│    │
+ * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
+ * │    │L4 │ Ü │ Ö │ Ä │ P │ Z │ B │ M │ , │ . │ J │          │
+ * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │ L4 │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define NE_CIRC KC_GRV // ^ (dead)
+#define NE_1 KC_1 // 1
+#define NE_2 KC_2 // 2
+#define NE_3 KC_3 // 3
+#define NE_4 KC_4 // 4
+#define NE_5 KC_5 // 5
+#define NE_6 KC_6 // 6
+#define NE_7 KC_7 // 7
+#define NE_8 KC_8 // 8
+#define NE_9 KC_9 // 9
+#define NE_0 KC_0 // 0
+#define NE_MINS KC_MINS // -
+#define NE_GRV KC_EQL // ` (dead)
+// Row 2
+#define NE_X KC_Q // X
+#define NE_V KC_W // V
+#define NE_L KC_E // L
+#define NE_C KC_R // C
+#define NE_W KC_T // W
+#define NE_K KC_Y // K
+#define NE_H KC_U // H
+#define NE_G KC_I // G
+#define NE_F KC_O // F
+#define NE_Q KC_P // Q
+#define NE_SS KC_LBRC // ß
+#define NE_ACUT KC_RBRC // ´ (dead)
+// Row 3
+#define NE_L3L KC_CAPS // (layer 3)
+#define NE_U KC_A // U
+#define NE_I KC_S // I
+#define NE_A KC_D // A
+#define NE_E KC_F // E
+#define NE_O KC_G // O
+#define NE_S KC_H // S
+#define NE_N KC_J // N
+#define NE_R KC_K // R
+#define NE_T KC_L // T
+#define NE_D KC_SCLN // D
+#define NE_Y KC_QUOT // Y
+#define NE_L3R KC_NUHS // (layer 3)
+// Row 4
+#define NE_L4L KC_NUBS // (layer 4)
+#define NE_UDIA KC_Z // Ü
+#define NE_ODIA KC_X // Ö
+#define NE_ADIA KC_C // Ä
+#define NE_P KC_V // P
+#define NE_Z KC_B // Z
+#define NE_B KC_N // B
+#define NE_M KC_M // M
+#define NE_COMM KC_COMM // ,
+#define NE_DOT KC_DOT // .
+#define NE_J KC_SLSH // J
+// Row 5
+#define NE_L4R KC_ALGR // (layer 4)
-#endif
+// DEPRECATED
+#define NEO_A NE_A
+#define NEO_B NE_B
+#define NEO_C NE_C
+#define NEO_D NE_D
+#define NEO_E NE_E
+#define NEO_F NE_F
+#define NEO_G NE_G
+#define NEO_H NE_H
+#define NEO_I NE_I
+#define NEO_J NE_J
+#define NEO_K NE_K
+#define NEO_L NE_L
+#define NEO_M NE_M
+#define NEO_N NE_N
+#define NEO_O NE_O
+#define NEO_P NE_P
+#define NEO_Q NE_Q
+#define NEO_R NE_R
+#define NEO_S NE_S
+#define NEO_T NE_T
+#define NEO_U NE_U
+#define NEO_V NE_V
+#define NEO_W NE_W
+#define NEO_X NE_X
+#define NEO_Y NE_Y
+#define NEO_Z NE_Z
+#define NEO_AE NE_ADIA
+#define NEO_OE NE_ODIA
+#define NEO_UE NE_UDIA
+#define NEO_SS NE_SS
+#define NEO_DOT NE_DOT
+#define NEO_COMM NE_COMM
+#define NEO_1 NE_1
+#define NEO_2 NE_2
+#define NEO_3 NE_3
+#define NEO_4 NE_4
+#define NEO_5 NE_5
+#define NEO_6 NE_6
+#define NEO_7 NE_7
+#define NEO_8 NE_8
+#define NEO_9 NE_9
+#define NEO_0 NE_0
+#define NEO_MINS NE_MINS
+#define NEO_ACUT NE_ACUT
+#define NEO_GRV NE_GRV
+#define NEO_CIRC NE_CIRC
+#define NEO_L1_L NE_L3L
+#define NEO_L1_R NE_L3R
+#define NEO_L2_L NE_L4L
+#define NEO_L2_R NE_L4R
diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h
index 7942533b31..76d2f4f6b0 100644
--- a/quantum/keymap_extras/keymap_nordic.h
+++ b/quantum/keymap_extras/keymap_nordic.h
@@ -66,8 +66,3 @@
#define NO_BSLS ALGR(KC_MINS)
#define NO_MU ALGR(KC_M)
-
-// Icelandic characters
-#define NO_TH KC_SLSH //Þ
-#define NO_ETH KC_LBRC //Ð
-#define NO_UMLT KC_MINS //Ö
diff --git a/quantum/keymap_extras/keymap_norwegian.h b/quantum/keymap_extras/keymap_norwegian.h
index b16339c8b3..8b6497f00f 100644
--- a/quantum/keymap_extras/keymap_norwegian.h
+++ b/quantum/keymap_extras/keymap_norwegian.h
@@ -34,57 +34,57 @@
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
-#define NRW_PIPE KC_GRV // |
-#define NRW_1 KC_1 // 1
-#define NRW_2 KC_2 // 2
-#define NRW_3 KC_3 // 3
-#define NRW_4 KC_4 // 4
-#define NRW_5 KC_5 // 5
-#define NRW_6 KC_6 // 6
-#define NRW_7 KC_7 // 7
-#define NRW_8 KC_8 // 8
-#define NRW_9 KC_9 // 9
-#define NRW_0 KC_0 // 0
-#define NRW_PLUS KC_MINS // +
-#define NRW_BSLS KC_EQL // (backslash)
+#define NWG_PIPE KC_GRV // |
+#define NWG_1 KC_1 // 1
+#define NWG_2 KC_2 // 2
+#define NWG_3 KC_3 // 3
+#define NWG_4 KC_4 // 4
+#define NWG_5 KC_5 // 5
+#define NWG_6 KC_6 // 6
+#define NWG_7 KC_7 // 7
+#define NWG_8 KC_8 // 8
+#define NWG_9 KC_9 // 9
+#define NWG_0 KC_0 // 0
+#define NWG_PLUS KC_MINS // +
+#define NWG_BSLS KC_EQL // (backslash)
// Row 2
-#define NRW_Q KC_Q // Q
-#define NRW_W KC_W // W
-#define NRW_E KC_E // E
-#define NRW_R KC_R // R
-#define NRW_T KC_T // T
-#define NRW_Y KC_Y // Y
-#define NRW_U KC_U // U
-#define NRW_I KC_I // I
-#define NRW_O KC_O // O
-#define NRW_P KC_P // P
-#define NRW_ARNG KC_LBRC // Å
-#define NRW_DIAE KC_RBRC // ¨ (dead)
+#define NWG_Q KC_Q // Q
+#define NWG_W KC_W // W
+#define NWG_E KC_E // E
+#define NWG_R KC_R // R
+#define NWG_T KC_T // T
+#define NWG_Y KC_Y // Y
+#define NWG_U KC_U // U
+#define NWG_I KC_I // I
+#define NWG_O KC_O // O
+#define NWG_P KC_P // P
+#define NWG_ARNG KC_LBRC // Å
+#define NWG_DIAE KC_RBRC // ¨ (dead)
// Row 3
-#define NRW_A KC_A // A
-#define NRW_S KC_S // S
-#define NRW_D KC_D // D
-#define NRW_F KC_F // F
-#define NRW_G KC_G // G
-#define NRW_H KC_H // H
-#define NRW_J KC_J // J
-#define NRW_K KC_K // K
-#define NRW_L KC_L // L
-#define NRW_OSTR KC_SCLN // Ø
-#define NRW_AE KC_QUOT // Æ
-#define NRW_QUOT KC_NUHS // '
+#define NWG_A KC_A // A
+#define NWG_S KC_S // S
+#define NWG_D KC_D // D
+#define NWG_F KC_F // F
+#define NWG_G KC_G // G
+#define NWG_H KC_H // H
+#define NWG_J KC_J // J
+#define NWG_K KC_K // K
+#define NWG_L KC_L // L
+#define NWG_OSTR KC_SCLN // Ø
+#define NWG_AE KC_QUOT // Æ
+#define NWG_QUOT KC_NUHS // '
// Row 4
-#define NRW_LABK KC_NUBS // <
-#define NRW_Z KC_Z // Z
-#define NRW_X KC_X // X
-#define NRW_C KC_C // C
-#define NRW_V KC_V // V
-#define NRW_B KC_B // B
-#define NRW_N KC_N // N
-#define NRW_M KC_M // M
-#define NRW_COMM KC_COMM // ,
-#define NRW_DOT KC_DOT // .
-#define NRW_MINS KC_SLSH // -
+#define NWG_LABK KC_NUBS // <
+#define NWG_Z KC_Z // Z
+#define NWG_X KC_X // X
+#define NWG_C KC_C // C
+#define NWG_V KC_V // V
+#define NWG_B KC_B // B
+#define NWG_N KC_N // N
+#define NWG_M KC_M // M
+#define NWG_COMM KC_COMM // ,
+#define NWG_DOT KC_DOT // .
+#define NWG_MINS KC_SLSH // -
/* Shifted symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
@@ -100,28 +100,28 @@
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
-#define NRW_SECT S(NRW_PIPE) // §
-#define NRW_EXLM S(NRW_1) // !
-#define NRW_DQUO S(NRW_2) // "
-#define NRW_HASH S(NRW_3) // #
-#define NRW_CURR S(NRW_4) // ¤
-#define NRW_PERC S(NRW_5) // %
-#define NRW_AMPR S(NRW_6) // &
-#define NRW_SLSH S(NRW_7) // /
-#define NRW_LPRN S(NRW_8) // (
-#define NRW_RPRN S(NRW_9) // )
-#define NRW_EQL S(NRW_0) // =
-#define NRW_QUES S(NRW_PLUS) // ?
-#define NRW_GRV S(NRW_BSLS) // ` (dead)
+#define NWG_SECT S(NWG_PIPE) // §
+#define NWG_EXLM S(NWG_1) // !
+#define NWG_DQUO S(NWG_2) // "
+#define NWG_HASH S(NWG_3) // #
+#define NWG_CURR S(NWG_4) // ¤
+#define NWG_PERC S(NWG_5) // %
+#define NWG_AMPR S(NWG_6) // &
+#define NWG_SLSH S(NWG_7) // /
+#define NWG_LPRN S(NWG_8) // (
+#define NWG_RPRN S(NWG_9) // )
+#define NWG_EQL S(NWG_0) // =
+#define NWG_QUES S(NWG_PLUS) // ?
+#define NWG_GRV S(NWG_BSLS) // ` (dead)
// Row 2
-#define NRW_CIRC S(NRW_DIAE) // ^ (dead)
+#define NWG_CIRC S(NWG_DIAE) // ^ (dead)
// Row 3
-#define NRW_ASTR S(NRW_QUOT) // *
+#define NWG_ASTR S(NWG_QUOT) // *
// Row 4
-#define NRW_RABK S(NRW_LABK) // >
-#define NRW_SCLN S(NRW_COMM) // ;
-#define NRW_COLN S(NRW_DOT) // :
-#define NRW_UNDS S(NRW_MINS) // _
+#define NWG_RABK S(NWG_LABK) // >
+#define NWG_SCLN S(NWG_COMM) // ;
+#define NWG_COLN S(NWG_DOT) // :
+#define NWG_UNDS S(NWG_MINS) // _
/* AltGr symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
@@ -137,39 +137,40 @@
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
-#define NRW_AT ALGR(NRW_2) // @
-#define NRW_PND ALGR(NRW_3) // £
-#define NRW_DLR ALGR(NRW_4) // $
-#define NRW_EURO ALGR(NRW_5) // €
-#define NRW_LCBR ALGR(NRW_7) // {
-#define NRW_LBRC ALGR(NRW_8) // [
-#define NRW_RBRC ALGR(NRW_9) // ]
-#define NRW_RCBR ALGR(NRW_0) // }
-#define NRW_ACUT ALGR(NRW_BSLS) // ´ (dead)
+
+#define NWG_AT ALGR(NWG_2) // @
+#define NWG_PND ALGR(NWG_3) // £
+#define NWG_DLR ALGR(NWG_4) // $
+#define NWG_EURO ALGR(NWG_5) // €
+#define NWG_LCBR ALGR(NWG_7) // {
+#define NWG_LBRC ALGR(NWG_8) // [
+#define NWG_RBRC ALGR(NWG_9) // ]
+#define NWG_RCBR ALGR(NWG_0) // }
+#define NWG_ACUT ALGR(NWG_BSLS) // ´ (dead)
// Row 2
-#define NRW_TILD ALGR(NRW_DIAE) // ~ (dead)
+#define NWG_TILD ALGR(NWG_DIAE) // ~ (dead)
// Row 4
-#define NRW_MICR ALGR(NRW_M) // µ
+#define NWG_MICR ALGR(NWG_M) // µ
// DEPRECATED
-#define NRW_AM NRW_ARNG
-#define NRW_AA NRW_ARNG
-#define NRW_OSLH NRW_OSTR
-#define NRW_APOS NRW_QUOT
-#define NRW_LESS NRW_LABK
-#define NRW_QUO2 NRW_DQUO
-#define NRW_BULT NRW_CURR
-#define NRW_GRTR NRW_RABK
-#define NRW_MU NRW_MICR
+#define NWG_AM NWG_ARNG
+#define NWG_AA NWG_ARNG
+#define NWG_OSLH NWG_OSTR
+#define NWG_APOS NWG_QUOT
+#define NWG_LESS NWG_LABK
+#define NWG_QUO2 NWG_DQUO
+#define NWG_BULT NWG_CURR
+#define NWG_GRTR NWG_RABK
+#define NWG_MU NWG_MICR
// Norwegian macOS symbols
-#define NRW_ACUT_MAC NRW_BSLS // ´
-#define NRW_APOS_MAC NRW_LABK // '
-#define NRW_AT_MAC NRW_QUOT // @
-#define NRW_BSLS_MAC S(ALGR(NRW_7)) // (backslash)
-#define NRW_DLR_MAC S(NRW_4) // $
-#define NRW_GRV_MAC ALGR(NRW_BSLS) // `
-#define NRW_GRTR_MAC S(NRW_PIPE) // >
-#define NRW_LCBR_MAC S(ALGR(NRW_8)) // {
-#define NRW_LESS_MAC NRW_PIPE // <
-#define NRW_PIPE_MAC ALGR(NRW_7) // |
-#define NRW_RCBR_MAC S(ALGR(NRW_9)) // }
+#define NWG_ACUT_MAC NWG_BSLS // ´
+#define NWG_APOS_MAC NWG_LABK // '
+#define NWG_AT_MAC NWG_QUOT // @
+#define NWG_BSLS_MAC S(ALGR(NWG_7)) // (backslash)
+#define NWG_DLR_MAC S(NWG_4) // $
+#define NWG_GRV_MAC ALGR(NWG_BSLS) // `
+#define NWG_GRTR_MAC S(NWG_PIPE) // >
+#define NWG_LCBR_MAC S(ALGR(NWG_8)) // {
+#define NWG_LESS_MAC NWG_PIPE // <
+#define NWG_PIPE_MAC ALGR(NWG_7) // |
+#define NWG_RCBR_MAC S(ALGR(NWG_9)) // }
diff --git a/quantum/keymap_extras/keymap_spanish_dvorak.h b/quantum/keymap_extras/keymap_spanish_dvorak.h
index b6bc734c37..8fd6214728 100644
--- a/quantum/keymap_extras/keymap_spanish_dvorak.h
+++ b/quantum/keymap_extras/keymap_spanish_dvorak.h
@@ -26,7 +26,7 @@
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
* │     │ . │ , │ Ñ │ P │ Y │ F │ G │ C │ H │ L │ ` │ + │     │
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
- * │      │ A │ O │ E │ U │ I │ D │ R │ T │ N │ S │ ' │ Ç │    │
+ * │      │ A │ O │ E │ U │ I │ D │ R │ T │ N │ S │ ´ │ Ç │    │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
* │    │ < │ - │ Q │ J │ K │ X │ B │ M │ W │ V │ Z │          │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
@@ -119,7 +119,11 @@
#define DV_CIRC S(DV_GRV) // ^ (dead)
#define DV_ASTR S(DV_PLUS) // *
// Row 3
+<<<<<<< HEAD
#define DV_DIAE S(DV_GRV) // ¨ (dead)
+=======
+#define DV_DIAE S(DV_ACUT) // ¨ (dead)
+>>>>>>> 0.12.52~1
// Row 4
#define DV_RABK S(DV_LABK) // >
#define DV_UNDS S(DV_MINS) // _
diff --git a/quantum/keymap_extras/keymap_us_extended.h b/quantum/keymap_extras/keymap_us_extended.h
new file mode 100644
index 0000000000..b2b3a734c9
--- /dev/null
+++ b/quantum/keymap_extras/keymap_us_extended.h
@@ -0,0 +1,227 @@
+/* Copyright 2020
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "keymap.h"
+
+// clang-format off
+
+/*
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ 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 │ , │ . │ / │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define US_GRV KC_GRV // `
+#define US_1 KC_1 // 1
+#define US_2 KC_2 // 2
+#define US_3 KC_3 // 3
+#define US_4 KC_4 // 4
+#define US_5 KC_5 // 5
+#define US_6 KC_6 // 6
+#define US_7 KC_7 // 7
+#define US_8 KC_8 // 8
+#define US_9 KC_9 // 9
+#define US_0 KC_0 // 0
+#define US_MINS KC_MINS // -
+#define US_EQL KC_EQL // =
+// Row 2
+#define US_Q KC_Q // Q
+#define US_W KC_W // W
+#define US_E KC_E // E
+#define US_R KC_R // R
+#define US_T KC_T // T
+#define US_Y KC_Y // Y
+#define US_U KC_U // U
+#define US_I KC_I // I
+#define US_O KC_O // O
+#define US_P KC_P // P
+#define US_LBRC KC_LBRC // [
+#define US_RBRC KC_RBRC // ]
+#define US_BSLS KC_BSLS // (backslash)
+// Row 3
+#define US_A KC_A // A
+#define US_S KC_S // S
+#define US_D KC_D // D
+#define US_F KC_F // F
+#define US_G KC_G // G
+#define US_H KC_H // H
+#define US_J KC_J // J
+#define US_K KC_K // K
+#define US_L KC_L // L
+#define US_SCLN KC_SCLN // ;
+#define US_QUOT KC_QUOT // '
+// Row 4
+#define US_Z KC_Z // Z
+#define US_X KC_X // X
+#define US_C KC_C // C
+#define US_V KC_V // V
+#define US_B KC_B // B
+#define US_N KC_N // N
+#define US_M KC_M // M
+#define US_COMM KC_COMM // ,
+#define US_DOT KC_DOT // .
+#define US_SLSH KC_SLSH // /
+
+/* Shifted symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ~ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ ( │ ) │ _ │ + │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │   │   │   │   │   │   │   │   │   │   │ { │ } │  |  │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
+ * │      │   │   │   │   │   │   │   │   │   │ : │ " │        │
+ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
+ * │        │   │   │   │   │   │   │   │ < │ > │ ? │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define US_TILD S(US_GRV) // ~
+#define US_EXLM S(US_1) // !
+#define US_AT S(US_2) // @
+#define US_HASH S(US_3) // #
+#define US_DLR S(US_4) // $
+#define US_PERC S(US_5) // %
+#define US_CIRC S(US_6) // ^
+#define US_AMPR S(US_7) // &
+#define US_ASTR S(US_8) // *
+#define US_LPRN S(US_9) // (
+#define US_RPRN S(US_0) // )
+#define US_UNDS S(US_MINS) // _
+#define US_PLUS S(US_EQL) // +
+// Row 2
+#define US_LCBR S(US_LBRC) // {
+#define US_RCBR S(US_RBRC) // }
+#define US_PIPE S(US_BSLS) // |
+// Row 3
+#define US_COLN S(US_SCLN) // :
+#define US_DQUO S(US_QUOT) // "
+// Row 4
+#define US_LABK S(US_COMM) // <
+#define US_RABK S(US_DOT) // >
+#define US_QUES S(US_SLSH) // ?
+
+/* AltGr symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ` │ ¹ │ ² │ ³ │ ¤ │ € │ ^ │ ̛  │ ¾ │ ‘ │ ’ │ ¥ │ × │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ Ä │ Å │ É │ ® │ Þ │ Ü │ Ú │ Í │ Ó │ Ö │ « │ » │  ¬  │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
+ * │      │ Á │ ß │ Ð │   │   │   │ Ï │ Œ │ Ø │ ¶ │ ' │        │
+ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
+ * │        │ Æ │   │ © │   │   │ Ñ │ µ │ Ç │ ˙ │ ¿ │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define US_DGRV ALGR(US_GRV) // ` (dead)
+#define US_SUP1 ALGR(US_1) // ¹
+#define US_SUP2 ALGR(US_2) // ²
+#define US_SUP3 ALGR(US_3) // ³
+#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_OGON ALGR(US_8) // ˛ (dead)
+#define US_LSQU ALGR(US_9) // ‘
+#define US_RSQU ALGR(US_0) // ’
+#define US_YEN ALGR(US_MINS) // ¥
+#define US_MUL ALGR(US_EQL) // ×
+// Row 2
+#define US_ADIA ALGR(US_Q) // Ä
+#define US_ARNG ALGR(US_W) // Å
+#define US_EACU ALGR(US_E) // É
+#define US_EDIA ALGR(US_R) // Ë
+#define US_THRN ALGR(US_T) // Þ
+#define US_UDIA ALGR(US_Y) // Ü
+#define US_UACU ALGR(US_U) // Ú
+#define US_IACU ALGR(US_I) // Í
+#define US_OACU ALGR(US_O) // Ó
+#define US_ODIA ALGR(US_P) // Ö
+#define US_LDAQ ALGR(US_LBRC) // «
+#define US_RDAQ ALGR(US_RBRC) // »
+#define US_NOT ALGR(US_BSLS) // ¬
+// Row 3
+#define US_AACU ALGR(US_A) // Á
+#define US_SS ALGR(US_S) // ß
+#define US_ETH ALGR(US_D) // Ð
+#define US_IDIA ALGR(US_J) // Ï
+#define US_OE ALGR(US_K) // Œ
+#define US_OSTR ALGR(US_L) // Ø
+#define US_PILC ALGR(US_SCLN) // ¶
+#define US_ACUT ALGR(US_QUOT) // ´ (dead)
+// Row 4
+#define US_AE ALGR(US_Z) // Æ
+#define US_OE_2 ALGR(US_X) // Œ
+#define US_COPY ALGR(US_C) // ©
+#define US_REGD ALGR(US_V) // ®
+#define US_NTIL ALGR(US_N) // Ñ
+#define US_MICR ALGR(US_M) // µ
+#define US_CCED ALGR(US_COMM) // Ç
+#define US_DOTA ALGR(US_DOT) // ˙ (dead)
+#define US_IQUE ALGR(US_SLSH) // ¿
+
+/* Shift+AltGr symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ~ │ ¡ │ ˝ │ ¯ │ £ │ ¸ │ ¼ │ ½ │ ¾ │ ˘ │ ° │  ̣ │ ÷ │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │   │   │   │   │   │   │   │   │   │   │ “ │ ” │  ¦  │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
+ * │      │   │ § │   │   │   │   │   │   │   │ ° │ " │        │
+ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
+ * │        │   │   │ ¢ │   │   │   │   │   │ ˇ │  ̉ │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define US_DTIL S(ALGR(US_GRV)) // ~ (dead)
+#define US_IEXL S(ALGR(US_1)) // ¡
+#define US_DACU S(ALGR(US_2)) // ˝ (dead)
+#define US_MACR S(ALGR(US_3)) // ¯ (dead)
+#define US_PND S(ALGR(US_4)) // £
+#define US_CEDL S(ALGR(US_5)) // ¸ (dead)
+#define US_QRTR S(ALGR(US_6)) // ¼
+#define US_HALF S(ALGR(US_7)) // ½
+#define US_TQTR S(ALGR(US_8)) // ¾
+#define US_BREV S(ALGR(US_9)) // ˘ (dead)
+#define US_RNGA S(ALGR(US_0)) // ° (dead)
+#define US_DOTB S(ALGR(US_MINS)) // ̣ (dead)
+#define US_DIV S(ALGR(US_EQL)) // ÷
+// Row 2
+#define US_LDQU S(ALGR(US_LBRC)) // “
+#define US_RDQU S(ALGR(US_LBRC)) // ”
+#define US_BRKP S(ALGR(US_BSLS)) // ¦
+// Row 3
+#define US_SECT S(ALGR(US_S)) // §
+#define US_DEG S(ALGR(US_SCLN)) // °
+#define US_DIAE S(ALGR(US_QUOT)) // ¨ (dead)
+// Row 4
+#define US_CENT S(ALGR(US_C)) // ¢
+#define US_CARN S(ALGR(US_DOT)) // ˇ (dead)
+#define US_HOKA S(ALGR(US_SLSH)) // ̉ (dead)
+
diff --git a/quantum/keymap_extras/keymap_us_international.h b/quantum/keymap_extras/keymap_us_international.h
index a3bc465971..49afcc4fb2 100644
--- a/quantum/keymap_extras/keymap_us_international.h
+++ b/quantum/keymap_extras/keymap_us_international.h
@@ -26,7 +26,7 @@
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
* │     │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │  \  │
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
- * │      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │        │
+ * │      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ´ │        │
* ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
* │        │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │          │
* ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
@@ -34,7 +34,7 @@
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
-#define US_GRV KC_GRV // ` (dead)
+#define US_DGRV KC_GRV // ` (dead)
#define US_1 KC_1 // 1
#define US_2 KC_2 // 2
#define US_3 KC_3 // 3
@@ -72,7 +72,7 @@
#define US_K KC_K // K
#define US_L KC_L // L
#define US_SCLN KC_SCLN // ;
-#define US_QUOT KC_QUOT // ' (dead)
+#define US_ACUT KC_QUOT // ´ (dead)
// Row 4
#define US_Z KC_Z // Z
#define US_X KC_X // X
@@ -91,7 +91,7 @@
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
* │     │   │   │   │   │   │   │   │   │   │   │ { │ } │  |  │
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
- * │      │   │   │   │   │   │   │   │   │   │ : │ " │        │
+ * │      │   │   │   │   │   │   │   │   │   │ : │ ¨ │        │
* ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
* │        │   │   │   │   │   │   │   │ < │ > │ ? │          │
* ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
@@ -99,13 +99,13 @@
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
// Row 1
-#define US_TILD S(US_GRV) // ~ (dead)
+#define US_DTIL S(US_DGRV) // ~ (dead)
#define US_EXLM S(US_1) // !
-#define US_AT S(US_2) // "
+#define US_AT S(US_2) // @
#define US_HASH S(US_3) // #
#define US_DLR S(US_4) // $
#define US_PERC S(US_5) // %
-#define US_CIRC S(US_6) // ^
+#define US_DCIR S(US_6) // ^ (dead)
#define US_AMPR S(US_7) // &
#define US_ASTR S(US_8) // *
#define US_LPRN S(US_9) // (
@@ -118,7 +118,7 @@
#define US_PIPE S(US_BSLS) // |
// Row 3
#define US_COLN S(US_SCLN) // :
-#define US_DQUO S(US_QUOT) // " (dead)
+#define US_DIAE S(US_ACUT) // ¨ (dead)
// Row 4
#define US_LABK S(US_COMM) // <
#define US_RABK S(US_DOT) // >
@@ -170,7 +170,7 @@
#define US_ETH ALGR(US_D) // Ð
#define US_OSTR ALGR(US_L) // Ø
#define US_PILC ALGR(US_SCLN) // ¶
-#define US_ACUT ALGR(US_QUOT) // ´
+#define US_NDAC ALGR(US_ACUT) // ´
// Row 4
#define US_AE ALGR(US_Z) // Æ
#define US_COPY ALGR(US_C) // ©
@@ -201,6 +201,6 @@
// Row 3
#define US_SECT S(ALGR(US_S)) // §
#define US_DEG S(ALGR(US_SCLN)) // °
-#define US_DIAE S(ALGR(US_QUOT)) // ¨
+#define US_NDDR S(ALGR(US_ACUT)) // ¨
// Row 4
#define US_CENT S(ALGR(US_C)) // ¢
diff --git a/quantum/keymap_extras/keymap_us_international_linux.h b/quantum/keymap_extras/keymap_us_international_linux.h
new file mode 100644
index 0000000000..2c3e230393
--- /dev/null
+++ b/quantum/keymap_extras/keymap_us_international_linux.h
@@ -0,0 +1,224 @@
+/* Copyright 2020
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "keymap.h"
+
+// clang-format off
+
+/*
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ 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 │ , │ . │ / │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define US_DGRV KC_GRV // ` (dead)
+#define US_1 KC_1 // 1
+#define US_2 KC_2 // 2
+#define US_3 KC_3 // 3
+#define US_4 KC_4 // 4
+#define US_5 KC_5 // 5
+#define US_6 KC_6 // 6
+#define US_7 KC_7 // 7
+#define US_8 KC_8 // 8
+#define US_9 KC_9 // 9
+#define US_0 KC_0 // 0
+#define US_MINS KC_MINS // -
+#define US_EQL KC_EQL // =
+// Row 2
+#define US_Q KC_Q // Q
+#define US_W KC_W // W
+#define US_E KC_E // E
+#define US_R KC_R // R
+#define US_T KC_T // T
+#define US_Y KC_Y // Y
+#define US_U KC_U // U
+#define US_I KC_I // I
+#define US_O KC_O // O
+#define US_P KC_P // P
+#define US_LBRC KC_LBRC // [
+#define US_RBRC KC_RBRC // ]
+#define US_BSLS KC_BSLS // (backslash)
+// Row 3
+#define US_A KC_A // A
+#define US_S KC_S // S
+#define US_D KC_D // D
+#define US_F KC_F // F
+#define US_G KC_G // G
+#define US_H KC_H // H
+#define US_J KC_J // J
+#define US_K KC_K // K
+#define US_L KC_L // L
+#define US_SCLN KC_SCLN // ;
+#define US_ACUT KC_QUOT // ´ (dead)
+// Row 4
+#define US_Z KC_Z // Z
+#define US_X KC_X // X
+#define US_C KC_C // C
+#define US_V KC_V // V
+#define US_B KC_B // B
+#define US_N KC_N // N
+#define US_M KC_M // M
+#define US_COMM KC_COMM // ,
+#define US_DOT KC_DOT // .
+#define US_SLSH KC_SLSH // /
+
+/* Shifted symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ~ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ ( │ ) │ _ │ + │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │   │   │   │   │   │   │   │   │   │   │ { │ } │  |  │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
+ * │      │   │   │   │   │   │   │   │   │   │ : │ ¨ │        │
+ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
+ * │        │   │   │   │   │   │   │   │ < │ > │ ? │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define US_DTIL S(US_DGRV) // ~ (dead)
+#define US_EXLM S(US_1) // !
+#define US_AT S(US_2) // @
+#define US_HASH S(US_3) // #
+#define US_DLR S(US_4) // $
+#define US_PERC S(US_5) // %
+#define US_DCIR S(US_6) // ^ (dead)
+#define US_AMPR S(US_7) // &
+#define US_ASTR S(US_8) // *
+#define US_LPRN S(US_9) // (
+#define US_RPRN S(US_0) // )
+#define US_UNDS S(US_MINS) // _
+#define US_PLUS S(US_EQL) // +
+// Row 2
+#define US_LCBR S(US_LBRC) // {
+#define US_RCBR S(US_RBRC) // }
+#define US_PIPE S(US_BSLS) // |
+// Row 3
+#define US_COLN S(US_SCLN) // :
+#define US_DIAE S(US_ACUT) // ¨ (dead)
+// Row 4
+#define US_LABK S(US_COMM) // <
+#define US_RABK S(US_DOT) // >
+#define US_QUES S(US_SLSH) // ?
+
+/* AltGr symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ` │ ¡ │ ² │ ³ │ ¤ │ € │ ¼ │ ½ │ ¾ │ ‘ │ ’ │ ¥ │ × │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │ Ä │ Å │ É │ ® │ Þ │ Ü │ Ú │ Í │ Ó │ Ö │ « │ » │  ¬  │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
+ * │      │ Á │ ß │ Ð │   │   │   │   │ Œ │ Ø │ ¶ │ ' │        │
+ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
+ * │        │ Æ │   │ © │   │   │ Ñ │ µ │ Ç │ ˙ │ ¿ │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+
+// Row 1
+#define US_GRV ALGR(US_DGRV) // `
+#define US_IEXL ALGR(US_1) // ¡
+#define US_SUP2 ALGR(US_2) // ²
+#define US_SUP3 ALGR(US_3) // ³
+#define US_CURR ALGR(US_4) // ¤
+#define US_EURO ALGR(US_5) // €
+#define US_QRTR ALGR(US_6) // ¼
+#define US_HALF ALGR(US_7) // ½
+#define US_TQTR ALGR(US_8) // ¾
+#define US_LSQU ALGR(US_9) // ‘
+#define US_RSQU ALGR(US_0) // ’
+#define US_YEN ALGR(US_MINS) // ¥
+#define US_MUL ALGR(US_EQL) // ×
+// Row 2
+#define US_ADIA ALGR(US_Q) // Ä
+#define US_ARNG ALGR(US_W) // Å
+#define US_EACU ALGR(US_E) // É
+#define US_REGD ALGR(US_R) // ®
+#define US_THRN ALGR(US_T) // Þ
+#define US_UDIA ALGR(US_Y) // Ü
+#define US_UACU ALGR(US_U) // Ú
+#define US_IACU ALGR(US_I) // Í
+#define US_OACU ALGR(US_O) // Ó
+#define US_ODIA ALGR(US_P) // Ö
+#define US_LDAQ ALGR(US_LBRC) // «
+#define US_RDAQ ALGR(US_RBRC) // »
+#define US_NOT ALGR(US_BSLS) // ¬
+// Row 3
+#define US_AACU ALGR(US_A) // Á
+#define US_SS ALGR(US_S) // ß
+#define US_ETH ALGR(US_D) // Ð
+#define US_OE ALGR(US_K) // Œ
+#define US_OSTR ALGR(US_L) // Ø
+#define US_PILC ALGR(US_SCLN) // ¶
+#define US_QUOT ALGR(US_ACUT) // '
+// Row 4
+#define US_AE ALGR(US_Z) // Æ
+#define US_COPY ALGR(US_C) // ©
+#define US_NTIL ALGR(US_N) // Ñ
+#define US_MICR ALGR(US_M) // µ
+#define US_CCED ALGR(US_COMM) // Ç
+#define US_DOTA ALGR(US_DOT) // ˙ (dead)
+#define US_IQUE ALGR(US_SLSH) // ¿
+
+/* Shift+AltGr symbols
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
+ * │ ~ │ ¹ │ ˝ │ ¯ │ £ │ ¸ │ ^ │ ̛  │ ˛ │ ˘ │ ° │  ̣ │ ÷ │       │
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
+ * │     │   │   │   │   │   │   │   │   │   │   │ “ │ ” │  ¦  │
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
+ * │      │   │ § │   │   │   │   │   │   │   │ ° │ " │        │
+ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
+ * │        │   │   │ ¢ │   │   │   │   │   │ ˇ │  ̉ │          │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
+ * │    │    │    │                        │    │    │    │    │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
+ */
+// Row 1
+#define US_TILD S(ALGR(US_DGRV)) // ~
+#define US_SUP1 S(ALGR(US_1)) // ¹
+#define US_DACU S(ALGR(US_2)) // ˝ (dead)
+#define US_MACR S(ALGR(US_3)) // ¯ (dead)
+#define US_PND S(ALGR(US_4)) // £
+#define US_CEDL S(ALGR(US_5)) // ¸ (dead)
+#define US_CIRC S(ALGR(US_6)) // ^
+#define US_HORN S(ALGR(US_7)) // ̛ (dead)
+#define US_OGON S(ALGR(US_8)) // ˛ (dead)
+#define US_BREV S(ALGR(US_9)) // ˘ (dead)
+#define US_RNGA S(ALGR(US_0)) // ° (dead)
+#define US_DOTB S(ALGR(US_MINS)) // ̣ (dead)
+#define US_DIV S(ALGR(US_EQL)) // ÷
+// Row 2
+#define US_LDQU S(ALGR(US_LBRC)) // “
+#define US_RDQU S(ALGR(US_LBRC)) // ”
+#define US_BRKP S(ALGR(US_BSLS)) // ¦
+// Row 3
+#define US_SECT S(ALGR(US_S)) // §
+#define US_DEG S(ALGR(US_SCLN)) // °
+#define US_DQUO S(ALGR(US_ACUT)) // "
+// Row 4
+#define US_CENT S(ALGR(US_C)) // ¢
+#define US_CARN S(ALGR(US_DOT)) // ˇ (dead)
+#define US_HOKA S(ALGR(US_SLSH)) // ̉ (dead)
diff --git a/quantum/keymap_extras/sendstring_belgian.h b/quantum/keymap_extras/sendstring_belgian.h
index 9ff92f010d..5e7218a2fa 100644
--- a/quantum/keymap_extras/sendstring_belgian.h
+++ b/quantum/keymap_extras/sendstring_belgian.h
@@ -21,6 +21,8 @@
#include "keymap_belgian.h"
#include "quantum.h"
+// clang-format off
+
const uint8_t ascii_to_shift_lut[16] PROGMEM = {
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
@@ -65,16 +67,16 @@ 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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
KC_SPC, BE_EXLM, BE_DQUO, BE_DQUO, BE_DLR, BE_UGRV, BE_AMPR, BE_QUOT,
// ( ) * + , - . /
- BE_LPRN, BE_RPRN, BE_DLR, BE_EQL, BE_COMM, BE_MINS, BE_SCLN, BE_COLN,
+ BE_LPRN, BE_RPRN, BE_DLR, BE_EQL, BE_COMM, BE_MINS, BE_SCLN, BE_COLN,
// 0 1 2 3 4 5 6 7
BE_AGRV, BE_AMPR, BE_EACU, BE_DQUO, BE_QUOT, BE_LPRN, BE_SECT, BE_EGRV,
// 8 9 : ; < = > ?
diff --git a/quantum/keymap_extras/sendstring_bepo.h b/quantum/keymap_extras/sendstring_bepo.h
index be442070dc..8119cd9f54 100644
--- a/quantum/keymap_extras/sendstring_bepo.h
+++ b/quantum/keymap_extras/sendstring_bepo.h
@@ -21,6 +21,7 @@
#include "keymap_bepo.h"
#include "quantum.h"
+// clang-format off
const uint8_t ascii_to_shift_lut[16] PROGMEM = {
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
@@ -66,16 +67,16 @@ 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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
KC_SPC, BP_DCIR, BP_DQUO, BP_DLR, BP_DLR, BP_PERC, BP_P, BP_QUOT,
// ( ) * + , - . /
- BP_LPRN, BP_RPRN, BP_ASTR, BP_PLUS, BP_COMM, BP_MINS, BP_DOT, BP_SLSH,
+ BP_LPRN, BP_RPRN, BP_ASTR, BP_PLUS, BP_COMM, BP_MINS, BP_DOT, BP_SLSH,
// 0 1 2 3 4 5 6 7
BP_ASTR, BP_DQUO, BP_LDAQ, BP_RDAQ, BP_LPRN, BP_RPRN, BP_AT, BP_PLUS,
// 8 9 : ; < = > ?
@@ -95,4 +96,5 @@ const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
// p q r s t u v w
BP_P, BP_Q, BP_R, BP_S, BP_T, BP_U, BP_V, BP_W,
// x y z { | } ~ DEL
- BP_X, BP_Y, BP_Z, BP_Y, BP_B, BP_X, BP_K, KC_DEL};
+ BP_X, BP_Y, BP_Z, BP_Y, BP_B, BP_X, BP_K, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_canadian_multilingual.h b/quantum/keymap_extras/sendstring_canadian_multilingual.h
new file mode 100644
index 0000000000..c3fcc62c37
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_canadian_multilingual.h
@@ -0,0 +1,100 @@
+/* Copyright 2020
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Sendstring lookup tables for Canadian Multilingual layouts
+
+#pragma once
+
+#include "keymap_canadian_multilingual.h"
+#include "quantum.h"
+
+// clang-format off
+
+const uint8_t ascii_to_shift_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 1),
+ 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, 0, 0, 0, 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, 1, 0, 0, 1),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
+};
+
+const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 1, 0, 1, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 1, 0, 1, 0, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
+};
+
+const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
+ // NUL SOH STX ETX EOT ENQ ACK BEL
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // BS TAB LF VT FF CR SO SI
+ KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // CAN EM SUB ESC FS GS RS US
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+
+ // ! " # $ % & '
+ KC_SPC, CA_1, CA_DOT, CA_3, CA_4, CA_5, CA_7, CA_COMM,
+ // ( ) * + , - . /
+ CA_9, CA_0, CA_8, CA_EQL, CA_COMM, CA_MINS, CA_DOT, CA_SLSH,
+ // 0 1 2 3 4 5 6 7
+ CA_0, CA_1, CA_2, CA_3, CA_4, CA_5, CA_6, CA_7,
+ // 8 9 : ; < = > ?
+ CA_8, CA_9, CA_SCLN, CA_SCLN, CA_DOT, CA_EQL, CA_COMM, CA_6,
+ // @ A B C D E F G
+ CA_2, CA_A, CA_B, CA_C, CA_D, CA_E, CA_F, CA_G,
+ // H I J K L M N O
+ CA_H, CA_I, CA_J, CA_K, CA_L, CA_M, CA_N, CA_O,
+ // P Q R S T U V W
+ CA_P, CA_Q, CA_R, CA_S, CA_T, CA_U, CA_V, CA_W,
+ // X Y Z [ \ ] ^ _
+ CA_X, CA_Y, CA_Z, CA_9, CA_SLSH, CA_0, CA_CIRC, CA_MINS,
+ // ` a b c d e f g
+ CA_CIRC, CA_A, CA_B, CA_C, CA_D, CA_E, CA_F, CA_G,
+ // h i j k l m n o
+ CA_H, CA_I, CA_J, CA_K, CA_L, CA_M, CA_N, CA_O,
+ // p q r s t u v w
+ CA_P, CA_Q, CA_R, CA_S, CA_T, CA_U, CA_V, CA_W,
+ // x y z { | } ~ DEL
+ CA_X, CA_Y, CA_Z, CA_7, CA_SLSH, CA_8, CA_CCED, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_colemak.h b/quantum/keymap_extras/sendstring_colemak.h
index 8564ec1dea..3aef96b24a 100644
--- a/quantum/keymap_extras/sendstring_colemak.h
+++ b/quantum/keymap_extras/sendstring_colemak.h
@@ -20,15 +20,17 @@
#include "keymap_colemak.h"
+// clang-format off
+
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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
KC_SPC, CM_1, CM_QUOT, CM_3, CM_4, CM_5, CM_7, CM_QUOT,
@@ -41,17 +43,17 @@ const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
// @ A B C D E F G
CM_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
// H I J K L M N O
- CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
+ CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
// P Q R S T U V W
- CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
+ CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
// X Y Z [ \ ] ^ _
CM_X, CM_Y, CM_Z, CM_LBRC, CM_BSLS, CM_RBRC, CM_6, CM_MINS,
// ` a b c d e f g
CM_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
// h i j k l m n o
- CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
+ CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
// p q r s t u v w
- CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
+ CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
// x y z { | } ~ DEL
CM_X, CM_Y, CM_Z, CM_LBRC, CM_BSLS, CM_RBRC, CM_GRV, KC_DEL
};
diff --git a/quantum/keymap_extras/sendstring_croatian.h b/quantum/keymap_extras/sendstring_croatian.h
new file mode 100644
index 0000000000..67f75992ae
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_croatian.h
@@ -0,0 +1,100 @@
+/* Copyright 2020
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Sendstring lookup tables for Croatian layouts
+
+#pragma once
+
+#include "keymap_croatian.h"
+#include "quantum.h"
+
+// clang-format off
+
+const uint8_t ascii_to_shift_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 0),
+ KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 0, 1),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 1, 1, 0, 1, 1, 1),
+ KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 0, 1),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
+};
+
+const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
+};
+
+const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
+ // NUL SOH STX ETX EOT ENQ ACK BEL
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // BS TAB LF VT FF CR SO SI
+ KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // CAN EM SUB ESC FS GS RS US
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+
+ // ! " # $ % & '
+ KC_SPC, HR_1, HR_2, HR_3, HR_4, HR_5, HR_6, HR_QUOT,
+ // ( ) * + , - . /
+ HR_8, HR_9, HR_PLUS, HR_PLUS, HR_COMM, HR_MINS, HR_DOT, HR_7,
+ // 0 1 2 3 4 5 6 7
+ HR_0, HR_1, HR_2, HR_3, HR_4, HR_5, HR_6, HR_7,
+ // 8 9 : ; < = > ?
+ HR_8, HR_9, HR_DOT, HR_COMM, HR_LABK, HR_0, HR_LABK, HR_QUOT,
+ // @ A B C D E F G
+ HR_V, HR_A, HR_B, HR_C, HR_D, HR_E, HR_F, HR_G,
+ // H I J K L M N O
+ HR_H, HR_I, HR_J, HR_K, HR_L, HR_M, HR_N, HR_O,
+ // P Q R S T U V W
+ HR_P, HR_Q, HR_R, HR_S, HR_T, HR_U, HR_V, HR_W,
+ // X Y Z [ \ ] ^ _
+ HR_X, HR_Y, HR_Z, HR_F, HR_Q, HR_G, HR_3, HR_MINS,
+ // ` a b c d e f g
+ HR_7, HR_A, HR_B, HR_C, HR_D, HR_E, HR_F, HR_G,
+ // h i j k l m n o
+ HR_H, HR_I, HR_J, HR_K, HR_L, HR_M, HR_N, HR_O,
+ // p q r s t u v w
+ HR_P, HR_Q, HR_R, HR_S, HR_T, HR_U, HR_V, HR_W,
+ // x y z { | } ~ DEL
+ HR_X, HR_Y, HR_Z, HR_B, HR_W, HR_N, HR_1, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_dvorak.h b/quantum/keymap_extras/sendstring_dvorak.h
index 3ddb00b112..9bad0dc13a 100644
--- a/quantum/keymap_extras/sendstring_dvorak.h
+++ b/quantum/keymap_extras/sendstring_dvorak.h
@@ -20,10 +20,16 @@
#include "keymap_dvorak.h"
+<<<<<<< HEAD
+=======
+// clang-format off
+
+>>>>>>> 0.12.52~1
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
+<<<<<<< HEAD
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,
@@ -54,3 +60,36 @@ const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
DV_P, DV_Q, DV_R, DV_S, DV_T, DV_U, DV_V, DV_W,
// x y z { | } ~ DEL
DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_GRV, KC_DEL};
+=======
+ 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, DV_1, DV_QUOT, DV_3, DV_4, DV_5, DV_7, DV_QUOT,
+ // ( ) * + , - . /
+ DV_9, DV_0, DV_8, DV_EQL, DV_COMM, DV_MINS, DV_DOT, DV_SLSH,
+ // 0 1 2 3 4 5 6 7
+ DV_0, DV_1, DV_2, DV_3, DV_4, DV_5, DV_6, DV_7,
+ // 8 9 : ; < = > ?
+ DV_8, DV_9, DV_SCLN, DV_SCLN, DV_COMM, DV_EQL, DV_DOT, DV_SLSH,
+ // @ A B C D E F G
+ DV_2, DV_A, DV_B, DV_C, DV_D, DV_E, DV_F, DV_G,
+ // H I J K L M N O
+ DV_H, DV_I, DV_J, DV_K, DV_L, DV_M, DV_N, DV_O,
+ // P Q R S T U V W
+ DV_P, DV_Q, DV_R, DV_S, DV_T, DV_U, DV_V, DV_W,
+ // X Y Z [ \ ] ^ _
+ DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_6, DV_MINS,
+ // ` a b c d e f g
+ DV_GRV, DV_A, DV_B, DV_C, DV_D, DV_E, DV_F, DV_G,
+ // h i j k l m n o
+ DV_H, DV_I, DV_J, DV_K, DV_L, DV_M, DV_N, DV_O,
+ // p q r s t u v w
+ DV_P, DV_Q, DV_R, DV_S, DV_T, DV_U, DV_V, DV_W,
+ // x y z { | } ~ DEL
+ DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_GRV, KC_DEL
+};
+>>>>>>> 0.12.52~1
diff --git a/quantum/keymap_extras/sendstring_french.h b/quantum/keymap_extras/sendstring_french.h
index 9b7f5e8ed7..ab65f28eb7 100644
--- a/quantum/keymap_extras/sendstring_french.h
+++ b/quantum/keymap_extras/sendstring_french.h
@@ -21,6 +21,8 @@
#include "keymap_french.h"
#include "quantum.h"
+// clang-format off
+
const uint8_t ascii_to_shift_lut[16] PROGMEM = {
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
@@ -65,20 +67,20 @@ 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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
- KC_SPC, FR_EXLM, FR_QUOT, FR_DQUO, FR_DLR, FR_UGRV, FR_AMPR, FR_QUOT,
+ KC_SPC, FR_EXLM, FR_DQUO, FR_DQUO, FR_DLR, FR_UGRV, FR_AMPR, FR_QUOT,
// ( ) * + , - . /
- FR_LPRN, FR_RPRN, FR_ASTR, FR_EQL, FR_COMM, FR_MINS, FR_SCLN, FR_COLN,
+ FR_LPRN, FR_RPRN, FR_ASTR, FR_EQL, FR_COMM, FR_MINS, FR_SCLN, FR_COLN,
// 0 1 2 3 4 5 6 7
FR_AGRV, FR_AMPR, FR_EACU, FR_DQUO, FR_QUOT, FR_LPRN, FR_MINS, FR_EGRV,
// 8 9 : ; < = > ?
- FR_CCED, FR_AGRV, FR_COLN, FR_SCLN, FR_LABK, FR_EQL, FR_LABK, FR_COMM,
+ FR_UNDS, FR_CCED, FR_COLN, FR_SCLN, FR_LABK, FR_EQL, FR_LABK, FR_COMM,
// @ A B C D E F G
FR_AGRV, FR_A, FR_B, FR_C, FR_D, FR_E, FR_F, FR_G,
// H I J K L M N O
diff --git a/quantum/keymap_extras/sendstring_french_afnor.h b/quantum/keymap_extras/sendstring_french_afnor.h
new file mode 100644
index 0000000000..690daaaf02
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_french_afnor.h
@@ -0,0 +1,100 @@
+/* Copyright 2020 Guillaume Gérard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Sendstring lookup tables for French (AZERTY - AFNOR NF Z71-300) layouts
+
+#pragma once
+
+#include "keymap_french_afnor.h"
+#include "quantum.h"
+
+// clang-format off
+
+const uint8_t ascii_to_shift_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 1, 1, 1, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 0, 0, 0, 1, 1, 1),
+ KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
+ KCLUT_ENTRY(1, 1, 1, 0, 1, 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)
+};
+
+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, 1, 1, 1, 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, 1, 0, 1, 0, 1),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
+};
+
+const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
+ // NUL SOH STX ETX EOT ENQ ACK BEL
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // BS TAB LF VT FF CR SO SI
+ KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // CAN EM SUB ESC FS GS RS US
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+
+ // ! " # $ % & '
+ KC_SPC, FR_COMM, FR_QUOT, FR_AT, FR_D, FR_P, FR_ECIR, FR_QUOT,
+ // ( ) * + , - . /
+ FR_LPRN, FR_RPRN, FR_ASTR, FR_PLUS, FR_COMM, FR_MINS, FR_DOT, FR_SLSH,
+ // 0 1 2 3 4 5 6 7
+ FR_RDAQ, FR_AGRV, FR_EACU, FR_EGRV, FR_ECIR, FR_LPRN, FR_RPRN, FR_LSQU,
+ // 8 9 : ; < = > ?
+ FR_RSQU, FR_LDAQ, FR_COLN, FR_SCLN, FR_LABK, FR_SCLN, FR_LABK, FR_DOT,
+ // @ A B C D E F G
+ FR_AT, FR_A, FR_B, FR_C, FR_D, FR_E, FR_F, FR_G,
+ // H I J K L M N O
+ FR_H, FR_I, FR_J, FR_K, FR_L, FR_M, FR_N, FR_O,
+ // P Q R S T U V W
+ FR_P, FR_Q, FR_R, FR_S, FR_T, FR_U, FR_V, FR_W,
+ // X Y Z [ \ ] ^ _
+ FR_X, FR_Y, FR_Z, FR_LPRN, FR_SLSH, FR_RPRN, FR_DCIR, FR_RSQU,
+ // ` a b c d e f g
+ FR_EGRV, FR_A, FR_B, FR_C, FR_D, FR_E, FR_F, FR_G,
+ // h i j k l m n o
+ FR_H, FR_I, FR_J, FR_K, FR_L, FR_M, FR_N, FR_O,
+ // p q r s t u v w
+ FR_P, FR_Q, FR_R, FR_S, FR_T, FR_U, FR_V, FR_W,
+ // x y z { | } ~ DEL
+ FR_X, FR_Y, FR_Z, FR_T, FR_L, FR_Y, FR_N, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_german.h b/quantum/keymap_extras/sendstring_german.h
index 639c22b3a7..3445a0e5fb 100644
--- a/quantum/keymap_extras/sendstring_german.h
+++ b/quantum/keymap_extras/sendstring_german.h
@@ -21,6 +21,8 @@
#include "keymap_german.h"
#include "quantum.h"
+// clang-format off
+
const uint8_t ascii_to_shift_lut[16] PROGMEM = {
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
@@ -65,34 +67,34 @@ 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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
- KC_SPC, DE_1, DE_2, DE_HASH, DE_4, DE_5, DE_6, DE_HASH,
+ KC_SPC, DE_1, DE_2, DE_HASH, DE_4, DE_5, DE_6, DE_HASH,
// ( ) * + , - . /
- DE_8, DE_9, DE_PLUS, DE_PLUS, DE_COMM, DE_MINS, DE_DOT, DE_7,
+ DE_8, DE_9, DE_PLUS, DE_PLUS, DE_COMM, DE_MINS, DE_DOT, DE_7,
// 0 1 2 3 4 5 6 7
- DE_0, DE_1, DE_2, DE_3, DE_4, DE_5, DE_6, DE_7,
+ DE_0, DE_1, DE_2, DE_3, DE_4, DE_5, DE_6, DE_7,
// 8 9 : ; < = > ?
DE_8, DE_9, DE_DOT, DE_COMM, DE_LABK, DE_0, DE_LABK, DE_SS,
// @ A B C D E F G
- DE_Q, DE_A, DE_B, DE_C, DE_D, DE_E, DE_F, DE_G,
+ DE_Q, DE_A, DE_B, DE_C, DE_D, DE_E, DE_F, DE_G,
// H I J K L M N O
- DE_H, DE_I, DE_J, DE_K, DE_L, DE_M, DE_N, DE_O,
+ DE_H, DE_I, DE_J, DE_K, DE_L, DE_M, DE_N, DE_O,
// P Q R S T U V W
- DE_P, DE_Q, DE_R, DE_S, DE_T, DE_U, DE_V, DE_W,
+ DE_P, DE_Q, DE_R, DE_S, DE_T, DE_U, DE_V, DE_W,
// X Y Z [ \ ] ^ _
- DE_X, DE_Y, DE_Z, DE_8, DE_SS, DE_9, DE_CIRC, DE_MINS,
+ DE_X, DE_Y, DE_Z, DE_8, DE_SS, DE_9, DE_CIRC, DE_MINS,
// ` a b c d e f g
- DE_ACUT, DE_A, DE_B, DE_C, DE_D, DE_E, DE_F, DE_G,
+ DE_ACUT, DE_A, DE_B, DE_C, DE_D, DE_E, DE_F, DE_G,
// h i j k l m n o
- DE_H, DE_I, DE_J, DE_K, DE_L, DE_M, DE_N, DE_O,
+ DE_H, DE_I, DE_J, DE_K, DE_L, DE_M, DE_N, DE_O,
// p q r s t u v w
- DE_P, DE_Q, DE_R, DE_S, DE_T, DE_U, DE_V, DE_W,
+ DE_P, DE_Q, DE_R, DE_S, DE_T, DE_U, DE_V, DE_W,
// x y z { | } ~ DEL
DE_X, DE_Y, DE_Z, DE_7, DE_LABK, DE_0, DE_PLUS, KC_DEL
};
diff --git a/quantum/keymap_extras/sendstring_jis.h b/quantum/keymap_extras/sendstring_jis.h
index f9c574560b..58335ad41d 100644
--- a/quantum/keymap_extras/sendstring_jis.h
+++ b/quantum/keymap_extras/sendstring_jis.h
@@ -21,6 +21,8 @@
#include "keymap_jp.h"
#include "quantum.h"
+// clang-format off
+
const uint8_t ascii_to_shift_lut[16] PROGMEM = {
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
@@ -45,33 +47,34 @@ 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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
- KC_SPC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
+ KC_SPC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
// ( ) * + , - . /
- KC_8, KC_9, JP_COLN, JP_SCLN, JP_COMM, JP_MINS, JP_DOT, JP_SLSH,
+ KC_8, KC_9, JP_COLN, JP_SCLN, JP_COMM, JP_MINS, JP_DOT, JP_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,
+ KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
// 8 9 : ; < = > ?
- KC_8, KC_9, JP_COLN, JP_SCLN, JP_COMM, JP_MINS, JP_DOT, JP_SLSH,
+ KC_8, KC_9, JP_COLN, JP_SCLN, JP_COMM, JP_MINS, JP_DOT, JP_SLSH,
// @ A B C D E F G
- JP_AT, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
+ JP_AT, 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,
+ 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,
+ 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, JP_LBRC, JP_BSLS, JP_RBRC, JP_CIRC, JP_BSLS,
+ KC_X, KC_Y, KC_Z, JP_LBRC, JP_BSLS, JP_RBRC, JP_CIRC, JP_BSLS,
// ` a b c d e f g
- JP_AT, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
+ JP_AT, 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,
+ 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,
+ 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, JP_LBRC, JP_YEN, JP_RBRC, JP_CIRC, KC_DEL};
+ KC_X, KC_Y, KC_Z, JP_LBRC, JP_YEN, JP_RBRC, JP_CIRC, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_norman.h b/quantum/keymap_extras/sendstring_norman.h
index e52afc2a6a..21dbbdd705 100644
--- a/quantum/keymap_extras/sendstring_norman.h
+++ b/quantum/keymap_extras/sendstring_norman.h
@@ -20,15 +20,17 @@
#include "keymap_norman.h"
+// clang-format off
+
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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
KC_SPC, NM_1, NM_QUOT, NM_3, NM_4, NM_5, NM_7, NM_QUOT,
@@ -41,17 +43,17 @@ const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
// @ A B C D E F G
NM_2, NM_A, NM_B, NM_C, NM_D, NM_E, NM_F, NM_G,
// H I J K L M N O
- NM_H, NM_I, NM_J, NM_K, NM_L, NM_M, NM_N, NM_O,
+ NM_H, NM_I, NM_J, NM_K, NM_L, NM_M, NM_N, NM_O,
// P Q R S T U V W
- NM_P, NM_Q, NM_R, NM_S, NM_T, NM_U, NM_V, NM_W,
+ NM_P, NM_Q, NM_R, NM_S, NM_T, NM_U, NM_V, NM_W,
// X Y Z [ \ ] ^ _
NM_X, NM_Y, NM_Z, NM_LBRC, NM_BSLS, NM_RBRC, NM_6, NM_MINS,
// ` a b c d e f g
NM_GRV, NM_A, NM_B, NM_C, NM_D, NM_E, NM_F, NM_G,
// h i j k l m n o
- NM_H, NM_I, NM_J, NM_K, NM_L, NM_M, NM_N, NM_O,
+ NM_H, NM_I, NM_J, NM_K, NM_L, NM_M, NM_N, NM_O,
// p q r s t u v w
- NM_P, NM_Q, NM_R, NM_S, NM_T, NM_U, NM_V, NM_W,
+ NM_P, NM_Q, NM_R, NM_S, NM_T, NM_U, NM_V, NM_W,
// x y z { | } ~ DEL
NM_X, NM_Y, NM_Z, NM_LBRC, NM_BSLS, NM_RBRC, NM_GRV, KC_DEL
};
diff --git a/quantum/keymap_extras/sendstring_spanish.h b/quantum/keymap_extras/sendstring_spanish.h
index 03c8fe7483..b984a6f463 100644
--- a/quantum/keymap_extras/sendstring_spanish.h
+++ b/quantum/keymap_extras/sendstring_spanish.h
@@ -21,6 +21,8 @@
#include "keymap_spanish.h"
#include "quantum.h"
+// clang-format off
+
const uint8_t ascii_to_shift_lut[16] PROGMEM = {
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
@@ -65,11 +67,11 @@ 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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
KC_SPC, ES_1, ES_2, ES_3, ES_4, ES_5, ES_6, ES_QUOT,
diff --git a/quantum/keymap_extras/sendstring_uk.h b/quantum/keymap_extras/sendstring_uk.h
index 1319c8164d..bbd30769b0 100644
--- a/quantum/keymap_extras/sendstring_uk.h
+++ b/quantum/keymap_extras/sendstring_uk.h
@@ -21,6 +21,8 @@
#include "keymap_uk.h"
#include "quantum.h"
+// clang-format off
+
const uint8_t ascii_to_shift_lut[16] PROGMEM = {
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
@@ -45,33 +47,34 @@ 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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
KC_SPC, UK_1, UK_2, UK_HASH, UK_4, UK_5, UK_7, UK_QUOT,
// ( ) * + , - . /
- UK_9, UK_0, UK_8, UK_EQL, UK_COMM, UK_MINS, UK_DOT, UK_SLSH,
+ UK_9, UK_0, UK_8, UK_EQL, UK_COMM, UK_MINS, UK_DOT, UK_SLSH,
// 0 1 2 3 4 5 6 7
- UK_0, UK_1, UK_2, UK_3, UK_4, UK_5, UK_6, UK_7,
+ UK_0, UK_1, UK_2, UK_3, UK_4, UK_5, UK_6, UK_7,
// 8 9 : ; < = > ?
- UK_8, UK_9, UK_SCLN, UK_SCLN, UK_COMM, UK_EQL, UK_DOT, UK_SLSH,
+ UK_8, UK_9, UK_SCLN, UK_SCLN, UK_COMM, UK_EQL, UK_DOT, UK_SLSH,
// @ A B C D E F G
- UK_QUOT, UK_A, UK_B, UK_C, UK_D, UK_E, UK_F, UK_G,
+ UK_QUOT, UK_A, UK_B, UK_C, UK_D, UK_E, UK_F, UK_G,
// H I J K L M N O
- UK_H, UK_I, UK_J, UK_K, UK_L, UK_M, UK_N, UK_O,
+ UK_H, UK_I, UK_J, UK_K, UK_L, UK_M, UK_N, UK_O,
// P Q R S T U V W
- UK_P, UK_Q, UK_R, UK_S, UK_T, UK_U, UK_V, UK_W,
+ UK_P, UK_Q, UK_R, UK_S, UK_T, UK_U, UK_V, UK_W,
// X Y Z [ \ ] ^ _
- UK_X, UK_Y, UK_Z, UK_LBRC, UK_BSLS, UK_RBRC, UK_6, UK_MINS,
+ UK_X, UK_Y, UK_Z, UK_LBRC, UK_BSLS, UK_RBRC, UK_6, UK_MINS,
// ` a b c d e f g
- UK_GRV, UK_A, UK_B, UK_C, UK_D, UK_E, UK_F, UK_G,
+ UK_GRV, UK_A, UK_B, UK_C, UK_D, UK_E, UK_F, UK_G,
// h i j k l m n o
- UK_H, UK_I, UK_J, UK_K, UK_L, UK_M, UK_N, UK_O,
+ UK_H, UK_I, UK_J, UK_K, UK_L, UK_M, UK_N, UK_O,
// p q r s t u v w
- UK_P, UK_Q, UK_R, UK_S, UK_T, UK_U, UK_V, UK_W,
+ UK_P, UK_Q, UK_R, UK_S, UK_T, UK_U, UK_V, UK_W,
// x y z { | } ~ DEL
- UK_X, UK_Y, UK_Z, UK_LBRC, UK_BSLS, UK_RBRC, UK_HASH, KC_DEL};
+ UK_X, UK_Y, UK_Z, UK_LBRC, UK_BSLS, UK_RBRC, UK_HASH, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_us_international.h b/quantum/keymap_extras/sendstring_us_international.h
new file mode 100644
index 0000000000..53a5891fb1
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_us_international.h
@@ -0,0 +1,100 @@
+/* Copyright 2019 Rys Sommefeldt
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Sendstring lookup tables for UK layouts
+
+#pragma once
+
+#include "keymap_us_international.h"
+#include "quantum.h"
+
+// clang-format off
+
+const uint8_t ascii_to_shift_lut[16] PROGMEM = {
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+
+ KCLUT_ENTRY(0, 1, 1, 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),
+};
+
+__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, 1, 0, 0, 0, 0, 1),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
+ KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
+ KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
+};
+
+const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
+ // NUL SOH STX ETX EOT ENQ ACK BEL
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // BS TAB LF VT FF CR SO SI
+ KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ // CAN EM SUB ESC FS GS RS US
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+
+ // ! " # $ % & '
+ KC_SPC, US_1, US_ACUT, US_3, US_4, US_5, US_7, US_ACUT,
+ // ( ) * + , - . /
+ US_9, US_0, US_8, US_EQL, US_COMM, US_MINS, US_DOT, US_SLSH,
+ // 0 1 2 3 4 5 6 7
+ US_0, US_1, US_2, US_3, US_4, US_5, US_6, US_7,
+ // 8 9 : ; < = > ?
+ US_8, US_9, US_SCLN, US_SCLN, US_COMM, US_EQL, US_DOT, US_SLSH,
+ // @ A B C D E F G
+ US_2, US_A, US_B, US_C, US_D, US_E, US_F, US_G,
+ // H I J K L M N O
+ US_H, US_I, US_J, US_K, US_L, US_M, US_N, US_O,
+ // P Q R S T U V W
+ US_P, US_Q, US_R, US_S, US_T, US_U, US_V, US_W,
+ // X Y Z [ \ ] ^ _
+ US_X, US_Y, US_Z, US_LBRC, US_BSLS, US_RBRC, US_6, US_MINS,
+ // ` a b c d e f g
+ US_DGRV, US_A, US_B, US_C, US_D, US_E, US_F, US_G,
+ // h i j k l m n o
+ US_H, US_I, US_J, US_K, US_L, US_M, US_N, US_O,
+ // p q r s t u v w
+ US_P, US_Q, US_R, US_S, US_T, US_U, US_V, US_W,
+ // x y z { | } ~ DEL
+ US_X, US_Y, US_Z, US_LBRC, US_BSLS, US_RBRC, US_DGRV, KC_DEL
+};
diff --git a/quantum/keymap_extras/sendstring_workman.h b/quantum/keymap_extras/sendstring_workman.h
index 6e7f17b965..04f8e3908a 100644
--- a/quantum/keymap_extras/sendstring_workman.h
+++ b/quantum/keymap_extras/sendstring_workman.h
@@ -20,15 +20,17 @@
#include "keymap_workman.h"
+// clang-format off
+
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,
+ 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,
+ XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
// ! " # $ % & '
KC_SPC, WK_1, WK_QUOT, WK_3, WK_4, WK_5, WK_7, WK_QUOT,
@@ -41,17 +43,17 @@ const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
// @ A B C D E F G
WK_2, WK_A, WK_B, WK_C, WK_D, WK_E, WK_F, WK_G,
// H I J K L M N O
- WK_H, WK_I, WK_J, WK_K, WK_L, WK_M, WK_N, WK_O,
+ WK_H, WK_I, WK_J, WK_K, WK_L, WK_M, WK_N, WK_O,
// P Q R S T U V W
- WK_P, WK_Q, WK_R, WK_S, WK_T, WK_U, WK_V, WK_W,
+ WK_P, WK_Q, WK_R, WK_S, WK_T, WK_U, WK_V, WK_W,
// X Y Z [ \ ] ^ _
WK_X, WK_Y, WK_Z, WK_LBRC, WK_BSLS, WK_RBRC, WK_6, WK_MINS,
// ` a b c d e f g
WK_GRV, WK_A, WK_B, WK_C, WK_D, WK_E, WK_F, WK_G,
// h i j k l m n o
- WK_H, WK_I, WK_J, WK_K, WK_L, WK_M, WK_N, WK_O,
+ WK_H, WK_I, WK_J, WK_K, WK_L, WK_M, WK_N, WK_O,
// p q r s t u v w
- WK_P, WK_Q, WK_R, WK_S, WK_T, WK_U, WK_V, WK_W,
+ WK_P, WK_Q, WK_R, WK_S, WK_T, WK_U, WK_V, WK_W,
// x y z { | } ~ DEL
WK_X, WK_Y, WK_Z, WK_LBRC, WK_BSLS, WK_RBRC, WK_GRV, KC_DEL
};
diff --git a/quantum/led.h b/quantum/led.h
new file mode 100644
index 0000000000..0fe38ea035
--- /dev/null
+++ b/quantum/led.h
@@ -0,0 +1,54 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/* FIXME: Add doxygen comments here. */
+
+/* keyboard LEDs */
+#define USB_LED_NUM_LOCK 0
+#define USB_LED_CAPS_LOCK 1
+#define USB_LED_SCROLL_LOCK 2
+#define USB_LED_COMPOSE 3
+#define USB_LED_KANA 4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef union {
+ uint8_t raw;
+ struct {
+ bool num_lock : 1;
+ bool caps_lock : 1;
+ bool scroll_lock : 1;
+ bool compose : 1;
+ bool kana : 1;
+ uint8_t reserved : 3;
+ };
+} led_t;
+
+void led_set(uint8_t usb_led);
+
+void led_init_ports(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c
index eb523990a6..4f1f06c7ac 100644
--- a/quantum/led_matrix.c
+++ b/quantum/led_matrix.c
@@ -27,7 +27,7 @@
#include <string.h>
#include <math.h>
-led_config_t led_matrix_config;
+led_eeconfig_t led_matrix_eeconfig;
#ifndef MAX
# define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
@@ -59,7 +59,7 @@ bool g_suspend_state = false;
uint32_t g_tick = 0;
// Ticks since this key was last hit.
-uint8_t g_key_hit[LED_DRIVER_LED_COUNT];
+uint8_t g_key_hit[DRIVER_LED_TOTAL];
// Ticks since any key was last hit.
uint32_t g_any_key_hit = 0;
@@ -70,40 +70,32 @@ void eeconfig_update_led_matrix(uint32_t config_value) { eeprom_update_dword(EEC
void eeconfig_update_led_matrix_default(void) {
dprintf("eeconfig_update_led_matrix_default\n");
- led_matrix_config.enable = 1;
- led_matrix_config.mode = LED_MATRIX_UNIFORM_BRIGHTNESS;
- led_matrix_config.val = 128;
- led_matrix_config.speed = 0;
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ led_matrix_eeconfig.enable = 1;
+ led_matrix_eeconfig.mode = LED_MATRIX_UNIFORM_BRIGHTNESS;
+ led_matrix_eeconfig.val = 128;
+ led_matrix_eeconfig.speed = 0;
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
void eeconfig_debug_led_matrix(void) {
- dprintf("led_matrix_config eeprom\n");
- dprintf("led_matrix_config.enable = %d\n", led_matrix_config.enable);
- dprintf("led_matrix_config.mode = %d\n", led_matrix_config.mode);
- dprintf("led_matrix_config.val = %d\n", led_matrix_config.val);
- dprintf("led_matrix_config.speed = %d\n", led_matrix_config.speed);
+ dprintf("led_matrix_eeconfig eeprom\n");
+ dprintf("led_matrix_eeconfig.enable = %d\n", led_matrix_eeconfig.enable);
+ dprintf("led_matrix_eeconfig.mode = %d\n", led_matrix_eeconfig.mode);
+ dprintf("led_matrix_eeconfig.val = %d\n", led_matrix_eeconfig.val);
+ dprintf("led_matrix_eeconfig.speed = %d\n", led_matrix_eeconfig.speed);
}
-// Last led hit
-#ifndef LED_HITS_TO_REMEMBER
-# define LED_HITS_TO_REMEMBER 8
-#endif
uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255};
uint8_t g_last_led_count = 0;
-void map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count) {
- led_matrix led;
- *led_count = 0;
-
- for (uint8_t i = 0; i < LED_DRIVER_LED_COUNT; i++) {
- // map_index_to_led(i, &led);
- led = g_leds[i];
- if (row == led.matrix_co.row && column == led.matrix_co.col) {
- led_i[*led_count] = i;
- (*led_count)++;
- }
+uint8_t map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) {
+ uint8_t led_count = 0;
+ uint8_t led_index = g_led_config.matrix_co[row][column];
+ if (led_index != NO_LED) {
+ led_i[led_count] = led_index;
+ led_count++;
}
+ return led_count;
}
void led_matrix_update_pwm_buffers(void) { led_matrix_driver.flush(); }
@@ -114,8 +106,8 @@ void led_matrix_set_index_value_all(uint8_t value) { led_matrix_driver.set_value
bool process_led_matrix(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
- uint8_t led[8], led_count;
- map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
+ uint8_t led[8];
+ uint8_t led_count = map_row_column_to_led(record->event.key.row, record->event.key.col, led);
if (led_count > 0) {
for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) {
g_last_led_hit[i - 1] = g_last_led_hit[i - 2];
@@ -127,8 +119,8 @@ bool process_led_matrix(uint16_t keycode, keyrecord_t *record) {
g_any_key_hit = 0;
} else {
#ifdef LED_MATRIX_KEYRELEASES
- uint8_t led[8], led_count;
- map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
+ uint8_t led[8];
+ uint8_t led_count = map_row_column_to_led(record->event.key.row, record->event.key.col, led);
for (uint8_t i = 0; i < led_count; i++) g_key_hit[led[i]] = 255;
g_any_key_hit = 255;
@@ -143,12 +135,12 @@ void led_matrix_set_suspend_state(bool state) { g_suspend_state = state; }
void led_matrix_all_off(void) { led_matrix_set_index_value_all(0); }
// Uniform brightness
-void led_matrix_uniform_brightness(void) { led_matrix_set_index_value_all(LED_MATRIX_MAXIMUM_BRIGHTNESS / BACKLIGHT_LEVELS * led_matrix_config.val); }
+void led_matrix_uniform_brightness(void) { led_matrix_set_index_value_all(LED_MATRIX_MAXIMUM_BRIGHTNESS / BACKLIGHT_LEVELS * led_matrix_eeconfig.val); }
void led_matrix_custom(void) {}
void led_matrix_task(void) {
- if (!led_matrix_config.enable) {
+ if (!led_matrix_eeconfig.enable) {
led_matrix_all_off();
led_matrix_indicators();
return;
@@ -160,7 +152,7 @@ void led_matrix_task(void) {
g_any_key_hit++;
}
- for (int led = 0; led < LED_DRIVER_LED_COUNT; led++) {
+ for (int led = 0; led < DRIVER_LED_TOTAL; led++) {
if (g_key_hit[led] < 255) {
if (g_key_hit[led] == 254) g_last_led_count = MAX(g_last_led_count - 1, 0);
g_key_hit[led]++;
@@ -170,7 +162,7 @@ void led_matrix_task(void) {
// Ideally we would also stop sending zeros to the LED driver PWM buffers
// while suspended and just do a software shutdown. This is a cheap hack for now.
bool suspend_backlight = ((g_suspend_state && LED_DISABLE_WHEN_USB_SUSPENDED) || (LED_DISABLE_AFTER_TIMEOUT > 0 && g_any_key_hit > LED_DISABLE_AFTER_TIMEOUT * 60 * 20));
- uint8_t effect = suspend_backlight ? 0 : led_matrix_config.mode;
+ uint8_t effect = suspend_backlight ? 0 : led_matrix_eeconfig.mode;
// this gets ticked at 20 Hz.
// each effect can opt to do calculations
@@ -211,8 +203,8 @@ __attribute__((weak)) void led_matrix_indicators_user(void) {}
// else
// {
// // This needs updated to something like
-// // uint8_t led[8], led_count;
-// // map_row_column_to_led(row,column,led,&led_count);
+// // uint8_t led[8];
+// // uint8_t led_count = map_row_column_to_led(row, column, led);
// // for(uint8_t i = 0; i < led_count; i++)
// map_row_column_to_led(row, column, index);
// }
@@ -225,7 +217,7 @@ void led_matrix_init(void) {
wait_ms(500);
// clear the key hits
- for (int led = 0; led < LED_DRIVER_LED_COUNT; led++) {
+ for (int led = 0; led < DRIVER_LED_TOTAL; led++) {
g_key_hit[led] = 255;
}
@@ -235,12 +227,12 @@ void led_matrix_init(void) {
eeconfig_update_led_matrix_default();
}
- led_matrix_config.raw = eeconfig_read_led_matrix();
+ led_matrix_eeconfig.raw = eeconfig_read_led_matrix();
- if (!led_matrix_config.mode) {
- dprintf("led_matrix_init_drivers led_matrix_config.mode = 0. Write default values to EEPROM.\n");
+ if (!led_matrix_eeconfig.mode) {
+ dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n");
eeconfig_update_led_matrix_default();
- led_matrix_config.raw = eeconfig_read_led_matrix();
+ led_matrix_eeconfig.raw = eeconfig_read_led_matrix();
}
eeconfig_debug_led_matrix(); // display current eeprom values
@@ -270,10 +262,10 @@ static uint8_t decrement(uint8_t value, uint8_t step, uint8_t min, uint8_t max)
// }
// void backlight_set_key_value(uint8_t row, uint8_t column, uint8_t value) {
-// uint8_t led[8], led_count;
-// map_row_column_to_led(row,column,led,&led_count);
+// uint8_t led[8];
+// uint8_t led_count = map_row_column_to_led(row, column, led);
// for(uint8_t i = 0; i < led_count; i++) {
-// if (led[i] < LED_DRIVER_LED_COUNT) {
+// if (led[i] < DRIVER_LED_TOTAL) {
// void *address = backlight_get_custom_key_value_eeprom_address(led[i]);
// eeprom_update_byte(address, value);
// }
@@ -283,74 +275,74 @@ static uint8_t decrement(uint8_t value, uint8_t step, uint8_t min, uint8_t max)
uint32_t led_matrix_get_tick(void) { return g_tick; }
void led_matrix_toggle(void) {
- led_matrix_config.enable ^= 1;
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ led_matrix_eeconfig.enable ^= 1;
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
void led_matrix_enable(void) {
- led_matrix_config.enable = 1;
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ led_matrix_eeconfig.enable = 1;
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
-void led_matrix_enable_noeeprom(void) { led_matrix_config.enable = 1; }
+void led_matrix_enable_noeeprom(void) { led_matrix_eeconfig.enable = 1; }
void led_matrix_disable(void) {
- led_matrix_config.enable = 0;
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ led_matrix_eeconfig.enable = 0;
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
-void led_matrix_disable_noeeprom(void) { led_matrix_config.enable = 0; }
+void led_matrix_disable_noeeprom(void) { led_matrix_eeconfig.enable = 0; }
void led_matrix_step(void) {
- led_matrix_config.mode++;
- if (led_matrix_config.mode >= LED_MATRIX_EFFECT_MAX) {
- led_matrix_config.mode = 1;
+ led_matrix_eeconfig.mode++;
+ if (led_matrix_eeconfig.mode >= LED_MATRIX_EFFECT_MAX) {
+ led_matrix_eeconfig.mode = 1;
}
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
void led_matrix_step_reverse(void) {
- led_matrix_config.mode--;
- if (led_matrix_config.mode < 1) {
- led_matrix_config.mode = LED_MATRIX_EFFECT_MAX - 1;
+ led_matrix_eeconfig.mode--;
+ if (led_matrix_eeconfig.mode < 1) {
+ led_matrix_eeconfig.mode = LED_MATRIX_EFFECT_MAX - 1;
}
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
void led_matrix_increase_val(void) {
- led_matrix_config.val = increment(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ led_matrix_eeconfig.val = increment(led_matrix_eeconfig.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
void led_matrix_decrease_val(void) {
- led_matrix_config.val = decrement(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ led_matrix_eeconfig.val = decrement(led_matrix_eeconfig.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
void led_matrix_increase_speed(void) {
- led_matrix_config.speed = increment(led_matrix_config.speed, 1, 0, 3);
- eeconfig_update_led_matrix(led_matrix_config.raw); // EECONFIG needs to be increased to support this
+ led_matrix_eeconfig.speed = increment(led_matrix_eeconfig.speed, 1, 0, 3);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw); // EECONFIG needs to be increased to support this
}
void led_matrix_decrease_speed(void) {
- led_matrix_config.speed = decrement(led_matrix_config.speed, 1, 0, 3);
- eeconfig_update_led_matrix(led_matrix_config.raw); // EECONFIG needs to be increased to support this
+ led_matrix_eeconfig.speed = decrement(led_matrix_eeconfig.speed, 1, 0, 3);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw); // EECONFIG needs to be increased to support this
}
void led_matrix_mode(uint8_t mode, bool eeprom_write) {
- led_matrix_config.mode = mode;
+ led_matrix_eeconfig.mode = mode;
if (eeprom_write) {
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
}
-uint8_t led_matrix_get_mode(void) { return led_matrix_config.mode; }
+uint8_t led_matrix_get_mode(void) { return led_matrix_eeconfig.mode; }
-void led_matrix_set_value_noeeprom(uint8_t val) { led_matrix_config.val = val; }
+void led_matrix_set_value_noeeprom(uint8_t val) { led_matrix_eeconfig.val = val; }
void led_matrix_set_value(uint8_t val) {
led_matrix_set_value_noeeprom(val);
- eeconfig_update_led_matrix(led_matrix_config.raw);
+ eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
}
void backlight_set(uint8_t val) { led_matrix_set_value(val); }
diff --git a/quantum/led_matrix.h b/quantum/led_matrix.h
index 7dcdf1d482..85bae43c15 100644
--- a/quantum/led_matrix.h
+++ b/quantum/led_matrix.h
@@ -19,46 +19,12 @@
#pragma once
+#include "led_matrix_types.h"
+
#ifndef BACKLIGHT_ENABLE
# error You must define BACKLIGHT_ENABLE with LED_MATRIX_ENABLE
#endif
-typedef struct Point {
- uint8_t x;
- uint8_t y;
-} __attribute__((packed)) Point;
-
-typedef struct led_matrix {
- union {
- uint8_t raw;
- struct {
- uint8_t row : 4; // 16 max
- uint8_t col : 4; // 16 max
- };
- } matrix_co;
- Point point;
- uint8_t modifier : 1;
-} __attribute__((packed)) led_matrix;
-
-extern const led_matrix g_leds[LED_DRIVER_LED_COUNT];
-
-typedef struct {
- uint8_t index;
- uint8_t value;
-} led_indicator;
-
-typedef union {
- uint32_t raw;
- struct {
- bool enable : 1;
- uint8_t mode : 6;
- uint8_t hue : 8; // Unused by led_matrix
- uint8_t sat : 8; // Unused by led_matrix
- uint8_t val : 8;
- uint8_t speed : 8; // EECONFIG needs to be increased to support this
- };
-} led_config_t;
-
enum led_matrix_effects {
LED_MATRIX_UNIFORM_BRIGHTNESS = 1,
// All new effects go above this line
@@ -122,3 +88,7 @@ typedef struct {
} led_matrix_driver_t;
extern const led_matrix_driver_t led_matrix_driver;
+
+extern led_eeconfig_t led_matrix_eeconfig;
+
+extern led_config_t g_led_config;
diff --git a/quantum/led_matrix_drivers.c b/quantum/led_matrix_drivers.c
index 9decaa33c2..eddf3f2863 100644
--- a/quantum/led_matrix_drivers.c
+++ b/quantum/led_matrix_drivers.c
@@ -66,7 +66,7 @@ static void init(void) {
# endif
# endif
- for (int index = 0; index < LED_DRIVER_LED_COUNT; index++) {
+ for (int index = 0; index < DRIVER_LED_TOTAL; index++) {
# ifdef IS31FL3731
IS31FL3731_set_led_control_register(index, true);
# else
diff --git a/quantum/led_matrix_types.h b/quantum/led_matrix_types.h
new file mode 100644
index 0000000000..669b67042b
--- /dev/null
+++ b/quantum/led_matrix_types.h
@@ -0,0 +1,69 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#if defined(__GNUC__)
+# define PACKED __attribute__((__packed__))
+#else
+# define PACKED
+#endif
+
+#if defined(_MSC_VER)
+# pragma pack(push, 1)
+#endif
+
+// Last led hit
+#ifndef LED_HITS_TO_REMEMBER
+# define LED_HITS_TO_REMEMBER 8
+#endif // LED_HITS_TO_REMEMBER
+
+typedef struct PACKED {
+ uint8_t x;
+ uint8_t y;
+} point_t;
+
+#define LED_FLAG_ALL 0xFF
+#define LED_FLAG_NONE 0x00
+#define LED_FLAG_MODIFIER 0x01
+#define LED_FLAG_KEYLIGHT 0x04
+#define LED_FLAG_INDICATOR 0x08
+
+#define NO_LED 255
+
+typedef struct PACKED {
+ uint8_t matrix_co[MATRIX_ROWS][MATRIX_COLS];
+ point_t point[DRIVER_LED_TOTAL];
+ uint8_t flags[DRIVER_LED_TOTAL];
+} led_config_t;
+
+typedef union {
+ uint32_t raw;
+ struct PACKED {
+ uint8_t enable : 2;
+ uint8_t mode : 6;
+ uint16_t reserved;
+ uint8_t val;
+ uint8_t speed; // EECONFIG needs to be increased to support this
+ };
+} led_eeconfig_t;
+
+#if defined(_MSC_VER)
+# pragma pack(pop)
+#endif
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 9083ff3861..c027b7bf27 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -101,9 +101,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
// Start with a clear matrix row
matrix_row_t current_row_value = 0;
- // Select row and wait for row selecton to stabilize
+ // Select row
select_row(current_row);
- matrix_io_delay();
+ matrix_output_select_delay();
// For each col...
for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
@@ -116,6 +116,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
// Unselect row
unselect_row(current_row);
+ if (current_row + 1 < MATRIX_ROWS) {
+ matrix_output_unselect_delay(); // wait for row signal to go HIGH
+ }
// If the row has changed, store the row and return the changed flag.
if (current_matrix[current_row] != current_row_value) {
@@ -147,9 +150,9 @@ static void init_pins(void) {
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
bool matrix_changed = false;
- // Select col and wait for col selecton to stabilize
+ // Select col
select_col(current_col);
- matrix_io_delay();
+ matrix_output_select_delay();
// For each row...
for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
@@ -175,6 +178,9 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
// Unselect col
unselect_col(current_col);
+ if (current_col + 1 < MATRIX_COLS) {
+ matrix_output_unselect_delay(); // wait for col signal to go HIGH
+ }
return matrix_changed;
}
diff --git a/quantum/matrix.h b/quantum/matrix.h
new file mode 100644
index 0000000000..ce57010a47
--- /dev/null
+++ b/quantum/matrix.h
@@ -0,0 +1,79 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#if (MATRIX_COLS <= 8)
+typedef uint8_t matrix_row_t;
+#elif (MATRIX_COLS <= 16)
+typedef uint16_t matrix_row_t;
+#elif (MATRIX_COLS <= 32)
+typedef uint32_t matrix_row_t;
+#else
+# error "MATRIX_COLS: invalid value"
+#endif
+
+#define MATRIX_ROW_SHIFTER ((matrix_row_t)1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* number of matrix rows */
+uint8_t matrix_rows(void);
+/* number of matrix columns */
+uint8_t matrix_cols(void);
+/* should be called at early stage of startup before matrix_init.(optional) */
+void matrix_setup(void);
+/* intialize matrix for scaning. */
+void matrix_init(void);
+/* scan all key states on matrix */
+uint8_t matrix_scan(void);
+/* whether modified from previous scan. used after matrix_scan. */
+bool matrix_is_modified(void) __attribute__((deprecated));
+/* whether a switch is on */
+bool matrix_is_on(uint8_t row, uint8_t col);
+/* matrix state on row */
+matrix_row_t matrix_get_row(uint8_t row);
+/* print matrix for debug */
+void matrix_print(void);
+/* delay between changing matrix pin state and reading values */
+void matrix_output_select_delay(void);
+void matrix_output_unselect_delay(void);
+/* only for backwards compatibility. delay between changing matrix pin state and reading values */
+void matrix_io_delay(void);
+
+/* power control */
+void matrix_power_up(void);
+void matrix_power_down(void);
+
+/* executes code for Quantum */
+void matrix_init_quantum(void);
+void matrix_scan_quantum(void);
+
+void matrix_init_kb(void);
+void matrix_scan_kb(void);
+
+void matrix_init_user(void);
+void matrix_scan_user(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/quantum/matrix_common.c b/quantum/matrix_common.c
index 15f1e0e82e..efbad6a5fd 100644
--- a/quantum/matrix_common.c
+++ b/quantum/matrix_common.c
@@ -1,3 +1,4 @@
+#include "quantum.h"
#include "matrix.h"
#include "debounce.h"
#include "wait.h"
@@ -68,7 +69,7 @@ void matrix_print(void) {
print_matrix_header();
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
- phex(row);
+ print_hex8(row);
print(": ");
print_matrix_row(row);
print("\n");
@@ -83,8 +84,12 @@ uint8_t matrix_key_count(void) {
return count;
}
+/* `matrix_io_delay ()` exists for backwards compatibility. From now on, use matrix_output_unselect_delay(). */
__attribute__((weak)) void matrix_io_delay(void) { wait_us(MATRIX_IO_DELAY); }
+__attribute__((weak)) void matrix_output_select_delay(void) { waitInputPinDelay(); }
+__attribute__((weak)) void matrix_output_unselect_delay(void) { matrix_io_delay(); }
+
// CUSTOM MATRIX 'LITE'
__attribute__((weak)) void matrix_init_custom(void) {}
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk
index ea88d9ab9e..f7329fc4d9 100644
--- a/quantum/mcu_selection.mk
+++ b/quantum/mcu_selection.mk
@@ -16,7 +16,6 @@ ifneq ($(findstring MKL26Z64, $(MCU)),)
# Linker script to use
# - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
# or <keyboard_dir>/ld/
- # - NOTE: a custom ld script is needed for EEPROM on Teensy LC
MCU_LDSCRIPT ?= MKL26Z64
# Startup code to use
@@ -280,7 +279,73 @@ ifneq ($(findstring STM32F411, $(MCU)),)
DFU_SUFFIX_ARGS ?= -v 0483 -p DF11
endif
-ifneq (,$(filter $(MCU),atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb1286))
+ifneq ($(findstring STM32G431, $(MCU)),)
+ # Cortex version
+ MCU = cortex-m4
+
+ # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
+ ARMV = 7
+
+ ## chip/board settings
+ # - the next two should match the directories in
+ # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
+ MCU_FAMILY = STM32
+ MCU_SERIES = STM32G4xx
+
+ # Linker script to use
+ # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
+ # or <keyboard_dir>/ld/
+ MCU_LDSCRIPT ?= STM32G431xB
+
+ # Startup code to use
+ # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
+ MCU_STARTUP ?= stm32g4xx
+
+ # Board: it should exist either in <chibios>/os/hal/boards/,
+ # <keyboard_dir>/boards/, or drivers/boards/
+ BOARD ?= GENERIC_STM32_G431XB
+
+ USE_FPU ?= yes
+
+ # Options to pass to dfu-util when flashing
+ DFU_ARGS ?= -d 0483:DF11 -a 0 -s 0x08000000:leave
+ DFU_SUFFIX_ARGS ?= -v 0483 -p DF11
+endif
+
+ifneq ($(findstring STM32G474, $(MCU)),)
+ # Cortex version
+ MCU = cortex-m4
+
+ # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
+ ARMV = 7
+
+ ## chip/board settings
+ # - the next two should match the directories in
+ # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
+ MCU_FAMILY = STM32
+ MCU_SERIES = STM32G4xx
+
+ # Linker script to use
+ # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
+ # or <keyboard_dir>/ld/
+ MCU_LDSCRIPT ?= STM32G474xE
+
+ # Startup code to use
+ # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
+ MCU_STARTUP ?= stm32g4xx
+
+ # Board: it should exist either in <chibios>/os/hal/boards/,
+ # <keyboard_dir>/boards/, or drivers/boards/
+ BOARD ?= GENERIC_STM32_G474XE
+
+ USE_FPU ?= yes
+
+ # Options to pass to dfu-util when flashing
+ DFU_ARGS ?= -d 0483:DF11 -a 0 -s 0x08000000:leave
+ DFU_SUFFIX_ARGS ?= -v 0483 -p DF11
+endif
+
+ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647 at90usb1286 at90usb1287))
PROTOCOL = LUFA
# Processor frequency.
@@ -318,12 +383,15 @@ ifneq (,$(filter $(MCU),atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 a
ifeq (,$(filter $(NO_INTERRUPT_CONTROL_ENDPOINT),yes))
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
endif
- ifneq (,$(filter $(MCU),atmega16u2 atmega32u2))
+ ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2))
NO_I2C = yes
endif
endif
ifneq (,$(filter $(MCU),atmega32a))
+ # MCU name for avrdude
+ AVRDUDE_MCU = m32
+
PROTOCOL = VUSB
# Processor frequency.
@@ -332,15 +400,12 @@ ifneq (,$(filter $(MCU),atmega32a))
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
F_CPU ?= 12000000
-
- # unsupported features for now
- NO_SUSPEND_POWER_DOWN ?= yes
-
- # Programming options
- PROGRAM_CMD ?= ./util/atmega32a_program.py $(TARGET).hex
endif
ifneq (,$(filter $(MCU),atmega328p))
+ # MCU name for avrdude
+ AVRDUDE_MCU = m328p
+
PROTOCOL = VUSB
# Processor frequency.
@@ -349,9 +414,6 @@ ifneq (,$(filter $(MCU),atmega328p))
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
F_CPU ?= 16000000
-
- # unsupported features for now
- NO_SUSPEND_POWER_DOWN ?= yes
endif
ifneq (,$(filter $(MCU),atmega328))
@@ -366,10 +428,6 @@ ifneq (,$(filter $(MCU),atmega328))
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
F_CPU ?= 16000000
-
- # unsupported features for now
- NO_UART ?= yes
- NO_SUSPEND_POWER_DOWN ?= yes
endif
ifneq (,$(filter $(MCU),attiny85))
@@ -381,7 +439,4 @@ ifneq (,$(filter $(MCU),attiny85))
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
F_CPU ?= 16500000
-
- # unsupported features for now
- NO_SUSPEND_POWER_DOWN ?= yes
endif
diff --git a/quantum/mousekey.c b/quantum/mousekey.c
new file mode 100644
index 0000000000..99bfd6b96f
--- /dev/null
+++ b/quantum/mousekey.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright 2011 Jun Wako <wakojun@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include "keycode.h"
+#include "host.h"
+#include "timer.h"
+#include "print.h"
+#include "debug.h"
+#include "mousekey.h"
+
+inline int8_t times_inv_sqrt2(int8_t x) {
+ // 181/256 is pretty close to 1/sqrt(2)
+ // 0.70703125 0.707106781
+ // 1 too small for x=99 and x=198
+ // This ends up being a mult and discard lower 8 bits
+ return (x * 181) >> 8;
+}
+
+static report_mouse_t mouse_report = {0};
+static void mousekey_debug(void);
+static uint8_t mousekey_accel = 0;
+static uint8_t mousekey_repeat = 0;
+static uint8_t mousekey_wheel_repeat = 0;
+#ifdef MK_KINETIC_SPEED
+static uint16_t mouse_timer = 0;
+#endif
+
+#ifndef MK_3_SPEED
+
+static uint16_t last_timer_c = 0;
+static uint16_t last_timer_w = 0;
+
+/*
+ * Mouse keys acceleration algorithm
+ * http://en.wikipedia.org/wiki/Mouse_keys
+ *
+ * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000)
+ */
+/* milliseconds between the initial key press and first repeated motion event (0-2550) */
+uint8_t mk_delay = MOUSEKEY_DELAY / 10;
+/* milliseconds between repeated motion events (0-255) */
+uint8_t mk_interval = MOUSEKEY_INTERVAL;
+/* steady speed (in action_delta units) applied each event (0-255) */
+uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED;
+/* number of events (count) accelerating to steady speed (0-255) */
+uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
+/* ramp used to reach maximum pointer speed (NOT SUPPORTED) */
+// int8_t mk_curve = 0;
+/* wheel params */
+/* 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;
+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
+
+static uint8_t move_unit(void) {
+ uint16_t unit;
+ if (mousekey_accel & (1 << 0)) {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 4;
+ } else if (mousekey_accel & (1 << 1)) {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2;
+ } else if (mousekey_accel & (1 << 2)) {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed);
+ } else if (mousekey_repeat == 0) {
+ unit = MOUSEKEY_MOVE_DELTA;
+ } else if (mousekey_repeat >= mk_time_to_max) {
+ unit = MOUSEKEY_MOVE_DELTA * mk_max_speed;
+ } else {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max;
+ }
+ return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit));
+}
+
+static uint8_t wheel_unit(void) {
+ uint16_t unit;
+ if (mousekey_accel & (1 << 0)) {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 4;
+ } else if (mousekey_accel & (1 << 1)) {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2;
+ } else if (mousekey_accel & (1 << 2)) {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed);
+ } else if (mousekey_wheel_repeat == 0) {
+ unit = MOUSEKEY_WHEEL_DELTA;
+ } else if (mousekey_wheel_repeat >= mk_wheel_time_to_max) {
+ unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed;
+ } else {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_wheel_repeat) / mk_wheel_time_to_max;
+ }
+ return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit));
+}
+
+# else /* #ifndef MK_COMBINED */
+# ifdef MK_KINETIC_SPEED
+
+/*
+ * Kinetic movement acceleration algorithm
+ *
+ * current speed = I + A * T/50 + A * 0.5 * T^2 | maximum B
+ *
+ * T: time since the mouse movement started
+ * E: mouse events per second (set through MOUSEKEY_INTERVAL, UHK sends 250, the
+ * pro micro on my Signum 3.0 sends only 125!)
+ * I: initial speed at time 0
+ * A: acceleration
+ * B: base mouse travel speed
+ */
+const uint16_t mk_accelerated_speed = MOUSEKEY_ACCELERATED_SPEED;
+const uint16_t mk_base_speed = MOUSEKEY_BASE_SPEED;
+const uint16_t mk_decelerated_speed = MOUSEKEY_DECELERATED_SPEED;
+const uint16_t mk_initial_speed = MOUSEKEY_INITIAL_SPEED;
+
+static uint8_t move_unit(void) {
+ float speed = mk_initial_speed;
+
+ if (mousekey_accel & ((1 << 0) | (1 << 2))) {
+ speed = mousekey_accel & (1 << 2) ? mk_accelerated_speed : mk_decelerated_speed;
+ } else if (mousekey_repeat && mouse_timer) {
+ const float time_elapsed = timer_elapsed(mouse_timer) / 50;
+ speed = mk_initial_speed + MOUSEKEY_MOVE_DELTA * time_elapsed + MOUSEKEY_MOVE_DELTA * 0.5 * time_elapsed * time_elapsed;
+
+ speed = speed > mk_base_speed ? mk_base_speed : speed;
+ }
+
+ /* convert speed to USB mouse speed 1 to 127 */
+ speed = (uint8_t)(speed / (1000.0f / mk_interval));
+ speed = speed < 1 ? 1 : speed;
+
+ 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) {
+ 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;
+}
+
+# else /* #ifndef MK_KINETIC_SPEED */
+
+static uint8_t move_unit(void) {
+ uint16_t unit;
+ if (mousekey_accel & (1 << 0)) {
+ unit = 1;
+ } else if (mousekey_accel & (1 << 1)) {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2;
+ } else if (mousekey_accel & (1 << 2)) {
+ unit = MOUSEKEY_MOVE_MAX;
+ } else if (mousekey_repeat == 0) {
+ unit = MOUSEKEY_MOVE_DELTA;
+ } else if (mousekey_repeat >= mk_time_to_max) {
+ unit = MOUSEKEY_MOVE_DELTA * mk_max_speed;
+ } else {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max;
+ }
+ return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit));
+}
+
+static uint8_t wheel_unit(void) {
+ uint16_t unit;
+ if (mousekey_accel & (1 << 0)) {
+ unit = 1;
+ } else if (mousekey_accel & (1 << 1)) {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2;
+ } else if (mousekey_accel & (1 << 2)) {
+ unit = MOUSEKEY_WHEEL_MAX;
+ } else if (mousekey_repeat == 0) {
+ unit = MOUSEKEY_WHEEL_DELTA;
+ } else if (mousekey_repeat >= mk_wheel_time_to_max) {
+ unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed;
+ } else {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max;
+ }
+ return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit));
+}
+
+# endif /* #ifndef MK_KINETIC_SPEED */
+# endif /* #ifndef MK_COMBINED */
+
+void mousekey_task(void) {
+ // report cursor and scroll movement independently
+ report_mouse_t const tmpmr = mouse_report;
+
+ mouse_report.x = 0;
+ mouse_report.y = 0;
+ mouse_report.v = 0;
+ mouse_report.h = 0;
+
+ if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > (mousekey_repeat ? mk_interval : mk_delay * 10)) {
+ if (mousekey_repeat != UINT8_MAX) mousekey_repeat++;
+ if (tmpmr.x != 0) mouse_report.x = move_unit() * ((tmpmr.x > 0) ? 1 : -1);
+ if (tmpmr.y != 0) mouse_report.y = move_unit() * ((tmpmr.y > 0) ? 1 : -1);
+
+ /* diagonal move [1/sqrt(2)] */
+ if (mouse_report.x && mouse_report.y) {
+ mouse_report.x = times_inv_sqrt2(mouse_report.x);
+ if (mouse_report.x == 0) {
+ mouse_report.x = 1;
+ }
+ mouse_report.y = times_inv_sqrt2(mouse_report.y);
+ if (mouse_report.y == 0) {
+ mouse_report.y = 1;
+ }
+ }
+ }
+ if ((tmpmr.v || tmpmr.h) && timer_elapsed(last_timer_w) > (mousekey_wheel_repeat ? mk_wheel_interval : mk_wheel_delay * 10)) {
+ if (mousekey_wheel_repeat != UINT8_MAX) mousekey_wheel_repeat++;
+ if (tmpmr.v != 0) mouse_report.v = wheel_unit() * ((tmpmr.v > 0) ? 1 : -1);
+ if (tmpmr.h != 0) mouse_report.h = wheel_unit() * ((tmpmr.h > 0) ? 1 : -1);
+
+ /* diagonal move [1/sqrt(2)] */
+ if (mouse_report.v && mouse_report.h) {
+ mouse_report.v = times_inv_sqrt2(mouse_report.v);
+ if (mouse_report.v == 0) {
+ mouse_report.v = 1;
+ }
+ mouse_report.h = times_inv_sqrt2(mouse_report.h);
+ if (mouse_report.h == 0) {
+ mouse_report.h = 1;
+ }
+ }
+ }
+
+ if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send();
+ mouse_report = tmpmr;
+}
+
+void mousekey_on(uint8_t code) {
+# ifdef MK_KINETIC_SPEED
+ if (mouse_timer == 0) {
+ mouse_timer = timer_read();
+ }
+# endif /* #ifdef MK_KINETIC_SPEED */
+
+ if (code == KC_MS_UP)
+ mouse_report.y = move_unit() * -1;
+ else if (code == KC_MS_DOWN)
+ mouse_report.y = move_unit();
+ else if (code == KC_MS_LEFT)
+ mouse_report.x = move_unit() * -1;
+ else if (code == KC_MS_RIGHT)
+ mouse_report.x = move_unit();
+ else if (code == KC_MS_WH_UP)
+ mouse_report.v = wheel_unit();
+ else if (code == KC_MS_WH_DOWN)
+ mouse_report.v = wheel_unit() * -1;
+ else if (code == KC_MS_WH_LEFT)
+ mouse_report.h = wheel_unit() * -1;
+ else if (code == KC_MS_WH_RIGHT)
+ mouse_report.h = wheel_unit();
+ else if (IS_MOUSEKEY_BUTTON(code))
+ mouse_report.buttons |= 1 << (code - KC_MS_BTN1);
+ else if (code == KC_MS_ACCEL0)
+ mousekey_accel |= (1 << 0);
+ else if (code == KC_MS_ACCEL1)
+ mousekey_accel |= (1 << 1);
+ else if (code == KC_MS_ACCEL2)
+ mousekey_accel |= (1 << 2);
+}
+
+void mousekey_off(uint8_t code) {
+ if (code == KC_MS_UP && mouse_report.y < 0)
+ mouse_report.y = 0;
+ else if (code == KC_MS_DOWN && mouse_report.y > 0)
+ mouse_report.y = 0;
+ else if (code == KC_MS_LEFT && mouse_report.x < 0)
+ mouse_report.x = 0;
+ else if (code == KC_MS_RIGHT && mouse_report.x > 0)
+ mouse_report.x = 0;
+ else if (code == KC_MS_WH_UP && mouse_report.v > 0)
+ mouse_report.v = 0;
+ else if (code == KC_MS_WH_DOWN && mouse_report.v < 0)
+ mouse_report.v = 0;
+ else if (code == KC_MS_WH_LEFT && mouse_report.h < 0)
+ mouse_report.h = 0;
+ else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0)
+ mouse_report.h = 0;
+ else if (IS_MOUSEKEY_BUTTON(code))
+ mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1));
+ else if (code == KC_MS_ACCEL0)
+ mousekey_accel &= ~(1 << 0);
+ else if (code == KC_MS_ACCEL1)
+ mousekey_accel &= ~(1 << 1);
+ else if (code == KC_MS_ACCEL2)
+ mousekey_accel &= ~(1 << 2);
+ if (mouse_report.x == 0 && mouse_report.y == 0) {
+ mousekey_repeat = 0;
+# ifdef MK_KINETIC_SPEED
+ mouse_timer = 0;
+# endif /* #ifdef MK_KINETIC_SPEED */
+ }
+ if (mouse_report.v == 0 && mouse_report.h == 0) mousekey_wheel_repeat = 0;
+}
+
+#else /* #ifndef MK_3_SPEED */
+
+enum { mkspd_unmod, mkspd_0, mkspd_1, mkspd_2, mkspd_COUNT };
+# ifndef MK_MOMENTARY_ACCEL
+static uint8_t mk_speed = mkspd_1;
+# else
+static uint8_t mk_speed = mkspd_unmod;
+static uint8_t mkspd_DEFAULT = mkspd_unmod;
+# endif
+static uint16_t last_timer_c = 0;
+static uint16_t last_timer_w = 0;
+uint16_t c_offsets[mkspd_COUNT] = {MK_C_OFFSET_UNMOD, MK_C_OFFSET_0, MK_C_OFFSET_1, MK_C_OFFSET_2};
+uint16_t c_intervals[mkspd_COUNT] = {MK_C_INTERVAL_UNMOD, MK_C_INTERVAL_0, MK_C_INTERVAL_1, MK_C_INTERVAL_2};
+uint16_t w_offsets[mkspd_COUNT] = {MK_W_OFFSET_UNMOD, MK_W_OFFSET_0, MK_W_OFFSET_1, MK_W_OFFSET_2};
+uint16_t w_intervals[mkspd_COUNT] = {MK_W_INTERVAL_UNMOD, MK_W_INTERVAL_0, MK_W_INTERVAL_1, MK_W_INTERVAL_2};
+
+void mousekey_task(void) {
+ // report cursor and scroll movement independently
+ report_mouse_t const tmpmr = mouse_report;
+ mouse_report.x = 0;
+ mouse_report.y = 0;
+ mouse_report.v = 0;
+ mouse_report.h = 0;
+
+ if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > c_intervals[mk_speed]) {
+ mouse_report.x = tmpmr.x;
+ mouse_report.y = tmpmr.y;
+ }
+ if ((tmpmr.h || tmpmr.v) && timer_elapsed(last_timer_w) > w_intervals[mk_speed]) {
+ mouse_report.v = tmpmr.v;
+ mouse_report.h = tmpmr.h;
+ }
+
+ if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send();
+ mouse_report = tmpmr;
+}
+
+void adjust_speed(void) {
+ uint16_t const c_offset = c_offsets[mk_speed];
+ uint16_t const w_offset = w_offsets[mk_speed];
+ if (mouse_report.x > 0) mouse_report.x = c_offset;
+ if (mouse_report.x < 0) mouse_report.x = c_offset * -1;
+ if (mouse_report.y > 0) mouse_report.y = c_offset;
+ if (mouse_report.y < 0) mouse_report.y = c_offset * -1;
+ if (mouse_report.h > 0) mouse_report.h = w_offset;
+ if (mouse_report.h < 0) mouse_report.h = w_offset * -1;
+ if (mouse_report.v > 0) mouse_report.v = w_offset;
+ if (mouse_report.v < 0) mouse_report.v = w_offset * -1;
+ // adjust for diagonals
+ if (mouse_report.x && mouse_report.y) {
+ mouse_report.x = times_inv_sqrt2(mouse_report.x);
+ if (mouse_report.x == 0) {
+ mouse_report.x = 1;
+ }
+ mouse_report.y = times_inv_sqrt2(mouse_report.y);
+ if (mouse_report.y == 0) {
+ mouse_report.y = 1;
+ }
+ }
+ if (mouse_report.h && mouse_report.v) {
+ mouse_report.h = times_inv_sqrt2(mouse_report.h);
+ mouse_report.v = times_inv_sqrt2(mouse_report.v);
+ }
+}
+
+void mousekey_on(uint8_t code) {
+ uint16_t const c_offset = c_offsets[mk_speed];
+ uint16_t const w_offset = w_offsets[mk_speed];
+ uint8_t const old_speed = mk_speed;
+ if (code == KC_MS_UP)
+ mouse_report.y = c_offset * -1;
+ else if (code == KC_MS_DOWN)
+ mouse_report.y = c_offset;
+ else if (code == KC_MS_LEFT)
+ mouse_report.x = c_offset * -1;
+ else if (code == KC_MS_RIGHT)
+ mouse_report.x = c_offset;
+ else if (code == KC_MS_WH_UP)
+ mouse_report.v = w_offset;
+ else if (code == KC_MS_WH_DOWN)
+ mouse_report.v = w_offset * -1;
+ else if (code == KC_MS_WH_LEFT)
+ mouse_report.h = w_offset * -1;
+ else if (code == KC_MS_WH_RIGHT)
+ mouse_report.h = w_offset;
+ else if (IS_MOUSEKEY_BUTTON(code))
+ mouse_report.buttons |= 1 << (code - KC_MS_BTN1);
+ else if (code == KC_MS_ACCEL0)
+ mk_speed = mkspd_0;
+ else if (code == KC_MS_ACCEL1)
+ mk_speed = mkspd_1;
+ else if (code == KC_MS_ACCEL2)
+ mk_speed = mkspd_2;
+ if (mk_speed != old_speed) adjust_speed();
+}
+
+void mousekey_off(uint8_t code) {
+# ifdef MK_MOMENTARY_ACCEL
+ uint8_t const old_speed = mk_speed;
+# endif
+ if (code == KC_MS_UP && mouse_report.y < 0)
+ mouse_report.y = 0;
+ else if (code == KC_MS_DOWN && mouse_report.y > 0)
+ mouse_report.y = 0;
+ else if (code == KC_MS_LEFT && mouse_report.x < 0)
+ mouse_report.x = 0;
+ else if (code == KC_MS_RIGHT && mouse_report.x > 0)
+ mouse_report.x = 0;
+ else if (code == KC_MS_WH_UP && mouse_report.v > 0)
+ mouse_report.v = 0;
+ else if (code == KC_MS_WH_DOWN && mouse_report.v < 0)
+ mouse_report.v = 0;
+ else if (code == KC_MS_WH_LEFT && mouse_report.h < 0)
+ mouse_report.h = 0;
+ else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0)
+ mouse_report.h = 0;
+ else if (IS_MOUSEKEY_BUTTON(code))
+ mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1));
+# ifdef MK_MOMENTARY_ACCEL
+ else if (code == KC_MS_ACCEL0)
+ mk_speed = mkspd_DEFAULT;
+ else if (code == KC_MS_ACCEL1)
+ mk_speed = mkspd_DEFAULT;
+ else if (code == KC_MS_ACCEL2)
+ mk_speed = mkspd_DEFAULT;
+ if (mk_speed != old_speed) adjust_speed();
+# endif
+}
+
+#endif /* #ifndef MK_3_SPEED */
+
+void mousekey_send(void) {
+ mousekey_debug();
+ uint16_t time = timer_read();
+ if (mouse_report.x || mouse_report.y) last_timer_c = time;
+ if (mouse_report.v || mouse_report.h) last_timer_w = time;
+ host_mouse_send(&mouse_report);
+}
+
+void mousekey_clear(void) {
+ mouse_report = (report_mouse_t){};
+ mousekey_repeat = 0;
+ mousekey_wheel_repeat = 0;
+ mousekey_accel = 0;
+}
+
+static void mousekey_debug(void) {
+ if (!debug_mouse) return;
+ print("mousekey [btn|x y v h](rep/acl): [");
+ print_hex8(mouse_report.buttons);
+ print("|");
+ print_decs(mouse_report.x);
+ print(" ");
+ print_decs(mouse_report.y);
+ print(" ");
+ print_decs(mouse_report.v);
+ print(" ");
+ print_decs(mouse_report.h);
+ print("](");
+ print_dec(mousekey_repeat);
+ print("/");
+ print_dec(mousekey_accel);
+ print(")\n");
+}
diff --git a/quantum/mousekey.h b/quantum/mousekey.h
new file mode 100644
index 0000000000..70dc4bb5c5
--- /dev/null
+++ b/quantum/mousekey.h
@@ -0,0 +1,179 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include "host.h"
+
+#ifndef MK_3_SPEED
+
+/* max value on report descriptor */
+# ifndef MOUSEKEY_MOVE_MAX
+# define MOUSEKEY_MOVE_MAX 127
+# elif MOUSEKEY_MOVE_MAX > 127
+# error MOUSEKEY_MOVE_MAX needs to be smaller than 127
+# endif
+
+# ifndef MOUSEKEY_WHEEL_MAX
+# define MOUSEKEY_WHEEL_MAX 127
+# elif MOUSEKEY_WHEEL_MAX > 127
+# error MOUSEKEY_WHEEL_MAX needs to be smaller than 127
+# endif
+
+# ifndef MOUSEKEY_MOVE_DELTA
+# ifndef MK_KINETIC_SPEED
+# define MOUSEKEY_MOVE_DELTA 5
+# else
+# define MOUSEKEY_MOVE_DELTA 25
+# endif
+# endif
+# ifndef MOUSEKEY_WHEEL_DELTA
+# define MOUSEKEY_WHEEL_DELTA 1
+# endif
+# ifndef MOUSEKEY_DELAY
+# ifndef MK_KINETIC_SPEED
+# define MOUSEKEY_DELAY 300
+# else
+# define MOUSEKEY_DELAY 8
+# endif
+# endif
+# ifndef MOUSEKEY_INTERVAL
+# ifndef MK_KINETIC_SPEED
+# define MOUSEKEY_INTERVAL 50
+# else
+# define MOUSEKEY_INTERVAL 8
+# endif
+# endif
+# ifndef MOUSEKEY_MAX_SPEED
+# define MOUSEKEY_MAX_SPEED 10
+# endif
+# ifndef MOUSEKEY_TIME_TO_MAX
+# define MOUSEKEY_TIME_TO_MAX 20
+# endif
+# ifndef MOUSEKEY_WHEEL_DELAY
+# define MOUSEKEY_WHEEL_DELAY 300
+# endif
+# ifndef MOUSEKEY_WHEEL_INTERVAL
+# define MOUSEKEY_WHEEL_INTERVAL 100
+# endif
+# ifndef MOUSEKEY_WHEEL_MAX_SPEED
+# define MOUSEKEY_WHEEL_MAX_SPEED 8
+# endif
+# ifndef MOUSEKEY_WHEEL_TIME_TO_MAX
+# define MOUSEKEY_WHEEL_TIME_TO_MAX 40
+# endif
+
+# ifndef MOUSEKEY_INITIAL_SPEED
+# define MOUSEKEY_INITIAL_SPEED 100
+# endif
+# ifndef MOUSEKEY_BASE_SPEED
+# define MOUSEKEY_BASE_SPEED 1000
+# endif
+# ifndef MOUSEKEY_DECELERATED_SPEED
+# define MOUSEKEY_DECELERATED_SPEED 400
+# endif
+# ifndef MOUSEKEY_ACCELERATED_SPEED
+# define MOUSEKEY_ACCELERATED_SPEED 3000
+# endif
+# ifndef MOUSEKEY_WHEEL_INITIAL_MOVEMENTS
+# define MOUSEKEY_WHEEL_INITIAL_MOVEMENTS 16
+# endif
+# ifndef MOUSEKEY_WHEEL_BASE_MOVEMENTS
+# define MOUSEKEY_WHEEL_BASE_MOVEMENTS 32
+# endif
+# ifndef MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS
+# define MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS 48
+# endif
+# ifndef MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS
+# define MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS 8
+# endif
+
+#else /* #ifndef MK_3_SPEED */
+
+# ifndef MK_C_OFFSET_UNMOD
+# define MK_C_OFFSET_UNMOD 16
+# endif
+# ifndef MK_C_INTERVAL_UNMOD
+# define MK_C_INTERVAL_UNMOD 16
+# endif
+# ifndef MK_C_OFFSET_0
+# define MK_C_OFFSET_0 1
+# endif
+# ifndef MK_C_INTERVAL_0
+# define MK_C_INTERVAL_0 32
+# endif
+# ifndef MK_C_OFFSET_1
+# define MK_C_OFFSET_1 4
+# endif
+# ifndef MK_C_INTERVAL_1
+# define MK_C_INTERVAL_1 16
+# endif
+# ifndef MK_C_OFFSET_2
+# define MK_C_OFFSET_2 32
+# endif
+# ifndef MK_C_INTERVAL_2
+# define MK_C_INTERVAL_2 16
+# endif
+
+# ifndef MK_W_OFFSET_UNMOD
+# define MK_W_OFFSET_UNMOD 1
+# endif
+# ifndef MK_W_INTERVAL_UNMOD
+# define MK_W_INTERVAL_UNMOD 40
+# endif
+# ifndef MK_W_OFFSET_0
+# define MK_W_OFFSET_0 1
+# endif
+# ifndef MK_W_INTERVAL_0
+# define MK_W_INTERVAL_0 360
+# endif
+# ifndef MK_W_OFFSET_1
+# define MK_W_OFFSET_1 1
+# endif
+# ifndef MK_W_INTERVAL_1
+# define MK_W_INTERVAL_1 120
+# endif
+# ifndef MK_W_OFFSET_2
+# define MK_W_OFFSET_2 1
+# endif
+# ifndef MK_W_INTERVAL_2
+# define MK_W_INTERVAL_2 20
+# endif
+
+#endif /* #ifndef MK_3_SPEED */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint8_t mk_delay;
+extern uint8_t mk_interval;
+extern uint8_t mk_max_speed;
+extern uint8_t mk_time_to_max;
+extern uint8_t mk_wheel_max_speed;
+extern uint8_t mk_wheel_time_to_max;
+
+void mousekey_task(void);
+void mousekey_on(uint8_t code);
+void mousekey_off(uint8_t code);
+void mousekey_clear(void);
+void mousekey_send(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/quantum/pointing_device.c b/quantum/pointing_device.c
index 9b7629f307..09d889f697 100644
--- a/quantum/pointing_device.c
+++ b/quantum/pointing_device.c
@@ -25,18 +25,25 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
static report_mouse_t mouseReport = {};
+__attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return (new.buttons != old.buttons) || (new.x&& new.x != old.x) || (new.y&& new.y != old.y) || (new.h&& new.h != old.h) || (new.v&& new.v != old.v); }
+
__attribute__((weak)) void pointing_device_init(void) {
// initialize device, if that needs to be done.
}
__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.
- host_mouse_send(&mouseReport);
+ if (has_mouse_report_changed(mouseReport, old_report)) {
+ host_mouse_send(&mouseReport);
+ }
// send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device
mouseReport.x = 0;
mouseReport.y = 0;
mouseReport.v = 0;
mouseReport.h = 0;
+ old_report = mouseReport;
}
__attribute__((weak)) void pointing_device_task(void) {
diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h
index aa074bb37d..56a542d545 100644
--- a/quantum/pointing_device.h
+++ b/quantum/pointing_device.h
@@ -26,3 +26,4 @@ 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 newMouseReport);
+bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old);
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c
index 0f1257e396..f38d7d47a0 100644
--- a/quantum/process_keycode/process_combo.c
+++ b/quantum/process_keycode/process_combo.c
@@ -20,8 +20,8 @@
#ifndef COMBO_VARIABLE_LEN
__attribute__((weak)) combo_t key_combos[COMBO_COUNT] = {};
#else
-extern combo_t key_combos[];
-extern int COMBO_LEN;
+extern combo_t key_combos[];
+extern int COMBO_LEN;
#endif
__attribute__((weak)) void process_combo_event(uint16_t combo_index, bool pressed) {}
@@ -146,7 +146,7 @@ bool process_combo(uint16_t keycode, keyrecord_t *record) {
}
#ifndef COMBO_VARIABLE_LEN
for (current_combo_index = 0; current_combo_index < COMBO_COUNT; ++current_combo_index) {
-#else
+#else
for (current_combo_index = 0; current_combo_index < COMBO_LEN; ++current_combo_index) {
#endif
combo_t *combo = &key_combos[current_combo_index];
diff --git a/quantum/process_keycode/process_grave_esc.h b/quantum/process_keycode/process_grave_esc.h
index bbf4483763..bbf4483763 100644..100755
--- a/quantum/process_keycode/process_grave_esc.h
+++ b/quantum/process_keycode/process_grave_esc.h
diff --git a/quantum/process_keycode/process_magic.c b/quantum/process_keycode/process_magic.c
index c70764dea1..44dd5f0579 100644
--- a/quantum/process_keycode/process_magic.c
+++ b/quantum/process_keycode/process_magic.c
@@ -42,7 +42,7 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
switch (keycode) {
case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_TOGGLE_ALT_GUI:
- case MAGIC_SWAP_LCTL_LGUI ... MAGIC_TOGGLE_CTL_GUI:
+ case MAGIC_SWAP_LCTL_LGUI ... MAGIC_EE_HANDS_RIGHT:
/* keymap config */
keymap_config.raw = eeconfig_read_keymap();
switch (keycode) {
@@ -158,15 +158,14 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) {
clear_keyboard(); // clear first buffer to prevent stuck keys
keymap_config.nkro = !keymap_config.nkro;
break;
-#if 0
case MAGIC_EE_HANDS_LEFT:
eeconfig_update_handedness(true);
break;
case MAGIC_EE_HANDS_RIGHT:
eeconfig_update_handedness(false);
break;
-#endif
}
+
eeconfig_update_keymap(keymap_config.raw);
clear_keyboard(); // clear to prevent stuck keys
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c
index 8e2fb955e7..9632d2b757 100644
--- a/quantum/process_keycode/process_midi.c
+++ b/quantum/process_keycode/process_midi.c
@@ -34,7 +34,7 @@ void process_midi_all_notes_off(void) { midi_send_cc(&midi_device, 0, 0x7B, 0);
# include "timer.h"
-static uint8_t tone_status[MIDI_TONE_COUNT];
+static uint8_t tone_status[2][MIDI_TONE_COUNT];
static uint8_t midi_modulation;
static int8_t midi_modulation_step;
@@ -51,7 +51,8 @@ void midi_init(void) {
midi_config.modulation_interval = 8;
for (uint8_t i = 0; i < MIDI_TONE_COUNT; i++) {
- tone_status[i] = MIDI_INVALID_NOTE;
+ tone_status[0][i] = MIDI_INVALID_NOTE;
+ tone_status[1][i] = 0;
}
midi_modulation = 0;
@@ -68,19 +69,21 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) {
uint8_t tone = keycode - MIDI_TONE_MIN;
uint8_t velocity = midi_config.velocity;
if (record->event.pressed) {
- if (tone_status[tone] == MIDI_INVALID_NOTE) {
- uint8_t note = midi_compute_note(keycode);
- midi_send_noteon(&midi_device, channel, note, velocity);
- dprintf("midi noteon channel:%d note:%d velocity:%d\n", channel, note, velocity);
- tone_status[tone] = note;
+ uint8_t note = midi_compute_note(keycode);
+ midi_send_noteon(&midi_device, channel, note, velocity);
+ dprintf("midi noteon channel:%d note:%d velocity:%d\n", channel, note, velocity);
+ tone_status[1][tone] += 1;
+ if (tone_status[0][tone] == MIDI_INVALID_NOTE) {
+ tone_status[0][tone] = note;
}
} else {
- uint8_t note = tone_status[tone];
- if (note != MIDI_INVALID_NOTE) {
+ uint8_t note = tone_status[0][tone];
+ tone_status[1][tone] -= 1;
+ if (tone_status[1][tone] == 0) {
midi_send_noteoff(&midi_device, channel, note, velocity);
dprintf("midi noteoff channel:%d note:%d velocity:%d\n", channel, note, velocity);
+ tone_status[0][tone] = MIDI_INVALID_NOTE;
}
- tone_status[tone] = MIDI_INVALID_NOTE;
}
return false;
}
diff --git a/quantum/process_keycode/process_rgb.c b/quantum/process_keycode/process_rgb.c
index db31011d98..5dd8e7809d 100644
--- a/quantum/process_keycode/process_rgb.c
+++ b/quantum/process_keycode/process_rgb.c
@@ -167,7 +167,7 @@ bool process_rgb(const uint16_t keycode, const keyrecord_t *record) {
#endif
return false;
case RGB_MODE_RAINBOW:
-#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined( RGBLIGHT_EFFECT_RAINBOW_MOOD)
+#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined(RGBLIGHT_EFFECT_RAINBOW_MOOD)
handleKeycodeRGBMode(RGBLIGHT_MODE_RAINBOW_MOOD, RGBLIGHT_MODE_RAINBOW_MOOD_end);
#endif
#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_KEYCODES) && !defined(DISABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT)
@@ -175,7 +175,7 @@ bool process_rgb(const uint16_t keycode, const keyrecord_t *record) {
#endif
return false;
case RGB_MODE_SWIRL:
-#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined( RGBLIGHT_EFFECT_RAINBOW_SWIRL)
+#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL)
handleKeycodeRGBMode(RGBLIGHT_MODE_RAINBOW_SWIRL, RGBLIGHT_MODE_RAINBOW_SWIRL_end);
#endif
#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_KEYCODES) && !defined(DISABLE_RGB_MATRIX_CYCLE_PINWHEEL)
@@ -183,27 +183,27 @@ bool process_rgb(const uint16_t keycode, const keyrecord_t *record) {
#endif
return false;
case RGB_MODE_SNAKE:
-#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined( RGBLIGHT_EFFECT_SNAKE)
+#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined(RGBLIGHT_EFFECT_SNAKE)
handleKeycodeRGBMode(RGBLIGHT_MODE_SNAKE, RGBLIGHT_MODE_SNAKE_end);
#endif
return false;
case RGB_MODE_KNIGHT:
-#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined( RGBLIGHT_EFFECT_KNIGHT)
+#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined(RGBLIGHT_EFFECT_KNIGHT)
handleKeycodeRGBMode(RGBLIGHT_MODE_KNIGHT, RGBLIGHT_MODE_KNIGHT_end);
#endif
return false;
case RGB_MODE_XMAS:
-#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined( RGBLIGHT_EFFECT_CHRISTMAS)
+#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined(RGBLIGHT_EFFECT_CHRISTMAS)
rgblight_mode(RGBLIGHT_MODE_CHRISTMAS);
#endif
return false;
case RGB_MODE_GRADIENT:
-#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined( RGBLIGHT_EFFECT_STATIC_GRADIENT)
+#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined(RGBLIGHT_EFFECT_STATIC_GRADIENT)
handleKeycodeRGBMode(RGBLIGHT_MODE_STATIC_GRADIENT, RGBLIGHT_MODE_STATIC_GRADIENT_end);
#endif
return false;
case RGB_MODE_RGBTEST:
-#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined( RGBLIGHT_EFFECT_RGB_TEST)
+#if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_DISABLE_KEYCODES) && defined(RGBLIGHT_EFFECT_RGB_TEST)
rgblight_mode(RGBLIGHT_MODE_RGB_TEST);
#endif
return false;
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index 138de0eba2..17dc540a64 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -117,6 +117,10 @@ void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
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();
}
}
}
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index b04767ca65..a013c5cabf 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -63,10 +63,10 @@ typedef struct {
{ .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) \
- { .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 }), }
+ { .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_TOGGLE_LAYER(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_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)
@@ -79,8 +79,6 @@ typedef struct {
# 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, }
-
-
extern qk_tap_dance_action_t tap_dance_actions[];
/* To be used internally */
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index bac9fbcc0f..46fcaaa86b 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -158,7 +158,7 @@ __attribute__((weak)) void unicode_input_cancel(void) {
void register_hex(uint16_t hex) {
for (int i = 3; i >= 0; i--) {
uint8_t digit = ((hex >> (i * 4)) & 0xF);
- tap_code16(hex_to_keycode(digit));
+ send_nibble(digit);
}
}
@@ -171,10 +171,10 @@ void register_hex32(uint32_t hex) {
uint8_t digit = ((hex >> (i * 4)) & 0xF);
if (digit == 0) {
if (!onzerostart) {
- tap_code16(hex_to_keycode(digit));
+ send_nibble(digit);
}
} else {
- tap_code16(hex_to_keycode(digit));
+ send_nibble(digit);
onzerostart = false;
}
}
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 3c98e9c459..d5d97f3242 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -25,10 +25,6 @@
# include "backlight.h"
#endif
-#ifdef FAUXCLICKY_ENABLE
-# include "fauxclicky.h"
-#endif
-
#ifdef API_ENABLE
# include "api.h"
#endif
@@ -53,6 +49,9 @@ float goodbye_song[][2] = GOODBYE_SONG;
# ifdef DEFAULT_LAYER_SONGS
float default_layer_songs[][16][2] = DEFAULT_LAYER_SONGS;
# endif
+# ifdef SENDSTRING_BELL
+float bell_song[][2] = SONG(TERMINAL_SOUND);
+# endif
#endif
#ifdef AUTO_SHIFT_ENABLE
@@ -146,7 +145,6 @@ void reset_keyboard(void) {
/* Convert record into usable keycode via the contained event. */
uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) { return get_event_keycode(record->event, update_layer_cache); }
-
/* Convert event into usable keycode. Checks the layer cache to ensure that it
* retains the correct keycode after a layer change, if the key is still pressed.
* "update_layer_cache" is to ensure that it only updates the layer cache when
@@ -222,9 +220,6 @@ bool process_record_quantum(keyrecord_t *record) {
#ifdef HAPTIC_ENABLE
process_haptic(keycode, record) &&
#endif // HAPTIC_ENABLE
-#if defined(RGB_MATRIX_ENABLE)
- process_rgb_matrix(keycode, record) &&
-#endif
#ifdef ORYX_ENABLE
process_record_oryx(keycode, record) &&
#endif
@@ -310,17 +305,6 @@ bool process_record_quantum(keyrecord_t *record) {
case EEPROM_RESET:
eeconfig_init();
return false;
-#ifdef FAUXCLICKY_ENABLE
- case FC_TOG:
- FAUXCLICKY_TOGGLE;
- return false;
- case FC_ON:
- FAUXCLICKY_ON;
- return false;
- case FC_OFF:
- FAUXCLICKY_OFF;
- return false;
-#endif
#ifdef VELOCIKEY_ENABLE
case VLK_TOG:
velocikey_toggle();
@@ -337,224 +321,11 @@ bool process_record_quantum(keyrecord_t *record) {
set_output(OUTPUT_BLUETOOTH);
return false;
#endif
-#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_BREATHING)
- case BL_BRTG:
- backlight_toggle_breathing();
- return false;
-#endif
-#ifdef WEBUSB_ENABLE
- case WEBUSB_PAIR:
- webusb_state.pairing ^= true;
- return false;
-#endif
- }
- }
-
- return process_action_kb(record);
-}
-
-// 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),
-};
-
-/* 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);
- 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);
- }
+ return process_action_kb(record);
}
void set_single_persistent_default_layer(uint8_t default_layer) {
@@ -573,34 +344,6 @@ layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_
void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) { layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3)); }
-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;
- }
-}
-
void matrix_init_quantum() {
#ifdef BOOTMAGIC_LITE
bootmagic_lite();
@@ -682,10 +425,6 @@ void matrix_scan_quantum() {
led_matrix_task();
#endif
-#ifdef RGB_MATRIX_ENABLE
- rgb_matrix_task();
-#endif
-
#ifdef WPM_ENABLE
decay_wpm();
#endif
@@ -709,42 +448,6 @@ void matrix_scan_quantum() {
# include "hd44780.h"
#endif
-// Functions for spitting out values
-//
-
-void send_dword(uint32_t number) {
- uint16_t word = (number >> 16);
- send_word(word);
- send_word(number & 0xFFFFUL);
-}
-
-void send_word(uint16_t number) {
- uint8_t byte = number >> 8;
- send_byte(byte);
- send_byte(number & 0xFF);
-}
-
-void send_byte(uint8_t number) {
- uint8_t nibble = number >> 4;
- send_nibble(nibble);
- send_nibble(number & 0xF);
-}
-
-void send_nibble(uint8_t number) {
- tap_code16(hex_to_keycode(number));
-}
-
-__attribute__((weak)) uint16_t hex_to_keycode(uint8_t hex) {
- hex = hex & 0xF;
- if (hex == 0x0) {
- return KC_0;
- } else if (hex < 0xA) {
- return KC_1 + (hex - 0x1);
- } else {
- return KC_A + (hex - 0xA);
- }
-}
-
void api_send_unicode(uint32_t unicode) {
#ifdef API_ENABLE
uint8_t chunk[4];
@@ -761,8 +464,6 @@ __attribute__((weak)) void startup_user() {}
__attribute__((weak)) void shutdown_user() {}
-//------------------------------------------------------------------------------
-
#ifdef WEBUSB_ENABLE
__attribute__((weak)) bool webusb_receive_user(uint8_t *data, uint8_t length) { return false; }
__attribute__((weak)) bool webusb_receive_kb(uint8_t *data, uint8_t length) { return webusb_receive_user(data, length); }
diff --git a/quantum/quantum.h b/quantum/quantum.h
index b105c66664..a5ed1b66bd 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -53,12 +53,15 @@
#include "eeconfig.h"
#include "bootloader.h"
#include "timer.h"
+#include "sync_timer.h"
#include "config_common.h"
+#include "gpio.h"
+#include "atomic_util.h"
#include "led.h"
#include "action_util.h"
#include "action_tapping.h"
#include "print.h"
-#include "send_string_keycodes.h"
+#include "send_string.h"
#include "suspend.h"
#include <stddef.h>
#include <stdlib.h>
@@ -201,128 +204,50 @@ extern layer_state_t layer_state;
# include "wpm.h"
#endif
-// Function substitutions to ease GPIO manipulation
-#if defined(__AVR__)
-typedef uint8_t pin_t;
-
-# define setPinInput(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
-# define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
-# define setPinInputLow(pin) _Static_assert(0, "AVR processors cannot implement an input as pull low")
-# define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
-
-# define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
-# define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
-# define writePin(pin, level) ((level) ? writePinHigh(pin) : writePinLow(pin))
-
-# define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
-
-# define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF))
-
-#elif defined(PROTOCOL_CHIBIOS)
-typedef ioline_t pin_t;
-
-# define setPinInput(pin) palSetLineMode(pin, PAL_MODE_INPUT)
-# define setPinInputHigh(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)
-# define setPinInputLow(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)
-# define setPinOutput(pin) palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)
-# define writePinHigh(pin) palSetLine(pin)
-# define writePinLow(pin) palClearLine(pin)
-# define writePin(pin, level) ((level) ? (writePinHigh(pin)) : (writePinLow(pin)))
-
-# define readPin(pin) palReadLine(pin)
-
-# define togglePin(pin) palToggleLine(pin)
+#ifdef USBPD_ENABLE
+# include "usbpd.h"
#endif
-// Atomic macro to help make GPIO and other controls atomic.
-#ifdef IGNORE_ATOMIC_BLOCK
-/* do nothing atomic macro */
-# define ATOMIC_BLOCK for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0)
-# define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK
-# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK
-
-#elif defined(__AVR__)
-/* atomic macro for AVR */
-# include <util/atomic.h>
-
-# define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
-# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
+// Function substitutions to ease GPIO manipulation
+#if defined(__AVR__)
-#elif defined(PROTOCOL_CHIBIOS) || defined(PROTOCOL_ARM_ATSAM)
-/* atomic macro for ChibiOS / ARM ATSAM */
-# if defined(PROTOCOL_ARM_ATSAM)
-# include "arm_atsam_protocol.h"
+/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal.
+ * But here's more margin to make it two clocks. */
+# if !defined(GPIO_INPUT_PIN_DELAY)
+# define GPIO_INPUT_PIN_DELAY 2
# endif
+# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
-static __inline__ uint8_t __interrupt_disable__(void) {
-# if defined(PROTOCOL_CHIBIOS)
- chSysLock();
-# endif
-# if defined(PROTOCOL_ARM_ATSAM)
- __disable_irq();
-# endif
- return 1;
-}
+#elif defined(__ARMEL__) || defined(__ARMEB__)
-static __inline__ void __interrupt_enable__(const uint8_t *__s) {
-# if defined(PROTOCOL_CHIBIOS)
- chSysUnlock();
-# endif
-# if defined(PROTOCOL_ARM_ATSAM)
- __enable_irq();
+/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
+ * to which the GPIO is connected.
+ * The connected buses differ depending on the various series of MCUs.
+ * And since the instruction execution clock of the CPU and the bus clock of GPIO are different,
+ * there is a delay of several clocks to read the change of the input signal.
+ *
+ * Define this delay with the GPIO_INPUT_PIN_DELAY macro.
+ * If the GPIO_INPUT_PIN_DELAY macro is not defined, the following default values will be used.
+ * (A fairly large value of 0.25 microseconds is set.)
+ */
+# if !defined(GPIO_INPUT_PIN_DELAY)
+# if defined(STM32_SYSCLK)
+# define GPIO_INPUT_PIN_DELAY (STM32_SYSCLK / 1000000L / 4)
+# elif defined(KINETIS_SYSCLK_FREQUENCY)
+# define GPIO_INPUT_PIN_DELAY (KINETIS_SYSCLK_FREQUENCY / 1000000L / 4)
+# endif
# endif
- __asm__ volatile("" ::: "memory");
- (void)__s;
-}
-
-# define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0)
-# define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0
-
-# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE dose not implement")
-# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
-
-/* Other platform */
-#else
-
-# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE dose not implement")
-# define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON dose not implement")
+# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
#endif
-#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_keycode_lut[128];
-extern const uint8_t ascii_to_shift_lut[16];
-extern const uint8_t ascii_to_altgr_lut[16];
-// 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);
-
// For tri-layer
void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3);
void set_single_persistent_default_layer(uint8_t default_layer);
-void tap_random_base64(void);
-
#define IS_LAYER_ON(layer) layer_state_is(layer)
#define IS_LAYER_OFF(layer) !layer_state_is(layer)
@@ -359,12 +284,6 @@ void register_code16(uint16_t code);
void unregister_code16(uint16_t code);
void tap_code16(uint16_t 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);
-uint16_t hex_to_keycode(uint8_t hex);
-
void led_set_user(uint8_t usb_led);
void led_set_kb(uint8_t usb_led);
bool led_update_user(led_t led_state);
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index 37e01751a7..97d200c8cf 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -73,31 +73,22 @@ enum quantum_keycodes {
QK_LAYER_TAP_TOGGLE_MAX = 0x58FF,
QK_LAYER_MOD = 0x5900,
QK_LAYER_MOD_MAX = 0x59FF,
-#ifdef STENO_ENABLE
- QK_STENO = 0x5A00,
- QK_STENO_BOLT = 0x5A30,
- QK_STENO_GEMINI = 0x5A31,
- QK_STENO_MAX = 0x5A3F,
-#endif
-#ifdef SWAP_HANDS_ENABLE
- QK_SWAP_HANDS = 0x5B00,
- QK_SWAP_HANDS_MAX = 0x5BFF,
-#endif
- QK_MOD_TAP = 0x6000,
- QK_MOD_TAP_MAX = 0x7FFF,
-#ifdef UNICODE_ENABLE
- QK_UNICODE = 0x8000,
- QK_UNICODE_MAX = 0xFFFF,
-#endif
-#ifdef UNICODEMAP_ENABLE
- QK_UNICODEMAP = 0x8000,
- QK_UNICODEMAP_MAX = 0xBFFF,
- QK_UNICODEMAP_PAIR = 0xC000,
- QK_UNICODEMAP_PAIR_MAX = 0xFFFF,
-#endif
+ QK_STENO = 0x5A00,
+ QK_STENO_BOLT = 0x5A30,
+ QK_STENO_GEMINI = 0x5A31,
+ QK_STENO_MAX = 0x5A3F,
+ QK_SWAP_HANDS = 0x5B00,
+ QK_SWAP_HANDS_MAX = 0x5BFF,
+ QK_MOD_TAP = 0x6000,
+ QK_MOD_TAP_MAX = 0x7FFF,
+ QK_UNICODE = 0x8000,
+ QK_UNICODE_MAX = 0xFFFF,
+ QK_UNICODEMAP = 0x8000,
+ QK_UNICODEMAP_MAX = 0xBFFF,
+ QK_UNICODEMAP_PAIR = 0xC000,
+ QK_UNICODEMAP_PAIR_MAX = 0xFFFF,
// Loose keycodes - to be used directly
-
RESET = 0x5C00,
DEBUG,
MAGIC_SWAP_CONTROL_CAPSLOCK,
@@ -150,13 +141,6 @@ enum quantum_keycodes {
CLICKY_DOWN,
CLICKY_RESET,
-#ifdef FAUXCLICKY_ENABLE
- // Faux clicky
- FC_ON,
- FC_OFF,
- FC_TOG,
-#endif
-
// Music mode on/off/toggle
MU_ON,
MU_OFF,
@@ -348,7 +332,11 @@ enum quantum_keycodes {
MIDI_VELOCITY_MIN,
MI_VEL_0 = MIDI_VELOCITY_MIN,
+# ifdef VIA_ENABLE
+ MI_VEL_1 = MIDI_VELOCITY_MIN,
+# else
MI_VEL_1,
+# endif
MI_VEL_2,
MI_VEL_3,
MI_VEL_4,
@@ -719,6 +707,9 @@ enum quantum_keycodes {
#define CK_DOWN CLICKY_DOWN
#define CK_ON CLICKY_ENABLE
#define CK_OFF CLICKY_DISABLE
+#define FC_ON CLICKY_ENABLE
+#define FC_OFF CLICKY_DISABLE
+#define FC_TOGG CLICKY_TOGGLE
#define RGB_MOD RGB_MODE_FORWARD
#define RGB_RMOD RGB_MODE_REVERSE
@@ -853,15 +844,11 @@ enum quantum_keycodes {
#define KC_HYPR HYPR(KC_NO)
#define KC_MEH MEH(KC_NO)
-#ifdef UNICODE_ENABLE
-// Allows Unicode input up to 0x7FFF
-# define UC(c) (QK_UNICODE | (c))
-#endif
-#ifdef UNICODEMAP_ENABLE
-// Allows Unicode input up to 0x10FFFF, requires unicode_map
-# define X(i) (QK_UNICODEMAP | (i))
-# define XP(i, j) (QK_UNICODEMAP_PAIR | ((i)&0x7F) | (((j)&0x7F) << 7)) // 127 max i and j
-#endif
+// UNICODE_ENABLE - Allows Unicode input up to 0x7FFF
+#define UC(c) (QK_UNICODE | (c))
+// UNICODEMAP_ENABLE - Allows Unicode input up to 0x10FFFF, requires unicode_map
+#define X(i) (QK_UNICODEMAP | (i))
+#define XP(i, j) (QK_UNICODEMAP_PAIR | ((i)&0x7F) | (((j)&0x7F) << 7)) // 127 max i and j
#define UC_MOD UNICODE_MODE_FORWARD
#define UC_RMOD UNICODE_MODE_REVERSE
@@ -874,16 +861,14 @@ enum quantum_keycodes {
#define UC_M_BS UNICODE_MODE_BSD
#define UC_M_WC UNICODE_MODE_WINC
-#ifdef SWAP_HANDS_ENABLE
-# define SH_T(kc) (QK_SWAP_HANDS | (kc))
-# define SH_TG (QK_SWAP_HANDS | OP_SH_TOGGLE)
-# define SH_TT (QK_SWAP_HANDS | OP_SH_TAP_TOGGLE)
-# define SH_OS (QK_SWAP_HANDS | OP_SH_ONESHOT)
-# define SH_MON (QK_SWAP_HANDS | OP_SH_ON_OFF)
-# define SH_MOFF (QK_SWAP_HANDS | OP_SH_OFF_ON)
-# define SH_ON (QK_SWAP_HANDS | OP_SH_ON)
-# define SH_OFF (QK_SWAP_HANDS | OP_SH_OFF)
-#endif
+#define SH_T(kc) (QK_SWAP_HANDS | (kc))
+#define SH_TG (QK_SWAP_HANDS | OP_SH_TOGGLE)
+#define SH_TT (QK_SWAP_HANDS | OP_SH_TAP_TOGGLE)
+#define SH_OS (QK_SWAP_HANDS | OP_SH_ONESHOT)
+#define SH_MON (QK_SWAP_HANDS | OP_SH_ON_OFF)
+#define SH_MOFF (QK_SWAP_HANDS | OP_SH_OFF_ON)
+#define SH_ON (QK_SWAP_HANDS | OP_SH_ON)
+#define SH_OFF (QK_SWAP_HANDS | OP_SH_OFF)
// Dynamic Macros aliases
#define DM_REC1 DYN_REC_START1
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
index a5c2229d72..ec17b4d72c 100644
--- a/quantum/rgb_matrix.c
+++ b/quantum/rgb_matrix.c
@@ -117,7 +117,6 @@ __attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv
# define RGB_MATRIX_STARTUP_SPD UINT8_MAX / 2
#endif
-
// globals
bool g_suspend_state = false;
rgb_config_t rgb_matrix_config; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr
@@ -185,11 +184,12 @@ void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { rgb_matrix_driver.set_color_all(red, green, blue); }
-bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
+void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) {
+#ifndef RGB_MATRIX_SPLIT
+ if (!is_keyboard_master()) return;
+#endif
#if RGB_DISABLE_TIMEOUT > 0
- if (record->event.pressed) {
- rgb_anykey_timer = 0;
- }
+ rgb_anykey_timer = 0;
#endif // RGB_DISABLE_TIMEOUT > 0
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
@@ -197,12 +197,12 @@ bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
uint8_t led_count = 0;
# if defined(RGB_MATRIX_KEYRELEASES)
- if (!record->event.pressed)
+ if (!pressed)
# elif defined(RGB_MATRIX_KEYPRESSES)
- if (record->event.pressed)
+ if (pressed)
# endif // defined(RGB_MATRIX_KEYRELEASES)
{
- led_count = rgb_matrix_map_row_column_to_led(record->event.key.row, record->event.key.col, led);
+ led_count = rgb_matrix_map_row_column_to_led(row, col, led);
}
if (last_hit_buffer.count + led_count > LED_HITS_TO_REMEMBER) {
@@ -225,11 +225,9 @@ bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
if (rgb_matrix_config.mode == RGB_MATRIX_TYPING_HEATMAP) {
- process_rgb_matrix_typing_heatmap(record);
+ process_rgb_matrix_typing_heatmap(row, col);
}
#endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
-
- return true;
}
void rgb_matrix_test(void) {
@@ -267,9 +265,9 @@ static bool rgb_matrix_none(effect_params_t *params) {
static void rgb_task_timers(void) {
#if defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
- uint32_t deltaTime = timer_elapsed32(rgb_timer_buffer);
+ uint32_t deltaTime = sync_timer_elapsed32(rgb_timer_buffer);
#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
- rgb_timer_buffer = timer_read32();
+ rgb_timer_buffer = sync_timer_read32();
// Update double buffer timers
#if RGB_DISABLE_TIMEOUT > 0
@@ -297,7 +295,7 @@ static void rgb_task_timers(void) {
static void rgb_task_sync(void) {
// next task
- if (timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
+ if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
}
static void rgb_task_start(void) {
diff --git a/quantum/rgb_matrix.h b/quantum/rgb_matrix.h
index 8c80c1bff0..bb8bcfab68 100644
--- a/quantum/rgb_matrix.h
+++ b/quantum/rgb_matrix.h
@@ -98,7 +98,7 @@ uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *l
void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
-bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record);
+void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed);
void rgb_matrix_task(void);
diff --git a/quantum/rgb_matrix_animations/hue_breathing_anim.h b/quantum/rgb_matrix_animations/hue_breathing_anim.h
new file mode 100644
index 0000000000..54dea958af
--- /dev/null
+++ b/quantum/rgb_matrix_animations/hue_breathing_anim.h
@@ -0,0 +1,22 @@
+#ifndef DISABLE_RGB_MATRIX_HUE_BREATHING
+RGB_MATRIX_EFFECT(HUE_BREATHING)
+# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+
+// Change huedelta to adjust range of hue change. 0-255.
+// Hue Breathing - All LED's light up
+bool HUE_BREATHING(effect_params_t* params) {
+ RGB_MATRIX_USE_LIMITS(led_min, led_max);
+ uint8_t huedelta = 12;
+ HSV hsv = rgb_matrix_config.hsv;
+ uint16_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 8);
+ hsv.h = hsv.h + scale8(abs8(sin8(time) - 128) * 2, huedelta);
+ RGB rgb = hsv_to_rgb(hsv);
+ for (uint8_t i = led_min; i < led_max; i++) {
+ RGB_MATRIX_TEST_LED_FLAGS();
+ rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
+ }
+ return led_max < DRIVER_LED_TOTAL;
+}
+
+# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+#endif // DISABLE_RGB_HUE_BREATHING
diff --git a/quantum/rgb_matrix_animations/hue_pendulum_anim.h b/quantum/rgb_matrix_animations/hue_pendulum_anim.h
new file mode 100644
index 0000000000..2d8d36174f
--- /dev/null
+++ b/quantum/rgb_matrix_animations/hue_pendulum_anim.h
@@ -0,0 +1,17 @@
+#ifndef DISABLE_RGB_MATRIX_HUE_PENDULUM
+RGB_MATRIX_EFFECT(HUE_PENDULUM)
+# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+
+// Change huedelta to adjust range of hue change. 0-255.
+// Looks better with a low value and slow speed for subtle change.
+// Hue Pendulum - color changes in a wave to the right before reversing direction
+static HSV HUE_PENDULUM_math(HSV hsv, uint8_t i, uint8_t time) {
+ uint8_t huedelta = 12;
+ hsv.h = hsv.h + scale8(abs8(sin8(time) + (g_led_config.point[i].x) - 128) * 2, huedelta);
+ return hsv;
+}
+
+bool HUE_PENDULUM(effect_params_t* params) { return effect_runner_i(params, &HUE_PENDULUM_math); }
+
+# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+#endif // DISABLE_RGB_HUE_PENDULUM
diff --git a/quantum/rgb_matrix_animations/hue_wave_anim.h b/quantum/rgb_matrix_animations/hue_wave_anim.h
new file mode 100644
index 0000000000..fd9026fc90
--- /dev/null
+++ b/quantum/rgb_matrix_animations/hue_wave_anim.h
@@ -0,0 +1,17 @@
+#ifndef DISABLE_RGB_MATRIX_HUE_WAVE
+RGB_MATRIX_EFFECT(HUE_WAVE)
+# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+
+// Change huedelta to adjust range of hue change. 0-255.
+// Looks better with a low value and slow speed for subtle change.
+// Hue Wave - color changes in a wave to the right
+static HSV HUE_WAVE_math(HSV hsv, uint8_t i, uint8_t time) {
+ uint8_t huedelta = 24;
+ hsv.h = hsv.h + scale8(abs8(g_led_config.point[i].x - time), huedelta);
+ return hsv;
+}
+
+bool HUE_WAVE(effect_params_t* params) { return effect_runner_i(params, &HUE_WAVE_math); }
+
+# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+#endif // DISABLE_RGB_HUE_WAVE
diff --git a/quantum/rgb_matrix_animations/rgb_matrix_effects.inc b/quantum/rgb_matrix_animations/rgb_matrix_effects.inc
index 4c1723d933..053d441506 100644
--- a/quantum/rgb_matrix_animations/rgb_matrix_effects.inc
+++ b/quantum/rgb_matrix_animations/rgb_matrix_effects.inc
@@ -23,6 +23,9 @@
#include "rgb_matrix_animations/rainbow_pinwheels_anim.h"
#include "rgb_matrix_animations/raindrops_anim.h"
#include "rgb_matrix_animations/jellybean_raindrops_anim.h"
+#include "rgb_matrix_animations/hue_breathing_anim.h"
+#include "rgb_matrix_animations/hue_pendulum_anim.h"
+#include "rgb_matrix_animations/hue_wave_anim.h"
#include "rgb_matrix_animations/typing_heatmap_anim.h"
#include "rgb_matrix_animations/digital_rain_anim.h"
#include "rgb_matrix_animations/solid_reactive_simple_anim.h"
diff --git a/quantum/rgb_matrix_animations/typing_heatmap_anim.h b/quantum/rgb_matrix_animations/typing_heatmap_anim.h
index e06437bf76..e7dda11a2f 100644
--- a/quantum/rgb_matrix_animations/typing_heatmap_anim.h
+++ b/quantum/rgb_matrix_animations/typing_heatmap_anim.h
@@ -6,9 +6,7 @@ RGB_MATRIX_EFFECT(TYPING_HEATMAP)
# define RGB_MATRIX_TYPING_HEATMAP_DECREASE_DELAY_MS 25
# endif
-void process_rgb_matrix_typing_heatmap(keyrecord_t* record) {
- uint8_t row = record->event.key.row;
- uint8_t col = record->event.key.col;
+void process_rgb_matrix_typing_heatmap(uint8_t row, uint8_t col) {
uint8_t m_row = row - 1;
uint8_t p_row = row + 1;
uint8_t m_col = col - 1;
diff --git a/quantum/rgb_matrix_types.h b/quantum/rgb_matrix_types.h
index f7ebec1d5d..7b8171fb23 100644
--- a/quantum/rgb_matrix_types.h
+++ b/quantum/rgb_matrix_types.h
@@ -1,3 +1,19 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
#pragma once
#include <stdint.h>
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index 3842c9130b..119d3eab21 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -29,7 +29,7 @@
#endif
#include "wait.h"
#include "progmem.h"
-#include "timer.h"
+#include "sync_timer.h"
#include "rgblight.h"
#include "color.h"
#include "debug.h"
@@ -42,6 +42,9 @@
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
+#ifndef MAX
+# define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
#ifdef RGBLIGHT_SPLIT
/* for split keyboard */
@@ -81,6 +84,26 @@ static uint8_t mode_base_table[] = {
#include "rgblight_modes.h"
};
+#if !defined(RGBLIGHT_DEFAULT_MODE)
+# define RGBLIGHT_DEFAULT_MODE RGBLIGHT_MODE_STATIC_LIGHT
+#endif
+
+#if !defined(RGBLIGHT_DEFAULT_HUE)
+# define RGBLIGHT_DEFAULT_HUE 0
+#endif
+
+#if !defined(RGBLIGHT_DEFAULT_SAT)
+# define RGBLIGHT_DEFAULT_SAT UINT8_MAX
+#endif
+
+#if !defined(RGBLIGHT_DEFAULT_VAL)
+# define RGBLIGHT_DEFAULT_VAL RGBLIGHT_LIMIT_VAL
+#endif
+
+#if !defined(RGBLIGHT_DEFAULT_SPD)
+# define RGBLIGHT_DEFAULT_SPD 0
+#endif
+
static inline int is_static_effect(uint8_t mode) { return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL; }
#ifdef RGBLIGHT_LED_MAP
@@ -180,11 +203,11 @@ void eeconfig_update_rgblight_current(void) { eeconfig_update_rgblight(rgblight_
void eeconfig_update_rgblight_default(void) {
rgblight_config.enable = 1;
- rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
- rgblight_config.hue = 0;
- rgblight_config.sat = UINT8_MAX;
- rgblight_config.val = RGBLIGHT_LIMIT_VAL;
- rgblight_config.speed = 0;
+ rgblight_config.mode = RGBLIGHT_DEFAULT_MODE;
+ rgblight_config.hue = RGBLIGHT_DEFAULT_HUE;
+ rgblight_config.sat = RGBLIGHT_DEFAULT_SAT;
+ rgblight_config.val = RGBLIGHT_DEFAULT_VAL;
+ rgblight_config.speed = RGBLIGHT_DEFAULT_SPD;
RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
eeconfig_update_rgblight(rgblight_config.raw);
}
@@ -551,9 +574,7 @@ uint8_t rgblight_get_sat(void) { return rgblight_config.sat; }
uint8_t rgblight_get_val(void) { return rgblight_config.val; }
-HSV rgblight_get_hsv(void) {
- return (HSV){ rgblight_config.hue, rgblight_config.sat, rgblight_config.val };
-}
+HSV rgblight_get_hsv(void) { return (HSV){rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; }
void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
if (!rgblight_config.enable) {
@@ -702,18 +723,16 @@ static void rgblight_layers_write(void) {
# ifdef RGBLIGHT_LAYER_BLINK
rgblight_layer_mask_t _blinked_layer_mask = 0;
-uint16_t _blink_duration = 0;
static uint16_t _blink_timer;
void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
rgblight_set_layer_state(layer, true);
_blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer;
- _blink_timer = timer_read();
- _blink_duration = duration_ms;
+ _blink_timer = sync_timer_read() + duration_ms;
}
void rgblight_unblink_layers(void) {
- if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) {
+ if (_blinked_layer_mask != 0 && timer_expired(sync_timer_read(), _blink_timer)) {
for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) {
rgblight_set_layer_state(layer, false);
@@ -865,22 +884,6 @@ typedef void (*effect_func_t)(animation_status_t *anim);
// Animation timer -- use system timer (AVR Timer0)
void rgblight_timer_init(void) {
- // OLD!!!! Animation timer -- AVR Timer3
- // static uint8_t rgblight_timer_is_init = 0;
- // if (rgblight_timer_is_init) {
- // return;
- // }
- // rgblight_timer_is_init = 1;
- // /* Timer 3 setup */
- // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP
- // | _BV(CS30); // Clock selelct: clk/1
- // /* Set TOP value */
- // uint8_t sreg = SREG;
- // cli();
- // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
- // OCR3AL = RGBLED_TIMER_TOP & 0xff;
- // SREG = sreg;
-
rgblight_status.timer_enabled = false;
RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
}
@@ -888,7 +891,7 @@ void rgblight_timer_enable(void) {
if (!is_static_effect(rgblight_config.mode)) {
rgblight_status.timer_enabled = true;
}
- animation_status.last_timer = timer_read();
+ animation_status.last_timer = sync_timer_read();
RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
dprintf("rgblight timer enabled.\n");
}
@@ -991,24 +994,25 @@ void rgblight_task(void) {
# endif
# ifdef RGBLIGHT_EFFECT_TWINKLE
else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) {
- interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50);
+ interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30);
effect_func = (effect_func_t)rgblight_effect_twinkle;
}
# endif
if (animation_status.restart) {
animation_status.restart = false;
- animation_status.last_timer = timer_read() - interval_time - 1;
+ animation_status.last_timer = sync_timer_read();
animation_status.pos16 = 0; // restart signal to local each effect
}
- if (timer_elapsed(animation_status.last_timer) >= interval_time) {
+ uint16_t now = sync_timer_read();
+ if (timer_expired(now, animation_status.last_timer)) {
# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
static uint16_t report_last_timer = 0;
static bool tick_flag = false;
uint16_t oldpos16;
if (tick_flag) {
tick_flag = false;
- if (timer_elapsed(report_last_timer) >= 30000) {
- report_last_timer = timer_read();
+ if (timer_expired(now, report_last_timer)) {
+ report_last_timer += 30000;
dprintf("rgblight animation tick report to slave\n");
RGBLIGHT_SPLIT_ANIMATION_TICK;
}
@@ -1032,8 +1036,7 @@ void rgblight_task(void) {
#endif /* RGBLIGHT_USE_TIMER */
-// Effects
-#ifdef RGBLIGHT_EFFECT_BREATHING
+#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE)
# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
# ifndef RGBLIGHT_BREATHE_TABLE_SIZE
@@ -1042,17 +1045,24 @@ void rgblight_task(void) {
# include <rgblight_breathe_table.h>
# endif
-__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
-
-void rgblight_effect_breathing(animation_status_t *anim) {
- float val;
-
+static uint8_t breathe_calc(uint8_t pos) {
// http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
- val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]);
+ return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]);
# else
- val = (exp(sin((anim->pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
+ return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
# endif
+}
+
+#endif
+
+// Effects
+#ifdef RGBLIGHT_EFFECT_BREATHING
+
+__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
+
+void rgblight_effect_breathing(animation_status_t *anim) {
+ uint8_t val = breathe_calc(anim->pos);
rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
anim->pos = (anim->pos + 1);
}
@@ -1122,7 +1132,7 @@ void rgblight_effect_snake(animation_status_t *anim) {
ledp->g = 0;
ledp->b = 0;
# ifdef RGBW
- ledp->w = 0;
+ ledp->w = 0;
# endif
for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
k = pos + j * increment;
@@ -1304,48 +1314,54 @@ void rgblight_effect_alternating(animation_status_t *anim) {
#endif
#ifdef RGBLIGHT_EFFECT_TWINKLE
-__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10};
+__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5};
typedef struct PACKED {
HSV hsv;
uint8_t life;
- bool up;
+ uint8_t max_life;
} TwinkleState;
static TwinkleState led_twinkle_state[RGBLED_NUM];
void rgblight_effect_twinkle(animation_status_t *anim) {
- bool random_color = anim->delta / 3;
- bool restart = anim->pos == 0;
- anim->pos = 1;
+ const bool random_color = anim->delta / 3;
+ const bool restart = anim->pos == 0;
+ anim->pos = 1;
+
+ const uint8_t bottom = breathe_calc(0);
+ const uint8_t top = breathe_calc(127);
+
+ uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; }
+ uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; }
for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) {
TwinkleState *t = &(led_twinkle_state[i]);
HSV * c = &(t->hsv);
+
+ if (!random_color) {
+ c->h = rgblight_config.hue;
+ c->s = rgblight_config.sat;
+ }
+
if (restart) {
// Restart
- t->life = 0;
- t->hsv.v = 0;
+ t->life = 0;
+ c->v = 0;
} else if (t->life) {
// This LED is already on, either brightening or dimming
t->life--;
- uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life;
- c->v = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE;
- if (t->life == 0 && t->up) {
- t->up = false;
- t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE;
- }
- if (!random_color) {
- c->h = rgblight_config.hue;
- c->s = rgblight_config.sat;
- }
- } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) {
+ uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom);
+ c->v = scale(rgblight_config.val, unscaled);
+ } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) {
// This LED is off, but was randomly selected to start brightening
- c->h = random_color ? rand() % 0xFF : rgblight_config.hue;
- c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat;
- c->v = 0;
- t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE;
- t->up = true;
+ if (random_color) {
+ c->h = rand() % 0xFF;
+ c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2);
+ }
+ c->v = 0;
+ t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val));
+ t->life = t->max_life;
} else {
// This LED is off, and was NOT selected to start brightening
}
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index 1854fee999..6fb3ab9380 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -150,7 +150,7 @@ enum RGBLIGHT_EFFECT_MODE {
# endif
# ifndef RGBLIGHT_EFFECT_TWINKLE_LIFE
-# define RGBLIGHT_EFFECT_TWINKLE_LIFE 75
+# define RGBLIGHT_EFFECT_TWINKLE_LIFE 200
# endif
# ifndef RGBLIGHT_EFFECT_TWINKLE_PROBABILITY
@@ -170,9 +170,6 @@ enum RGBLIGHT_EFFECT_MODE {
# define RGBLIGHT_LIMIT_VAL 255
# endif
-# define RGBLED_TIMER_TOP F_CPU / (256 * 64)
-// #define RGBLED_TIMER_TOP 0xFF10
-
# include <stdint.h>
# include <stdbool.h>
# include "eeconfig.h"
diff --git a/quantum/ring_buffer.h b/quantum/ring_buffer.h
new file mode 100644
index 0000000000..284745ca8e
--- /dev/null
+++ b/quantum/ring_buffer.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <util/atomic.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifndef RBUF_SIZE
+# define RBUF_SIZE 32
+#endif
+
+static uint8_t rbuf[RBUF_SIZE];
+static uint8_t rbuf_head = 0;
+static uint8_t rbuf_tail = 0;
+static inline bool rbuf_enqueue(uint8_t data) {
+ bool ret = false;
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ uint8_t next = (rbuf_head + 1) % RBUF_SIZE;
+ if (next != rbuf_tail) {
+ rbuf[rbuf_head] = data;
+ rbuf_head = next;
+ ret = true;
+ }
+ }
+ return ret;
+}
+static inline uint8_t rbuf_dequeue(void) {
+ uint8_t val = 0;
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ if (rbuf_head != rbuf_tail) {
+ val = rbuf[rbuf_tail];
+ rbuf_tail = (rbuf_tail + 1) % RBUF_SIZE;
+ }
+ }
+
+ return val;
+}
+static inline bool rbuf_has_data(void) {
+ bool has_data;
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { has_data = (rbuf_head != rbuf_tail); }
+ return has_data;
+}
+static inline void rbuf_clear(void) {
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { rbuf_head = rbuf_tail = 0; }
+}
diff --git a/quantum/send_string.c b/quantum/send_string.c
new file mode 100644
index 0000000000..7d096b4273
--- /dev/null
+++ b/quantum/send_string.c
@@ -0,0 +1,306 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+
+#include "quantum.h"
+
+#include "send_string.h"
+
+// 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
new file mode 100644
index 0000000000..b90e6f6890
--- /dev/null
+++ b/quantum/send_string.h
@@ -0,0 +1,54 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#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_keycodes.h b/quantum/send_string_keycodes.h
index 1e8a8e9ff5..7017e03d5a 100644
--- a/quantum/send_string_keycodes.h
+++ b/quantum/send_string_keycodes.h
@@ -362,6 +362,7 @@
#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
@@ -371,6 +372,23 @@
#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
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 51bf8b1095..d6636b886a 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -114,9 +114,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
// Start with a clear matrix row
matrix_row_t current_row_value = 0;
- // Select row and wait for row selecton to stabilize
+ // Select row
select_row(current_row);
- matrix_io_delay();
+ matrix_output_select_delay();
// For each col...
for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
@@ -129,6 +129,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
// Unselect row
unselect_row(current_row);
+ if (current_row + 1 < MATRIX_ROWS) {
+ matrix_output_unselect_delay(); // wait for row signal to go HIGH
+ }
// If the row has changed, store the row and return the changed flag.
if (current_matrix[current_row] != current_row_value) {
@@ -160,9 +163,9 @@ static void init_pins(void) {
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
bool matrix_changed = false;
- // Select col and wait for col selecton to stabilize
+ // Select col
select_col(current_col);
- matrix_io_delay();
+ matrix_output_select_delay();
// For each row...
for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
@@ -188,6 +191,9 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
// Unselect col
unselect_col(current_col);
+ if (current_col + 1 < MATRIX_COLS) {
+ matrix_output_unselect_delay(); // wait for col signal to go HIGH
+ }
return matrix_changed;
}
@@ -245,48 +251,62 @@ void matrix_init(void) {
split_post_init();
}
-void matrix_post_scan(void) {
+bool matrix_post_scan(void) {
+ bool changed = false;
if (is_keyboard_master()) {
static uint8_t error_count;
- if (!transport_master(matrix + thatHand)) {
+ matrix_row_t slave_matrix[ROWS_PER_HAND] = {0};
+ if (!transport_master(matrix + thisHand, slave_matrix)) {
error_count++;
if (error_count > ERROR_DISCONNECT_COUNT) {
// reset other half if disconnected
for (int i = 0; i < ROWS_PER_HAND; ++i) {
matrix[thatHand + i] = 0;
+ slave_matrix[i] = 0;
}
+
+ changed = true;
}
} else {
error_count = 0;
+
+ for (int i = 0; i < ROWS_PER_HAND; ++i) {
+ if (matrix[thatHand + i] != slave_matrix[i]) {
+ matrix[thatHand + i] = slave_matrix[i];
+ changed = true;
+ }
+ }
}
matrix_scan_quantum();
} else {
- transport_slave(matrix + thisHand);
+ transport_slave(matrix + thatHand, matrix + thisHand);
matrix_slave_scan_user();
}
+
+ return changed;
}
uint8_t matrix_scan(void) {
- bool changed = false;
+ bool local_changed = false;
#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
// Set row, read cols
for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
- changed |= read_cols_on_row(raw_matrix, current_row);
+ local_changed |= read_cols_on_row(raw_matrix, current_row);
}
#elif (DIODE_DIRECTION == ROW2COL)
// Set col, read rows
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
- changed |= read_rows_on_col(raw_matrix, current_col);
+ local_changed |= read_rows_on_col(raw_matrix, current_col);
}
#endif
- debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed);
+ debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, local_changed);
- matrix_post_scan();
- return (uint8_t)changed;
+ bool remote_changed = matrix_post_scan();
+ return (uint8_t)(local_changed || remote_changed);
}
diff --git a/quantum/split_common/post_config.h b/quantum/split_common/post_config.h
index 5c0b414fb3..4ae1d52732 100644
--- a/quantum/split_common/post_config.h
+++ b/quantum/split_common/post_config.h
@@ -1,4 +1,4 @@
-#if defined(USE_I2C) || defined(EH)
+#if defined(USE_I2C)
// When using I2C, using rgblight implicitly involves split support.
# if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_SPLIT)
# define RGBLIGHT_SPLIT
diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c
index 575bdc0fdc..2ae44e6e15 100644
--- a/quantum/split_common/split_util.c
+++ b/quantum/split_common/split_util.c
@@ -40,7 +40,10 @@ volatile bool isLeftHand = true;
#if defined(SPLIT_USB_DETECT)
# if defined(PROTOCOL_LUFA)
static inline bool usbHasActiveConnection(void) { return USB_Device_IsAddressSet(); }
-static inline void usbDisable(void) { USB_Disable(); }
+static inline void usbDisable(void) {
+ USB_Disable();
+ USB_DeviceState = DEVICE_STATE_Unattached;
+}
# elif defined(PROTOCOL_CHIBIOS)
static inline bool usbHasActiveConnection(void) { return usbGetDriverStateI(&USBD1) == USB_ACTIVE; }
static inline void usbDisable(void) { usbStop(&USBD1); }
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index 487dbcae64..61b61ea08c 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -6,6 +6,7 @@
#include "quantum.h"
#define ROWS_PER_HAND (MATRIX_ROWS / 2)
+#define SYNC_TIMER_OFFSET 2
#ifdef RGBLIGHT_ENABLE
# include "rgblight.h"
@@ -21,14 +22,29 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
# define NUMBER_OF_ENCODERS (sizeof(encoders_pad) / sizeof(pin_t))
#endif
-#if defined(USE_I2C) || defined(EH)
+#if defined(USE_I2C)
# include "i2c_master.h"
# include "i2c_slave.h"
typedef struct _I2C_slave_buffer_t {
+# ifndef DISABLE_SYNC_TIMER
+ uint32_t sync_timer;
+# endif
+# ifdef SPLIT_TRANSPORT_MIRROR
+ matrix_row_t mmatrix[ROWS_PER_HAND];
+# endif
matrix_row_t smatrix[ROWS_PER_HAND];
- uint8_t backlight_level;
+# ifdef SPLIT_MODS_ENABLE
+ uint8_t real_mods;
+ uint8_t weak_mods;
+# ifndef NO_ACTION_ONESHOT
+ uint8_t oneshot_mods;
+# endif
+# endif
+# ifdef BACKLIGHT_ENABLE
+ uint8_t backlight_level;
+# endif
# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
rgblight_syncinfo_t rgblight_sync;
# endif
@@ -42,9 +58,14 @@ typedef struct _I2C_slave_buffer_t {
static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg;
+# define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer)
+# define I2C_KEYMAP_MASTER_START offsetof(I2C_slave_buffer_t, mmatrix)
+# define I2C_KEYMAP_SLAVE_START offsetof(I2C_slave_buffer_t, smatrix)
+# define I2C_REAL_MODS_START offsetof(I2C_slave_buffer_t, real_mods)
+# define I2C_WEAK_MODS_START offsetof(I2C_slave_buffer_t, weak_mods)
+# define I2C_ONESHOT_MODS_START offsetof(I2C_slave_buffer_t, oneshot_mods)
# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
-# define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)
@@ -55,8 +76,11 @@ static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_re
# endif
// Get rows from other half over i2c
-bool transport_master(matrix_row_t matrix[]) {
- i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_START, (void *)matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
+bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_SLAVE_START, (void *)slave_matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
+# ifdef SPLIT_TRANSPORT_MIRROR
+ i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_MASTER_START, (void *)master_matrix, sizeof(i2c_buffer->mmatrix), TIMEOUT);
+# endif
// write backlight info
# ifdef BACKLIGHT_ENABLE
@@ -85,18 +109,54 @@ bool transport_master(matrix_row_t matrix[]) {
# ifdef WPM_ENABLE
uint8_t current_wpm = get_current_wpm();
- if(current_wpm != i2c_buffer->current_wpm) {
+ if (current_wpm != i2c_buffer->current_wpm) {
if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WPM_START, (void *)&current_wpm, sizeof(current_wpm), TIMEOUT) >= 0) {
i2c_buffer->current_wpm = current_wpm;
}
}
# endif
+
+# ifdef SPLIT_MODS_ENABLE
+ uint8_t real_mods = get_mods();
+ if (real_mods != i2c_buffer->real_mods) {
+ if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_REAL_MODS_START, (void *)&real_mods, sizeof(real_mods), TIMEOUT) >= 0) {
+ i2c_buffer->real_mods = real_mods;
+ }
+ }
+
+ uint8_t weak_mods = get_weak_mods();
+ if (weak_mods != i2c_buffer->weak_mods) {
+ if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WEAK_MODS_START, (void *)&weak_mods, sizeof(weak_mods), TIMEOUT) >= 0) {
+ i2c_buffer->weak_mods = weak_mods;
+ }
+ }
+
+# ifndef NO_ACTION_ONESHOT
+ uint8_t oneshot_mods = get_oneshot_mods();
+ if (oneshot_mods != i2c_buffer->oneshot_mods) {
+ if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_ONESHOT_MODS_START, (void *)&oneshot_mods, sizeof(oneshot_mods), TIMEOUT) >= 0) {
+ i2c_buffer->oneshot_mods = oneshot_mods;
+ }
+ }
+# endif
+# endif
+
+# ifndef DISABLE_SYNC_TIMER
+ i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
+ i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT);
+# endif
return true;
}
-void transport_slave(matrix_row_t matrix[]) {
+void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+# ifndef DISABLE_SYNC_TIMER
+ sync_timer_update(i2c_buffer->sync_timer);
+# endif
// Copy matrix to I2C buffer
- memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
+ memcpy((void *)i2c_buffer->smatrix, (void *)slave_matrix, sizeof(i2c_buffer->smatrix));
+# ifdef SPLIT_TRANSPORT_MIRROR
+ memcpy((void *)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix));
+# endif
// Read Backlight Info
# ifdef BACKLIGHT_ENABLE
@@ -118,6 +178,14 @@ void transport_slave(matrix_row_t matrix[]) {
# ifdef WPM_ENABLE
set_current_wpm(i2c_buffer->current_wpm);
# endif
+
+# ifdef SPLIT_MODS_ENABLE
+ set_mods(i2c_buffer->real_mods);
+ set_weak_mods(i2c_buffer->weak_mods);
+# ifndef NO_ACTION_ONESHOT
+ set_oneshot_mods(i2c_buffer->oneshot_mods);
+# endif
+# endif
}
void transport_master_init(void) { i2c_init(); }
@@ -139,11 +207,24 @@ typedef struct _Serial_s2m_buffer_t {
} Serial_s2m_buffer_t;
typedef struct _Serial_m2s_buffer_t {
+# ifdef SPLIT_MODS_ENABLE
+ uint8_t real_mods;
+ uint8_t weak_mods;
+# ifndef NO_ACTION_ONESHOT
+ uint8_t oneshot_mods;
+# endif
+# endif
+# ifndef DISABLE_SYNC_TIMER
+ uint32_t sync_timer;
+# endif
+# ifdef SPLIT_TRANSPORT_MIRROR
+ matrix_row_t mmatrix[ROWS_PER_HAND];
+# endif
# ifdef BACKLIGHT_ENABLE
- uint8_t backlight_level;
+ uint8_t backlight_level;
# endif
# ifdef WPM_ENABLE
- uint8_t current_wpm;
+ uint8_t current_wpm;
# endif
} Serial_m2s_buffer_t;
@@ -221,7 +302,7 @@ void transport_rgblight_slave(void) {
# define transport_rgblight_slave()
# endif
-bool transport_master(matrix_row_t matrix[]) {
+bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
# ifndef SERIAL_USE_MULTI_TRANSACTION
if (soft_serial_transaction() != TRANSACTION_END) {
return false;
@@ -235,7 +316,10 @@ bool transport_master(matrix_row_t matrix[]) {
// TODO: if MATRIX_COLS > 8 change to unpack()
for (int i = 0; i < ROWS_PER_HAND; ++i) {
- matrix[i] = serial_s2m_buffer.smatrix[i];
+ slave_matrix[i] = serial_s2m_buffer.smatrix[i];
+# ifdef SPLIT_TRANSPORT_MIRROR
+ serial_m2s_buffer.mmatrix[i] = master_matrix[i];
+# endif
}
# ifdef BACKLIGHT_ENABLE
@@ -249,16 +333,34 @@ bool transport_master(matrix_row_t matrix[]) {
# ifdef WPM_ENABLE
// Write wpm to slave
- serial_m2s_buffer.current_wpm = get_current_wpm();
+ serial_m2s_buffer.current_wpm = get_current_wpm();
+# endif
+
+# ifdef SPLIT_MODS_ENABLE
+ serial_m2s_buffer.real_mods = get_mods();
+ serial_m2s_buffer.weak_mods = get_weak_mods();
+# ifndef NO_ACTION_ONESHOT
+ serial_m2s_buffer.oneshot_mods = get_oneshot_mods();
+# endif
+# endif
+# ifndef DISABLE_SYNC_TIMER
+ serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
# endif
return true;
}
-void transport_slave(matrix_row_t matrix[]) {
+void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
transport_rgblight_slave();
+# ifndef DISABLE_SYNC_TIMER
+ sync_timer_update(serial_m2s_buffer.sync_timer);
+# endif
+
// TODO: if MATRIX_COLS > 8 change to pack()
for (int i = 0; i < ROWS_PER_HAND; ++i) {
- serial_s2m_buffer.smatrix[i] = matrix[i];
+ serial_s2m_buffer.smatrix[i] = slave_matrix[i];
+# ifdef SPLIT_TRANSPORT_MIRROR
+ master_matrix[i] = serial_m2s_buffer.mmatrix[i];
+# endif
}
# ifdef BACKLIGHT_ENABLE
backlight_set(serial_m2s_buffer.backlight_level);
@@ -269,7 +371,15 @@ void transport_slave(matrix_row_t matrix[]) {
# endif
# ifdef WPM_ENABLE
- set_current_wpm(serial_m2s_buffer.current_wpm);
+ set_current_wpm(serial_m2s_buffer.current_wpm);
+# endif
+
+# ifdef SPLIT_MODS_ENABLE
+ set_mods(serial_m2s_buffer.real_mods);
+ set_weak_mods(serial_m2s_buffer.weak_mods);
+# ifndef NO_ACTION_ONESHOT
+ set_oneshot_mods(serial_m2s_buffer.oneshot_mods);
+# endif
# endif
}
diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h
index f3e752bf9b..a9f66301bf 100644
--- a/quantum/split_common/transport.h
+++ b/quantum/split_common/transport.h
@@ -1,10 +1,10 @@
#pragma once
-#include "common/matrix.h"
+#include "matrix.h"
void transport_master_init(void);
void transport_slave_init(void);
// returns false if valid data not received from slave
-bool transport_master(matrix_row_t matrix[]);
-void transport_slave(matrix_row_t matrix[]);
+bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
+void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
diff --git a/quantum/template/avr/config.h b/quantum/template/avr/config.h
index 82c6d3bec9..4192bbcfa2 100644
--- a/quantum/template/avr/config.h
+++ b/quantum/template/avr/config.h
@@ -25,7 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define DEVICE_VER 0x0001
#define MANUFACTURER %YOUR_NAME%
#define PRODUCT %KEYBOARD%
-#define DESCRIPTION A custom keyboard
/* key matrix size */
#define MATRIX_ROWS 2
@@ -41,10 +40,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
*
*/
-#define MATRIX_ROW_PINS \
- { D0, D5 }
-#define MATRIX_COL_PINS \
- { F1, F0, B0 }
+#define MATRIX_ROW_PINS { D0, D5 }
+#define MATRIX_COL_PINS { F1, F0, B0 }
#define UNUSED_PINS
/* COL2ROW, ROW2COL */
@@ -145,8 +142,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT
-//#define NO_ACTION_MACRO
-//#define NO_ACTION_FUNCTION
/* disable these deprecated features by default */
#define NO_ACTION_MACRO
diff --git a/quantum/template/avr/rules.mk b/quantum/template/avr/rules.mk
index ed6357c39f..5c0d8f307c 100644
--- a/quantum/template/avr/rules.mk
+++ b/quantum/template/avr/rules.mk
@@ -1,8 +1,6 @@
# MCU name
-#MCU = at90usb1286
MCU = atmega32u4
-
# Bootloader selection
BOOTLOADER = atmel-dfu
diff --git a/quantum/template/avr/template.c b/quantum/template/avr/template.c
deleted file mode 100644
index 7a5434f30e..0000000000
--- a/quantum/template/avr/template.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright %YEAR% %YOUR_NAME%
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#include "%KEYBOARD%.h"
-
-void matrix_init_kb(void) {
- // put your keyboard start-up code here
- // runs once when the firmware starts up
-
- matrix_init_user();
-}
-
-void matrix_scan_kb(void) {
- // put your looping keyboard code here
- // runs every cycle (a lot)
-
- matrix_scan_user();
-}
-
-bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
- // put your per-action keyboard code here
- // runs for every action, just before processing by the firmware
-
- return process_record_user(keycode, record);
-}
-
-void led_set_kb(uint8_t usb_led) {
- // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
-
- led_set_user(usb_led);
-}
diff --git a/quantum/template/base/keymaps/default/keymap.c b/quantum/template/base/keymaps/default/keymap.c
index fad132d159..b8ffb0156c 100644
--- a/quantum/template/base/keymaps/default/keymap.c
+++ b/quantum/template/base/keymaps/default/keymap.c
@@ -22,6 +22,12 @@ enum layer_names {
};
// Defines the keycodes used by our macros in process_record_user
+enum custom_keycodes {
+ QMKBEST = SAFE_RANGE,
+ QMKURL
+};
+
+// Defines the keycodes used by our macros in process_record_user
enum custom_keycodes { QMKBEST = SAFE_RANGE, QMKURL };
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
diff --git a/quantum/template/base/keymaps/default/readme.md b/quantum/template/base/keymaps/default/readme.md
index 21aa663d55..e052ed80f1 100644
--- a/quantum/template/base/keymaps/default/readme.md
+++ b/quantum/template/base/keymaps/default/readme.md
@@ -1 +1 @@
-# The default keymap for %KEYBOARD% \ No newline at end of file
+# The default keymap for %KEYBOARD%
diff --git a/quantum/template/ps2avrgb/config.h b/quantum/template/ps2avrgb/config.h
index 2701d53c43..6150bcce6d 100644
--- a/quantum/template/ps2avrgb/config.h
+++ b/quantum/template/ps2avrgb/config.h
@@ -25,7 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define DEVICE_VER 0x0001
#define MANUFACTURER %YOUR_NAME%
#define PRODUCT %KEYBOARD%
-#define DESCRIPTION A custom keyboard
/* key matrix size */
#define MATRIX_ROWS 8
diff --git a/quantum/template/ps2avrgb/i2c.c b/quantum/template/ps2avrgb/i2c.c
deleted file mode 100644
index e8c4455ad1..0000000000
--- a/quantum/template/ps2avrgb/i2c.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-Copyright 2016 Luiz Ribeiro <luizribeiro@gmail.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-// Please do not modify this file
-
-#include <avr/io.h>
-#include <util/twi.h>
-
-#include "i2c.h"
-
-void i2c_set_bitrate(uint16_t bitrate_khz) {
- uint8_t bitrate_div = ((F_CPU / 1000l) / bitrate_khz);
- if (bitrate_div >= 16) {
- bitrate_div = (bitrate_div - 16) / 2;
- }
- TWBR = bitrate_div;
-}
-
-void i2c_init(void) {
- // set pull-up resistors on I2C bus pins
- PORTC |= 0b11;
-
- i2c_set_bitrate(400);
-
- // enable TWI (two-wire interface)
- TWCR |= (1 << TWEN);
-
- // enable TWI interrupt and slave address ACK
- TWCR |= (1 << TWIE);
- TWCR |= (1 << TWEA);
-}
-
-uint8_t i2c_start(uint8_t address) {
- // reset TWI control register
- TWCR = 0;
-
- // begin transmission and wait for it to end
- TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
- while (!(TWCR & (1<<TWINT)));
-
- // check if the start condition was successfully transmitted
- if ((TWSR & 0xF8) != TW_START) {
- return 1;
- }
-
- // transmit address and wait
- TWDR = address;
- TWCR = (1<<TWINT) | (1<<TWEN);
- while (!(TWCR & (1<<TWINT)));
-
- // check if the device has acknowledged the READ / WRITE mode
- uint8_t twst = TW_STATUS & 0xF8;
- if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
- return 1;
- }
-
- return 0;
-}
-
-void i2c_stop(void) {
- TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
-}
-
-uint8_t i2c_write(uint8_t data) {
- TWDR = data;
-
- // transmit data and wait
- TWCR = (1<<TWINT) | (1<<TWEN);
- while (!(TWCR & (1<<TWINT)));
-
- if ((TWSR & 0xF8) != TW_MT_DATA_ACK) {
- return 1;
- }
-
- return 0;
-}
-
-uint8_t i2c_send(uint8_t address, uint8_t *data, uint16_t length) {
- if (i2c_start(address)) {
- return 1;
- }
-
- for (uint16_t i = 0; i < length; i++) {
- if (i2c_write(data[i])) {
- return 1;
- }
- }
-
- i2c_stop();
-
- return 0;
-}
diff --git a/quantum/template/ps2avrgb/matrix.c b/quantum/template/ps2avrgb/matrix.c
deleted file mode 100644
index 245813dfd2..0000000000
--- a/quantum/template/ps2avrgb/matrix.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
-Copyright 2017 Luiz Ribeiro <luizribeiro@gmail.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <avr/io.h>
-#include <util/delay.h>
-
-#include "matrix.h"
-
-#ifndef DEBOUNCE
-# define DEBOUNCE 5
-#endif
-
-static uint8_t debouncing = DEBOUNCE;
-
-static matrix_row_t matrix[MATRIX_ROWS];
-static matrix_row_t matrix_debouncing[MATRIX_ROWS];
-
-void matrix_set_row_status(uint8_t row);
-uint8_t bit_reverse(uint8_t x);
-
-void matrix_init(void) {
- // all outputs for rows high
- DDRB = 0xFF;
- PORTB = 0xFF;
- // all inputs for columns
- DDRA = 0x00;
- DDRC &= ~(0x111111<<2);
- DDRD &= ~(1<<PIND7);
- // all columns are pulled-up
- PORTA = 0xFF;
- PORTC |= (0b111111<<2);
- PORTD |= (1<<PIND7);
-
- // initialize matrix state: all keys off
- for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
- matrix[row] = 0x00;
- matrix_debouncing[row] = 0x00;
- }
-
- matrix_init_quantum();
-}
-
-uint8_t matrix_scan(void) {
- for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
- matrix_set_row_status(row);
- _delay_us(5);
-
- matrix_row_t cols = (
- // cols 0..7, PORTA 0 -> 7
- (~PINA) & 0xFF
- ) | (
- // cols 8..13, PORTC 7 -> 0
- bit_reverse((~PINC) & 0xFF) << 8
- ) | (
- // col 14, PORTD 7
- ((~PIND) & (1 << PIND7)) << 7
- );
-
- if (matrix_debouncing[row] != cols) {
- matrix_debouncing[row] = cols;
- debouncing = DEBOUNCE;
- }
- }
-
- if (debouncing) {
- if (--debouncing) {
- _delay_ms(1);
- } else {
- for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
- matrix[i] = matrix_debouncing[i];
- }
- }
- }
-
- matrix_scan_quantum();
-
- return 1;
-}
-
-// declarations
-void matrix_set_row_status(uint8_t row) {
- DDRB = (1 << row);
- PORTB = ~(1 << row);
-}
-
-uint8_t bit_reverse(uint8_t x) {
- x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa);
- x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc);
- x = ((x >> 4) & 0x0f) | ((x << 4) & 0xf0);
- return x;
-}
-
-inline matrix_row_t matrix_get_row(uint8_t row) {
- return matrix[row];
-}
-
-void matrix_print(void) {
-}
diff --git a/quantum/template/ps2avrgb/readme.md b/quantum/template/ps2avrgb/readme.md
index a1322535bd..f19743a163 100644
--- a/quantum/template/ps2avrgb/readme.md
+++ b/quantum/template/ps2avrgb/readme.md
@@ -12,7 +12,7 @@ Make example for this keyboard (after setting up your build environment):
make %KEYBOARD%:default
-Flashing example for this keyboard ([after setting up the bootloadHID flashing environment](flashing_bootloadhid.md))
+Flashing example for this keyboard ([after setting up the bootloadHID flashing environment](https://docs.qmk.fm/#/flashing_bootloadhid))
make %KEYBOARD%:default:flash
diff --git a/quantum/template/ps2avrgb/rules.mk b/quantum/template/ps2avrgb/rules.mk
index 7c73d2c232..1b61e9534d 100644
--- a/quantum/template/ps2avrgb/rules.mk
+++ b/quantum/template/ps2avrgb/rules.mk
@@ -17,5 +17,3 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
WS2812_DRIVER = i2c
-
-OPT_DEFS = -DDEBUG_LEVEL=0
diff --git a/quantum/template/ps2avrgb/template.c b/quantum/template/ps2avrgb/template.c
deleted file mode 100644
index 503da7ca71..0000000000
--- a/quantum/template/ps2avrgb/template.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright %YEAR% %YOUR_NAME%
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#include "%KEYBOARD%.h"
-
-
-// Optional override functions below.
-// You can leave any or all of these undefined.
-// These are only required if you want to perform custom actions.
-
-/*
-
-void matrix_init_kb(void) {
- // put your keyboard start-up code here
- // runs once when the firmware starts up
-
- matrix_init_user();
-}
-
-void matrix_scan_kb(void) {
- // put your looping keyboard code here
- // runs every cycle (a lot)
-
- matrix_scan_user();
-}
-
-bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
- // put your per-action keyboard code here
- // runs for every action, just before processing by the firmware
-
- return process_record_user(keycode, record);
-}
diff --git a/quantum/template/ps2avrgb/usbconfig.h b/quantum/template/ps2avrgb/usbconfig.h
deleted file mode 100644
index da078545fc..0000000000
--- a/quantum/template/ps2avrgb/usbconfig.h
+++ /dev/null
@@ -1,346 +0,0 @@
-#pragma once
-
-#include "config.h"
-
-/*
-General Description:
-This file is an example configuration (with inline documentation) for the USB
-driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is
-also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may
-wire the lines to any other port, as long as D+ is also wired to INT0 (or any
-other hardware interrupt, as long as it is the highest level interrupt, see
-section at the end of this file).
-*/
-
-/* ---------------------------- Hardware Config ---------------------------- */
-
-#ifndef USB_CFG_IOPORTNAME
-#define USB_CFG_IOPORTNAME D
-#endif
-/* This is the port where the USB bus is connected. When you configure it to
- * "B", the registers PORTB, PINB and DDRB will be used.
- */
-#ifndef USB_CFG_DMINUS_BIT
-#define USB_CFG_DMINUS_BIT 3
-#endif
-/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
- * This may be any bit in the port.
- */
-#ifndef USB_CFG_DPLUS_BIT
-#define USB_CFG_DPLUS_BIT 2
-#endif
-/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
- * This may be any bit in the port. Please note that D+ must also be connected
- * to interrupt pin INT0! [You can also use other interrupts, see section
- * "Optional MCU Description" below, or you can connect D- to the interrupt, as
- * it is required if you use the USB_COUNT_SOF feature. If you use D- for the
- * interrupt, the USB interrupt will also be triggered at Start-Of-Frame
- * markers every millisecond.]
- */
-#define USB_CFG_CHECK_CRC 0
-/* Define this to 1 if you want that the driver checks integrity of incoming
- * data packets (CRC checks). CRC checks cost quite a bit of code size and are
- * currently only available for 18 MHz crystal clock. You must choose
- * USB_CFG_CLOCK_KHZ = 18000 if you enable this option.
- */
-
-/* ----------------------- Optional Hardware Config ------------------------ */
-
-/* #define USB_CFG_PULLUP_IOPORTNAME D */
-/* If you connect the 1.5k pullup resistor from D- to a port pin instead of
- * V+, you can connect and disconnect the device from firmware by calling
- * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h).
- * This constant defines the port on which the pullup resistor is connected.
- */
-/* #define USB_CFG_PULLUP_BIT 4 */
-/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
- * above) where the 1.5k pullup resistor is connected. See description
- * above for details.
- */
-
-/* --------------------------- Functional Range ---------------------------- */
-
-#define USB_CFG_HAVE_INTRIN_ENDPOINT 1
-/* Define this to 1 if you want to compile a version with two endpoints: The
- * default control endpoint 0 and an interrupt-in endpoint (any other endpoint
- * number).
- */
-#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1
-/* Define this to 1 if you want to compile a version with three endpoints: The
- * default control endpoint 0, an interrupt-in endpoint 3 (or the number
- * configured below) and a catch-all default interrupt-in endpoint as above.
- * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature.
- */
-#define USB_CFG_EP3_NUMBER 3
-/* If the so-called endpoint 3 is used, it can now be configured to any other
- * endpoint number (except 0) with this macro. Default if undefined is 3.
- */
-#define USB_CFG_HAVE_INTRIN_ENDPOINT4 1
-/* Define this to 1 if you want to compile a version with three endpoints: The
- * default control endpoint 0, an interrupt-in endpoint 4 (or the number
- * configured below) and a catch-all default interrupt-in endpoint as above.
- * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature.
- */
-#define USB_CFG_EP4_NUMBER 4
-/* If the so-called endpoint 4 is used, it can now be configured to any other
- * endpoint number (except 0) with this macro. Default if undefined is 4.
- */
-/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */
-/* The above macro defines the startup condition for data toggling on the
- * interrupt/bulk endpoints 1, 3 and 4. Defaults to USBPID_DATA1.
- * Since the token is toggled BEFORE sending any data, the first packet is
- * sent with the oposite value of this configuration!
- */
-#define USB_CFG_IMPLEMENT_HALT 0
-/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
- * for endpoint 1 (interrupt endpoint). Although you may not need this feature,
- * it is required by the standard. We have made it a config option because it
- * bloats the code considerably.
- */
-#define USB_CFG_SUPPRESS_INTR_CODE 0
-/* Define this to 1 if you want to declare interrupt-in endpoints, but don't
- * want to send any data over them. If this macro is defined to 1, functions
- * usbSetInterrupt(), usbSetInterrupt3() and usbSetInterrupt4() are omitted.
- * This is useful if you need the interrupt-in endpoints in order to comply
- * to an interface (e.g. HID), but never want to send any data. This option
- * saves a couple of bytes in flash memory and the transmit buffers in RAM.
- */
-#define USB_CFG_IS_SELF_POWERED 0
-/* Define this to 1 if the device has its own power supply. Set it to 0 if the
- * device is powered from the USB bus.
- */
-#define USB_CFG_IMPLEMENT_FN_WRITE 1
-/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
- * transfers. Set it to 0 if you don't need it and want to save a couple of
- * bytes.
- */
-#define USB_CFG_IMPLEMENT_FN_READ 0
-/* Set this to 1 if you need to send control replies which are generated
- * "on the fly" when usbFunctionRead() is called. If you only want to send
- * data from a static buffer, set it to 0 and return the data from
- * usbFunctionSetup(). This saves a couple of bytes.
- */
-#define USB_CFG_IMPLEMENT_FN_WRITEOUT 1
-/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints.
- * You must implement the function usbFunctionWriteOut() which receives all
- * interrupt/bulk data sent to any endpoint other than 0. The endpoint number
- * can be found in 'usbRxToken'.
- */
-#define USB_CFG_HAVE_FLOWCONTROL 0
-/* Define this to 1 if you want flowcontrol over USB data. See the definition
- * of the macros usbDisableAllRequests() and usbEnableAllRequests() in
- * usbdrv.h.
- */
-#define USB_CFG_DRIVER_FLASH_PAGE 0
-/* If the device has more than 64 kBytes of flash, define this to the 64 k page
- * where the driver's constants (descriptors) are located. Or in other words:
- * Define this to 1 for boot loaders on the ATMega128.
- */
-#define USB_CFG_LONG_TRANSFERS 0
-/* Define this to 1 if you want to send/receive blocks of more than 254 bytes
- * in a single control-in or control-out transfer. Note that the capability
- * for long transfers increases the driver size.
- */
-/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */
-/* This macro is a hook if you want to do unconventional things. If it is
- * defined, it's inserted at the beginning of received message processing.
- * If you eat the received message and don't want default processing to
- * proceed, do a return after doing your things. One possible application
- * (besides debugging) is to flash a status LED on each packet.
- */
-/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */
-/* This macro is a hook if you need to know when an USB RESET occurs. It has
- * one parameter which distinguishes between the start of RESET state and its
- * end.
- */
-/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */
-/* This macro (if defined) is executed when a USB SET_ADDRESS request was
- * received.
- */
-#ifndef USB_COUNT_SOF
-#define USB_COUNT_SOF 1
-#endif
-/* define this macro to 1 if you need the global variable "usbSofCount" which
- * counts SOF packets. This feature requires that the hardware interrupt is
- * connected to D- instead of D+.
- */
-/* #ifdef __ASSEMBLER__
- * macro myAssemblerMacro
- * in YL, TCNT0
- * sts timer0Snapshot, YL
- * endm
- * #endif
- * #define USB_SOF_HOOK myAssemblerMacro
- * This macro (if defined) is executed in the assembler module when a
- * Start Of Frame condition is detected. It is recommended to define it to
- * the name of an assembler macro which is defined here as well so that more
- * than one assembler instruction can be used. The macro may use the register
- * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages
- * immediately after an SOF pulse may be lost and must be retried by the host.
- * What can you do with this hook? Since the SOF signal occurs exactly every
- * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in
- * designs running on the internal RC oscillator.
- * Please note that Start Of Frame detection works only if D- is wired to the
- * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES!
- */
-#define USB_CFG_CHECK_DATA_TOGGLING 0
-/* define this macro to 1 if you want to filter out duplicate data packets
- * sent by the host. Duplicates occur only as a consequence of communication
- * errors, when the host does not receive an ACK. Please note that you need to
- * implement the filtering yourself in usbFunctionWriteOut() and
- * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable
- * for each control- and out-endpoint to check for duplicate packets.
- */
-#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0
-/* define this macro to 1 if you want the function usbMeasureFrameLength()
- * compiled in. This function can be used to calibrate the AVR's RC oscillator.
- */
-#define USB_USE_FAST_CRC 0
-/* The assembler module has two implementations for the CRC algorithm. One is
- * faster, the other is smaller. This CRC routine is only used for transmitted
- * messages where timing is not critical. The faster routine needs 31 cycles
- * per byte while the smaller one needs 61 to 69 cycles. The faster routine
- * may be worth the 32 bytes bigger code size if you transmit lots of data and
- * run the AVR close to its limit.
- */
-
-/* -------------------------- Device Description --------------------------- */
-
-#define USB_CFG_VENDOR_ID
-/* USB vendor ID for the device, low byte first. If you have registered your
- * own Vendor ID, define it here. Otherwise you may use one of obdev's free
- * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules!
- * *** IMPORTANT NOTE ***
- * This template uses obdev's shared VID/PID pair for Vendor Class devices
- * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
- * the implications!
- */
-#define USB_CFG_DEVICE_ID
-/* This is the ID of the product, low byte first. It is interpreted in the
- * scope of the vendor ID. If you have registered your own VID with usb.org
- * or if you have licensed a PID from somebody else, define it here. Otherwise
- * you may use one of obdev's free shared VID/PID pairs. See the file
- * USB-IDs-for-free.txt for details!
- * *** IMPORTANT NOTE ***
- * This template uses obdev's shared VID/PID pair for Vendor Class devices
- * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
- * the implications!
- */
-#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0
-/* Define this to the length of the HID report descriptor, if you implement
- * an HID device. Otherwise don't define it or define it to 0.
- * If you use this define, you must add a PROGMEM character array named
- * "usbHidReportDescriptor" to your code which contains the report descriptor.
- * Don't forget to keep the array and this define in sync!
- */
-
-/* #define USB_PUBLIC static */
-/* Use the define above if you #include usbdrv.c instead of linking against it.
- * This technique saves a couple of bytes in flash memory.
- */
-
-/* ------------------- Fine Control over USB Descriptors ------------------- */
-/* If you don't want to use the driver's default USB descriptors, you can
- * provide our own. These can be provided as (1) fixed length static data in
- * flash memory, (2) fixed length static data in RAM or (3) dynamically at
- * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more
- * information about this function.
- * Descriptor handling is configured through the descriptor's properties. If
- * no properties are defined or if they are 0, the default descriptor is used.
- * Possible properties are:
- * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched
- * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is
- * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if
- * you want RAM pointers.
- * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found
- * in static memory is in RAM, not in flash memory.
- * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash),
- * the driver must know the descriptor's length. The descriptor itself is
- * found at the address of a well known identifier (see below).
- * List of static descriptor names (must be declared PROGMEM if in flash):
- * char usbDescriptorDevice[];
- * char usbDescriptorConfiguration[];
- * char usbDescriptorHidReport[];
- * char usbDescriptorString0[];
- * int usbDescriptorStringVendor[];
- * int usbDescriptorStringDevice[];
- * int usbDescriptorStringSerialNumber[];
- * Other descriptors can't be provided statically, they must be provided
- * dynamically at runtime.
- *
- * Descriptor properties are or-ed or added together, e.g.:
- * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18))
- *
- * The following descriptors are defined:
- * USB_CFG_DESCR_PROPS_DEVICE
- * USB_CFG_DESCR_PROPS_CONFIGURATION
- * USB_CFG_DESCR_PROPS_STRINGS
- * USB_CFG_DESCR_PROPS_STRING_0
- * USB_CFG_DESCR_PROPS_STRING_VENDOR
- * USB_CFG_DESCR_PROPS_STRING_PRODUCT
- * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
- * USB_CFG_DESCR_PROPS_HID
- * USB_CFG_DESCR_PROPS_HID_REPORT
- * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver)
- *
- * Note about string descriptors: String descriptors are not just strings, they
- * are Unicode strings prefixed with a 2 byte header. Example:
- * int serialNumberDescriptor[] = {
- * USB_STRING_DESCRIPTOR_HEADER(6),
- * 'S', 'e', 'r', 'i', 'a', 'l'
- * };
- */
-
-#define USB_CFG_DESCR_PROPS_DEVICE USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_STRINGS USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_STRING_0 USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_STRING_VENDOR USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_STRING_PRODUCT USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_HID USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_HID_REPORT USB_PROP_IS_DYNAMIC
-#define USB_CFG_DESCR_PROPS_UNKNOWN 0
-
-#define usbMsgPtr_t unsigned short
-/* If usbMsgPtr_t is not defined, it defaults to 'uchar *'. We define it to
- * a scalar type here because gcc generates slightly shorter code for scalar
- * arithmetics than for pointer arithmetics. Remove this define for backward
- * type compatibility or define it to an 8 bit type if you use data in RAM only
- * and all RAM is below 256 bytes (tiny memory model in IAR CC).
- */
-
-/* ----------------------- Optional MCU Description ------------------------ */
-
-/* The following configurations have working defaults in usbdrv.h. You
- * usually don't need to set them explicitly. Only if you want to run
- * the driver on a device which is not yet supported or with a compiler
- * which is not fully supported (such as IAR C) or if you use a differnt
- * interrupt than INT0, you may have to define some of these.
- */
-/* #define USB_INTR_CFG MCUCR */
-/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */
-/* #define USB_INTR_CFG_CLR 0 */
-/* #define USB_INTR_ENABLE GIMSK */
-/* #define USB_INTR_ENABLE_BIT INT0 */
-/* #define USB_INTR_PENDING GIFR */
-/* #define USB_INTR_PENDING_BIT INTF0 */
-/* #define USB_INTR_VECTOR INT0_vect */
-
-/* Set INT1 for D- falling edge to count SOF */
-/* #define USB_INTR_CFG EICRA */
-#ifndef USB_INTR_CFG_SET
-#define USB_INTR_CFG_SET ((1 << ISC11) | (0 << ISC10))
-#endif
-/* #define USB_INTR_CFG_CLR 0 */
-/* #define USB_INTR_ENABLE EIMSK */
-#ifndef USB_INTR_ENABLE_BIT
-#define USB_INTR_ENABLE_BIT INT1
-#endif
-/* #define USB_INTR_PENDING EIFR */
-#ifndef USB_INTR_PENDING_BIT
-#define USB_INTR_PENDING_BIT INTF1
-#endif
-#ifndef USB_INTR_VECTOR
-#define USB_INTR_VECTOR INT1_vect
-#endif
diff --git a/quantum/template/ps2avrgb/i2c.h b/quantum/util.h
index 7ce50cdb57..bef3b9abe3 100644
--- a/quantum/template/ps2avrgb/i2c.h
+++ b/quantum/util.h
@@ -1,5 +1,5 @@
/*
-Copyright 2016 Luiz Ribeiro <luizribeiro@gmail.com>
+Copyright 2011 Jun Wako <wakojun@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,14 +14,13 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#pragma once
-// Please do not modify this file
+#include "bitwise.h"
-#ifndef __I2C_H__
-#define __I2C_H__
-
-void i2c_init(void);
-void i2c_set_bitrate(uint16_t bitrate_khz);
-uint8_t i2c_send(uint8_t address, uint8_t *data, uint16_t length);
-
-#endif
+// convert to L string
+#define LSTR(s) XLSTR(s)
+#define XLSTR(s) L## #s
+// convert to string
+#define STR(s) XSTR(s)
+#define XSTR(s) #s
diff --git a/quantum/via.c b/quantum/via.c
index 288299ada8..c89b663b9b 100644
--- a/quantum/via.c
+++ b/quantum/via.c
@@ -46,6 +46,7 @@
#include "dynamic_keymap.h"
#include "tmk_core/common/eeprom.h"
#include "version.h" // for QMK_BUILDDATE used in EEPROM magic
+#include "via_ensure_keycode.h"
// Forward declare some helpers.
#if defined(VIA_QMK_BACKLIGHT_ENABLE)
@@ -111,7 +112,7 @@ void via_init(void) {
if (via_eeprom_is_valid()) {
} else {
// This resets the layout options
- via_set_layout_options(0);
+ via_set_layout_options(VIA_EEPROM_LAYOUT_OPTIONS_DEFAULT);
// This resets the keymaps in EEPROM to what is in flash.
dynamic_keymap_reset();
// This resets the macros in EEPROM to nothing.
@@ -186,7 +187,7 @@ bool process_record_via(uint16_t keycode, keyrecord_t *record) {
// Keyboard level code can override this to handle custom messages from VIA.
// See raw_hid_receive() implementation.
-// DO NOT call raw_hid_send() in the overide function.
+// DO NOT call raw_hid_send() in the override function.
__attribute__((weak)) void raw_hid_receive_kb(uint8_t *data, uint8_t length) {
uint8_t *command_id = &(data[0]);
*command_id = id_unhandled;
@@ -370,19 +371,6 @@ void raw_hid_receive(uint8_t *data, uint8_t length) {
dynamic_keymap_set_buffer(offset, size, &command_data[3]);
break;
}
- case id_eeprom_reset: {
- via_eeprom_reset();
- break;
- }
- case id_bootloader_jump: {
- // Need to send data back before the jump
- // Informs host that the command is handled
- raw_hid_send(data, length);
- // Give host time to read it
- wait_ms(100);
- bootloader_jump();
- break;
- }
default: {
// The command ID is not known
// Return the unhandled state
diff --git a/quantum/via.h b/quantum/via.h
index 8c2d545e9d..d0510fcabd 100644
--- a/quantum/via.h
+++ b/quantum/via.h
@@ -37,6 +37,14 @@
# define VIA_EEPROM_LAYOUT_OPTIONS_SIZE 1
#endif
+// Allow override of the layout options default value.
+// This requires advanced knowledge of how VIA stores layout options
+// and is only really useful for setting a boolean layout option
+// state to true by default.
+#ifndef VIA_EEPROM_LAYOUT_OPTIONS_DEFAULT
+# define VIA_EEPROM_LAYOUT_OPTIONS_DEFAULT 0x00000000
+#endif
+
// The end of the EEPROM memory used by VIA
// By default, dynamic keymaps will start at this if there is no
// custom config
diff --git a/quantum/via_ensure_keycode.h b/quantum/via_ensure_keycode.h
new file mode 100644
index 0000000000..a9c1b8ba5d
--- /dev/null
+++ b/quantum/via_ensure_keycode.h
@@ -0,0 +1,366 @@
+#pragma once
+
+#include "quantum.h"
+#include "via.h"
+
+#ifndef VIA_HAS_BROKEN_KEYCODES
+
+_Static_assert(KC_NO == 0, "");
+_Static_assert(KC_TRNS == 1, "");
+
+_Static_assert(KC_A == 0x04, "");
+_Static_assert(KC_B == 0x05, "");
+_Static_assert(KC_C == 0x06, "");
+_Static_assert(KC_D == 0x07, "");
+_Static_assert(KC_E == 0x08, "");
+_Static_assert(KC_F == 0x09, "");
+_Static_assert(KC_G == 0x0A, "");
+_Static_assert(KC_H == 0x0B, "");
+_Static_assert(KC_I == 0x0C, "");
+_Static_assert(KC_J == 0x0D, "");
+_Static_assert(KC_K == 0x0E, "");
+_Static_assert(KC_L == 0x0F, "");
+_Static_assert(KC_M == 0x10, "");
+_Static_assert(KC_N == 0x11, "");
+_Static_assert(KC_O == 0x12, "");
+_Static_assert(KC_P == 0x13, "");
+_Static_assert(KC_Q == 0x14, "");
+_Static_assert(KC_R == 0x15, "");
+_Static_assert(KC_S == 0x16, "");
+_Static_assert(KC_T == 0x17, "");
+_Static_assert(KC_U == 0x18, "");
+_Static_assert(KC_V == 0x19, "");
+_Static_assert(KC_W == 0x1A, "");
+_Static_assert(KC_X == 0x1B, "");
+_Static_assert(KC_Y == 0x1C, "");
+_Static_assert(KC_Z == 0x1D, "");
+_Static_assert(KC_1 == 0x1E, "");
+_Static_assert(KC_2 == 0x1F, "");
+_Static_assert(KC_3 == 0x20, "");
+_Static_assert(KC_4 == 0x21, "");
+_Static_assert(KC_5 == 0x22, "");
+_Static_assert(KC_6 == 0x23, "");
+_Static_assert(KC_7 == 0x24, "");
+_Static_assert(KC_8 == 0x25, "");
+_Static_assert(KC_9 == 0x26, "");
+_Static_assert(KC_0 == 0x27, "");
+_Static_assert(KC_ENTER == 0x28, "");
+_Static_assert(KC_ESCAPE == 0x29, "");
+_Static_assert(KC_BSPACE == 0x2A, "");
+_Static_assert(KC_TAB == 0x2B, "");
+_Static_assert(KC_SPACE == 0x2C, "");
+_Static_assert(KC_MINUS == 0x2D, "");
+_Static_assert(KC_EQUAL == 0x2E, "");
+_Static_assert(KC_LBRACKET == 0x2F, "");
+_Static_assert(KC_RBRACKET == 0x30, "");
+_Static_assert(KC_BSLASH == 0x31, "");
+_Static_assert(KC_SCOLON == 0x33, "");
+_Static_assert(KC_QUOTE == 0x34, "");
+_Static_assert(KC_GRAVE == 0x35, "");
+_Static_assert(KC_COMMA == 0x36, "");
+_Static_assert(KC_DOT == 0x37, "");
+_Static_assert(KC_SLASH == 0x38, "");
+_Static_assert(KC_CAPSLOCK == 0x39, "");
+_Static_assert(KC_F1 == 0x3A, "");
+_Static_assert(KC_F2 == 0x3B, "");
+_Static_assert(KC_F3 == 0x3C, "");
+_Static_assert(KC_F4 == 0x3D, "");
+_Static_assert(KC_F5 == 0x3E, "");
+_Static_assert(KC_F6 == 0x3F, "");
+_Static_assert(KC_F7 == 0x40, "");
+_Static_assert(KC_F8 == 0x41, "");
+_Static_assert(KC_F9 == 0x42, "");
+_Static_assert(KC_F10 == 0x43, "");
+_Static_assert(KC_F11 == 0x44, "");
+_Static_assert(KC_F12 == 0x45, "");
+_Static_assert(KC_PSCREEN == 0x46, "");
+_Static_assert(KC_SCROLLLOCK == 0x47, "");
+_Static_assert(KC_PAUSE == 0x48, "");
+_Static_assert(KC_INSERT == 0x49, "");
+_Static_assert(KC_HOME == 0x4A, "");
+_Static_assert(KC_PGUP == 0x4B, "");
+_Static_assert(KC_DELETE == 0x4C, "");
+_Static_assert(KC_END == 0x4D, "");
+_Static_assert(KC_PGDOWN == 0x4E, "");
+_Static_assert(KC_RIGHT == 0x4F, "");
+_Static_assert(KC_LEFT == 0x50, "");
+_Static_assert(KC_DOWN == 0x51, "");
+_Static_assert(KC_UP == 0x52, "");
+_Static_assert(KC_NUMLOCK == 0x53, "");
+_Static_assert(KC_KP_SLASH == 0x54, "");
+_Static_assert(KC_KP_ASTERISK == 0x55, "");
+_Static_assert(KC_KP_MINUS == 0x56, "");
+_Static_assert(KC_KP_PLUS == 0x57, "");
+_Static_assert(KC_KP_ENTER == 0x58, "");
+_Static_assert(KC_KP_1 == 0x59, "");
+_Static_assert(KC_KP_2 == 0x5A, "");
+_Static_assert(KC_KP_3 == 0x5B, "");
+_Static_assert(KC_KP_4 == 0x5C, "");
+_Static_assert(KC_KP_5 == 0x5D, "");
+_Static_assert(KC_KP_6 == 0x5E, "");
+_Static_assert(KC_KP_7 == 0x5F, "");
+_Static_assert(KC_KP_8 == 0x60, "");
+_Static_assert(KC_KP_9 == 0x61, "");
+_Static_assert(KC_KP_0 == 0x62, "");
+_Static_assert(KC_KP_DOT == 0x63, "");
+_Static_assert(KC_APPLICATION == 0x65, "");
+_Static_assert(KC_KP_EQUAL == 0x67, "");
+_Static_assert(KC_KP_COMMA == 0x85, "");
+_Static_assert(KC_LCTRL == 0xE0, "");
+_Static_assert(KC_LSHIFT == 0xE1, "");
+_Static_assert(KC_LALT == 0xE2, "");
+_Static_assert(KC_LGUI == 0xE3, "");
+_Static_assert(KC_RCTRL == 0xE4, "");
+_Static_assert(KC_RSHIFT == 0xE5, "");
+_Static_assert(KC_RALT == 0xE6, "");
+_Static_assert(KC_RGUI == 0xE7, "");
+
+_Static_assert(KC_TILD == 0x235, "");
+_Static_assert(KC_EXLM == 0x21E, "");
+_Static_assert(KC_AT == 0x21F, "");
+_Static_assert(KC_HASH == 0x220, "");
+_Static_assert(KC_DLR == 0x221, "");
+_Static_assert(KC_PERC == 0x222, "");
+_Static_assert(KC_CIRC == 0x223, "");
+_Static_assert(KC_AMPR == 0x224, "");
+_Static_assert(KC_ASTR == 0x225, "");
+_Static_assert(KC_LPRN == 0x226, "");
+_Static_assert(KC_RPRN == 0x227, "");
+_Static_assert(KC_UNDS == 0x22D, "");
+_Static_assert(KC_PLUS == 0x22E, "");
+_Static_assert(KC_LCBR == 0x22F, "");
+_Static_assert(KC_RCBR == 0x230, "");
+_Static_assert(KC_LT == 0x236, "");
+_Static_assert(KC_GT == 0x237, "");
+_Static_assert(KC_COLN == 0x233, "");
+_Static_assert(KC_PIPE == 0x231, "");
+_Static_assert(KC_QUES == 0x238, "");
+_Static_assert(KC_DQUO == 0x234, "");
+
+_Static_assert(KC_NONUS_HASH == 0x32, "");
+_Static_assert(KC_NONUS_BSLASH == 0x64, "");
+_Static_assert(KC_RO == 0x87, "");
+_Static_assert(KC_KANA == 0x88, "");
+_Static_assert(KC_JYEN == 0x89, "");
+_Static_assert(KC_HENK == 0x8A, "");
+_Static_assert(KC_MHEN == 0x8B, "");
+_Static_assert(KC_LANG1 == 0x90, "");
+_Static_assert(KC_LANG2 == 0x91, "");
+
+_Static_assert(KC_GESC == 0x5C16, "");
+_Static_assert(KC_LSPO == 0x5CD7, "");
+_Static_assert(KC_RSPC == 0x5CD8, "");
+_Static_assert(KC_LCPO == 0x5CF3, "");
+_Static_assert(KC_RCPC == 0x5CF4, "");
+_Static_assert(KC_LAPO == 0x5CF5, "");
+_Static_assert(KC_RAPC == 0x5CF6, "");
+_Static_assert(KC_SFTENT == 0x5CD9, "");
+
+_Static_assert(BL_TOGG == 23743, "");
+_Static_assert(BL_STEP == 23744, "");
+_Static_assert(BL_BRTG == 23745, "");
+_Static_assert(BL_ON == 23739, "");
+_Static_assert(BL_OFF == 23740, "");
+_Static_assert(BL_INC == 23742, "");
+_Static_assert(BL_DEC == 23741, "");
+_Static_assert(RGB_TOG == 23746, "");
+_Static_assert(RGB_MOD == 23747, "");
+_Static_assert(RGB_RMOD == 23748, "");
+_Static_assert(RGB_HUI == 23749, "");
+_Static_assert(RGB_HUD == 23750, "");
+_Static_assert(RGB_SAI == 23751, "");
+_Static_assert(RGB_SAD == 23752, "");
+_Static_assert(RGB_VAI == 23753, "");
+_Static_assert(RGB_VAD == 23754, "");
+_Static_assert(RGB_SPI == 23755, "");
+_Static_assert(RGB_SPD == 23756, "");
+_Static_assert(RGB_M_P == 23757, "");
+_Static_assert(RGB_M_B == 23758, "");
+_Static_assert(RGB_M_R == 23759, "");
+_Static_assert(RGB_M_SW == 23760, "");
+_Static_assert(RGB_M_SN == 23761, "");
+_Static_assert(RGB_M_K == 23762, "");
+_Static_assert(RGB_M_X == 23763, "");
+_Static_assert(RGB_M_G == 23764, "");
+_Static_assert(RGB_M_T == 23765, "");
+
+_Static_assert(KC_F13 == 104, "");
+_Static_assert(KC_F14 == 105, "");
+_Static_assert(KC_F15 == 106, "");
+_Static_assert(KC_F16 == 107, "");
+_Static_assert(KC_F17 == 108, "");
+_Static_assert(KC_F18 == 109, "");
+_Static_assert(KC_F19 == 110, "");
+_Static_assert(KC_F20 == 111, "");
+_Static_assert(KC_F21 == 112, "");
+_Static_assert(KC_F22 == 113, "");
+_Static_assert(KC_F23 == 114, "");
+_Static_assert(KC_F24 == 115, "");
+_Static_assert(KC_PWR == 165, "");
+_Static_assert(KC_SLEP == 166, "");
+_Static_assert(KC_WAKE == 167, "");
+_Static_assert(KC_EXEC == 116, "");
+_Static_assert(KC_HELP == 117, "");
+_Static_assert(KC_SLCT == 119, "");
+_Static_assert(KC_STOP == 120, "");
+_Static_assert(KC_AGIN == 121, "");
+_Static_assert(KC_UNDO == 122, "");
+_Static_assert(KC_CUT == 123, "");
+_Static_assert(KC_COPY == 124, "");
+_Static_assert(KC_PSTE == 125, "");
+_Static_assert(KC_FIND == 126, "");
+_Static_assert(KC_CALC == 178, "");
+_Static_assert(KC_MAIL == 177, "");
+_Static_assert(KC_MSEL == 175, "");
+_Static_assert(KC_MYCM == 179, "");
+_Static_assert(KC_WSCH == 180, "");
+_Static_assert(KC_WHOM == 181, "");
+_Static_assert(KC_WBAK == 182, "");
+_Static_assert(KC_WFWD == 183, "");
+_Static_assert(KC_WSTP == 184, "");
+_Static_assert(KC_WREF == 185, "");
+_Static_assert(KC_WFAV == 186, "");
+_Static_assert(KC_BRIU == 189, "");
+_Static_assert(KC_BRID == 190, "");
+_Static_assert(KC_MPRV == 172, "");
+_Static_assert(KC_MNXT == 171, "");
+_Static_assert(KC_MUTE == 168, "");
+_Static_assert(KC_VOLD == 170, "");
+_Static_assert(KC_VOLU == 169, "");
+_Static_assert(KC_MSTP == 173, "");
+_Static_assert(KC_MPLY == 174, "");
+_Static_assert(KC_MRWD == 188, "");
+_Static_assert(KC_MFFD == 187, "");
+_Static_assert(KC_EJCT == 176, "");
+_Static_assert(KC_MS_U == 240, "");
+_Static_assert(KC_MS_D == 241, "");
+_Static_assert(KC_MS_L == 242, "");
+_Static_assert(KC_MS_R == 243, "");
+_Static_assert(KC_BTN1 == 244, "");
+_Static_assert(KC_BTN2 == 245, "");
+_Static_assert(KC_BTN3 == 246, "");
+_Static_assert(KC_BTN4 == 247, "");
+_Static_assert(KC_BTN5 == 248, "");
+_Static_assert(KC_WH_U == 249, "");
+_Static_assert(KC_WH_D == 250, "");
+_Static_assert(KC_WH_L == 251, "");
+_Static_assert(KC_WH_R == 252, "");
+_Static_assert(KC_ACL0 == 253, "");
+_Static_assert(KC_ACL1 == 254, "");
+_Static_assert(KC_ACL2 == 255, "");
+_Static_assert(KC_LCAP == 130, "");
+_Static_assert(KC_LNUM == 131, "");
+_Static_assert(KC_LSCR == 132, "");
+
+_Static_assert(FN_MO13 == 0x5F10, "");
+_Static_assert(FN_MO23 == 0x5F11, "");
+
+_Static_assert(MACRO00 == 0x5F12, "");
+_Static_assert(MACRO01 == 0x5F13, "");
+_Static_assert(MACRO02 == 0x5F14, "");
+_Static_assert(MACRO03 == 0x5F15, "");
+_Static_assert(MACRO04 == 0x5F16, "");
+_Static_assert(MACRO05 == 0x5F17, "");
+_Static_assert(MACRO06 == 0x5F18, "");
+_Static_assert(MACRO07 == 0x5F19, "");
+_Static_assert(MACRO08 == 0x5F1A, "");
+_Static_assert(MACRO09 == 0x5F1B, "");
+_Static_assert(MACRO10 == 0x5F1C, "");
+_Static_assert(MACRO11 == 0x5F1D, "");
+_Static_assert(MACRO12 == 0x5F1E, "");
+_Static_assert(MACRO13 == 0x5F1F, "");
+_Static_assert(MACRO14 == 0x5F20, "");
+_Static_assert(MACRO15 == 0x5F21, "");
+
+_Static_assert(USER00 == 0x5F80, "");
+_Static_assert(USER01 == 0x5F81, "");
+_Static_assert(USER02 == 0x5F82, "");
+_Static_assert(USER03 == 0x5F83, "");
+_Static_assert(USER04 == 0x5F84, "");
+_Static_assert(USER05 == 0x5F85, "");
+_Static_assert(USER06 == 0x5F86, "");
+_Static_assert(USER07 == 0x5F87, "");
+_Static_assert(USER08 == 0x5F88, "");
+_Static_assert(USER09 == 0x5F89, "");
+_Static_assert(USER10 == 0x5F8A, "");
+_Static_assert(USER11 == 0x5F8B, "");
+_Static_assert(USER12 == 0x5F8C, "");
+_Static_assert(USER13 == 0x5F8D, "");
+_Static_assert(USER14 == 0x5F8E, "");
+_Static_assert(USER15 == 0x5F8F, "");
+
+_Static_assert(KC_POWER == 102, "");
+_Static_assert(KC_MENU == 118, "");
+_Static_assert(KC_KP_EQUAL_AS400 == 134, "");
+_Static_assert(KC_INT6 == 140, "");
+_Static_assert(KC_INT7 == 141, "");
+_Static_assert(KC_INT8 == 142, "");
+_Static_assert(KC_INT9 == 143, "");
+_Static_assert(KC_LANG3 == 146, "");
+_Static_assert(KC_LANG4 == 147, "");
+_Static_assert(KC_LANG5 == 148, "");
+_Static_assert(KC_LANG6 == 149, "");
+_Static_assert(KC_LANG7 == 150, "");
+_Static_assert(KC_LANG8 == 151, "");
+_Static_assert(KC_LANG9 == 152, "");
+_Static_assert(KC_ERAS == 153, "");
+_Static_assert(KC_SYSREQ == 154, "");
+_Static_assert(KC_CANCEL == 155, "");
+_Static_assert(KC_CLEAR == 156, "");
+_Static_assert(KC_CLR == 156, "");
+_Static_assert(KC_PRIOR == 157, "");
+_Static_assert(KC_OUT == 160, "");
+_Static_assert(KC_OPER == 161, "");
+_Static_assert(KC_CLEAR_AGAIN == 162, "");
+_Static_assert(KC_CRSEL == 163, "");
+_Static_assert(KC_EXSEL == 164, "");
+_Static_assert(KC_FN0 == 192, "");
+_Static_assert(KC_FN1 == 193, "");
+_Static_assert(KC_FN2 == 194, "");
+_Static_assert(KC_FN3 == 195, "");
+_Static_assert(KC_FN4 == 196, "");
+_Static_assert(KC_FN5 == 197, "");
+_Static_assert(KC_FN6 == 198, "");
+_Static_assert(KC_FN7 == 199, "");
+_Static_assert(KC_FN8 == 200, "");
+_Static_assert(KC_FN9 == 201, "");
+_Static_assert(KC_FN10 == 202, "");
+_Static_assert(KC_FN11 == 203, "");
+_Static_assert(KC_FN12 == 204, "");
+_Static_assert(KC_FN13 == 205, "");
+_Static_assert(KC_FN14 == 206, "");
+_Static_assert(KC_FN15 == 207, "");
+_Static_assert(KC_FN16 == 208, "");
+_Static_assert(KC_FN17 == 209, "");
+_Static_assert(KC_FN18 == 210, "");
+_Static_assert(KC_FN19 == 211, "");
+_Static_assert(KC_FN20 == 212, "");
+_Static_assert(KC_FN21 == 213, "");
+_Static_assert(KC_FN22 == 214, "");
+_Static_assert(KC_FN23 == 215, "");
+_Static_assert(KC_FN24 == 216, "");
+_Static_assert(KC_FN25 == 217, "");
+_Static_assert(KC_FN26 == 218, "");
+_Static_assert(KC_FN27 == 219, "");
+_Static_assert(KC_FN28 == 220, "");
+_Static_assert(KC_FN29 == 221, "");
+_Static_assert(KC_FN30 == 222, "");
+_Static_assert(KC_FN31 == 223, "");
+_Static_assert(RESET == 23552, "");
+_Static_assert(DEBUG == 23553, "");
+_Static_assert(MAGIC_TOGGLE_NKRO == 23572, "");
+_Static_assert(AU_ON == 23581, "");
+_Static_assert(AU_OFF == 23582, "");
+_Static_assert(AU_TOG == 23583, "");
+_Static_assert(CLICKY_TOGGLE == 23584, "");
+_Static_assert(CLICKY_ENABLE == 23585, "");
+_Static_assert(CLICKY_DISABLE == 23586, "");
+_Static_assert(CLICKY_UP == 23587, "");
+_Static_assert(CLICKY_DOWN == 23588, "");
+_Static_assert(CLICKY_RESET == 23589, "");
+_Static_assert(MU_ON == 23590, "");
+_Static_assert(MU_OFF == 23591, "");
+_Static_assert(MU_TOG == 23592, "");
+_Static_assert(MU_MOD == 23593, "");
+
+#endif
diff --git a/quantum/wpm.c b/quantum/wpm.c
index d4c971f313..da30bd252c 100644
--- a/quantum/wpm.c
+++ b/quantum/wpm.c
@@ -17,12 +17,12 @@
#include "wpm.h"
-//WPM Stuff
-static uint8_t current_wpm = 0;
-static uint8_t latest_wpm = 0;
-static uint16_t wpm_timer = 0;
+// WPM Stuff
+static uint8_t current_wpm = 0;
+static uint8_t latest_wpm = 0;
+static uint16_t wpm_timer = 0;
-//This smoothing is 40 keystrokes
+// This smoothing is 40 keystrokes
static const float wpm_smoothing = 0.0487;
void set_current_wpm(uint8_t new_wpm) { current_wpm = new_wpm; }
@@ -34,34 +34,31 @@ bool wpm_keycode(uint16_t keycode) { return wpm_keycode_kb(keycode); }
__attribute__((weak)) bool wpm_keycode_kb(uint16_t keycode) { return wpm_keycode_user(keycode); }
__attribute__((weak)) bool wpm_keycode_user(uint16_t keycode) {
-
if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) || (keycode >= QK_MODS && keycode <= QK_MODS_MAX)) {
keycode = keycode & 0xFF;
} else if (keycode > 0xFF) {
- keycode = 0;
+ keycode = 0;
}
- if((keycode >= KC_A && keycode <= KC_0) || (keycode >= KC_TAB && keycode <= KC_SLASH)) {
- return true;
+ if ((keycode >= KC_A && keycode <= KC_0) || (keycode >= KC_TAB && keycode <= KC_SLASH)) {
+ return true;
}
return false;
}
-
void update_wpm(uint16_t keycode) {
- if(wpm_keycode(keycode)) {
- if(wpm_timer > 0) {
- latest_wpm = 60000 / timer_elapsed(wpm_timer) / 5;
- current_wpm = (latest_wpm - current_wpm) * wpm_smoothing + current_wpm;
- }
- wpm_timer = timer_read();
+ if (wpm_keycode(keycode)) {
+ if (wpm_timer > 0) {
+ latest_wpm = 60000 / timer_elapsed(wpm_timer) / 5;
+ current_wpm = (latest_wpm - current_wpm) * wpm_smoothing + current_wpm;
+ }
+ wpm_timer = timer_read();
}
}
void decay_wpm(void) {
- if (timer_elapsed(wpm_timer) > 1000) {
- current_wpm = (0 - current_wpm) * wpm_smoothing +
- current_wpm;
- wpm_timer = timer_read();
- }
+ if (timer_elapsed(wpm_timer) > 1000) {
+ current_wpm = (0 - current_wpm) * wpm_smoothing + current_wpm;
+ wpm_timer = timer_read();
+ }
}
diff --git a/quantum/wpm.h b/quantum/wpm.h
index fa0b6d1288..15ab4ffcd1 100644
--- a/quantum/wpm.h
+++ b/quantum/wpm.h
@@ -23,8 +23,8 @@ bool wpm_keycode(uint16_t keycode);
bool wpm_keycode_kb(uint16_t keycode);
bool wpm_keycode_user(uint16_t keycode);
-void set_current_wpm(uint8_t);
+void set_current_wpm(uint8_t);
uint8_t get_current_wpm(void);
-void update_wpm(uint16_t);
+void update_wpm(uint16_t);
void decay_wpm(void);