~ruther/qmk_firmware

63646e8906e062d1c1de3925cba70c4e3426a855 — QMK Bot 3 years ago afcdd70
Format code according to conventions (#16322)

345 files changed, 4939 insertions(+), 3252 deletions(-)

M drivers/bluetooth/bluefruit_le.cpp
M drivers/bluetooth/outputselect.c
M drivers/bluetooth/rn42.c
M drivers/eeprom/eeprom_driver.c
M drivers/eeprom/eeprom_i2c.c
M drivers/eeprom/eeprom_spi.c
M drivers/eeprom/eeprom_transient.c
M drivers/eeprom/eeprom_transient.h
M drivers/flash/flash_spi.c
M drivers/gpio/mcp23018.c
M drivers/haptic/DRV2605L.c
M drivers/haptic/solenoid.c
M drivers/lcd/st7565.c
M drivers/lcd/st7565.h
M drivers/led/apa102.c
M drivers/led/aw20216.c
M drivers/led/issi/is31fl3731-simple.c
M drivers/led/issi/is31fl3731.c
M drivers/led/issi/is31fl3733-simple.c
M drivers/led/issi/is31fl3733-simple.h
M drivers/led/issi/is31fl3733.c
M drivers/led/issi/is31fl3733.h
M drivers/led/issi/is31fl3736.c
M drivers/led/issi/is31fl3736.h
M drivers/led/issi/is31fl3737.c
M drivers/led/issi/is31fl3737.h
M drivers/led/issi/is31fl3741.c
M drivers/led/issi/is31fl3741.h
M drivers/oled/oled_driver.h
M drivers/oled/ssd1306_sh1106.c
M drivers/ps2/ps2_busywait.c
M drivers/ps2/ps2_interrupt.c
M drivers/ps2/ps2_mouse.c
M drivers/sensors/adns5050.c
M drivers/sensors/adns9800.c
M drivers/sensors/analog_joystick.c
M drivers/sensors/cirque_pinnacle.c
M drivers/sensors/cirque_pinnacle.h
M drivers/sensors/cirque_pinnacle_i2c.c
M drivers/sensors/cirque_pinnacle_spi.c
M drivers/sensors/pimoroni_trackball.c
M drivers/sensors/pmw3360.c
M drivers/sensors/pmw3360.h
M drivers/sensors/pmw3389.c
M drivers/sensors/pmw3389.h
M drivers/usb2422.c
M drivers/ws2812.h
M platforms/arm_atsam/bootloaders/md_boot.c
M platforms/arm_atsam/eeprom_samd.c
M platforms/arm_atsam/eeprom_samd.h -rwxr-xr-x => -rw-r--r--
M platforms/arm_atsam/suspend.c
M platforms/arm_atsam/timer.c
M platforms/avr/bootloaders/dfu.c
M platforms/avr/bootloaders/halfkay.c
M platforms/avr/drivers/analog.c
M platforms/avr/drivers/analog.h
M platforms/avr/drivers/audio_pwm_hardware.c
M platforms/avr/drivers/glcdfont.c
M platforms/avr/drivers/hd44780.c
M platforms/avr/drivers/i2c_master.c
M platforms/avr/drivers/i2c_slave.c
M platforms/avr/drivers/i2c_slave.h
M platforms/avr/drivers/ps2/ps2_io.c
M platforms/avr/drivers/ps2/ps2_usart.c
M platforms/avr/drivers/serial.c
M platforms/avr/drivers/spi_master.c
M platforms/avr/drivers/ssd1306.c
M platforms/avr/drivers/uart.c
M platforms/avr/drivers/ws2812.c
M platforms/avr/drivers/ws2812_i2c.c
M platforms/avr/pin_defs.h
M platforms/avr/printf.c
M platforms/avr/sleep_led.c
M platforms/avr/suspend.c
M platforms/avr/timer.c
M platforms/chibios/bootloaders/stm32_dfu.c
M platforms/chibios/bootloaders/stm32duino.c
M platforms/chibios/chibios_config.h
M platforms/chibios/drivers/analog.c
M platforms/chibios/drivers/analog.h
M platforms/chibios/drivers/audio_dac_additive.c
M platforms/chibios/drivers/audio_dac_basic.c
M platforms/chibios/drivers/audio_pwm_hardware.c
M platforms/chibios/drivers/audio_pwm_software.c
M platforms/chibios/drivers/eeprom/eeprom_stm32_L0_L1.h
M platforms/chibios/drivers/i2c_master.c
M platforms/chibios/drivers/serial.c
M platforms/chibios/drivers/serial_usart.c
M platforms/chibios/drivers/serial_usart.h
M platforms/chibios/drivers/spi_master.c
M platforms/chibios/drivers/uart.c
M platforms/chibios/drivers/usbpd_stm32g4.c
M platforms/chibios/drivers/ws2812.c
M platforms/chibios/drivers/ws2812_pwm.c
M platforms/chibios/drivers/ws2812_spi.c
M platforms/chibios/eeprom_stm32.c
M platforms/chibios/eeprom_stm32_defs.h
M platforms/chibios/eeprom_teensy.c
M platforms/chibios/gd32v_compatibility.h
M platforms/chibios/sleep_led.c
M platforms/chibios/syscall-fallbacks.c
M platforms/chibios/timer.c
M platforms/suspend.c
M platforms/test/eeprom.c
M platforms/test/eeprom_stm32_tests.cpp
M platforms/test/flash_stm32_mock.c
M platforms/test/timer.c
M platforms/timer.h
M quantum/action.c
M quantum/action_layer.c
M quantum/action_tapping.c
M quantum/action_util.c
M quantum/action_util.h
M quantum/audio/audio.c
M quantum/audio/audio.h
M quantum/audio/song_list.h
M quantum/audio/voices.c
M quantum/audio/voices.h
M quantum/backlight/backlight.c
M quantum/backlight/backlight.h
M quantum/backlight/backlight_avr.c
M quantum/backlight/backlight_chibios.c
M quantum/backlight/backlight_driver_common.c
M quantum/backlight/backlight_software.c
M quantum/backlight/backlight_timer.c
M quantum/bitwise.c
M quantum/bootmagic/bootmagic_lite.c
M quantum/color.c
M quantum/command.c
M quantum/debounce/sym_defer_g.c
M quantum/debounce/sym_defer_pr.c
M quantum/debounce/sym_eager_pk.c
M quantum/debounce/tests/debounce_test_common.cpp
M quantum/deferred_exec.c
M quantum/digitizer.c
M quantum/dip_switch.c
M quantum/dynamic_keymap.c
M quantum/eeconfig.c
M quantum/eeconfig.h
M quantum/encoder.c
M quantum/encoder/tests/mock.c
M quantum/encoder/tests/mock_split.c
M quantum/haptic.c
M quantum/keyboard.c
M quantum/keyboard.h
M quantum/keycode.h
M quantum/keymap_common.c
M quantum/keymap_extras/keymap_nordic.h
M quantum/keymap_extras/keymap_steno.h
M quantum/led.c
M quantum/led_matrix/animations/alpha_mods_anim.h
M quantum/led_matrix/animations/band_anim.h
M quantum/led_matrix/animations/band_pinwheel_anim.h
M quantum/led_matrix/animations/band_spiral_anim.h
M quantum/led_matrix/animations/breathing_anim.h
M quantum/led_matrix/animations/cycle_left_right_anim.h
M quantum/led_matrix/animations/cycle_out_in_anim.h
M quantum/led_matrix/animations/cycle_up_down_anim.h
M quantum/led_matrix/animations/dual_beacon_anim.h
M quantum/led_matrix/animations/runners/effect_runner_reactive.h
M quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h
M quantum/led_matrix/animations/solid_anim.h
M quantum/led_matrix/animations/solid_reactive_cross.h
M quantum/led_matrix/animations/solid_reactive_nexus.h
M quantum/led_matrix/animations/solid_reactive_simple_anim.h
M quantum/led_matrix/animations/solid_reactive_wide.h
M quantum/led_matrix/animations/solid_splash_anim.h
M quantum/led_matrix/animations/wave_left_right_anim.h
M quantum/led_matrix/animations/wave_up_down_anim.h
M quantum/led_matrix/led_matrix.c
M quantum/led_matrix/led_matrix_types.h
M quantum/logging/debug.c
M quantum/logging/print.c
M quantum/logging/print.h
M quantum/logging/sendchar.c
M quantum/main.c
M quantum/matrix.c
M quantum/matrix_common.c
M quantum/mousekey.c
M quantum/pointing_device.c
M quantum/pointing_device.h
M quantum/pointing_device_drivers.c
M quantum/process_keycode/process_audio.c
M quantum/process_keycode/process_auto_shift.c
M quantum/process_keycode/process_clicky.c
M quantum/process_keycode/process_combo.c
M quantum/process_keycode/process_dynamic_macro.c
M quantum/process_keycode/process_joystick.c
M quantum/process_keycode/process_key_override.c
M quantum/process_keycode/process_leader.c
M quantum/process_keycode/process_magic.c
M quantum/process_keycode/process_midi.c
M quantum/process_keycode/process_midi.h
M quantum/process_keycode/process_music.c
M quantum/process_keycode/process_music.h
M quantum/process_keycode/process_printer.c
M quantum/process_keycode/process_printer_bb.c
M quantum/process_keycode/process_steno.c
M quantum/process_keycode/process_tap_dance.c
M quantum/process_keycode/process_terminal.c
M quantum/process_keycode/process_ucis.c
M quantum/process_keycode/process_unicode_common.c
M quantum/process_keycode/process_unicode_common.h
M quantum/programmable_button.c
M quantum/quantum.c
M quantum/quantum_keycodes.h
M quantum/rgb_matrix/animations/alpha_mods_anim.h
M quantum/rgb_matrix/animations/breathing_anim.h
M quantum/rgb_matrix/animations/colorband_pinwheel_sat_anim.h
M quantum/rgb_matrix/animations/colorband_pinwheel_val_anim.h
M quantum/rgb_matrix/animations/colorband_sat_anim.h
M quantum/rgb_matrix/animations/colorband_spiral_sat_anim.h
M quantum/rgb_matrix/animations/colorband_spiral_val_anim.h
M quantum/rgb_matrix/animations/colorband_val_anim.h
M quantum/rgb_matrix/animations/cycle_all_anim.h
M quantum/rgb_matrix/animations/cycle_left_right_anim.h
M quantum/rgb_matrix/animations/cycle_out_in_anim.h
M quantum/rgb_matrix/animations/cycle_out_in_dual_anim.h
M quantum/rgb_matrix/animations/cycle_pinwheel_anim.h
M quantum/rgb_matrix/animations/cycle_spiral_anim.h
M quantum/rgb_matrix/animations/cycle_up_down_anim.h
M quantum/rgb_matrix/animations/digital_rain_anim.h
M quantum/rgb_matrix/animations/dual_beacon_anim.h
M quantum/rgb_matrix/animations/gradient_left_right_anim.h
M quantum/rgb_matrix/animations/gradient_up_down_anim.h
M quantum/rgb_matrix/animations/hue_breathing_anim.h
M quantum/rgb_matrix/animations/hue_pendulum_anim.h
M quantum/rgb_matrix/animations/hue_wave_anim.h
M quantum/rgb_matrix/animations/jellybean_raindrops_anim.h
M quantum/rgb_matrix/animations/pixel_flow_anim.h
M quantum/rgb_matrix/animations/pixel_fractal_anim.h
M quantum/rgb_matrix/animations/pixel_rain_anim.h
M quantum/rgb_matrix/animations/rainbow_beacon_anim.h
M quantum/rgb_matrix/animations/rainbow_moving_chevron_anim.h
M quantum/rgb_matrix/animations/rainbow_pinwheels_anim.h
M quantum/rgb_matrix/animations/raindrops_anim.h
M quantum/rgb_matrix/animations/runners/effect_runner_reactive.h
M quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h
M quantum/rgb_matrix/animations/solid_color_anim.h
M quantum/rgb_matrix/animations/solid_reactive_anim.h
M quantum/rgb_matrix/animations/solid_reactive_cross.h
M quantum/rgb_matrix/animations/solid_reactive_nexus.h
M quantum/rgb_matrix/animations/solid_reactive_simple_anim.h
M quantum/rgb_matrix/animations/solid_reactive_wide.h
M quantum/rgb_matrix/animations/solid_splash_anim.h
M quantum/rgb_matrix/animations/splash_anim.h
M quantum/rgb_matrix/animations/typing_heatmap_anim.h
M quantum/rgb_matrix/rgb_matrix.c
M quantum/rgb_matrix/rgb_matrix_types.h
M quantum/rgblight/rgblight.c
M quantum/rgblight/rgblight.h
M quantum/ring_buffer.h
M quantum/send_string.c
M quantum/sequencer/sequencer.c
M quantum/sequencer/sequencer.h
M quantum/sequencer/tests/midi_mock.c
M quantum/sequencer/tests/sequencer_tests.cpp
M quantum/split_common/post_config.h
M quantum/split_common/split_util.c
M quantum/split_common/transaction_id_define.h
M quantum/split_common/transactions.c
M quantum/split_common/transport.c
M quantum/split_common/transport.h
M quantum/sync_timer.c
M quantum/velocikey.c
M quantum/via.c
M quantum/via.h
M quantum/wpm.c
M tests/test_common/keyboard_report_util.cpp
M tests/test_common/matrix.c
M tests/test_common/test_driver.cpp
M tests/test_common/test_fixture.cpp
M tests/test_common/test_logger.cpp
M tmk_core/protocol/arm_atsam/adc.c
M tmk_core/protocol/arm_atsam/adc.h
M tmk_core/protocol/arm_atsam/arm_atsam_protocol.h
M tmk_core/protocol/arm_atsam/clks.c
M tmk_core/protocol/arm_atsam/clks.h
M tmk_core/protocol/arm_atsam/d51_util.c
M tmk_core/protocol/arm_atsam/d51_util.h
M tmk_core/protocol/arm_atsam/i2c_master.c
M tmk_core/protocol/arm_atsam/i2c_master.h
M tmk_core/protocol/arm_atsam/issi3733_driver.h
M tmk_core/protocol/arm_atsam/main_arm_atsam.c
M tmk_core/protocol/arm_atsam/main_arm_atsam.h
M tmk_core/protocol/arm_atsam/md_rgb_matrix.c
M tmk_core/protocol/arm_atsam/md_rgb_matrix.h
M tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c
M tmk_core/protocol/arm_atsam/shift_register.c
M tmk_core/protocol/arm_atsam/spi_master.c
M tmk_core/protocol/arm_atsam/usb/compiler.h
M tmk_core/protocol/arm_atsam/usb/conf_usb.h
M tmk_core/protocol/arm_atsam/usb/main_usb.c
M tmk_core/protocol/arm_atsam/usb/status_codes.h
M tmk_core/protocol/arm_atsam/usb/udc.c
M tmk_core/protocol/arm_atsam/usb/udc.h
M tmk_core/protocol/arm_atsam/usb/udc_desc.h
M tmk_core/protocol/arm_atsam/usb/udd.h
M tmk_core/protocol/arm_atsam/usb/udi.h
M tmk_core/protocol/arm_atsam/usb/udi_cdc.c
M tmk_core/protocol/arm_atsam/usb/udi_cdc.h
M tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h
M tmk_core/protocol/arm_atsam/usb/udi_device_conf.h
M tmk_core/protocol/arm_atsam/usb/udi_device_epsize.h
M tmk_core/protocol/arm_atsam/usb/udi_hid.c
M tmk_core/protocol/arm_atsam/usb/udi_hid.h
M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h
M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h
M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c
M tmk_core/protocol/arm_atsam/usb/ui.c
M tmk_core/protocol/arm_atsam/usb/ui.h
M tmk_core/protocol/arm_atsam/usb/usb.c
M tmk_core/protocol/arm_atsam/usb/usb.h
M tmk_core/protocol/arm_atsam/usb/usb_atmel.h
M tmk_core/protocol/arm_atsam/usb/usb_device_udd.c
M tmk_core/protocol/arm_atsam/usb/usb_hub.c
M tmk_core/protocol/arm_atsam/usb/usb_hub.h
M tmk_core/protocol/arm_atsam/usb/usb_main.h
M tmk_core/protocol/arm_atsam/usb/usb_protocol.h
M tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h
M tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h
M tmk_core/protocol/arm_atsam/usb/usb_util.c
M tmk_core/protocol/arm_atsam/usb/usb_util.h
M tmk_core/protocol/chibios/chibios.c
M tmk_core/protocol/chibios/usb_driver.c
M tmk_core/protocol/chibios/usb_main.c
M tmk_core/protocol/chibios/usb_util.c
M tmk_core/protocol/host.c
M tmk_core/protocol/lufa/lufa.c
M tmk_core/protocol/lufa/usb_util.c
M tmk_core/protocol/midi/bytequeue/bytequeue.c
M tmk_core/protocol/midi/bytequeue/interrupt_setting.c
M tmk_core/protocol/midi/midi.c
M tmk_core/protocol/midi/midi.h
M tmk_core/protocol/midi/midi_device.c
M tmk_core/protocol/midi/qmk_midi.c
M tmk_core/protocol/midi/sysex_tools.c
M tmk_core/protocol/usb_descriptor.h
M tmk_core/protocol/usb_device_state.c
M tmk_core/protocol/usb_device_state.h
M tmk_core/protocol/usb_util.c
M tmk_core/protocol/vusb/protocol.c
M tmk_core/protocol/vusb/usb_util.c
M tmk_core/protocol/vusb/vusb.c
M drivers/bluetooth/bluefruit_le.cpp => drivers/bluetooth/bluefruit_le.cpp +16 -10
@@ 29,7 29,7 @@
#endif

#ifndef BLUEFRUIT_LE_SCK_DIVISOR
#    define BLUEFRUIT_LE_SCK_DIVISOR 2  // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
#    define BLUEFRUIT_LE_SCK_DIVISOR 2 // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
#endif

#define SAMPLE_BATTERY


@@ 77,10 77,10 @@ struct sdep_msg {
// information here.

enum queue_type {
    QTKeyReport,  // 1-byte modifier + 6-byte key report
    QTConsumer,   // 16-bit key code
    QTKeyReport, // 1-byte modifier + 6-byte key report
    QTConsumer,  // 16-bit key code
#ifdef MOUSE_ENABLE
    QTMouseMove,  // 4-byte mouse report
    QTMouseMove, // 4-byte mouse report
#endif
};



@@ 115,8 115,8 @@ enum sdep_type {
    SdepResponse      = 0x20,
    SdepAlert         = 0x40,
    SdepError         = 0x80,
    SdepSlaveNotReady = 0xFE,  // Try again later
    SdepSlaveOverflow = 0xFF,  // You read more data than is available
    SdepSlaveNotReady = 0xFE, // Try again later
    SdepSlaveOverflow = 0xFF, // You read more data than is available
};

enum ble_cmd {


@@ 306,13 306,15 @@ static bool ble_init(void) {
    wait_ms(10);
    writePinHigh(BLUEFRUIT_LE_RST_PIN);

    wait_ms(1000);  // Give it a second to initialize
    wait_ms(1000); // Give it a second to initialize

    state.initialized = true;
    return state.initialized;
}

static inline uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; }
static inline uint8_t min(uint8_t a, uint8_t b) {
    return a < b ? a : b;
}

static bool read_response(char *resp, uint16_t resplen, bool verbose) {
    char *dest = resp;


@@ 424,7 426,9 @@ bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) {
    return at_command(cmdbuf, resp, resplen, verbose);
}

bool bluefruit_le_is_connected(void) { return state.is_connected; }
bool bluefruit_le_is_connected(void) {
    return state.is_connected;
}

bool bluefruit_le_enable_keyboard(void) {
    char resbuf[128];


@@ 671,7 675,9 @@ void bluefruit_le_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan,
}
#endif

uint32_t bluefruit_le_read_battery_voltage(void) { return state.vbat; }
uint32_t bluefruit_le_read_battery_voltage(void) {
    return state.vbat;
}

bool bluefruit_le_set_mode_leds(bool on) {
    if (!state.configured) {

M drivers/bluetooth/outputselect.c => drivers/bluetooth/outputselect.c +1 -1
@@ 52,7 52,7 @@ uint8_t auto_detect_output(void) {
#endif

#ifdef BLUETOOTH_ENABLE
    return OUTPUT_BLUETOOTH;  // should check if BT is connected here
    return OUTPUT_BLUETOOTH; // should check if BT is connected here
#endif

    return OUTPUT_NONE;

M drivers/bluetooth/rn42.c => drivers/bluetooth/rn42.c +5 -3
@@ 61,7 61,9 @@ static inline uint16_t rn42_consumer_usage_to_bitmap(uint16_t usage) {
    }
}

void rn42_init(void) { uart_init(RN42_BAUD_RATE); }
void rn42_init(void) {
    uart_init(RN42_BAUD_RATE);
}

void rn42_send_keyboard(report_keyboard_t *report) {
    uart_write(0xFD);


@@ 81,8 83,8 @@ void rn42_send_mouse(report_mouse_t *report) {
    uart_write(report->buttons);
    uart_write(report->x);
    uart_write(report->y);
    uart_write(report->v);  // should try sending the wheel v here
    uart_write(report->h);  // should try sending the wheel h here
    uart_write(report->v); // should try sending the wheel v here
    uart_write(report->h); // should try sending the wheel h here
    uart_write(0x00);
}


M drivers/eeprom/eeprom_driver.c => drivers/eeprom/eeprom_driver.c +9 -3
@@ 37,11 37,17 @@ uint32_t eeprom_read_dword(const uint32_t *addr) {
    return ret;
}

void eeprom_write_byte(uint8_t *addr, uint8_t value) { eeprom_write_block(&value, addr, 1); }
void eeprom_write_byte(uint8_t *addr, uint8_t value) {
    eeprom_write_block(&value, addr, 1);
}

void eeprom_write_word(uint16_t *addr, uint16_t value) { eeprom_write_block(&value, addr, 2); }
void eeprom_write_word(uint16_t *addr, uint16_t value) {
    eeprom_write_block(&value, addr, 2);
}

void eeprom_write_dword(uint32_t *addr, uint32_t value) { eeprom_write_block(&value, addr, 4); }
void eeprom_write_dword(uint32_t *addr, uint32_t value) {
    eeprom_write_block(&value, addr, 4);
}

void eeprom_update_block(const void *buf, void *addr, size_t len) {
    uint8_t read_buf[len];

M drivers/eeprom/eeprom_i2c.c => drivers/eeprom/eeprom_i2c.c +3 -3
@@ 43,7 43,7 @@
#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
#    include "timer.h"
#    include "debug.h"
#endif  // DEBUG_EEPROM_OUTPUT
#endif // DEBUG_EEPROM_OUTPUT

static inline void fill_target_address(uint8_t *buffer, const void *addr) {
    uintptr_t p = (uintptr_t)addr;


@@ 91,7 91,7 @@ void eeprom_read_block(void *buf, const void *addr, size_t len) {
        dprintf(" %02X", (int)(((uint8_t *)buf)[i]));
    }
    dprintf("\n");
#endif  // DEBUG_EEPROM_OUTPUT
#endif // DEBUG_EEPROM_OUTPUT
}

void eeprom_write_block(const void *buf, void *addr, size_t len) {


@@ 122,7 122,7 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
            dprintf(" %02X", (int)(read_buf[i]));
        }
        dprintf("\n");
#endif  // DEBUG_EEPROM_OUTPUT
#endif // DEBUG_EEPROM_OUTPUT

        i2c_transmit(EXTERNAL_EEPROM_I2C_ADDRESS((uintptr_t)addr), complete_packet, EXTERNAL_EEPROM_ADDRESS_SIZE + write_length, 100);
        wait_ms(EXTERNAL_EEPROM_WRITE_TIME);

M drivers/eeprom/eeprom_spi.c => drivers/eeprom/eeprom_spi.c +8 -4
@@ 52,7 52,9 @@
#    define EXTERNAL_EEPROM_SPI_TIMEOUT 100
#endif

static bool spi_eeprom_start(void) { return spi_start(EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN, EXTERNAL_EEPROM_SPI_LSBFIRST, EXTERNAL_EEPROM_SPI_MODE, EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR); }
static bool spi_eeprom_start(void) {
    return spi_start(EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN, EXTERNAL_EEPROM_SPI_LSBFIRST, EXTERNAL_EEPROM_SPI_MODE, EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR);
}

static spi_status_t spi_eeprom_wait_while_busy(int timeout) {
    uint32_t     deadline = timer_read32() + timeout;


@@ 80,7 82,9 @@ static void spi_eeprom_transmit_address(uintptr_t addr) {

//----------------------------------------------------------------------------------------------------------------------

void eeprom_driver_init(void) { spi_init(); }
void eeprom_driver_init(void) {
    spi_init();
}

void eeprom_driver_erase(void) {
#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)


@@ 135,7 139,7 @@ void eeprom_read_block(void *buf, const void *addr, size_t len) {
        dprintf(" %02X", (int)(((uint8_t *)buf)[i]));
    }
    dprintf("\n");
#endif  // DEBUG_EEPROM_OUTPUT
#endif // DEBUG_EEPROM_OUTPUT

    spi_stop();
}


@@ 192,7 196,7 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
            dprintf(" %02X", (int)(uint8_t)(read_buf[i]));
        }
        dprintf("\n");
#endif  // DEBUG_EEPROM_OUTPUT
#endif // DEBUG_EEPROM_OUTPUT

        spi_write(CMD_WRITE);
        spi_eeprom_transmit_address(target_addr);

M drivers/eeprom/eeprom_transient.c => drivers/eeprom/eeprom_transient.c +6 -2
@@ 30,9 30,13 @@ size_t clamp_length(intptr_t offset, size_t len) {
    return len;
}

void eeprom_driver_init(void) { eeprom_driver_erase(); }
void eeprom_driver_init(void) {
    eeprom_driver_erase();
}

void eeprom_driver_erase(void) { memset(transientBuffer, 0x00, TRANSIENT_EEPROM_SIZE); }
void eeprom_driver_erase(void) {
    memset(transientBuffer, 0x00, TRANSIENT_EEPROM_SIZE);
}

void eeprom_read_block(void *buf, const void *addr, size_t len) {
    intptr_t offset = (intptr_t)addr;

M drivers/eeprom/eeprom_transient.h => drivers/eeprom/eeprom_transient.h +1 -1
@@ 21,5 21,5 @@
*/
#ifndef TRANSIENT_EEPROM_SIZE
#    include "eeconfig.h"
#    define TRANSIENT_EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4)  // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
#    define TRANSIENT_EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
#endif

M drivers/flash/flash_spi.c => drivers/flash/flash_spi.c +8 -4
@@ 65,7 65,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

// #define DEBUG_FLASH_SPI_OUTPUT

static bool spi_flash_start(void) { return spi_start(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN, EXTERNAL_FLASH_SPI_LSBFIRST, EXTERNAL_FLASH_SPI_MODE, EXTERNAL_FLASH_SPI_CLOCK_DIVISOR); }
static bool spi_flash_start(void) {
    return spi_start(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN, EXTERNAL_FLASH_SPI_LSBFIRST, EXTERNAL_FLASH_SPI_MODE, EXTERNAL_FLASH_SPI_CLOCK_DIVISOR);
}

static flash_status_t spi_flash_wait_while_busy(void) {
    uint32_t       deadline = timer_read32() + EXTERNAL_FLASH_SPI_TIMEOUT;


@@ 160,7 162,9 @@ static flash_status_t spi_flash_transaction(uint8_t cmd, uint32_t addr, uint8_t 
    return response;
}

void flash_init(void) { spi_init(); }
void flash_init(void) {
    spi_init();
}

flash_status_t flash_erase_chip(void) {
    flash_status_t response = FLASH_STATUS_SUCCESS;


@@ 304,7 308,7 @@ flash_status_t flash_read_block(uint32_t addr, void *buf, size_t len) {
        dprintf(" %02X", (int)(((uint8_t *)read_buf)[i]));
    }
    dprintf("\n");
#endif  // DEBUG_FLASH_SPI_OUTPUT
#endif // DEBUG_FLASH_SPI_OUTPUT

    return response;
}


@@ 340,7 344,7 @@ flash_status_t flash_write_block(uint32_t addr, const void *buf, size_t len) {
            dprintf(" %02X", (int)(uint8_t)(write_buf[i]));
        }
        dprintf("\n");
#endif  // DEBUG_FLASH_SPI_OUTPUT
#endif // DEBUG_FLASH_SPI_OUTPUT

        /* Perform the write. */
        response = spi_flash_transaction(FLASH_CMD_PP, addr, write_buf, write_length);

M drivers/gpio/mcp23018.c => drivers/gpio/mcp23018.c +3 -3
@@ 10,11 10,11 @@
#define TIMEOUT 100

enum {
    CMD_IODIRA = 0x00,  // i/o direction register
    CMD_IODIRA = 0x00, // i/o direction register
    CMD_IODIRB = 0x01,
    CMD_GPPUA  = 0x0C,  // GPIO pull-up resistor register
    CMD_GPPUA  = 0x0C, // GPIO pull-up resistor register
    CMD_GPPUB  = 0x0D,
    CMD_GPIOA  = 0x12,  // general purpose i/o port register (write modifies OLAT)
    CMD_GPIOA  = 0x12, // general purpose i/o port register (write modifies OLAT)
    CMD_GPIOB  = 0x13,
};


M drivers/haptic/DRV2605L.c => drivers/haptic/DRV2605L.c +4 -2
@@ 106,12 106,14 @@ void DRV_init(void) {

void DRV_rtp_init(void) {
    DRV_write(DRV_GO, 0x00);
    DRV_write(DRV_RTP_INPUT, 20);  // 20 is the lowest value I've found where haptics can still be felt.
    DRV_write(DRV_RTP_INPUT, 20); // 20 is the lowest value I've found where haptics can still be felt.
    DRV_write(DRV_MODE, 0x05);
    DRV_write(DRV_GO, 0x01);
}

void DRV_amplitude(uint8_t amplitude) { DRV_write(DRV_RTP_INPUT, amplitude); }
void DRV_amplitude(uint8_t amplitude) {
    DRV_write(DRV_RTP_INPUT, amplitude);
}

void DRV_pulse(uint8_t sequence) {
    DRV_write(DRV_GO, 0x00);

M drivers/haptic/solenoid.c => drivers/haptic/solenoid.c +15 -5
@@ 28,13 28,21 @@ uint8_t  solenoid_dwell   = SOLENOID_DEFAULT_DWELL;

extern haptic_config_t haptic_config;

void solenoid_buzz_on(void) { haptic_set_buzz(1); }
void solenoid_buzz_on(void) {
    haptic_set_buzz(1);
}

void solenoid_buzz_off(void) { haptic_set_buzz(0); }
void solenoid_buzz_off(void) {
    haptic_set_buzz(0);
}

void solenoid_set_buzz(int buzz) { haptic_set_buzz(buzz); }
void solenoid_set_buzz(int buzz) {
    haptic_set_buzz(buzz);
}

void solenoid_set_dwell(uint8_t dwell) { solenoid_dwell = dwell; }
void solenoid_set_dwell(uint8_t dwell) {
    solenoid_dwell = dwell;
}

void solenoid_stop(void) {
    SOLENOID_PIN_WRITE_INACTIVE();


@@ 89,4 97,6 @@ void solenoid_setup(void) {
    }
}

void solenoid_shutdown(void) { SOLENOID_PIN_WRITE_INACTIVE(); }
void solenoid_shutdown(void) {
    SOLENOID_PIN_WRITE_INACTIVE();
}

M drivers/lcd/st7565.c => drivers/lcd/st7565.c +17 -8
@@ 39,7 39,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
// Addressing Setting Commands
#define PAM_SETCOLUMN_LSB 0x00
#define PAM_SETCOLUMN_MSB 0x10
#define PAM_PAGE_ADDR 0xB0  // 0xb0 -- 0xb7
#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7

// Hardware Configuration Commands
#define DISPLAY_START_LINE 0x40


@@ 138,7 138,9 @@ bool st7565_init(display_rotation_t rotation) {
    return true;
}

__attribute__((weak)) display_rotation_t st7565_init_user(display_rotation_t rotation) { return rotation; }
__attribute__((weak)) display_rotation_t st7565_init_user(display_rotation_t rotation) {
    return rotation;
}

void st7565_clear(void) {
    memset(st7565_buffer, 0, sizeof(st7565_buffer));


@@ 212,7 214,8 @@ void st7565_advance_page(bool clearPageRemainder) {
        remaining = remaining / ST7565_FONT_WIDTH;

        // Write empty character until next line
        while (remaining--) st7565_write_char(' ', false);
        while (remaining--)
            st7565_write_char(' ', false);
    } else {
        // Next page index out of bounds?
        if (index + remaining >= ST7565_MATRIX_SIZE) {


@@ 263,7 266,7 @@ void st7565_write_char(const char data, bool invert) {
    _Static_assert(sizeof(font) >= ((ST7565_FONT_END + 1 - ST7565_FONT_START) * ST7565_FONT_WIDTH), "ST7565_FONT_END references outside array");

    // set the reder buffer data
    uint8_t cast_data = (uint8_t)data;  // font based on unsigned type for index
    uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index
    if (cast_data < ST7565_FONT_START || cast_data > ST7565_FONT_END) {
        memset(st7565_cursor, 0x00, ST7565_FONT_WIDTH);
    } else {


@@ 389,7 392,7 @@ void st7565_write_raw_P(const char *data, uint16_t size) {
        st7565_dirty |= ((ST7565_BLOCK_TYPE)1 << (i / ST7565_BLOCK_SIZE));
    }
}
#endif  // defined(__AVR__)
#endif // defined(__AVR__)

bool st7565_on(void) {
    if (!st7565_initialized) {


@@ 429,7 432,9 @@ bool st7565_off(void) {

__attribute__((weak)) void st7565_off_user(void) {}

bool st7565_is_on(void) { return st7565_active; }
bool st7565_is_on(void) {
    return st7565_active;
}

bool st7565_invert(bool invert) {
    if (!st7565_initialized) {


@@ 445,9 450,13 @@ bool st7565_invert(bool invert) {
    return st7565_inverted;
}

uint8_t st7565_max_chars(void) { return ST7565_DISPLAY_WIDTH / ST7565_FONT_WIDTH; }
uint8_t st7565_max_chars(void) {
    return ST7565_DISPLAY_WIDTH / ST7565_FONT_WIDTH;
}

uint8_t st7565_max_lines(void) { return ST7565_DISPLAY_HEIGHT / ST7565_FONT_HEIGHT; }
uint8_t st7565_max_lines(void) {
    return ST7565_DISPLAY_HEIGHT / ST7565_FONT_HEIGHT;
}

void st7565_task(void) {
    if (!st7565_initialized) {

M drivers/lcd/st7565.h => drivers/lcd/st7565.h +4 -4
@@ 29,16 29,16 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#    define ST7565_DISPLAY_HEIGHT 32
#endif
#ifndef ST7565_MATRIX_SIZE
#    define ST7565_MATRIX_SIZE (ST7565_DISPLAY_HEIGHT / 8 * ST7565_DISPLAY_WIDTH)  // 1024 (compile time mathed)
#    define ST7565_MATRIX_SIZE (ST7565_DISPLAY_HEIGHT / 8 * ST7565_DISPLAY_WIDTH) // 1024 (compile time mathed)
#endif
#ifndef ST7565_BLOCK_TYPE
#    define ST7565_BLOCK_TYPE uint16_t
#endif
#ifndef ST7565_BLOCK_COUNT
#    define ST7565_BLOCK_COUNT (sizeof(ST7565_BLOCK_TYPE) * 8)  // 32 (compile time mathed)
#    define ST7565_BLOCK_COUNT (sizeof(ST7565_BLOCK_TYPE) * 8) // 32 (compile time mathed)
#endif
#ifndef ST7565_BLOCK_SIZE
#    define ST7565_BLOCK_SIZE (ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT)  // 32 (compile time mathed)
#    define ST7565_BLOCK_SIZE (ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT) // 32 (compile time mathed)
#endif

// the column address corresponding to the first column in the display hardware


@@ 174,7 174,7 @@ void st7565_write_raw_P(const char *data, uint16_t size);
#    define st7565_write_P(data, invert) st7565_write(data, invert)
#    define st7565_write_ln_P(data, invert) st7565_write_ln(data, invert)
#    define st7565_write_raw_P(data, size) st7565_write_raw(data, size)
#endif  // defined(__AVR__)
#endif // defined(__AVR__)

// Can be used to manually turn on the screen if it is off
// Returns true if the screen was on or turns on

M drivers/led/apa102.c => drivers/led/apa102.c +6 -4
@@ 20,15 20,15 @@

#ifndef APA102_NOPS
#    if defined(__AVR__)
#        define APA102_NOPS 0  // AVR at 16 MHz already spends 62.5 ns per clock, so no extra delay is needed
#        define APA102_NOPS 0 // AVR at 16 MHz already spends 62.5 ns per clock, so no extra delay is needed
#    elif defined(PROTOCOL_CHIBIOS)

#        include "hal.h"
#        if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(GD32VF103)
#            define APA102_NOPS (100 / (1000000000L / (CPU_CLOCK / 4)))  // This calculates how many loops of 4 nops to run to delay 100 ns
#            define APA102_NOPS (100 / (1000000000L / (CPU_CLOCK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns
#        else
#            error("APA102_NOPS configuration required")
#            define APA102_NOPS 0  // this just pleases the compile so the above error is easier to spot
#            define APA102_NOPS 0 // this just pleases the compile so the above error is easier to spot
#        endif
#    endif
#endif


@@ 72,7 72,9 @@ void apa102_setleds(LED_TYPE *start_led, uint16_t num_leds) {
}

// Overwrite the default rgblight_call_driver to use apa102 driver
void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { apa102_setleds(start_led, num_leds); }
void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) {
    apa102_setleds(start_led, num_leds);
}

void static apa102_init(void) {
    setPinOutput(RGB_DI_PIN);

M drivers/led/aw20216.c => drivers/led/aw20216.c +7 -7
@@ 23,17 23,17 @@
 */
#define AWINIC_ID 0b1010 << 4

#define AW_PAGE_FUNCTION 0x00 << 1    // PG0, Function registers
#define AW_PAGE_PWM 0x01 << 1         // PG1, LED PWM control
#define AW_PAGE_SCALING 0x02 << 1     // PG2, LED current scaling control
#define AW_PAGE_PATCHOICE 0x03 << 1   // PG3, Pattern choice?
#define AW_PAGE_PWMSCALING 0x04 << 1  // PG4, LED PWM + Scaling control?
#define AW_PAGE_FUNCTION 0x00 << 1   // PG0, Function registers
#define AW_PAGE_PWM 0x01 << 1        // PG1, LED PWM control
#define AW_PAGE_SCALING 0x02 << 1    // PG2, LED current scaling control
#define AW_PAGE_PATCHOICE 0x03 << 1  // PG3, Pattern choice?
#define AW_PAGE_PWMSCALING 0x04 << 1 // PG4, LED PWM + Scaling control?

#define AW_WRITE 0
#define AW_READ 1

#define AW_REG_CONFIGURATION 0x00  // PG0
#define AW_REG_GLOBALCURRENT 0x01  // PG0
#define AW_REG_CONFIGURATION 0x00 // PG0
#define AW_REG_GLOBALCURRENT 0x01 // PG0

// Default value of AW_REG_CONFIGURATION
// D7:D4 = 1011, SWSEL (SW1~SW12 active)

M drivers/led/issi/is31fl3731-simple.c => drivers/led/issi/is31fl3731-simple.c +3 -3
@@ 42,13 42,13 @@
#define ISSI_REG_PICTUREFRAME 0x01

// Not defined in the datasheet -- See AN for IC
#define ISSI_REG_GHOST_IMAGE_PREVENTION 0xC2  // Set bit 4 to enable de-ghosting
#define ISSI_REG_GHOST_IMAGE_PREVENTION 0xC2 // Set bit 4 to enable de-ghosting

#define ISSI_REG_SHUTDOWN 0x0A
#define ISSI_REG_AUDIOSYNC 0x06

#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_BANK_FUNCTIONREG 0x0B  // helpfully called 'page nine'
#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'

#ifndef ISSI_TIMEOUT
#    define ISSI_TIMEOUT 100


@@ 148,7 148,7 @@ void IS31FL3731_init(uint8_t addr) {

    // enable software shutdown
    IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00);
#ifdef ISSI_3731_DEGHOST  // set to enable de-ghosting of the array
#ifdef ISSI_3731_DEGHOST // set to enable de-ghosting of the array
    IS31FL3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10);
#endif


M drivers/led/issi/is31fl3731.c => drivers/led/issi/is31fl3731.c +3 -3
@@ 41,13 41,13 @@
#define ISSI_REG_PICTUREFRAME 0x01

// Not defined in the datasheet -- See AN for IC
#define ISSI_REG_GHOST_IMAGE_PREVENTION 0xC2  // Set bit 4 to enable de-ghosting
#define ISSI_REG_GHOST_IMAGE_PREVENTION 0xC2 // Set bit 4 to enable de-ghosting

#define ISSI_REG_SHUTDOWN 0x0A
#define ISSI_REG_AUDIOSYNC 0x06

#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_BANK_FUNCTIONREG 0x0B  // helpfully called 'page nine'
#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'

#ifndef ISSI_TIMEOUT
#    define ISSI_TIMEOUT 100


@@ 136,7 136,7 @@ void IS31FL3731_init(uint8_t addr) {

    // enable software shutdown
    IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00);
#ifdef ISSI_3731_DEGHOST  // set to enable de-ghosting of the array
#ifdef ISSI_3731_DEGHOST // set to enable de-ghosting of the array
    IS31FL3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10);
#endif


M drivers/led/issi/is31fl3733-simple.c => drivers/led/issi/is31fl3733-simple.c +10 -10
@@ 39,16 39,16 @@
#define ISSI_INTERRUPTMASKREGISTER 0xF0
#define ISSI_INTERRUPTSTATUSREGISTER 0xF1

#define ISSI_PAGE_LEDCONTROL 0x00  // PG0
#define ISSI_PAGE_PWM 0x01         // PG1
#define ISSI_PAGE_AUTOBREATH 0x02  // PG2
#define ISSI_PAGE_FUNCTION 0x03    // PG3
#define ISSI_PAGE_LEDCONTROL 0x00 // PG0
#define ISSI_PAGE_PWM 0x01        // PG1
#define ISSI_PAGE_AUTOBREATH 0x02 // PG2
#define ISSI_PAGE_FUNCTION 0x03   // PG3

#define ISSI_REG_CONFIGURATION 0x00  // PG3
#define ISSI_REG_GLOBALCURRENT 0x01  // PG3
#define ISSI_REG_RESET 0x11          // PG3
#define ISSI_REG_SWPULLUP 0x0F       // PG3
#define ISSI_REG_CSPULLUP 0x10       // PG3
#define ISSI_REG_CONFIGURATION 0x00 // PG3
#define ISSI_REG_GLOBALCURRENT 0x01 // PG3
#define ISSI_REG_RESET 0x11         // PG3
#define ISSI_REG_SWPULLUP 0x0F      // PG3
#define ISSI_REG_CSPULLUP 0x10      // PG3

#ifndef ISSI_TIMEOUT
#    define ISSI_TIMEOUT 100


@@ 59,7 59,7 @@
#endif

#ifndef ISSI_PWM_FREQUENCY
#    define ISSI_PWM_FREQUENCY 0b000  // PFS - IS31FL3733B only
#    define ISSI_PWM_FREQUENCY 0b000 // PFS - IS31FL3733B only
#endif

#ifndef ISSI_SWPULLUP

M drivers/led/issi/is31fl3733-simple.h => drivers/led/issi/is31fl3733-simple.h +7 -7
@@ 47,13 47,13 @@ void IS31FL3733_set_led_control_register(uint8_t index, bool value);
void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index);
void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index);

#define PUR_0R 0x00    // No PUR resistor
#define PUR_05KR 0x02  // 0.5k Ohm resistor in t_NOL
#define PUR_3KR 0x03   // 3.0k Ohm resistor on all the time
#define PUR_4KR 0x04   // 4.0k Ohm resistor on all the time
#define PUR_8KR 0x05   // 8.0k Ohm resistor on all the time
#define PUR_16KR 0x06  // 16k Ohm resistor on all the time
#define PUR_32KR 0x07  // 32k Ohm resistor in t_NOL
#define PUR_0R 0x00   // No PUR resistor
#define PUR_05KR 0x02 // 0.5k Ohm resistor in t_NOL
#define PUR_3KR 0x03  // 3.0k Ohm resistor on all the time
#define PUR_4KR 0x04  // 4.0k Ohm resistor on all the time
#define PUR_8KR 0x05  // 8.0k Ohm resistor on all the time
#define PUR_16KR 0x06 // 16k Ohm resistor on all the time
#define PUR_32KR 0x07 // 32k Ohm resistor in t_NOL

#define A_1 0x00
#define A_2 0x01

M drivers/led/issi/is31fl3733.c => drivers/led/issi/is31fl3733.c +10 -10
@@ 38,16 38,16 @@
#define ISSI_INTERRUPTMASKREGISTER 0xF0
#define ISSI_INTERRUPTSTATUSREGISTER 0xF1

#define ISSI_PAGE_LEDCONTROL 0x00  // PG0
#define ISSI_PAGE_PWM 0x01         // PG1
#define ISSI_PAGE_AUTOBREATH 0x02  // PG2
#define ISSI_PAGE_FUNCTION 0x03    // PG3
#define ISSI_PAGE_LEDCONTROL 0x00 // PG0
#define ISSI_PAGE_PWM 0x01        // PG1
#define ISSI_PAGE_AUTOBREATH 0x02 // PG2
#define ISSI_PAGE_FUNCTION 0x03   // PG3

#define ISSI_REG_CONFIGURATION 0x00  // PG3
#define ISSI_REG_GLOBALCURRENT 0x01  // PG3
#define ISSI_REG_RESET 0x11          // PG3
#define ISSI_REG_SWPULLUP 0x0F       // PG3
#define ISSI_REG_CSPULLUP 0x10       // PG3
#define ISSI_REG_CONFIGURATION 0x00 // PG3
#define ISSI_REG_GLOBALCURRENT 0x01 // PG3
#define ISSI_REG_RESET 0x11         // PG3
#define ISSI_REG_SWPULLUP 0x0F      // PG3
#define ISSI_REG_CSPULLUP 0x10      // PG3

#ifndef ISSI_TIMEOUT
#    define ISSI_TIMEOUT 100


@@ 58,7 58,7 @@
#endif

#ifndef ISSI_PWM_FREQUENCY
#    define ISSI_PWM_FREQUENCY 0b000  // PFS - IS31FL3733B only
#    define ISSI_PWM_FREQUENCY 0b000 // PFS - IS31FL3733B only
#endif

#ifndef ISSI_SWPULLUP

M drivers/led/issi/is31fl3733.h => drivers/led/issi/is31fl3733.h +7 -7
@@ 48,13 48,13 @@ void IS31FL3733_set_led_control_register(uint8_t index, bool red, bool green, bo
void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index);
void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index);

#define PUR_0R 0x00    // No PUR resistor
#define PUR_05KR 0x02  // 0.5k Ohm resistor in t_NOL
#define PUR_3KR 0x03   // 3.0k Ohm resistor on all the time
#define PUR_4KR 0x04   // 4.0k Ohm resistor on all the time
#define PUR_8KR 0x05   // 8.0k Ohm resistor on all the time
#define PUR_16KR 0x06  // 16k Ohm resistor on all the time
#define PUR_32KR 0x07  // 32k Ohm resistor in t_NOL
#define PUR_0R 0x00   // No PUR resistor
#define PUR_05KR 0x02 // 0.5k Ohm resistor in t_NOL
#define PUR_3KR 0x03  // 3.0k Ohm resistor on all the time
#define PUR_4KR 0x04  // 4.0k Ohm resistor on all the time
#define PUR_8KR 0x05  // 8.0k Ohm resistor on all the time
#define PUR_16KR 0x06 // 16k Ohm resistor on all the time
#define PUR_32KR 0x07 // 32k Ohm resistor in t_NOL

#define A_1 0x00
#define A_2 0x01

M drivers/led/issi/is31fl3736.c => drivers/led/issi/is31fl3736.c +10 -10
@@ 36,16 36,16 @@
#define ISSI_INTERRUPTMASKREGISTER 0xF0
#define ISSI_INTERRUPTSTATUSREGISTER 0xF1

#define ISSI_PAGE_LEDCONTROL 0x00  // PG0
#define ISSI_PAGE_PWM 0x01         // PG1
#define ISSI_PAGE_AUTOBREATH 0x02  // PG2
#define ISSI_PAGE_FUNCTION 0x03    // PG3

#define ISSI_REG_CONFIGURATION 0x00  // PG3
#define ISSI_REG_GLOBALCURRENT 0x01  // PG3
#define ISSI_REG_RESET 0x11          // PG3
#define ISSI_REG_SWPULLUP 0x0F       // PG3
#define ISSI_REG_CSPULLUP 0x10       // PG3
#define ISSI_PAGE_LEDCONTROL 0x00 // PG0
#define ISSI_PAGE_PWM 0x01        // PG1
#define ISSI_PAGE_AUTOBREATH 0x02 // PG2
#define ISSI_PAGE_FUNCTION 0x03   // PG3

#define ISSI_REG_CONFIGURATION 0x00 // PG3
#define ISSI_REG_GLOBALCURRENT 0x01 // PG3
#define ISSI_REG_RESET 0x11         // PG3
#define ISSI_REG_SWPULLUP 0x0F      // PG3
#define ISSI_REG_CSPULLUP 0x10      // PG3

#ifndef ISSI_TIMEOUT
#    define ISSI_TIMEOUT 100

M drivers/led/issi/is31fl3736.h => drivers/led/issi/is31fl3736.h +8 -8
@@ 61,14 61,14 @@ void IS31FL3736_mono_set_led_control_register(uint8_t index, bool enabled);
void IS31FL3736_update_pwm_buffers(uint8_t addr1, uint8_t addr2);
void IS31FL3736_update_led_control_registers(uint8_t addr1, uint8_t addr2);

#define PUR_0R 0x00    // No PUR resistor
#define PUR_05KR 0x01  // 0.5k Ohm resistor
#define PUR_1KR 0x02   // 1.0k Ohm resistor
#define PUR_2KR 0x03   // 2.0k Ohm resistor
#define PUR_4KR 0x04   // 4.0k Ohm resistor
#define PUR_8KR 0x05   // 8.0k Ohm resistor
#define PUR_16KR 0x06  // 16k Ohm resistor
#define PUR_32KR 0x07  // 32k Ohm resistor
#define PUR_0R 0x00   // No PUR resistor
#define PUR_05KR 0x01 // 0.5k Ohm resistor
#define PUR_1KR 0x02  // 1.0k Ohm resistor
#define PUR_2KR 0x03  // 2.0k Ohm resistor
#define PUR_4KR 0x04  // 4.0k Ohm resistor
#define PUR_8KR 0x05  // 8.0k Ohm resistor
#define PUR_16KR 0x06 // 16k Ohm resistor
#define PUR_32KR 0x07 // 32k Ohm resistor

#define A_1 0x00
#define A_2 0x02

M drivers/led/issi/is31fl3737.c => drivers/led/issi/is31fl3737.c +10 -10
@@ 38,16 38,16 @@
#define ISSI_INTERRUPTMASKREGISTER 0xF0
#define ISSI_INTERRUPTSTATUSREGISTER 0xF1

#define ISSI_PAGE_LEDCONTROL 0x00  // PG0
#define ISSI_PAGE_PWM 0x01         // PG1
#define ISSI_PAGE_AUTOBREATH 0x02  // PG2
#define ISSI_PAGE_FUNCTION 0x03    // PG3

#define ISSI_REG_CONFIGURATION 0x00  // PG3
#define ISSI_REG_GLOBALCURRENT 0x01  // PG3
#define ISSI_REG_RESET 0x11          // PG3
#define ISSI_REG_SWPULLUP 0x0F       // PG3
#define ISSI_REG_CSPULLUP 0x10       // PG3
#define ISSI_PAGE_LEDCONTROL 0x00 // PG0
#define ISSI_PAGE_PWM 0x01        // PG1
#define ISSI_PAGE_AUTOBREATH 0x02 // PG2
#define ISSI_PAGE_FUNCTION 0x03   // PG3

#define ISSI_REG_CONFIGURATION 0x00 // PG3
#define ISSI_REG_GLOBALCURRENT 0x01 // PG3
#define ISSI_REG_RESET 0x11         // PG3
#define ISSI_REG_SWPULLUP 0x0F      // PG3
#define ISSI_REG_CSPULLUP 0x10      // PG3

#ifndef ISSI_TIMEOUT
#    define ISSI_TIMEOUT 100

M drivers/led/issi/is31fl3737.h => drivers/led/issi/is31fl3737.h +8 -8
@@ 48,14 48,14 @@ void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bo
void IS31FL3737_update_pwm_buffers(uint8_t addr1, uint8_t addr2);
void IS31FL3737_update_led_control_registers(uint8_t addr1, uint8_t addr2);

#define PUR_0R 0x00    // No PUR resistor
#define PUR_05KR 0x01  // 0.5k Ohm resistor in t_NOL
#define PUR_1KR 0x02   // 1.0k Ohm resistor in t_NOL
#define PUR_2KR 0x03   // 2.0k Ohm resistor in t_NOL
#define PUR_4KR 0x04   // 4.0k Ohm resistor in t_NOL
#define PUR_8KR 0x05   // 8.0k Ohm resistor in t_NOL
#define PUR_16KR 0x06  // 16k Ohm resistor in t_NOL
#define PUR_32KR 0x07  // 32k Ohm resistor in t_NOL
#define PUR_0R 0x00   // No PUR resistor
#define PUR_05KR 0x01 // 0.5k Ohm resistor in t_NOL
#define PUR_1KR 0x02  // 1.0k Ohm resistor in t_NOL
#define PUR_2KR 0x03  // 2.0k Ohm resistor in t_NOL
#define PUR_4KR 0x04  // 4.0k Ohm resistor in t_NOL
#define PUR_8KR 0x05  // 8.0k Ohm resistor in t_NOL
#define PUR_16KR 0x06 // 16k Ohm resistor in t_NOL
#define PUR_32KR 0x07 // 32k Ohm resistor in t_NOL

#define A_1 0x00
#define A_2 0x01

M drivers/led/issi/is31fl3741.c => drivers/led/issi/is31fl3741.c +10 -10
@@ 42,16 42,16 @@
#define ISSI_INTERRUPTSTATUSREGISTER 0xF1
#define ISSI_IDREGISTER 0xFC

#define ISSI_PAGE_PWM0 0x00       // PG0
#define ISSI_PAGE_PWM1 0x01       // PG1
#define ISSI_PAGE_SCALING_0 0x02  // PG2
#define ISSI_PAGE_SCALING_1 0x03  // PG3
#define ISSI_PAGE_FUNCTION 0x04   // PG4

#define ISSI_REG_CONFIGURATION 0x00  // PG4
#define ISSI_REG_GLOBALCURRENT 0x01  // PG4
#define ISSI_REG_PULLDOWNUP 0x02     // PG4
#define ISSI_REG_RESET 0x3F          // PG4
#define ISSI_PAGE_PWM0 0x00      // PG0
#define ISSI_PAGE_PWM1 0x01      // PG1
#define ISSI_PAGE_SCALING_0 0x02 // PG2
#define ISSI_PAGE_SCALING_1 0x03 // PG3
#define ISSI_PAGE_FUNCTION 0x04  // PG4

#define ISSI_REG_CONFIGURATION 0x00 // PG4
#define ISSI_REG_GLOBALCURRENT 0x01 // PG4
#define ISSI_REG_PULLDOWNUP 0x02    // PG4
#define ISSI_REG_RESET 0x3F         // PG4

#ifndef ISSI_TIMEOUT
#    define ISSI_TIMEOUT 100

M drivers/led/issi/is31fl3741.h => drivers/led/issi/is31fl3741.h +8 -8
@@ 51,14 51,14 @@ void IS31FL3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t

void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue);

#define PUR_0R 0x00    // No PUR resistor
#define PUR_05KR 0x01  // 0.5k Ohm resistor
#define PUR_1KR 0x02   // 1.0k Ohm resistor
#define PUR_2KR 0x03   // 2.0k Ohm resistor
#define PUR_4KR 0x04   // 4.0k Ohm resistor
#define PUR_8KR 0x05   // 8.0k Ohm resistor
#define PUR_16KR 0x06  // 16k Ohm resistor
#define PUR_32KR 0x07  // 32k Ohm resistor
#define PUR_0R 0x00   // No PUR resistor
#define PUR_05KR 0x01 // 0.5k Ohm resistor
#define PUR_1KR 0x02  // 1.0k Ohm resistor
#define PUR_2KR 0x03  // 2.0k Ohm resistor
#define PUR_4KR 0x04  // 4.0k Ohm resistor
#define PUR_8KR 0x05  // 8.0k Ohm resistor
#define PUR_16KR 0x06 // 16k Ohm resistor
#define PUR_32KR 0x07 // 32k Ohm resistor

#define CS1_SW1 0x00
#define CS2_SW1 0x01

M drivers/oled/oled_driver.h => drivers/oled/oled_driver.h +11 -11
@@ 34,16 34,16 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#        define OLED_DISPLAY_HEIGHT 64
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)  // 1024 (compile time mathed)
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 1024 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint16_t
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)  // 32 (compile time mathed)
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 32 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)  // 32 (compile time mathed)
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_ALT


@@ 68,7 68,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
// If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 }
// #define OLED_TARGET_MAP { 56, 120, 48, 112, 40, 104, 32, 96, 24, 88, 16, 80, 8, 72, 0, 64 }
#else  // defined(OLED_DISPLAY_128X64)
#else // defined(OLED_DISPLAY_128X64)
// Default 128x32
#    ifndef OLED_DISPLAY_WIDTH
#        define OLED_DISPLAY_WIDTH 128


@@ 77,16 77,16 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#        define OLED_DISPLAY_HEIGHT 32
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)  // 512 (compile time mathed)
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint16_t  // Type to use for segmenting the oled display for smart rendering, use unsigned types only
#        define OLED_BLOCK_TYPE uint16_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)  // 16 (compile time mathed)
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 16 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)  // 32 (compile time mathed)
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_SEQ


@@ 105,7 105,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
// If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
// #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 }
#endif  // defined(OLED_DISPLAY_CUSTOM)
#endif // defined(OLED_DISPLAY_CUSTOM)

#if !defined(OLED_IC)
#    define OLED_IC OLED_IC_SSD1306


@@ 180,7 180,7 @@ typedef enum {
    OLED_ROTATION_0   = 0,
    OLED_ROTATION_90  = 1,
    OLED_ROTATION_180 = 2,
    OLED_ROTATION_270 = 3,  // OLED_ROTATION_90 | OLED_ROTATION_180
    OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
} oled_rotation_t;

// Initialize the oled display, rotating the rendered output based on the define passed in.


@@ 262,7 262,7 @@ void oled_write_raw_P(const char *data, uint16_t size);
#    define oled_write_P(data, invert) oled_write(data, invert)
#    define oled_write_ln_P(data, invert) oled_write(data, invert)
#    define oled_write_raw_P(data, size) oled_write_raw(data, size)
#endif  // defined(__AVR__)
#endif // defined(__AVR__)

// Can be used to manually turn on the screen if it is off
// Returns true if the screen was on or turns on

M drivers/oled/ssd1306_sh1106.c => drivers/oled/ssd1306_sh1106.c +32 -17
@@ 53,7 53,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define PAGE_ADDR 0x22
#define PAM_SETCOLUMN_LSB 0x00
#define PAM_SETCOLUMN_MSB 0x10
#define PAM_PAGE_ADDR 0xB0  // 0xb0 -- 0xb7
#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7

// Hardware Configuration Commands
#define DISPLAY_START_LINE 0x40


@@ 97,9 97,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define I2C_DATA 0x40
#if defined(__AVR__)
#    define I2C_TRANSMIT_P(data) i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
#else  // defined(__AVR__)
#else // defined(__AVR__)
#    define I2C_TRANSMIT_P(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
#endif  // defined(__AVR__)
#endif // defined(__AVR__)
#define I2C_TRANSMIT(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
#define I2C_WRITE_REG(mode, data, size) i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), mode, data, size, OLED_I2C_TIMEOUT)



@@ 119,7 119,7 @@ bool            oled_inverted       = false;
uint8_t         oled_brightness     = OLED_BRIGHTNESS;
oled_rotation_t oled_rotation       = 0;
uint8_t         oled_rotation_width = 0;
uint8_t         oled_scroll_speed   = 0;  // this holds the speed after being remapped to ssd1306 internal values
uint8_t         oled_scroll_speed   = 0; // this holds the speed after being remapped to ssd1306 internal values
uint8_t         oled_scroll_start   = 0;
uint8_t         oled_scroll_end     = 7;
#if OLED_TIMEOUT > 0


@@ 190,7 190,7 @@ bool oled_init(oled_rotation_t rotation) {
#if (OLED_IC != OLED_IC_SH1106)
        // MEMORY_MODE is unsupported on SH1106 (Page Addressing only)
        MEMORY_MODE,
        0x00,  // Horizontal addressing mode
        0x00, // Horizontal addressing mode
#endif
    };
    if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) {


@@ 232,8 232,12 @@ bool oled_init(oled_rotation_t rotation) {
    return true;
}

__attribute__((weak)) oled_rotation_t oled_init_kb(oled_rotation_t rotation) { return rotation; }
__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { return rotation; }
__attribute__((weak)) oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
    return rotation;
}
__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    return rotation;
}

void oled_clear(void) {
    memset(oled_buffer, 0, sizeof(oled_buffer));


@@ 306,9 310,9 @@ void oled_render(void) {
    // Set column & page position
    static uint8_t display_start[] = {I2C_CMD, COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1, PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1};
    if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
        calc_bounds(update_start, &display_start[1]);  // Offset from I2C_CMD byte at the start
        calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
    } else {
        calc_bounds_90(update_start, &display_start[1]);  // Offset from I2C_CMD byte at the start
        calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
    }

    // Send column & page position


@@ 368,7 372,8 @@ void oled_advance_page(bool clearPageRemainder) {
        remaining = remaining / OLED_FONT_WIDTH;

        // Write empty character until next line
        while (remaining--) oled_write_char(' ', false);
        while (remaining--)
            oled_write_char(' ', false);
    } else {
        // Next page index out of bounds?
        if (index + remaining >= OLED_MATRIX_SIZE) {


@@ 419,7 424,7 @@ void oled_write_char(const char data, bool invert) {
    _Static_assert(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array");

    // set the reder buffer data
    uint8_t cast_data = (uint8_t)data;  // font based on unsigned type for index
    uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index
    if (cast_data < OLED_FONT_START || cast_data > OLED_FONT_END) {
        memset(oled_cursor, 0x00, OLED_FONT_WIDTH);
    } else {


@@ 545,7 550,7 @@ void oled_write_raw_P(const char *data, uint16_t size) {
        oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE));
    }
}
#endif  // defined(__AVR__)
#endif // defined(__AVR__)

bool oled_on(void) {
    if (!oled_initialized) {


@@ 595,7 600,9 @@ bool oled_off(void) {
    return !oled_active;
}

bool is_oled_on(void) { return oled_active; }
bool is_oled_on(void) {
    return oled_active;
}

uint8_t oled_set_brightness(uint8_t level) {
    if (!oled_initialized) {


@@ 613,7 620,9 @@ uint8_t oled_set_brightness(uint8_t level) {
    return oled_brightness;
}

uint8_t oled_get_brightness(void) { return oled_brightness; }
uint8_t oled_get_brightness(void) {
    return oled_brightness;
}

// Set the specific 8 lines rows of the screen to scroll.
// 0 is the default for start, and 7 for end, which is the entire


@@ 693,7 702,9 @@ bool oled_scroll_off(void) {
    return !oled_scrolling;
}

bool is_oled_scrolling(void) { return oled_scrolling; }
bool is_oled_scrolling(void) {
    return oled_scrolling;
}

bool oled_invert(bool invert) {
    if (!oled_initialized) {


@@ 777,5 788,9 @@ void oled_task(void) {
#endif
}

__attribute__((weak)) bool oled_task_kb(void) { return oled_task_user(); }
__attribute__((weak)) bool oled_task_user(void) { return true; }
__attribute__((weak)) bool oled_task_kb(void) {
    return oled_task_user();
}
__attribute__((weak)) bool oled_task_user(void) {
    return true;
}

M drivers/ps2/ps2_busywait.c => drivers/ps2/ps2_busywait.c +3 -3
@@ 71,12 71,12 @@ uint8_t ps2_host_send(uint8_t data) {

    /* terminate a transmission if we have */
    inhibit();
    wait_us(100);  // 100us [4]p.13, [5]p.50
    wait_us(100); // 100us [4]p.13, [5]p.50

    /* 'Request to Send' and Start bit */
    data_lo();
    clock_hi();
    WAIT(clock_lo, 10000, 10);  // 10ms [5]p.50
    WAIT(clock_lo, 10000, 10); // 10ms [5]p.50

    /* Data bit */
    for (uint8_t i = 0; i < 8; i++) {


@@ 143,7 143,7 @@ uint8_t ps2_host_recv(void) {
    idle();

    /* start bit [1] */
    WAIT(clock_lo, 100, 1);  // TODO: this is enough?
    WAIT(clock_lo, 100, 1); // TODO: this is enough?
    WAIT(data_lo, 1, 2);
    WAIT(clock_hi, 50, 3);


M drivers/ps2/ps2_interrupt.c => drivers/ps2/ps2_interrupt.c +10 -6
@@ 43,7 43,7 @@ POSSIBILITY OF SUCH DAMAGE.

#if defined(__AVR__)
#    include <avr/interrupt.h>
#elif defined(PROTOCOL_CHIBIOS)  // TODO: or STM32 ?
#elif defined(PROTOCOL_CHIBIOS) // TODO: or STM32 ?
// chibiOS headers
#    include "ch.h"
#    include "hal.h"


@@ 71,7 71,9 @@ static inline void    pbuf_clear(void);

#if defined(PROTOCOL_CHIBIOS)
void ps2_interrupt_service_routine(void);
void palCallback(void *arg) { ps2_interrupt_service_routine(); }
void palCallback(void *arg) {
    ps2_interrupt_service_routine();
}

#    define PS2_INT_INIT()                                 \
        { palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT); } \


@@ 85,7 87,7 @@ void palCallback(void *arg) { ps2_interrupt_service_routine(); }
#    define PS2_INT_OFF()                       \
        { palDisableLineEvent(PS2_CLOCK_PIN); } \
        while (0)
#endif  // PROTOCOL_CHIBIOS
#endif // PROTOCOL_CHIBIOS

void ps2_host_init(void) {
    idle();


@@ 103,12 105,12 @@ uint8_t ps2_host_send(uint8_t data) {

    /* terminate a transmission if we have */
    inhibit();
    wait_us(100);  // 100us [4]p.13, [5]p.50
    wait_us(100); // 100us [4]p.13, [5]p.50

    /* 'Request to Send' and Start bit */
    data_lo();
    clock_hi();
    WAIT(clock_lo, 10000, 10);  // 10ms [5]p.50
    WAIT(clock_lo, 10000, 10); // 10ms [5]p.50

    /* Data bit[2-9] */
    for (uint8_t i = 0; i < 8; i++) {


@@ 244,7 246,9 @@ RETURN:
}

#if defined(__AVR__)
ISR(PS2_INT_VECT) { ps2_interrupt_service_routine(); }
ISR(PS2_INT_VECT) {
    ps2_interrupt_service_routine();
}
#endif

/* send LED state to keyboard */

M drivers/ps2/ps2_mouse.c => drivers/ps2/ps2_mouse.c +20 -8
@@ 42,7 42,7 @@ static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report);
void ps2_mouse_init(void) {
    ps2_host_init();

    wait_ms(PS2_MOUSE_INIT_DELAY);  // wait for powering up
    wait_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up

    PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset");



@@ 113,9 113,13 @@ void ps2_mouse_task(void) {
    ps2_mouse_clear_report(&mouse_report);
}

void ps2_mouse_disable_data_reporting(void) { PS2_MOUSE_SEND(PS2_MOUSE_DISABLE_DATA_REPORTING, "ps2 mouse disable data reporting"); }
void ps2_mouse_disable_data_reporting(void) {
    PS2_MOUSE_SEND(PS2_MOUSE_DISABLE_DATA_REPORTING, "ps2 mouse disable data reporting");
}

void ps2_mouse_enable_data_reporting(void) { PS2_MOUSE_SEND(PS2_MOUSE_ENABLE_DATA_REPORTING, "ps2 mouse enable data reporting"); }
void ps2_mouse_enable_data_reporting(void) {
    PS2_MOUSE_SEND(PS2_MOUSE_ENABLE_DATA_REPORTING, "ps2 mouse enable data reporting");
}

void ps2_mouse_set_remote_mode(void) {
    PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_REMOTE_MODE, "ps2 mouse set remote mode");


@@ 127,13 131,21 @@ void ps2_mouse_set_stream_mode(void) {
    ps2_mouse_mode = PS2_MOUSE_STREAM_MODE;
}

void ps2_mouse_set_scaling_2_1(void) { PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_2_1, "ps2 mouse set scaling 2:1"); }
void ps2_mouse_set_scaling_2_1(void) {
    PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_2_1, "ps2 mouse set scaling 2:1");
}

void ps2_mouse_set_scaling_1_1(void) { PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_1_1, "ps2 mouse set scaling 1:1"); }
void ps2_mouse_set_scaling_1_1(void) {
    PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_1_1, "ps2 mouse set scaling 1:1");
}

void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution) { PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_RESOLUTION, resolution, "ps2 mouse set resolution"); }
void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution) {
    PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_RESOLUTION, resolution, "ps2 mouse set resolution");
}

void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate) { PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_SAMPLE_RATE, sample_rate, "ps2 mouse set sample rate"); }
void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate) {
    PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_SAMPLE_RATE, sample_rate, "ps2 mouse set sample rate");
}

/* ============================= HELPERS ============================ */



@@ 165,7 177,7 @@ static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report)
#ifdef PS2_MOUSE_INVERT_X
    mouse_report->x = -mouse_report->x;
#endif
#ifndef PS2_MOUSE_INVERT_Y  // NOTE if not!
#ifndef PS2_MOUSE_INVERT_Y // NOTE if not!
    // invert coordinate of y to conform to USB HID mouse
    mouse_report->y = -mouse_report->y;
#endif

M drivers/sensors/adns5050.c => drivers/sensors/adns5050.c +7 -3
@@ 74,9 74,13 @@ void adns5050_sync(void) {
    writePinHigh(ADNS5050_CS_PIN);
}

void adns5050_cs_select(void) { writePinLow(ADNS5050_CS_PIN); }
void adns5050_cs_select(void) {
    writePinLow(ADNS5050_CS_PIN);
}

void adns5050_cs_deselect(void) { writePinHigh(ADNS5050_CS_PIN); }
void adns5050_cs_deselect(void) {
    writePinHigh(ADNS5050_CS_PIN);
}

uint8_t adns5050_serial_read(void) {
    setPinInput(ADNS5050_SDIO_PIN);


@@ 190,7 194,7 @@ int8_t convert_twoscomp(uint8_t data) {

// Don't forget to use the definitions for CPI in the header file.
void adns5050_set_cpi(uint16_t cpi) {
    uint8_t cpival = constrain((cpi / 125), 0x1, 0xD);  // limits to 0--119
    uint8_t cpival = constrain((cpi / 125), 0x1, 0xD); // limits to 0--119

    adns5050_write_reg(REG_MOUSE_CONTROL2, 0b10000 | cpival);
}

M drivers/sensors/adns9800.c => drivers/sensors/adns9800.c +3 -1
@@ 77,7 77,9 @@
#define MSB1              0x80
// clang-format on

void adns9800_spi_start(void) { spi_start(ADNS9800_CS_PIN, false, ADNS9800_SPI_MODE, ADNS9800_SPI_DIVISOR); }
void adns9800_spi_start(void) {
    spi_start(ADNS9800_CS_PIN, false, ADNS9800_SPI_MODE, ADNS9800_SPI_DIVISOR);
}

void adns9800_write(uint8_t reg_addr, uint8_t data) {
    adns9800_spi_start();

M drivers/sensors/analog_joystick.c => drivers/sensors/analog_joystick.c +1 -1
@@ 24,7 24,7 @@ uint16_t minAxisValue = ANALOG_JOYSTICK_AXIS_MIN;
uint16_t maxAxisValue = ANALOG_JOYSTICK_AXIS_MAX;

uint8_t maxCursorSpeed = ANALOG_JOYSTICK_SPEED_MAX;
uint8_t speedRegulator = ANALOG_JOYSTICK_SPEED_REGULATOR;  // Lower Values Create Faster Movement
uint8_t speedRegulator = ANALOG_JOYSTICK_SPEED_REGULATOR; // Lower Values Create Faster Movement

int16_t xOrigin, yOrigin;


M drivers/sensors/cirque_pinnacle.c => drivers/sensors/cirque_pinnacle.c +22 -16
@@ 54,7 54,9 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count);
void RAP_Write(uint8_t address, uint8_t data);

#ifdef CONSOLE_ENABLE
void print_byte(uint8_t byte) { xprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); }
void print_byte(uint8_t byte) {
    xprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0'));
}
#endif

/*  Logical Scaling Functions */


@@ 73,8 75,12 @@ void ClipCoordinates(pinnacle_data_t* coordinates) {
    }
}

uint16_t cirque_pinnacle_get_scale(void) { return scale_data; }
void     cirque_pinnacle_set_scale(uint16_t scale) { scale_data = scale; }
uint16_t cirque_pinnacle_get_scale(void) {
    return scale_data;
}
void cirque_pinnacle_set_scale(uint16_t scale) {
    scale_data = scale;
}

// Scales data to desired X & Y resolution
void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution) {


@@ 105,13 111,13 @@ void cirque_pinnacle_clear_flags() {
void cirque_pinnacle_enable_feed(bool feedEnable) {
    uint8_t temp;

    RAP_ReadBytes(FEEDCONFIG_1, &temp, 1);  // Store contents of FeedConfig1 register
    RAP_ReadBytes(FEEDCONFIG_1, &temp, 1); // Store contents of FeedConfig1 register

    if (feedEnable) {
        temp |= 0x01;  // Set Feed Enable bit
        temp |= 0x01; // Set Feed Enable bit
        RAP_Write(0x04, temp);
    } else {
        temp &= ~0x01;  // Clear Feed Enable bit
        temp &= ~0x01; // Clear Feed Enable bit
        RAP_Write(0x04, temp);
    }
}


@@ 122,13 128,13 @@ void cirque_pinnacle_enable_feed(bool feedEnable) {
void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) {
    uint8_t ERAControlValue = 0xFF;

    cirque_pinnacle_enable_feed(false);  // Disable feed
    cirque_pinnacle_enable_feed(false); // Disable feed

    RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8));     // Send upper byte of ERA address
    RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF));  // Send lower byte of ERA address
    RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8));    // Send upper byte of ERA address
    RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address

    for (uint16_t i = 0; i < count; i++) {
        RAP_Write(ERA_CONTROL, 0x05);  // Signal ERA-read (auto-increment) to Pinnacle
        RAP_Write(ERA_CONTROL, 0x05); // Signal ERA-read (auto-increment) to Pinnacle

        // Wait for status register 0x1E to clear
        do {


@@ 145,14 151,14 @@ void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) {
void ERA_WriteByte(uint16_t address, uint8_t data) {
    uint8_t ERAControlValue = 0xFF;

    cirque_pinnacle_enable_feed(false);  // Disable feed
    cirque_pinnacle_enable_feed(false); // Disable feed

    RAP_Write(ERA_VALUE, data);  // Send data byte to be written
    RAP_Write(ERA_VALUE, data); // Send data byte to be written

    RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8));     // Upper byte of ERA address
    RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF));  // Lower byte of ERA address
    RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8));    // Upper byte of ERA address
    RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address

    RAP_Write(ERA_CONTROL, 0x02);  // Signal an ERA-write to Pinnacle
    RAP_Write(ERA_CONTROL, 0x02); // Signal an ERA-write to Pinnacle

    // Wait for status register 0x1E to clear
    do {


@@ 166,7 172,7 @@ void cirque_pinnacle_set_adc_attenuation(uint8_t adcGain) {
    uint8_t temp = 0x00;

    ERA_ReadBytes(0x0187, &temp, 1);
    temp &= 0x3F;  // clear top two bits
    temp &= 0x3F; // clear top two bits
    temp |= adcGain;
    ERA_WriteByte(0x0187, temp);
    ERA_ReadBytes(0x0187, &temp, 1);

M drivers/sensors/cirque_pinnacle.h => drivers/sensors/cirque_pinnacle.h +4 -4
@@ 26,16 26,16 @@ void            cirque_pinnacle_set_scale(uint16_t scale);

// Coordinate scaling values
#ifndef CIRQUE_PINNACLE_X_LOWER
#    define CIRQUE_PINNACLE_X_LOWER 127  // min "reachable" X value
#    define CIRQUE_PINNACLE_X_LOWER 127 // min "reachable" X value
#endif
#ifndef CIRQUE_PINNACLE_X_UPPER
#    define CIRQUE_PINNACLE_X_UPPER 1919  // max "reachable" X value
#    define CIRQUE_PINNACLE_X_UPPER 1919 // max "reachable" X value
#endif
#ifndef CIRQUE_PINNACLE_Y_LOWER
#    define CIRQUE_PINNACLE_Y_LOWER 63  // min "reachable" Y value
#    define CIRQUE_PINNACLE_Y_LOWER 63 // min "reachable" Y value
#endif
#ifndef CIRQUE_PINNACLE_Y_UPPER
#    define CIRQUE_PINNACLE_Y_UPPER 1471  // max "reachable" Y value
#    define CIRQUE_PINNACLE_Y_UPPER 1471 // max "reachable" Y value
#endif
#ifndef CIRQUE_PINNACLE_X_RANGE
#    define CIRQUE_PINNACLE_X_RANGE (CIRQUE_PINNACLE_X_UPPER - CIRQUE_PINNACLE_X_LOWER)

M drivers/sensors/cirque_pinnacle_i2c.c => drivers/sensors/cirque_pinnacle_i2c.c +2 -2
@@ 14,7 14,7 @@ extern bool touchpad_init;
/*  RAP Functions */
// Reads <count> Pinnacle registers starting at <address>
void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
    uint8_t cmdByte = READ_MASK | address;  // Form the READ command byte
    uint8_t cmdByte = READ_MASK | address; // Form the READ command byte
    if (touchpad_init) {
        i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, NULL, 0, CIRQUE_PINNACLE_TIMEOUT);
        if (i2c_readReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, data, count, CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {


@@ 29,7 29,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {

// Writes single-byte <data> to <address>
void RAP_Write(uint8_t address, uint8_t data) {
    uint8_t cmdByte = WRITE_MASK | address;  // Form the WRITE command byte
    uint8_t cmdByte = WRITE_MASK | address; // Form the WRITE command byte

    if (touchpad_init) {
        if (i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, &data, sizeof(data), CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {

M drivers/sensors/cirque_pinnacle_spi.c => drivers/sensors/cirque_pinnacle_spi.c +5 -5
@@ 13,14 13,14 @@ extern bool touchpad_init;
/*  RAP Functions */
// Reads <count> Pinnacle registers starting at <address>
void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
    uint8_t cmdByte = READ_MASK | address;  // Form the READ command byte
    uint8_t cmdByte = READ_MASK | address; // Form the READ command byte
    if (touchpad_init) {
        if (spi_start(CIRQUE_PINNACLE_SPI_CS_PIN, CIRQUE_PINNACLE_SPI_LSBFIRST, CIRQUE_PINNACLE_SPI_MODE, CIRQUE_PINNACLE_SPI_DIVISOR)) {
            spi_write(cmdByte);
            spi_read();  // filler
            spi_read();  // filler
            spi_read(); // filler
            spi_read(); // filler
            for (uint8_t i = 0; i < count; i++) {
                data[i] = spi_read();  // each sepsequent read gets another register's contents
                data[i] = spi_read(); // each sepsequent read gets another register's contents
            }
        } else {
#ifdef CONSOLE_ENABLE


@@ 34,7 34,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {

// Writes single-byte <data> to <address>
void RAP_Write(uint8_t address, uint8_t data) {
    uint8_t cmdByte = WRITE_MASK | address;  // Form the WRITE command byte
    uint8_t cmdByte = WRITE_MASK | address; // Form the WRITE command byte

    if (touchpad_init) {
        if (spi_start(CIRQUE_PINNACLE_SPI_CS_PIN, CIRQUE_PINNACLE_SPI_LSBFIRST, CIRQUE_PINNACLE_SPI_MODE, CIRQUE_PINNACLE_SPI_DIVISOR)) {

M drivers/sensors/pimoroni_trackball.c => drivers/sensors/pimoroni_trackball.c +3 -1
@@ 33,7 33,9 @@

static uint16_t precision = 128;

uint16_t pimoroni_trackball_get_cpi(void) { return (precision * 125); }
uint16_t pimoroni_trackball_get_cpi(void) {
    return (precision * 125);
}
/**
 * @brief Sets the scaling value for pimoroni trackball
 *

M drivers/sensors/pmw3360.c => drivers/sensors/pmw3360.c +8 -6
@@ 86,7 86,9 @@
bool _inBurst = false;

#ifdef CONSOLE_ENABLE
void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); }
void print_byte(uint8_t byte) {
    dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0'));
}
#endif
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))



@@ 144,7 146,7 @@ bool pmw3360_init(void) {
    pmw3360_spi_start();
    spi_stop();

    pmw3360_write(REG_Shutdown, 0xb6);  // Shutdown first
    pmw3360_write(REG_Shutdown, 0xb6); // Shutdown first
    wait_ms(300);

    pmw3360_spi_start();


@@ 222,7 224,7 @@ bool pmw3360_check_signature(void) {
    uint8_t pid      = pmw3360_read(REG_Product_ID);
    uint8_t iv_pid   = pmw3360_read(REG_Inverse_Product_ID);
    uint8_t SROM_ver = pmw3360_read(REG_SROM_ID);
    return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]);  // signature for SROM 0x04
    return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04
}

uint16_t pmw3360_get_cpi(void) {


@@ 248,17 250,17 @@ report_pmw3360_t pmw3360_read_burst(void) {

    pmw3360_spi_start();
    spi_write(REG_Motion_Burst);
    wait_us(35);  // waits for tSRAD_MOTBR
    wait_us(35); // waits for tSRAD_MOTBR

    report.motion = spi_read();
    spi_read();  // skip Observation
    spi_read(); // skip Observation
    // delta registers
    report.dx  = spi_read();
    report.mdx = spi_read();
    report.dy  = spi_read();
    report.mdy = spi_read();

    if (report.motion & 0b111) {  // panic recovery, sometimes burst mode works weird.
    if (report.motion & 0b111) { // panic recovery, sometimes burst mode works weird.
        _inBurst = false;
    }


M drivers/sensors/pmw3360.h => drivers/sensors/pmw3360.h +4 -4
@@ 58,11 58,11 @@

typedef struct {
    int8_t  motion;
    bool    isMotion;     // True if a motion is detected.
    bool    isOnSurface;  // True when a chip is on a surface
    int16_t dx;           // displacement on x directions. Unit: Count. (CPI * Count = Inch value)
    bool    isMotion;    // True if a motion is detected.
    bool    isOnSurface; // True when a chip is on a surface
    int16_t dx;          // displacement on x directions. Unit: Count. (CPI * Count = Inch value)
    int8_t  mdx;
    int16_t dy;  // displacement on y directions.
    int16_t dy; // displacement on y directions.
    int8_t  mdy;
} report_pmw3360_t;


M drivers/sensors/pmw3389.c => drivers/sensors/pmw3389.c +8 -6
@@ 90,7 90,9 @@
bool _inBurst = false;

#ifdef CONSOLE_ENABLE
void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); }
void print_byte(uint8_t byte) {
    dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0'));
}
#endif
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))



@@ 148,7 150,7 @@ bool pmw3389_init(void) {
    pmw3389_spi_start();
    spi_stop();

    pmw3389_write(REG_Shutdown, 0xb6);  // Shutdown first
    pmw3389_write(REG_Shutdown, 0xb6); // Shutdown first
    wait_ms(300);

    pmw3389_spi_start();


@@ 226,7 228,7 @@ bool pmw3389_check_signature(void) {
    uint8_t pid      = pmw3389_read(REG_Product_ID);
    uint8_t iv_pid   = pmw3389_read(REG_Inverse_Product_ID);
    uint8_t SROM_ver = pmw3389_read(REG_SROM_ID);
    return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]);  // signature for SROM 0x04
    return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04
}

uint16_t pmw3389_get_cpi(void) {


@@ 254,17 256,17 @@ report_pmw3389_t pmw3389_read_burst(void) {

    pmw3389_spi_start();
    spi_write(REG_Motion_Burst);
    wait_us(35);  // waits for tSRAD_MOTBR
    wait_us(35); // waits for tSRAD_MOTBR

    report.motion = spi_read();
    spi_read();  // skip Observation
    spi_read(); // skip Observation
    // delta registers
    report.dx  = spi_read();
    report.mdx = spi_read();
    report.dy  = spi_read();
    report.mdy = spi_read();

    if (report.motion & 0b111) {  // panic recovery, sometimes burst mode works weird.
    if (report.motion & 0b111) { // panic recovery, sometimes burst mode works weird.
        _inBurst = false;
    }


M drivers/sensors/pmw3389.h => drivers/sensors/pmw3389.h +4 -4
@@ 59,11 59,11 @@

typedef struct {
    int8_t  motion;
    bool    isMotion;     // True if a motion is detected.
    bool    isOnSurface;  // True when a chip is on a surface
    int16_t dx;           // displacement on x directions. Unit: Count. (CPI * Count = Inch value)
    bool    isMotion;    // True if a motion is detected.
    bool    isOnSurface; // True when a chip is on a surface
    int16_t dx;          // displacement on x directions. Unit: Count. (CPI * Count = Inch value)
    int8_t  mdx;
    int16_t dy;  // displacement on y directions.
    int16_t dy; // displacement on y directions.
    int8_t  mdy;
} report_pmw3389_t;


M drivers/usb2422.c => drivers/usb2422.c +7 -7
@@ 352,7 352,7 @@ void USB2422_init() {
    setPinInput(USB2422_ACTIVE_PIN);
#endif

    i2c_init();  // IC2 clk must be high at USB2422 reset release time to signal SMB configuration
    i2c_init(); // IC2 clk must be high at USB2422 reset release time to signal SMB configuration
}

void USB2422_configure() {


@@ 363,14 363,14 @@ void USB2422_configure() {
    // configure Usb2422 registers
    config.VID.reg               = USB2422_VENDOR_ID;
    config.PID.reg               = USB2422_PRODUCT_ID;
    config.DID.reg               = USB2422_DEVICE_VER;  // BCD format, eg 01.01
    config.CFG1.bit.SELF_BUS_PWR = 1;                   // self powered for now
    config.CFG1.bit.HS_DISABLE   = 1;                   // full or high speed
    config.DID.reg               = USB2422_DEVICE_VER; // BCD format, eg 01.01
    config.CFG1.bit.SELF_BUS_PWR = 1;                  // self powered for now
    config.CFG1.bit.HS_DISABLE   = 1;                  // full or high speed
    // config.CFG2.bit.COMPOUND = 0; // compound device
    config.CFG3.bit.STRING_EN = 1;  // strings enabled
    config.CFG3.bit.STRING_EN = 1; // strings enabled
    // config.NRD.bit.PORT2_NR = 0; // MCU is non-removable
    config.MAXPB.reg = 20;  // 0mA
    config.HCMCB.reg = 20;  // 0mA
    config.MAXPB.reg = 20; // 0mA
    config.HCMCB.reg = 20; // 0mA
    config.MFRSL.reg = sizeof(USB2422_MANUFACTURER);
    config.PRDSL.reg = sizeof(USB2422_PRODUCT);
    config.SERSL.reg = sizeof(SERNAME);

M drivers/ws2812.h => drivers/ws2812.h +4 -4
@@ 33,19 33,19 @@
#endif

#ifndef WS2812_T1H
#    define WS2812_T1H 900  // Width of a 1 bit in ns
#    define WS2812_T1H 900 // Width of a 1 bit in ns
#endif

#ifndef WS2812_T1L
#    define WS2812_T1L (WS2812_TIMING - WS2812_T1H)  // Width of a 1 bit in ns
#    define WS2812_T1L (WS2812_TIMING - WS2812_T1H) // Width of a 1 bit in ns
#endif

#ifndef WS2812_T0H
#    define WS2812_T0H 350  // Width of a 0 bit in ns
#    define WS2812_T0H 350 // Width of a 0 bit in ns
#endif

#ifndef WS2812_T0L
#    define WS2812_T0L (WS2812_TIMING - WS2812_T0H)  // Width of a 0 bit in ns
#    define WS2812_T0L (WS2812_TIMING - WS2812_T0H) // Width of a 0 bit in ns
#endif

/*

M platforms/arm_atsam/bootloaders/md_boot.c => platforms/arm_atsam/bootloaders/md_boot.c +11 -11
@@ 26,20 26,20 @@ extern uint32_t _eram;
// CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method.
void bootloader_jump(void) {
#ifdef KEYBOARD_massdrop_ctrl
    uint8_t  ver_ram_method[] = "v2.18Jun 22 2018 17:28:08";  // The version to match (NULL terminated by compiler)
    uint8_t *ver_check        = ver_ram_method;               // Pointer to version match string for traversal
    uint8_t *ver_rom          = (uint8_t *)0x21A0;            // Pointer to address in ROM where this specific bootloader version would exist
    uint8_t  ver_ram_method[] = "v2.18Jun 22 2018 17:28:08"; // The version to match (NULL terminated by compiler)
    uint8_t *ver_check        = ver_ram_method;              // Pointer to version match string for traversal
    uint8_t *ver_rom          = (uint8_t *)0x21A0;           // Pointer to address in ROM where this specific bootloader version would exist

    while (*ver_check && *ver_rom == *ver_check) {  // While there are check version characters to match and bootloader's version matches check's version
        ver_check++;                                // Move check version pointer to next character
        ver_rom++;                                  // Move ROM version pointer to next character
    while (*ver_check && *ver_rom == *ver_check) { // While there are check version characters to match and bootloader's version matches check's version
        ver_check++;                               // Move check version pointer to next character
        ver_rom++;                                 // Move ROM version pointer to next character
    }

    if (!*ver_check) {                   // If check version pointer is NULL, all characters have matched
        *MAGIC_ADDR = BOOTLOADER_MAGIC;  // Set magic number into RAM
        NVIC_SystemReset();              // Perform system reset
    if (!*ver_check) {                  // If check version pointer is NULL, all characters have matched
        *MAGIC_ADDR = BOOTLOADER_MAGIC; // Set magic number into RAM
        NVIC_SystemReset();             // Perform system reset
        while (1)
            ;  // Won't get here
            ; // Won't get here
    }
#endif



@@ 61,5 61,5 @@ void bootloader_jump(void) {
    while (!WDT->CTRLA.bit.ENABLE)
        ;
    while (1)
        ;  // Wait on timeout
        ; // Wait on timeout
}

M platforms/arm_atsam/eeprom_samd.c => platforms/arm_atsam/eeprom_samd.c +3 -1
@@ 155,7 155,9 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
    }
}

void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
void eeprom_update_byte(uint8_t *addr, uint8_t value) {
    eeprom_write_byte(addr, value);
}

void eeprom_update_word(uint16_t *addr, uint16_t value) {
    uint8_t *p = (uint8_t *)addr;

M platforms/arm_atsam/eeprom_samd.h => platforms/arm_atsam/eeprom_samd.h +1 -1
@@ 4,5 4,5 @@

#ifndef EEPROM_SIZE
#    include "eeconfig.h"
#    define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4)  // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
#    define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
#endif

M platforms/arm_atsam/suspend.c => platforms/arm_atsam/suspend.c +1 -1
@@ 9,7 9,7 @@
 */
void suspend_power_down(void) {
#ifdef RGB_MATRIX_ENABLE
    I2C3733_Control_Set(0);  // Disable LED driver
    I2C3733_Control_Set(0); // Disable LED driver
#endif

    suspend_power_down_kb();

M platforms/arm_atsam/timer.c => platforms/arm_atsam/timer.c +24 -8
@@ 2,18 2,34 @@
#include "timer.h"
#include "tmk_core/protocol/arm_atsam/clks.h"

void set_time(uint64_t tset) { ms_clk = tset; }
void set_time(uint64_t tset) {
    ms_clk = tset;
}

void timer_init(void) { timer_clear(); }
void timer_init(void) {
    timer_clear();
}

uint16_t timer_read(void) { return (uint16_t)ms_clk; }
uint16_t timer_read(void) {
    return (uint16_t)ms_clk;
}

uint32_t timer_read32(void) { return (uint32_t)ms_clk; }
uint32_t timer_read32(void) {
    return (uint32_t)ms_clk;
}

uint64_t timer_read64(void) { return ms_clk; }
uint64_t timer_read64(void) {
    return ms_clk;
}

uint16_t timer_elapsed(uint16_t tlast) { return TIMER_DIFF_16(timer_read(), tlast); }
uint16_t timer_elapsed(uint16_t tlast) {
    return TIMER_DIFF_16(timer_read(), tlast);
}

uint32_t timer_elapsed32(uint32_t tlast) { return TIMER_DIFF_32(timer_read32(), tlast); }
uint32_t timer_elapsed32(uint32_t tlast) {
    return TIMER_DIFF_32(timer_read32(), tlast);
}

void timer_clear(void) { set_time(0); }
void timer_clear(void) {
    set_time(0);
}

M platforms/avr/bootloaders/dfu.c => platforms/avr/bootloaders/dfu.c +2 -2
@@ 30,9 30,9 @@ uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));

__attribute__((weak)) void bootloader_jump(void) {
    UDCON  = 1;
    USBCON = (1 << FRZCLK);  // disable USB
    USBCON = (1 << FRZCLK); // disable USB
    UCSR1B = 0;
    _delay_ms(5);  // 5 seems to work fine
    _delay_ms(5); // 5 seems to work fine

    // watchdog reset
    reset_key = BOOTLOADER_RESET_KEY;

M platforms/avr/bootloaders/halfkay.c => platforms/avr/bootloaders/halfkay.c +5 -5
@@ 27,11 27,11 @@ __attribute__((weak)) void bootloader_jump(void) {
    // disable all peripherals
    // a shutdown call might make sense here
    UDCON  = 1;
    USBCON = (1 << FRZCLK);  // disable USB
    USBCON = (1 << FRZCLK); // disable USB
    UCSR1B = 0;
    _delay_ms(5);

#if defined(__AVR_AT90USB162__)  // Teensy 1.0
#if defined(__AVR_AT90USB162__) // Teensy 1.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;


@@ 47,7 47,7 @@ __attribute__((weak)) void bootloader_jump(void) {
    PORTC  = 0;
    PORTD  = 0;
    asm volatile("jmp 0x3E00");
#elif defined(__AVR_ATmega32U4__)   // Teensy 2.0
#elif defined(__AVR_ATmega32U4__)  // Teensy 2.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;


@@ 72,7 72,7 @@ __attribute__((weak)) void bootloader_jump(void) {
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0x7E00");
#elif defined(__AVR_AT90USB646__)   // Teensy++ 1.0
#elif defined(__AVR_AT90USB646__)  // Teensy++ 1.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;


@@ 98,7 98,7 @@ __attribute__((weak)) void bootloader_jump(void) {
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0xFC00");
#elif defined(__AVR_AT90USB1286__)  // Teensy++ 2.0
#elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;

M platforms/avr/drivers/analog.c => platforms/avr/drivers/analog.c +6 -2
@@ 21,9 21,13 @@

static uint8_t aref = ADC_REF_POWER;

void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); }
void analogReference(uint8_t mode) {
    aref = mode & (_BV(REFS1) | _BV(REFS0));
}

int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); }
int16_t analogReadPin(pin_t pin) {
    return adc_read(pinToMux(pin));
}

uint8_t pinToMux(pin_t pin) {
    switch (pin) {

M platforms/avr/drivers/analog.h => platforms/avr/drivers/analog.h +9 -9
@@ 32,21 32,21 @@ int16_t adc_read(uint8_t mux);
}
#endif

#define ADC_REF_EXTERNAL 0                          // AREF, Internal Vref turned off
#define ADC_REF_POWER _BV(REFS0)                    // AVCC with external capacitor on AREF pin
#define ADC_REF_INTERNAL (_BV(REFS1) | _BV(REFS0))  // Internal 2.56V Voltage Reference with external capacitor on AREF pin (1.1V for 328P)
#define ADC_REF_EXTERNAL 0                         // AREF, Internal Vref turned off
#define ADC_REF_POWER _BV(REFS0)                   // AVCC with external capacitor on AREF pin
#define ADC_REF_INTERNAL (_BV(REFS1) | _BV(REFS0)) // Internal 2.56V Voltage Reference with external capacitor on AREF pin (1.1V for 328P)

// These prescaler values are for high speed mode, ADHSM = 1
#if F_CPU == 16000000L || F_CPU == 12000000L
#    define ADC_PRESCALER (_BV(ADPS2) | _BV(ADPS1))  // /64
#    define ADC_PRESCALER (_BV(ADPS2) | _BV(ADPS1)) // /64
#elif F_CPU == 8000000L
#    define ADC_PRESCALER (_BV(ADPS2) | _BV(ADPS0))  // /32
#    define ADC_PRESCALER (_BV(ADPS2) | _BV(ADPS0)) // /32
#elif F_CPU == 4000000L
#    define ADC_PRESCALER (_BV(ADPS2))  // /16
#    define ADC_PRESCALER (_BV(ADPS2)) // /16
#elif F_CPU == 2000000L
#    define ADC_PRESCALER (_BV(ADPS1) | _BV(ADPS0))  // /8
#    define ADC_PRESCALER (_BV(ADPS1) | _BV(ADPS0)) // /8
#elif F_CPU == 1000000L
#    define ADC_PRESCALER _BV(ADPS1)  // /4
#    define ADC_PRESCALER _BV(ADPS1) // /4
#else
#    define ADC_PRESCALER _BV(ADPS0)  // /2
#    define ADC_PRESCALER _BV(ADPS0) // /2
#endif

M platforms/avr/drivers/audio_pwm_hardware.c => platforms/avr/drivers/audio_pwm_hardware.c +5 -3
@@ 152,7 152,7 @@ extern uint8_t note_timbre;
#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
    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


@@ 160,7 160,7 @@ void         channel_1_set_frequency(float freq) {
        AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
        return;
    } else {
        AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1);  // enable output, PWM mode
        AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode
    }

    channel_1_frequency = freq;


@@ 202,7 202,9 @@ void         channel_2_set_frequency(float freq) {
    AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
}

float channel_2_get_frequency(void) { return channel_2_frequency; }
float channel_2_get_frequency(void) {
    return channel_2_frequency;
}

void channel_2_start(void) {
    AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);

M platforms/avr/drivers/glcdfont.c => platforms/avr/drivers/glcdfont.c +9 -9
@@ 10,14 10,14 @@ static const unsigned char font[] PROGMEM = {
    0x30, 0x38, 0x3E, 0x38, 0x30, 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x80, 0x70, 0x30, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, 0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00,
    0x00, 0x08, 0x14, 0x22, 0x41, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x41, 0x22, 0x14, 0x08, 0x02, 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, 0x03, 0x04, 0x78, 0x04, 0x03,
    0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41, 0x41, 0x7F, 0x04, 0x02, 0x01, 0x02, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x03, 0x07, 0x08, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x7F, 0x28, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x28, 0x7F, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x7C, 0x08, 0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x18, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48, 0x54, 0x54, 0x54, 0x24, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x40, 0x30, 0x40, 0x3C,
    0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40, 0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41, 0x22, 0x54, 0x54, 0x78, 0x42,                                                                                                                                                                                                                                                                                                              // a-umlaut
    0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E, 0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54, 0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00, 0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0x7D, 0x12, 0x11, 0x12, 0x7D,                                                                                                                                                                                                                                                                                                                                                                                                        // A-umlaut
    0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54, 0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49, 0x32, 0x3A, 0x44, 0x44, 0x44, 0x3A,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                // o-umlaut
    0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42, 0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x3D, 0x42, 0x42, 0x42, 0x3D,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              // O-umlaut
    0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E, 0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6, 0x20, 0xC0, 0x88, 0x7E, 0x09, 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00, 0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40, 0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D, 0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48, 0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A, 0x14, 0x08, 0x55, 0x00, 0x55, 0x00, 0x55,  // #176 (25% block) missing in old code
    0xAA, 0x55, 0xAA, 0x55, 0xAA,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      // 50% block
    0xFF, 0x55, 0xFF, 0x55, 0xFF,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      // 75% block
    0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40, 0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41, 0x22, 0x54, 0x54, 0x78, 0x42,                                                                                                                                                                                                                                                                                                             // a-umlaut
    0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E, 0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54, 0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00, 0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0x7D, 0x12, 0x11, 0x12, 0x7D,                                                                                                                                                                                                                                                                                                                                                                                                       // A-umlaut
    0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54, 0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49, 0x32, 0x3A, 0x44, 0x44, 0x44, 0x3A,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // o-umlaut
    0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42, 0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x3D, 0x42, 0x42, 0x42, 0x3D,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             // O-umlaut
    0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E, 0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6, 0x20, 0xC0, 0x88, 0x7E, 0x09, 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00, 0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40, 0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D, 0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48, 0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A, 0x14, 0x08, 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
    0xAA, 0x55, 0xAA, 0x55, 0xAA,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     // 50% block
    0xFF, 0x55, 0xFF, 0x55, 0xFF,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     // 75% block
    0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x14, 0x14, 0x14, 0xFF, 0x00, 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x14, 0x14, 0x17, 0x10, 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0x1F, 0x00, 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x00, 0x00, 0x00, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x17, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x17, 0x14, 0x10, 0x10, 0x1F, 0x10, 0x1F,
    0x14, 0x14, 0x14, 0xF4, 0x14, 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44, 0x38, 0x44, 0xFC, 0x4A, 0x4A, 0x4A, 0x34,                                                                                                                                                                                                                                                                                                                                                                                                       // sharp-s or beta
    0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55, 0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E, 0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D, 0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D, 0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44, 0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0, 0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36, 0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00  // #255 NBSP
    0x14, 0x14, 0x14, 0xF4, 0x14, 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44, 0x38, 0x44, 0xFC, 0x4A, 0x4A, 0x4A, 0x34,                                                                                                                                                                                                                                                                                                                                                                                                      // sharp-s or beta
    0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55, 0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E, 0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D, 0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D, 0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44, 0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0, 0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36, 0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
};

M platforms/avr/drivers/hd44780.c => platforms/avr/drivers/hd44780.c +14 -8
@@ 262,7 262,7 @@ static uint8_t lcd_waitbusy(void)
    delay(LCD_DELAY_BUSY_FLAG);

    /* now read the address counter */
    return (lcd_read(0));  // return address counter
    return (lcd_read(0)); // return address counter

} /* lcd_waitbusy */



@@ 362,17 362,23 @@ void lcd_gotoxy(uint8_t x, uint8_t y) {

/*************************************************************************
*************************************************************************/
int lcd_getxy(void) { return lcd_waitbusy(); }
int lcd_getxy(void) {
    return lcd_waitbusy();
}

/*************************************************************************
Clear display and set cursor to home position
*************************************************************************/
void lcd_clrscr(void) { lcd_command(1 << LCD_CLR); }
void lcd_clrscr(void) {
    lcd_command(1 << LCD_CLR);
}

/*************************************************************************
Set cursor to home position
*************************************************************************/
void lcd_home(void) { lcd_command(1 << LCD_HOME); }
void lcd_home(void) {
    lcd_command(1 << LCD_HOME);
}

/*************************************************************************
Display character at current cursor position


@@ 382,7 388,7 @@ Returns:  none
void lcd_putc(char c) {
    uint8_t pos;

    pos = lcd_waitbusy();  // read busy-flag and address counter
    pos = lcd_waitbusy(); // read busy-flag and address counter
    if (c == '\n') {
        lcd_newline(pos);
    } else {


@@ 483,8 489,8 @@ void lcd_init(uint8_t dispAttr) {
    delay(LCD_DELAY_BOOTUP); /* wait 16ms or more after power-on       */

    /* initial write to lcd is 8bit */
    LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);  // LCD_FUNCTION>>4;
    LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);  // LCD_FUNCTION_8BIT>>4;
    LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // LCD_FUNCTION>>4;
    LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // LCD_FUNCTION_8BIT>>4;
    lcd_e_toggle();
    delay(LCD_DELAY_INIT); /* delay, busy flag can't be checked here */



@@ 497,7 503,7 @@ void lcd_init(uint8_t dispAttr) {
    delay(LCD_DELAY_INIT_REP); /* delay, busy flag can't be checked here */

    /* now configure for 4bit mode */
    LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);  // LCD_FUNCTION_4BIT_1LINE>>4
    LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4
    lcd_e_toggle();
    delay(LCD_DELAY_INIT_4BIT); /* some displays need this additional delay */


M platforms/avr/drivers/i2c_master.c => platforms/avr/drivers/i2c_master.c +3 -3
@@ 25,12 25,12 @@
#include "wait.h"

#ifndef F_SCL
#    define F_SCL 400000UL  // SCL frequency
#    define F_SCL 400000UL // SCL frequency
#endif

#ifndef I2C_START_RETRY_COUNT
#    define I2C_START_RETRY_COUNT 20
#endif  // I2C_START_RETRY_COUNT
#endif // I2C_START_RETRY_COUNT

#define I2C_ACTION_READ 0x01
#define I2C_ACTION_WRITE 0x00


@@ 98,7 98,7 @@ static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {
i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
    // Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled.
    uint16_t     timeout_timer = timer_read();
    uint16_t     time_slice    = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT)));  // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries
    uint16_t     time_slice    = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries
    i2c_status_t status;
    do {
        status = i2c_start_impl(address, time_slice);

M platforms/avr/drivers/i2c_slave.c => platforms/avr/drivers/i2c_slave.c +6 -6
@@ 29,7 29,7 @@
#    include "transactions.h"

static volatile bool is_callback_executor = false;
#endif  // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)

volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];



@@ 57,7 57,7 @@ ISR(TWI_vect) {
            slave_has_register_set = false;
#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
            is_callback_executor = false;
#endif  // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
            break;

        case TW_SR_DATA_ACK:


@@ 66,16 66,16 @@ ISR(TWI_vect) {
            if (!slave_has_register_set) {
                buffer_address = TWDR;

                if (buffer_address >= I2C_SLAVE_REG_COUNT) {  // address out of bounds dont ack
                if (buffer_address >= I2C_SLAVE_REG_COUNT) { // address out of bounds dont ack
                    ack            = 0;
                    buffer_address = 0;
                }
                slave_has_register_set = true;  // address has been received now fill in buffer
                slave_has_register_set = true; // address has been received now fill in buffer

#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
                // Work out if we're attempting to execute a callback
                is_callback_executor = buffer_address == split_transaction_table[I2C_EXECUTE_CALLBACK].initiator2target_offset;
#endif  // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
            } else {
                i2c_slave_reg[buffer_address] = TWDR;
                buffer_address++;


@@ 88,7 88,7 @@ ISR(TWI_vect) {
                        trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
                    }
                }
#endif  // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
            }
            break;


M platforms/avr/drivers/i2c_slave.h => platforms/avr/drivers/i2c_slave.h +3 -3
@@ 27,11 27,11 @@
#    if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#        include "transport.h"
#        define I2C_SLAVE_REG_COUNT sizeof(split_shared_memory_t)
#    else  // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#    else // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#        define I2C_SLAVE_REG_COUNT 30
#    endif  // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
#    endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)

#endif  // I2C_SLAVE_REG_COUNT
#endif // I2C_SLAVE_REG_COUNT

_Static_assert(I2C_SLAVE_REG_COUNT < 256, "I2C target registers must be single byte");


M platforms/avr/drivers/ps2/ps2_io.c => platforms/avr/drivers/ps2/ps2_io.c +6 -2
@@ 23,7 23,9 @@ void clock_lo(void) {
    setPinOutput(PS2_CLOCK_PIN);
}

void clock_hi(void) { setPinInputHigh(PS2_CLOCK_PIN); }
void clock_hi(void) {
    setPinInputHigh(PS2_CLOCK_PIN);
}

bool clock_in(void) {
    setPinInputHigh(PS2_CLOCK_PIN);


@@ 42,7 44,9 @@ void data_lo(void) {
    setPinOutput(PS2_DATA_PIN);
}

void data_hi(void) { setPinInputHigh(PS2_DATA_PIN); }
void data_hi(void) {
    setPinInputHigh(PS2_DATA_PIN);
}

bool data_in(void) {
    setPinInputHigh(PS2_DATA_PIN);

M platforms/avr/drivers/ps2/ps2_usart.c => platforms/avr/drivers/ps2/ps2_usart.c +4 -4
@@ 76,7 76,7 @@ static inline bool    pbuf_has_data(void);
static inline void    pbuf_clear(void);

void ps2_host_init(void) {
    idle();  // without this many USART errors occur when cable is disconnected
    idle(); // without this many USART errors occur when cable is disconnected
    PS2_USART_INIT();
    PS2_USART_RX_INT_ON();
    // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)


@@ 91,12 91,12 @@ uint8_t ps2_host_send(uint8_t data) {

    /* terminate a transmission if we have */
    inhibit();
    _delay_us(100);  // [4]p.13
    _delay_us(100); // [4]p.13

    /* 'Request to Send' and Start bit */
    data_lo();
    clock_hi();
    WAIT(clock_lo, 10000, 10);  // 10ms [5]p.50
    WAIT(clock_lo, 10000, 10); // 10ms [5]p.50

    /* Data bit[2-9] */
    for (uint8_t i = 0; i < 8; i++) {


@@ 165,7 165,7 @@ uint8_t ps2_host_recv(void) {

ISR(PS2_USART_RX_VECT) {
    // TODO: request RESEND when error occurs?
    uint8_t error = PS2_USART_ERROR;  // USART error should be read before data
    uint8_t error = PS2_USART_ERROR; // USART error should be read before data
    uint8_t data  = PS2_USART_RX_DATA;
    if (!error) {
        pbuf_enqueue(data);

M platforms/avr/drivers/serial.c => platforms/avr/drivers/serial.c +66 -50
@@ 156,59 156,59 @@

#        if SELECT_SOFT_SERIAL_SPEED == 0
// Very High speed
#            define SERIAL_DELAY 4  // micro sec
#            define SERIAL_DELAY 4 // micro sec
#            if __GNUC__ < 6
#                define READ_WRITE_START_ADJUST 33  // cycles
#                define READ_WRITE_WIDTH_ADJUST 3   // cycles
#                define READ_WRITE_START_ADJUST 33 // cycles
#                define READ_WRITE_WIDTH_ADJUST 3  // cycles
#            else
#                define READ_WRITE_START_ADJUST 34  // cycles
#                define READ_WRITE_WIDTH_ADJUST 7   // cycles
#                define READ_WRITE_START_ADJUST 34 // cycles
#                define READ_WRITE_WIDTH_ADJUST 7  // cycles
#            endif
#        elif SELECT_SOFT_SERIAL_SPEED == 1
// High speed
#            define SERIAL_DELAY 6  // micro sec
#            define SERIAL_DELAY 6 // micro sec
#            if __GNUC__ < 6
#                define READ_WRITE_START_ADJUST 30  // cycles
#                define READ_WRITE_WIDTH_ADJUST 3   // cycles
#                define READ_WRITE_START_ADJUST 30 // cycles
#                define READ_WRITE_WIDTH_ADJUST 3  // cycles
#            else
#                define READ_WRITE_START_ADJUST 33  // cycles
#                define READ_WRITE_WIDTH_ADJUST 7   // cycles
#                define READ_WRITE_START_ADJUST 33 // cycles
#                define READ_WRITE_WIDTH_ADJUST 7  // cycles
#            endif
#        elif SELECT_SOFT_SERIAL_SPEED == 2
// Middle speed
#            define SERIAL_DELAY 12             // micro sec
#            define READ_WRITE_START_ADJUST 30  // cycles
#            define SERIAL_DELAY 12            // micro sec
#            define READ_WRITE_START_ADJUST 30 // cycles
#            if __GNUC__ < 6
#                define READ_WRITE_WIDTH_ADJUST 3  // cycles
#                define READ_WRITE_WIDTH_ADJUST 3 // cycles
#            else
#                define READ_WRITE_WIDTH_ADJUST 7  // cycles
#                define READ_WRITE_WIDTH_ADJUST 7 // cycles
#            endif
#        elif SELECT_SOFT_SERIAL_SPEED == 3
// Low speed
#            define SERIAL_DELAY 24             // micro sec
#            define READ_WRITE_START_ADJUST 30  // cycles
#            define SERIAL_DELAY 24            // micro sec
#            define READ_WRITE_START_ADJUST 30 // cycles
#            if __GNUC__ < 6
#                define READ_WRITE_WIDTH_ADJUST 3  // cycles
#                define READ_WRITE_WIDTH_ADJUST 3 // cycles
#            else
#                define READ_WRITE_WIDTH_ADJUST 7  // cycles
#                define READ_WRITE_WIDTH_ADJUST 7 // cycles
#            endif
#        elif SELECT_SOFT_SERIAL_SPEED == 4
// Very Low speed
#            define SERIAL_DELAY 36             // micro sec
#            define READ_WRITE_START_ADJUST 30  // cycles
#            define SERIAL_DELAY 36            // micro sec
#            define READ_WRITE_START_ADJUST 30 // cycles
#            if __GNUC__ < 6
#                define READ_WRITE_WIDTH_ADJUST 3  // cycles
#                define READ_WRITE_WIDTH_ADJUST 3 // cycles
#            else
#                define READ_WRITE_WIDTH_ADJUST 7  // cycles
#                define READ_WRITE_WIDTH_ADJUST 7 // cycles
#            endif
#        elif SELECT_SOFT_SERIAL_SPEED == 5
// Ultra Low speed
#            define SERIAL_DELAY 48             // micro sec
#            define READ_WRITE_START_ADJUST 30  // cycles
#            define SERIAL_DELAY 48            // micro sec
#            define READ_WRITE_START_ADJUST 30 // cycles
#            if __GNUC__ < 6
#                define READ_WRITE_WIDTH_ADJUST 3  // cycles
#                define READ_WRITE_WIDTH_ADJUST 3 // cycles
#            else
#                define READ_WRITE_WIDTH_ADJUST 7  // cycles
#                define READ_WRITE_WIDTH_ADJUST 7 // cycles
#            endif
#        else
#            error invalid SELECT_SOFT_SERIAL_SPEED value


@@ 223,29 223,45 @@
#    define SLAVE_INT_ACK_WIDTH 4

inline static void serial_delay(void) ALWAYS_INLINE;
inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); }
inline static void serial_delay(void) {
    _delay_us(SERIAL_DELAY);
}

inline static void serial_delay_half1(void) ALWAYS_INLINE;
inline static void serial_delay_half1(void) { _delay_us(SERIAL_DELAY_HALF1); }
inline static void serial_delay_half1(void) {
    _delay_us(SERIAL_DELAY_HALF1);
}

inline static void serial_delay_half2(void) ALWAYS_INLINE;
inline static void serial_delay_half2(void) { _delay_us(SERIAL_DELAY_HALF2); }
inline static void serial_delay_half2(void) {
    _delay_us(SERIAL_DELAY_HALF2);
}

inline static void serial_output(void) ALWAYS_INLINE;
inline static void serial_output(void) { setPinOutput(SOFT_SERIAL_PIN); }
inline static void serial_output(void) {
    setPinOutput(SOFT_SERIAL_PIN);
}

// make the serial pin an input with pull-up resistor
inline static void serial_input_with_pullup(void) ALWAYS_INLINE;
inline static void serial_input_with_pullup(void) { setPinInputHigh(SOFT_SERIAL_PIN); }
inline static void serial_input_with_pullup(void) {
    setPinInputHigh(SOFT_SERIAL_PIN);
}

inline static uint8_t serial_read_pin(void) ALWAYS_INLINE;
inline static uint8_t serial_read_pin(void) { return !!readPin(SOFT_SERIAL_PIN); }
inline static uint8_t serial_read_pin(void) {
    return !!readPin(SOFT_SERIAL_PIN);
}

inline static void serial_low(void) ALWAYS_INLINE;
inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
inline static void serial_low(void) {
    writePinLow(SOFT_SERIAL_PIN);
}

inline static void serial_high(void) ALWAYS_INLINE;
inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
inline static void serial_high(void) {
    writePinHigh(SOFT_SERIAL_PIN);
}

void soft_serial_initiator_init(void) {
    serial_output();


@@ 286,7 302,7 @@ static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) {

    _delay_sub_us(READ_WRITE_START_ADJUST);
    for (i = 0, byte = 0, p = PARITY; i < bit; i++) {
        serial_delay_half1();  // read the middle of pulses
        serial_delay_half1(); // read the middle of pulses
        if (serial_read_pin()) {
            byte = (byte << 1) | 1;
            p ^= 1;


@@ 298,7 314,7 @@ static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) {
        serial_delay_half2();
    }
    /* recive parity bit */
    serial_delay_half1();  // read the middle of pulses
    serial_delay_half1(); // read the middle of pulses
    pb = serial_read_pin();
    _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
    serial_delay_half2();


@@ 330,7 346,7 @@ void serial_write_chunk(uint8_t data, uint8_t bit) {
    }
    serial_delay();

    serial_low();  // sync_send() / senc_recv() need raise edge
    serial_low(); // sync_send() / senc_recv() need raise edge
}

static void serial_send_packet(uint8_t *buffer, uint8_t size) NO_INLINE;


@@ 356,19 372,19 @@ static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) {
}

inline static void change_sender2reciver(void) {
    sync_send();                 // 0
    serial_delay_half1();        // 1
    serial_low();                // 2
    serial_input_with_pullup();  // 2
    serial_delay_half1();        // 3
    sync_send();                // 0
    serial_delay_half1();       // 1
    serial_low();               // 2
    serial_input_with_pullup(); // 2
    serial_delay_half1();       // 3
}

inline static void change_reciver2sender(void) {
    sync_recv();           // 0
    serial_delay();        // 1
    serial_low();          // 3
    serial_output();       // 3
    serial_delay_half1();  // 4
    sync_recv();          // 0
    serial_delay();       // 1
    serial_low();         // 3
    serial_output();      // 3
    serial_delay_half1(); // 4
}

static inline uint8_t nibble_bits_count(uint8_t bits) {


@@ 391,11 407,11 @@ ISR(SERIAL_PIN_INTERRUPT) {
    }
    serial_delay_half1();

    serial_high();  // response step1 low->high
    serial_high(); // response step1 low->high
    serial_output();
    _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT * SLAVE_INT_ACK_WIDTH);
    split_transaction_desc_t *trans = &split_transaction_table[tid];
    serial_low();  // response step2 ack high->low
    serial_low(); // response step2 ack high->low

    // If the transaction has a callback, we can execute it now
    if (trans->slave_callback) {


@@ 412,7 428,7 @@ ISR(SERIAL_PIN_INTERRUPT) {
        serial_recive_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size);
    }

    sync_recv();  // weit initiator output to high
    sync_recv(); // weit initiator output to high
}

/////////

M platforms/avr/drivers/spi_master.c => platforms/avr/drivers/spi_master.c +1 -1
@@ 125,7 125,7 @@ spi_status_t spi_write(uint8_t data) {
}

spi_status_t spi_read() {
    SPDR = 0x00;  // Dummy
    SPDR = 0x00; // Dummy

    uint16_t timeout_timer = timer_read();
    while (!(SPSR & _BV(SPIF))) {

M platforms/avr/drivers/ssd1306.c => platforms/avr/drivers/ssd1306.c +16 -6
@@ 161,7 161,7 @@ bool iota_gfx_init(void) {
    send_cmd1(DeActivateScroll);
    send_cmd1(DisplayOn);

    send_cmd2(SetContrast, 0);  // Dim
    send_cmd2(SetContrast, 0); // Dim

    clear_display();



@@ 226,7 226,9 @@ void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) {
    matrix_write_char_inner(matrix, c);
}

void iota_gfx_write_char(uint8_t c) { matrix_write_char(&display, c); }
void iota_gfx_write_char(uint8_t c) {
    matrix_write_char(&display, c);
}

void matrix_write(struct CharacterMatrix *matrix, const char *data) {
    const char *end = data + strlen(data);


@@ 236,7 238,9 @@ void matrix_write(struct CharacterMatrix *matrix, const char *data) {
    }
}

void iota_gfx_write(const char *data) { matrix_write(&display, data); }
void iota_gfx_write(const char *data) {
    matrix_write(&display, data);
}

void matrix_write_P(struct CharacterMatrix *matrix, const char *data) {
    while (true) {


@@ 249,7 253,9 @@ void matrix_write_P(struct CharacterMatrix *matrix, const char *data) {
    }
}

void iota_gfx_write_P(const char *data) { matrix_write_P(&display, data); }
void iota_gfx_write_P(const char *data) {
    matrix_write_P(&display, data);
}

void matrix_clear(struct CharacterMatrix *matrix) {
    memset(matrix->display, ' ', sizeof(matrix->display));


@@ 257,7 263,9 @@ void matrix_clear(struct CharacterMatrix *matrix) {
    matrix->dirty  = true;
}

void iota_gfx_clear_screen(void) { matrix_clear(&display); }
void iota_gfx_clear_screen(void) {
    matrix_clear(&display);
}

void matrix_render(struct CharacterMatrix *matrix) {
    last_flush = timer_read();


@@ 301,7 309,9 @@ done:
#    endif
}

void iota_gfx_flush(void) { matrix_render(&display); }
void iota_gfx_flush(void) {
    matrix_render(&display);
}

__attribute__((weak)) void iota_gfx_task_user(void) {}


M platforms/avr/drivers/uart.c => platforms/avr/drivers/uart.c +2 -2
@@ 108,7 108,7 @@ void uart_write(uint8_t data) {
    // return immediately to avoid deadlock when interrupt is disabled(called from ISR)
    if (tx_buffer_tail == i && (SREG & (1 << SREG_I)) == 0) return;
    while (tx_buffer_tail == i)
        ;  // wait until space in buffer
        ; // wait until space in buffer
    // cli();
    tx_buffer[i]   = data;
    tx_buffer_head = i;


@@ 121,7 121,7 @@ uint8_t uart_read(void) {
    uint8_t data, i;

    while (rx_buffer_head == rx_buffer_tail)
        ;  // wait for character
        ; // wait for character
    i = rx_buffer_tail + 1;
    if (i >= RX_BUFFER_SIZE) i = 0;
    data           = rx_buffer[i];

M platforms/avr/drivers/ws2812.c => platforms/avr/drivers/ws2812.c +7 -7
@@ 110,7 110,7 @@ static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t

        asm volatile("       ldi   %0,8  \n\t"
                     "loop%=:            \n\t"
                     "       out   %2,%3 \n\t"  //  '1' [01] '0' [01] - re
                     "       out   %2,%3 \n\t" //  '1' [01] '0' [01] - re
#if (w1_nops & 1)
                     w_nop1
#endif


@@ 126,9 126,9 @@ static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t
#if (w1_nops & 16)
                                     w_nop16
#endif
                     "       sbrs  %1,7  \n\t"  //  '1' [03] '0' [02]
                     "       out   %2,%4 \n\t"  //  '1' [--] '0' [03] - fe-low
                     "       lsl   %1    \n\t"  //  '1' [04] '0' [04]
                     "       sbrs  %1,7  \n\t" //  '1' [03] '0' [02]
                     "       out   %2,%4 \n\t" //  '1' [--] '0' [03] - fe-low
                     "       lsl   %1    \n\t" //  '1' [04] '0' [04]
#if (w2_nops & 1)
                     w_nop1
#endif


@@ 144,7 144,7 @@ static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t
#if (w2_nops & 16)
                                     w_nop16
#endif
                     "       out   %2,%4 \n\t"  //  '1' [+1] '0' [+1] - fe-high
                     "       out   %2,%4 \n\t" //  '1' [+1] '0' [+1] - fe-high
#if (w3_nops & 1)
                     w_nop1
#endif


@@ 161,8 161,8 @@ static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t
                                     w_nop16
#endif

                     "       dec   %0    \n\t"  //  '1' [+2] '0' [+2]
                     "       brne  loop%=\n\t"  //  '1' [+3] '0' [+4]
                     "       dec   %0    \n\t" //  '1' [+2] '0' [+2]
                     "       brne  loop%=\n\t" //  '1' [+3] '0' [+4]
                     : "=&d"(ctr)
                     : "r"(curbyte), "I"(_SFR_IO_ADDR(PORTx_ADDRESS(RGB_DI_PIN))), "r"(maskhi), "r"(masklo));
    }

M platforms/avr/drivers/ws2812_i2c.c => platforms/avr/drivers/ws2812_i2c.c +3 -1
@@ 13,7 13,9 @@
#    define WS2812_TIMEOUT 100
#endif

void ws2812_init(void) { i2c_init(); }
void ws2812_init(void) {
    i2c_init();
}

// Setleds for standard RGB
void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {

M platforms/avr/pin_defs.h => platforms/avr/pin_defs.h +1 -1
@@ 17,7 17,7 @@

#include <avr/io.h>

#define PORT_SHIFTER 4  // this may be 4 for all AVR chips
#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

M platforms/avr/printf.c => platforms/avr/printf.c +3 -1
@@ 17,4 17,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include "xprintf.h"
#include "sendchar.h"

void print_set_sendchar(sendchar_func_t func) { xdev_out(func); }
void print_set_sendchar(sendchar_func_t func) {
    xdev_out(func);
}

M platforms/avr/sleep_led.c => platforms/avr/sleep_led.c +1 -1
@@ 12,7 12,7 @@
#if SLEEP_LED_TIMER == 1
#    define TCCRxB TCCR1B
#    define TIMERx_COMPA_vect TIMER1_COMPA_vect
#    if defined(__AVR_ATmega32A__)  // This MCU has only one TIMSK register
#    if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
#        define TIMSKx TIMSK
#    else
#        define TIMSKx TIMSK1

M platforms/avr/suspend.c => platforms/avr/suspend.c +1 -1
@@ 81,7 81,7 @@ ISR(WDT_vect) {
    // compensate timer for sleep
    switch (wdt_timeout) {
        case WDTO_15MS:
            timer_count += 15 + 2;  // WDTO_15MS + 2(from observation)
            timer_count += 15 + 2; // WDTO_15MS + 2(from observation)
            break;
        default:;
    }

M platforms/avr/timer.c => platforms/avr/timer.c +18 -6
@@ 73,7 73,9 @@ void timer_init(void) {
 * FIXME: needs doc
 */
inline void timer_clear(void) {
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { timer_count = 0; }
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        timer_count = 0;
    }
}

/** \brief timer read


@@ 83,7 85,9 @@ inline void timer_clear(void) {
inline uint16_t timer_read(void) {
    uint32_t t;

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        t = timer_count;
    }

    return (t & 0xFFFF);
}


@@ 95,7 99,9 @@ inline uint16_t timer_read(void) {
inline uint32_t timer_read32(void) {
    uint32_t t;

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        t = timer_count;
    }

    return t;
}


@@ 107,7 113,9 @@ inline uint32_t timer_read32(void) {
inline uint16_t timer_elapsed(uint16_t last) {
    uint32_t t;

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        t = timer_count;
    }

    return TIMER_DIFF_16((t & 0xFFFF), last);
}


@@ 119,7 127,9 @@ inline uint16_t timer_elapsed(uint16_t last) {
inline uint32_t timer_elapsed32(uint32_t last) {
    uint32_t t;

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        t = timer_count;
    }

    return TIMER_DIFF_32(t, last);
}


@@ 130,4 140,6 @@ inline uint32_t timer_elapsed32(uint32_t last) {
#else
#    define TIMER_INTERRUPT_VECTOR TIMER0_COMP_vect
#endif
ISR(TIMER_INTERRUPT_VECTOR, ISR_NOBLOCK) { timer_count++; }
ISR(TIMER_INTERRUPT_VECTOR, ISR_NOBLOCK) {
    timer_count++;
}

M platforms/chibios/bootloaders/stm32_dfu.c => platforms/chibios/bootloaders/stm32_dfu.c +1 -1
@@ 72,7 72,7 @@ void enter_bootloader_mode_if_requested(void) {}
#    define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)

__attribute__((weak)) void bootloader_jump(void) {
    *MAGIC_ADDR = BOOTLOADER_MAGIC;  // set magic flag => reset handler will jump into boot loader
    *MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
    NVIC_SystemReset();
}


M platforms/chibios/bootloaders/stm32duino.c => platforms/chibios/bootloaders/stm32duino.c +3 -1
@@ 18,4 18,6 @@

#include <ch.h>

__attribute__((weak)) void bootloader_jump(void) { NVIC_SystemReset(); }
__attribute__((weak)) void bootloader_jump(void) {
    NVIC_SystemReset();
}

M platforms/chibios/chibios_config.h => platforms/chibios/chibios_config.h +2 -2
@@ 16,7 16,7 @@
#pragma once

#ifndef USB_VBUS_PIN
#    define SPLIT_USB_DETECT  // Force this on when dedicated pin is not used
#    define SPLIT_USB_DETECT // Force this on when dedicated pin is not used
#endif

// STM32 compatibility


@@ 76,7 76,7 @@

#    if defined(K20x) || defined(KL2x)
#        define USE_I2CV1
#        define USE_I2CV1_CONTRIB  // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed
#        define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed
#        define USE_GPIOV1
#    endif
#endif

M platforms/chibios/drivers/analog.c => platforms/chibios/drivers/analog.c +3 -3
@@ 101,9 101,9 @@

// Options are 12, 10, 8, and 6 bit.
#ifndef ADC_RESOLUTION
#    ifdef ADC_CFGR_RES_10BITS  // ADCv3, ADCv4
#    ifdef ADC_CFGR_RES_10BITS // ADCv3, ADCv4
#        define ADC_RESOLUTION ADC_CFGR_RES_10BITS
#    else  // ADCv1, ADCv5, or the bodge for ADCv2 above
#    else // ADCv1, ADCv5, or the bodge for ADCv2 above
#        define ADC_RESOLUTION ADC_CFGR1_RES_10BIT
#    endif
#endif


@@ 123,7 123,7 @@ static ADCConversionGroup adcConversionGroup = {
    .smpr  = ADC_SAMPLING_RATE,
#elif defined(USE_ADCV2)
#    if !defined(STM32F1XX) && !defined(GD32VF103)
    .cr2   = ADC_CR2_SWSTART,  // F103 seem very unhappy with, F401 seems very unhappy without...
    .cr2   = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
#    endif
    .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
    .smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),

M platforms/chibios/drivers/analog.h => platforms/chibios/drivers/analog.h +3 -1
@@ 28,7 28,9 @@ typedef struct {
    uint8_t  adc;
} adc_mux;
#define TO_MUX(i, a) \
    (adc_mux) { i, a }
    (adc_mux) {      \
        i, a         \
    }

int16_t analogReadPin(pin_t pin);
int16_t analogReadPinAdc(pin_t pin, uint8_t adc);

M platforms/chibios/drivers/audio_dac_additive.c => platforms/chibios/drivers/audio_dac_additive.c +14 -12
@@ 52,19 52,19 @@ 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
#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
#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
    [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
#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] = {


@@ 77,7 77,7 @@ static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = {
#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
#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID

static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE};



@@ 98,7 98,7 @@ typedef enum {
    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
    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;


@@ 171,7 171,7 @@ static void dac_end(DACDriver *dacp) {

    // work on the other half of the buffer
    if (dacIsBufferComplete(dacp)) {
        sample_p += AUDIO_DAC_BUFFER_SIZE / 2;  // 'half_index'
        sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index'
    }

    for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) {


@@ 196,8 196,8 @@ static void dac_end(DACDriver *dacp) {
         *   *       *
         * =====*=*================================================= 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 (((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;


@@ 220,7 220,7 @@ static void dac_end(DACDriver *dacp) {
            // -> 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
                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;
                }
            }


@@ 321,7 321,9 @@ void audio_driver_initialize() {
    gptStart(&GPTD6, &gpt6cfg1);
}

void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; }
void audio_driver_stop(void) {
    state = OUTPUT_SHOULD_STOP;
}

void audio_driver_start(void) {
    gptStartContinuous(&GPTD6, 2U);

M platforms/chibios/drivers/audio_dac_basic.c => platforms/chibios/drivers/audio_dac_basic.c +10 -6
@@ 115,13 115,15 @@ void         channel_1_set_frequency(float freq) {
    channel_1_frequency = freq;

    channel_1_stop();
    if (freq <= 0.0)  // a pause/rest has freq=0
    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; }
float channel_1_get_frequency(void) {
    return channel_1_frequency;
}

void channel_2_start(void) {
    gptStart(&GPTD7, &gpt7cfg1);


@@ 140,13 142,15 @@ void         channel_2_set_frequency(float freq) {
    channel_2_frequency = freq;

    channel_2_stop();
    if (freq <= 0.0)  // a pause/rest has freq=0
    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; }
float channel_2_get_frequency(void) {
    return channel_2_frequency;
}

static void gpt_audio_state_cb(GPTDriver *gptp) {
    if (audio_update_state()) {


@@ 155,8 159,8 @@ static void gpt_audio_state_cb(GPTDriver *gptp) {
        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
#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) {

M platforms/chibios/drivers/audio_pwm_hardware.c => platforms/chibios/drivers/audio_pwm_hardware.c +11 -7
@@ 72,7 72,7 @@ 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
    if (freq <= 0.0) // a pause/rest has freq=0
        return;

    pwmcnt_t period = (pwmCFG.frequency / freq);


@@ 82,14 82,18 @@ void         channel_1_set_frequency(float freq) {
                     PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
}

float channel_1_get_frequency(void) { return channel_1_frequency; }
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); }
void channel_1_stop(void) {
    pwmStop(&AUDIO_PWM_DRIVER);
}

static void gpt_callback(GPTDriver *gptp);
GPTConfig   gptCFG = {


@@ 108,9 112,9 @@ void audio_driver_initialize(void) {
    pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);

    // connect the AUDIO_PIN to the PWM hardware
#if defined(USE_GPIOV1)  // STM32F103C8
#if defined(USE_GPIOV1) // STM32F103C8
    palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
#else  // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
#else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
    palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE(AUDIO_PWM_PAL_MODE));
#endif



@@ 135,10 139,10 @@ void audio_driver_stop(void) {
 * and updates the pwm to output that frequency
 */
static void gpt_callback(GPTDriver *gptp) {
    float freq;  // TODO: freq_alt
    float freq; // TODO: freq_alt

    if (audio_update_state()) {
        freq = audio_get_processed_frequency(0);  // freq_alt would be index=1
        freq = audio_get_processed_frequency(0); // freq_alt would be index=1
        channel_1_set_frequency(freq);
    }
}

M platforms/chibios/drivers/audio_pwm_software.c => platforms/chibios/drivers/audio_pwm_software.c +10 -8
@@ 57,7 57,7 @@ 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
    if (freq <= 0.0) // a pause/rest has freq=0
        return;

    pwmcnt_t period = (pwmCFG.frequency / freq);


@@ 68,7 68,9 @@ void         channel_1_set_frequency(float freq) {
                     PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
}

float channel_1_get_frequency(void) { return channel_1_frequency; }
float channel_1_get_frequency(void) {
    return channel_1_frequency;
}

void channel_1_start(void) {
    pwmStop(&AUDIO_PWM_DRIVER);


@@ 81,10 83,10 @@ void channel_1_start(void) {
void channel_1_stop(void) {
    pwmStop(&AUDIO_PWM_DRIVER);

    palClearLine(AUDIO_PIN);  // leave the line low, after last note was played
    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
    palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played
#endif
}



@@ 100,7 102,7 @@ static void pwm_audio_period_callback(PWMDriver *pwmp) {
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
        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


@@ 131,7 133,7 @@ void audio_driver_initialize(void) {
    palClearLine(AUDIO_PIN_ALT);
#endif

    pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER);  // enable pwm callbacks
    pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks
    pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);

    gptStart(&AUDIO_STATE_TIMER, &gptCFG);


@@ 155,10 157,10 @@ void audio_driver_stop(void) {
 * and updates the pwm to output that frequency
 */
static void gpt_callback(GPTDriver *gptp) {
    float freq;  // TODO: freq_alt
    float freq; // TODO: freq_alt

    if (audio_update_state()) {
        freq = audio_get_processed_frequency(0);  // freq_alt would be index=1
        freq = audio_get_processed_frequency(0); // freq_alt would be index=1
        channel_1_set_frequency(freq);
    }
}

M platforms/chibios/drivers/eeprom/eeprom_stm32_L0_L1.h => platforms/chibios/drivers/eeprom/eeprom_stm32_L0_L1.h +1 -1
@@ 24,7 24,7 @@
#        define STM32_ONBOARD_EEPROM_SIZE 1024
#    else
#        include "eeconfig.h"
#        define STM32_ONBOARD_EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4)  // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO and EEPROM page sizing
#        define STM32_ONBOARD_EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO and EEPROM page sizing
#    endif
#endif


M platforms/chibios/drivers/i2c_master.c => platforms/chibios/drivers/i2c_master.c +3 -1
@@ 203,4 203,6 @@ i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uin
    return chibios_to_qmk(&status);
}

void i2c_stop(void) { i2cStop(&I2C_DRIVER); }
void i2c_stop(void) {
    i2cStop(&I2C_DRIVER);
}

M platforms/chibios/drivers/serial.c => platforms/chibios/drivers/serial.c +26 -10
@@ 50,14 50,30 @@
#    error invalid SELECT_SOFT_SERIAL_SPEED value
#endif

inline static void serial_delay(void) { wait_us(SERIAL_DELAY); }
inline static void serial_delay_half(void) { wait_us(SERIAL_DELAY / 2); }
inline static void serial_delay_blip(void) { wait_us(1); }
inline static void serial_output(void) { setPinOutput(SOFT_SERIAL_PIN); }
inline static void serial_input(void) { setPinInputHigh(SOFT_SERIAL_PIN); }
inline static bool serial_read_pin(void) { return !!readPin(SOFT_SERIAL_PIN); }
inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
inline static void serial_delay(void) {
    wait_us(SERIAL_DELAY);
}
inline static void serial_delay_half(void) {
    wait_us(SERIAL_DELAY / 2);
}
inline static void serial_delay_blip(void) {
    wait_us(1);
}
inline static void serial_output(void) {
    setPinOutput(SOFT_SERIAL_PIN);
}
inline static void serial_input(void) {
    setPinInputHigh(SOFT_SERIAL_PIN);
}
inline static bool serial_read_pin(void) {
    return !!readPin(SOFT_SERIAL_PIN);
}
inline static void serial_low(void) {
    writePinLow(SOFT_SERIAL_PIN);
}
inline static void serial_high(void) {
    writePinHigh(SOFT_SERIAL_PIN);
}

void interrupt_handler(void *arg);



@@ 226,7 242,7 @@ bool soft_serial_transaction(int sstd_index) {

    uint8_t checksum = 0;
    // send data to the slave
    serial_write_byte(sstd_index);  // first chunk is transaction id
    serial_write_byte(sstd_index); // first chunk is transaction id
    sync_recv();

    for (int i = 0; i < trans->initiator2target_buffer_size; ++i) {


@@ 238,7 254,7 @@ bool soft_serial_transaction(int sstd_index) {
    sync_recv();

    serial_delay();
    serial_delay();  // read mid pulses
    serial_delay(); // read mid pulses

    // receive data from the slave
    uint8_t checksum_computed = 0;

M platforms/chibios/drivers/serial_usart.c => platforms/chibios/drivers/serial_usart.c +1 -1
@@ 238,7 238,7 @@ void soft_serial_initiator_init(void) {
    usart_master_init(&serial_driver);

#if defined(MCU_STM32) && defined(SERIAL_USART_PIN_SWAP)
    serial_config.cr2 |= USART_CR2_SWAP;  // master has swapped TX/RX pins
    serial_config.cr2 |= USART_CR2_SWAP; // master has swapped TX/RX pins
#endif

    sdStart(serial_driver, &serial_config);

M platforms/chibios/drivers/serial_usart.h => platforms/chibios/drivers/serial_usart.h +3 -3
@@ 50,15 50,15 @@
#endif

#if !defined(USART_CR1_M0)
#    define USART_CR1_M0 USART_CR1_M  // some platforms (f1xx) dont have this so
#    define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
#endif

#if !defined(SERIAL_USART_CR1)
#    define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0)  // parity enable, odd parity, 9 bit length
#    define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0) // parity enable, odd parity, 9 bit length
#endif

#if !defined(SERIAL_USART_CR2)
#    define SERIAL_USART_CR2 (USART_CR2_STOP_1)  // 2 stop bits
#    define SERIAL_USART_CR2 (USART_CR2_STOP_1) // 2 stop bits
#endif

#if !defined(SERIAL_USART_CR3)

M platforms/chibios/drivers/spi_master.c => platforms/chibios/drivers/spi_master.c +1 -1
@@ 115,7 115,7 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {

#elif defined(HT32)
    spiConfig.cr0 = SPI_CR0_SELOEN;
    spiConfig.cr1 = SPI_CR1_MODE | 8;  // 8 bits and in master mode
    spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode

    if (lsbFirst) {
        spiConfig.cr1 |= SPI_CR1_FIRSTBIT;

M platforms/chibios/drivers/uart.c => platforms/chibios/drivers/uart.c +12 -4
@@ 43,7 43,9 @@ void uart_init(uint32_t baud) {
    }
}

void uart_write(uint8_t data) { sdPut(&SERIAL_DRIVER, c); }
void uart_write(uint8_t data) {
    sdPut(&SERIAL_DRIVER, c);
}

uint8_t uart_read(void) {
    msg_t res = sdGet(&SERIAL_DRIVER);


@@ 51,8 53,14 @@ uint8_t uart_read(void) {
    return (uint8_t)res;
}

void uart_transmit(const uint8_t *data, uint16_t length) { sdWrite(&SERIAL_DRIVER, data, length); }
void uart_transmit(const uint8_t *data, uint16_t length) {
    sdWrite(&SERIAL_DRIVER, data, length);
}

void uart_receive(uint8_t *data, uint16_t length) { sdRead(&SERIAL_DRIVER, data, length); }
void uart_receive(uint8_t *data, uint16_t length) {
    sdRead(&SERIAL_DRIVER, data, length);
}

bool uart_available(void) { return !sdGetWouldBlock(&SERIAL_DRIVER); }
bool uart_available(void) {
    return !sdGetWouldBlock(&SERIAL_DRIVER);
}

M platforms/chibios/drivers/usbpd_stm32g4.c => platforms/chibios/drivers/usbpd_stm32g4.c +2 -2
@@ 18,7 18,7 @@

#ifndef USBPD_UCPD1_CFG1
#    define USBPD_UCPD1_CFG1 (UCPD_CFG1_PSC_UCPDCLK_0 | UCPD_CFG1_TRANSWIN_3 | UCPD_CFG1_IFRGAP_4 | UCPD_CFG1_HBITCLKDIV_4)
#endif  // USBPD_UCPD1_CFG1
#endif // USBPD_UCPD1_CFG1

// Initialises the USBPD subsystem
__attribute__((weak)) void usbpd_init(void) {


@@ 64,7 64,7 @@ __attribute__((weak)) usbpd_allowance_t usbpd_get_allowance(void) {
        switch (vstate_max) {
            case 0:
            case 1:
                return USBPD_500MA;  // Note that this is 500mA (i.e. max USB 2.0), not 900mA, as we're not using USB 3.1 as a sink device.
                return USBPD_500MA; // Note that this is 500mA (i.e. max USB 2.0), not 900mA, as we're not using USB 3.1 as a sink device.
            case 2:
                return USBPD_1500MA;
            case 3:

M platforms/chibios/drivers/ws2812.c => platforms/chibios/drivers/ws2812.c +6 -4
@@ 10,7 10,7 @@
#        define NOP_FUDGE 0.4
#    else
#        error("NOP_FUDGE configuration required")
#        define NOP_FUDGE 1  // this just pleases the compile so the above error is easier to spot
#        define NOP_FUDGE 1 // this just pleases the compile so the above error is easier to spot
#    endif
#endif



@@ 25,12 25,12 @@
// The reset gap can be 6000 ns, but depending on the LED strip it may have to be increased
// to values like 600000 ns. If it is too small, the pixels will show nothing most of the time.
#ifndef WS2812_RES
#    define WS2812_RES (1000 * WS2812_TRST_US)  // Width of the low gap between bits to cause a frame to latch
#    define WS2812_RES (1000 * WS2812_TRST_US) // Width of the low gap between bits to cause a frame to latch
#endif

#define NUMBER_NOPS 6
#define CYCLES_PER_SEC (CPU_CLOCK / NUMBER_NOPS * NOP_FUDGE)
#define NS_PER_SEC (1000000000L)  // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
#define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC)
#define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE)



@@ 67,7 67,9 @@ void sendByte(uint8_t byte) {
    }
}

void ws2812_init(void) { palSetLineMode(RGB_DI_PIN, WS2812_OUTPUT_MODE); }
void ws2812_init(void) {
    palSetLineMode(RGB_DI_PIN, WS2812_OUTPUT_MODE);
}

// Setleds for standard RGB
void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {

M platforms/chibios/drivers/ws2812_pwm.c => platforms/chibios/drivers/ws2812_pwm.c +16 -14
@@ 11,19 11,19 @@
#endif

#ifndef WS2812_PWM_DRIVER
#    define WS2812_PWM_DRIVER PWMD2  // TIMx
#    define WS2812_PWM_DRIVER PWMD2 // TIMx
#endif
#ifndef WS2812_PWM_CHANNEL
#    define WS2812_PWM_CHANNEL 2  // Channel
#    define WS2812_PWM_CHANNEL 2 // Channel
#endif
#ifndef WS2812_PWM_PAL_MODE
#    define WS2812_PWM_PAL_MODE 2  // DI Pin's alternate function value
#    define WS2812_PWM_PAL_MODE 2 // DI Pin's alternate function value
#endif
#ifndef WS2812_DMA_STREAM
#    define WS2812_DMA_STREAM STM32_DMA1_STREAM2  // DMA Stream for TIMx_UP
#    define WS2812_DMA_STREAM STM32_DMA1_STREAM2 // DMA Stream for TIMx_UP
#endif
#ifndef WS2812_DMA_CHANNEL
#    define WS2812_DMA_CHANNEL 2  // DMA Channel for TIMx_UP
#    define WS2812_DMA_CHANNEL 2 // DMA Channel for TIMx_UP
#endif
#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_DMAMUX_ID)
#    error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM?_UP"


@@ 56,7 56,7 @@

#ifndef WS2812_PWM_TARGET_PERIOD
//#    define WS2812_PWM_TARGET_PERIOD 800000 // Original code is 800k...?
#    define WS2812_PWM_TARGET_PERIOD 80000  // TODO: work out why 10x less on f303/f4x1
#    define WS2812_PWM_TARGET_PERIOD 80000 // TODO: work out why 10x less on f303/f4x1
#endif

/* --- PRIVATE CONSTANTS ---------------------------------------------------- */


@@ 259,8 259,10 @@ write/read to/from the other buffer).
void ws2812_init(void) {
    // Initialize led frame buffer
    uint32_t i;
    for (i = 0; i < WS2812_COLOR_BIT_N; i++) ws2812_frame_buffer[i] = WS2812_DUTYCYCLE_0;      // All color bits are zero duty cycle
    for (i = 0; i < WS2812_RESET_BIT_N; i++) ws2812_frame_buffer[i + WS2812_COLOR_BIT_N] = 0;  // All reset bits are zero
    for (i = 0; i < WS2812_COLOR_BIT_N; i++)
        ws2812_frame_buffer[i] = WS2812_DUTYCYCLE_0; // All color bits are zero duty cycle
    for (i = 0; i < WS2812_RESET_BIT_N; i++)
        ws2812_frame_buffer[i + WS2812_COLOR_BIT_N] = 0; // All reset bits are zero

    palSetLineMode(RGB_DI_PIN, WS2812_OUTPUT_MODE);



@@ 268,22 270,22 @@ void ws2812_init(void) {
    //#pragma GCC diagnostic ignored "-Woverride-init"  // Turn off override-init warning for this struct. We use the overriding ability to set a "default" channel config
    static const PWMConfig ws2812_pwm_config = {
        .frequency = WS2812_PWM_FREQUENCY,
        .period    = WS2812_PWM_PERIOD,  // Mit dieser Periode wird UDE-Event erzeugt und ein neuer Wert (Länge WS2812_BIT_N) vom DMA ins CCR geschrieben
        .period    = WS2812_PWM_PERIOD, // Mit dieser Periode wird UDE-Event erzeugt und ein neuer Wert (Länge WS2812_BIT_N) vom DMA ins CCR geschrieben
        .callback  = NULL,
        .channels =
            {
                [0 ... 3]                = {.mode = PWM_OUTPUT_DISABLED, .callback = NULL},     // Channels default to disabled
                [WS2812_PWM_CHANNEL - 1] = {.mode = WS2812_PWM_OUTPUT_MODE, .callback = NULL},  // Turn on the channel we care about
                [0 ... 3]                = {.mode = PWM_OUTPUT_DISABLED, .callback = NULL},    // Channels default to disabled
                [WS2812_PWM_CHANNEL - 1] = {.mode = WS2812_PWM_OUTPUT_MODE, .callback = NULL}, // Turn on the channel we care about
            },
        .cr2  = 0,
        .dier = TIM_DIER_UDE,  // DMA on update event for next period
        .dier = TIM_DIER_UDE, // DMA on update event for next period
    };
    //#pragma GCC diagnostic pop  // Restore command-line warning options

    // Configure DMA
    // dmaInit(); // Joe added this
    dmaStreamAlloc(WS2812_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL);
    dmaStreamSetPeripheral(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1]));  // Ziel ist der An-Zeit im Cap-Comp-Register
    dmaStreamSetPeripheral(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
    dmaStreamSetMemory0(WS2812_DMA_STREAM, ws2812_frame_buffer);
    dmaStreamSetTransactionSize(WS2812_DMA_STREAM, WS2812_BIT_N);
    dmaStreamSetMode(WS2812_DMA_STREAM, STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) | STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3));


@@ 302,7 304,7 @@ void ws2812_init(void) {
    // ChibiOS driver code, so we don't have to do anything special to the timer. If we did, we'd have to start the timer,
    // disable counting, enable the channel, and then make whatever configuration changes we need.
    pwmStart(&WS2812_PWM_DRIVER, &ws2812_pwm_config);
    pwmEnableChannel(&WS2812_PWM_DRIVER, WS2812_PWM_CHANNEL - 1, 0);  // Initial period is 0; output will be low until first duty cycle is DMA'd in
    pwmEnableChannel(&WS2812_PWM_DRIVER, WS2812_PWM_CHANNEL - 1, 0); // Initial period is 0; output will be low until first duty cycle is DMA'd in
}

void ws2812_write_led(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b) {

M platforms/chibios/drivers/ws2812_spi.c => platforms/chibios/drivers/ws2812_spi.c +25 -15
@@ 42,7 42,7 @@
#    define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_0)
#elif WS2812_SPI_DIVISOR == 8
#    define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1)
#elif WS2812_SPI_DIVISOR == 16  // same as default
#elif WS2812_SPI_DIVISOR == 16 // same as default
#    define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0)
#elif WS2812_SPI_DIVISOR == 32
#    define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2)


@@ 53,14 53,14 @@
#elif WS2812_SPI_DIVISOR == 256
#    define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
#else
#    define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0)  // default
#    define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0) // default
#endif

// Use SPI circular buffer
#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
#    define WS2812_SPI_BUFFER_MODE 1  // circular buffer
#    define WS2812_SPI_BUFFER_MODE 1 // circular buffer
#else
#    define WS2812_SPI_BUFFER_MODE 0  // normal buffer
#    define WS2812_SPI_BUFFER_MODE 0 // normal buffer
#endif

#if defined(USE_GPIOV1)


@@ 104,20 104,30 @@ static void set_led_color_rgb(LED_TYPE color, int pos) {
    uint8_t* tx_start = &txbuf[PREAMBLE_SIZE];

#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.g, j);
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.r, j);
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.g, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.r, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j);
#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.r, j);
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j);
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.r, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j);
#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.b, j);
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j);
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.b, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j);
#endif
#ifdef RGBW
    for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 4 + j] = get_protocol_eq(color.w, j);
    for (int j = 0; j < 4; j++)
        tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 4 + j] = get_protocol_eq(color.w, j);
#endif
}



@@ 126,7 136,7 @@ void ws2812_init(void) {

#ifdef WS2812_SPI_SCK_PIN
    palSetLineMode(WS2812_SPI_SCK_PIN, WS2812_SCK_OUTPUT_MODE);
#endif  // WS2812_SPI_SCK_PIN
#endif // WS2812_SPI_SCK_PIN

    // TODO: more dynamic baudrate
    static const SPIConfig spicfg = {WS2812_SPI_BUFFER_MODE, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN), WS2812_SPI_DIVISOR_CR1_BR_X};

M platforms/chibios/eeprom_stm32.c => platforms/chibios/eeprom_stm32.c +6 -2
@@ 560,9 560,13 @@ uint16_t EEPROM_ReadDataWord(uint16_t Address) {
/*****************************************************************************
 *  Bind to eeprom_driver.c
 *******************************************************************************/
void eeprom_driver_init(void) { EEPROM_Init(); }
void eeprom_driver_init(void) {
    EEPROM_Init();
}

void eeprom_driver_erase(void) { EEPROM_Erase(); }
void eeprom_driver_erase(void) {
    EEPROM_Erase();
}

void eeprom_read_block(void *buf, const void *addr, size_t len) {
    const uint8_t *src  = (const uint8_t *)addr;

M platforms/chibios/eeprom_stm32_defs.h => platforms/chibios/eeprom_stm32_defs.h +13 -13
@@ 20,41 20,41 @@
#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT)
#    if defined(STM32F103xB) || defined(STM32F042x6) || defined(GD32VF103C8) || defined(GD32VF103CB)
#        ifndef FEE_PAGE_SIZE
#            define FEE_PAGE_SIZE 0x400  // Page size = 1KByte
#            define FEE_PAGE_SIZE 0x400 // Page size = 1KByte
#        endif
#        ifndef FEE_PAGE_COUNT
#            define FEE_PAGE_COUNT 2  // How many pages are used
#            define FEE_PAGE_COUNT 2 // How many pages are used
#        endif
#    elif defined(STM32F103xE) || defined(STM32F303xC) || defined(STM32F072xB) || defined(STM32F070xB)
#        ifndef FEE_PAGE_SIZE
#            define FEE_PAGE_SIZE 0x800  // Page size = 2KByte
#            define FEE_PAGE_SIZE 0x800 // Page size = 2KByte
#        endif
#        ifndef FEE_PAGE_COUNT
#            define FEE_PAGE_COUNT 4  // How many pages are used
#            define FEE_PAGE_COUNT 4 // How many pages are used
#        endif
#    elif defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE)
#        ifndef FEE_PAGE_SIZE
#            define FEE_PAGE_SIZE 0x4000  // Page size = 16KByte
#            define FEE_PAGE_SIZE 0x4000 // Page size = 16KByte
#        endif
#        ifndef FEE_PAGE_COUNT
#            define FEE_PAGE_COUNT 1  // How many pages are used
#            define FEE_PAGE_COUNT 1 // How many pages are used
#        endif
#    endif
#endif

#if !defined(FEE_MCU_FLASH_SIZE)
#    if defined(STM32F042x6)
#        define FEE_MCU_FLASH_SIZE 32  // Size in Kb
#        define FEE_MCU_FLASH_SIZE 32 // Size in Kb
#    elif defined(GD32VF103C8)
#        define FEE_MCU_FLASH_SIZE 64  // Size in Kb
#        define FEE_MCU_FLASH_SIZE 64 // Size in Kb
#    elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB) || defined(GD32VF103CB)
#        define FEE_MCU_FLASH_SIZE 128  // Size in Kb
#        define FEE_MCU_FLASH_SIZE 128 // Size in Kb
#    elif defined(STM32F303xC) || defined(STM32F401xC)
#        define FEE_MCU_FLASH_SIZE 256  // Size in Kb
#        define FEE_MCU_FLASH_SIZE 256 // Size in Kb
#    elif defined(STM32F103xE) || defined(STM32F401xE) || defined(STM32F411xE)
#        define FEE_MCU_FLASH_SIZE 512  // Size in Kb
#        define FEE_MCU_FLASH_SIZE 512 // Size in Kb
#    elif defined(STM32F405xG)
#        define FEE_MCU_FLASH_SIZE 1024  // Size in Kb
#        define FEE_MCU_FLASH_SIZE 1024 // Size in Kb
#    endif
#endif



@@ 62,7 62,7 @@
#if !defined(FEE_PAGE_BASE_ADDRESS)
#    if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE)
#        ifndef FEE_PAGE_BASE_ADDRESS
#            define FEE_PAGE_BASE_ADDRESS 0x08004000  // bodge to force 2nd 16k page
#            define FEE_PAGE_BASE_ADDRESS 0x08004000 // bodge to force 2nd 16k page
#        endif
#    else
#        ifndef FEE_FLASH_BASE

M platforms/chibios/eeprom_teensy.c => platforms/chibios/eeprom_teensy.c +20 -14
@@ 60,19 60,19 @@

// Minimum EEPROM Endurance
// ------------------------
#    if (EEPROM_SIZE == 2048)  // 35000 writes/byte or 70000 writes/word
#    if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
#        define EEESIZE 0x33
#    elif (EEPROM_SIZE == 1024)  // 75000 writes/byte or 150000 writes/word
#    elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
#        define EEESIZE 0x34
#    elif (EEPROM_SIZE == 512)  // 155000 writes/byte or 310000 writes/word
#    elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
#        define EEESIZE 0x35
#    elif (EEPROM_SIZE == 256)  // 315000 writes/byte or 630000 writes/word
#    elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
#        define EEESIZE 0x36
#    elif (EEPROM_SIZE == 128)  // 635000 writes/byte or 1270000 writes/word
#    elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
#        define EEESIZE 0x37
#    elif (EEPROM_SIZE == 64)  // 1275000 writes/byte or 2550000 writes/word
#    elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
#        define EEESIZE 0x38
#    elif (EEPROM_SIZE == 32)  // 2555000 writes/byte or 5110000 writes/word
#    elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
#        define EEESIZE 0x39
#    endif



@@ 88,9 88,9 @@ void eeprom_initialize(void) {
    if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
        // FlexRAM is configured as traditional RAM
        // We need to reconfigure for EEPROM usage
        FTFL->FCCOB0 = 0x80;     // PGMPART = Program Partition Command
        FTFL->FCCOB4 = EEESIZE;  // EEPROM Size
        FTFL->FCCOB5 = 0x03;     // 0K for Dataflash, 32K for EEPROM backup
        FTFL->FCCOB0 = 0x80;    // PGMPART = Program Partition Command
        FTFL->FCCOB4 = EEESIZE; // EEPROM Size
        FTFL->FCCOB5 = 0x03;    // 0K for Dataflash, 32K for EEPROM backup
        __disable_irq();
        // do_flash_cmd() must execute from RAM.  Luckily the C syntax is simple...
        (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));


@@ 98,7 98,7 @@ void eeprom_initialize(void) {
        status = FTFL->FSTAT;
        if (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)) {
            FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL));
            return;  // error
            return; // error
        }
    }
    // wait for eeprom to become ready (is this really necessary?)


@@ 162,7 162,9 @@ void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
 *
 * FIXME: needs doc
 */
int eeprom_is_ready(void) { return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; }
int eeprom_is_ready(void) {
    return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
}

/** \brief flexram wait
 *


@@ 486,7 488,9 @@ void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
    }
}

int eeprom_is_ready(void) { return 1; }
int eeprom_is_ready(void) {
    return 1;
}

void eeprom_write_word(uint16_t *addr, uint16_t value) {
    uint8_t *p = (uint8_t *)addr;


@@ 515,7 519,9 @@ void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
#endif /* chip selection */
// The update functions just calls write for now, but could probably be optimized

void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
void eeprom_update_byte(uint8_t *addr, uint8_t value) {
    eeprom_write_byte(addr, value);
}

void eeprom_update_word(uint16_t *addr, uint16_t value) {
    uint8_t *p = (uint8_t *)addr;

M platforms/chibios/gd32v_compatibility.h => platforms/chibios/gd32v_compatibility.h +2 -2
@@ 97,10 97,10 @@
/* Serial USART redefines. */
#if HAL_USE_SERIAL
#    if !defined(SERIAL_USART_CR1)
#        define SERIAL_USART_CR1 (USART_CTL0_PCEN | USART_CTL0_PM | USART_CTL0_WL)  // parity enable, odd parity, 9 bit length
#        define SERIAL_USART_CR1 (USART_CTL0_PCEN | USART_CTL0_PM | USART_CTL0_WL) // parity enable, odd parity, 9 bit length
#    endif
#    if !defined(SERIAL_USART_CR2)
#        define SERIAL_USART_CR2 (USART_CTL1_STB_1)  // 2 stop bits
#        define SERIAL_USART_CR2 (USART_CTL1_STB_1) // 2 stop bits
#    endif
#    if !defined(SERIAL_USART_CR3)
#        define SERIAL_USART_CR3 0x0

M platforms/chibios/sleep_led.c => platforms/chibios/sleep_led.c +24 -12
@@ 93,7 93,7 @@ void sleep_led_init(void) {
    /* Reset LPTMR settings */
    LPTMR0->CSR = 0;
    /* Set the compare value */
    LPTMR0->CMR = 0;  // trigger on counter value (i.e. every time)
    LPTMR0->CMR = 0; // trigger on counter value (i.e. every time)

/* Set up clock source and prescaler */
/* Software PWM


@@ 118,11 118,11 @@ void sleep_led_init(void) {
/* === OPTION 2 === */
#    if 1
    //  nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
    MCG->C2 |= MCG_C2_IRCS;  // fast (4MHz) internal ref clock
#        if defined(KL27)    // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
    MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
#        if defined(KL27)   // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
    MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
#        endif                  /* KL27 */
    MCG->C1 |= MCG_C1_IRCLKEN;  // enable internal ref clock
#        endif                 /* KL27 */
    MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
    //  to work in stop mode, also MCG_C1_IREFSTEN
    //  Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
    //  => approx F=61, R=256, duration = 4


@@ 140,7 140,7 @@ void sleep_led_init(void) {
    /* === END OPTIONS === */

    /* Interrupt on TCF set (compare flag) */
    nvicEnableVector(LPTMR0_IRQn, 2);  // vector, priority
    nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
    LPTMR0->CSR |= LPTMRx_CSR_TIE;
}



@@ 169,21 169,33 @@ static void gptTimerCallback(GPTDriver *gptp) {
static const GPTConfig gptcfg = {1000000, gptTimerCallback, 0, 0};

/* Initialise the timer */
void sleep_led_init(void) { gptStart(&SLEEP_LED_GPT_DRIVER, &gptcfg); }
void sleep_led_init(void) {
    gptStart(&SLEEP_LED_GPT_DRIVER, &gptcfg);
}

void sleep_led_enable(void) { gptStartContinuous(&SLEEP_LED_GPT_DRIVER, gptcfg.frequency / 0xFFFF); }
void sleep_led_enable(void) {
    gptStartContinuous(&SLEEP_LED_GPT_DRIVER, gptcfg.frequency / 0xFFFF);
}

void sleep_led_disable(void) { gptStopTimer(&SLEEP_LED_GPT_DRIVER); }
void sleep_led_disable(void) {
    gptStopTimer(&SLEEP_LED_GPT_DRIVER);
}

void sleep_led_toggle(void) { (SLEEP_LED_GPT_DRIVER.state == GPT_READY) ? sleep_led_enable() : sleep_led_disable(); }
void sleep_led_toggle(void) {
    (SLEEP_LED_GPT_DRIVER.state == GPT_READY) ? sleep_led_enable() : sleep_led_disable();
}

#else /* platform selection: not on familiar chips */

void sleep_led_init(void) {}

void sleep_led_enable(void) { led_set(1 << USB_LED_CAPS_LOCK); }
void sleep_led_enable(void) {
    led_set(1 << USB_LED_CAPS_LOCK);
}

void sleep_led_disable(void) { led_set(0); }
void sleep_led_disable(void) {
    led_set(0);
}

void sleep_led_toggle(void) {
    // not implemented

M platforms/chibios/syscall-fallbacks.c => platforms/chibios/syscall-fallbacks.c +6 -2
@@ 87,9 87,13 @@ __attribute__((weak, used)) int _kill(int pid, int sig) {
    return -1;
}

__attribute__((weak, used)) pid_t _getpid(void) { return 1; }
__attribute__((weak, used)) pid_t _getpid(void) {
    return 1;
}

__attribute__((weak, used)) void _fini(void) { return; }
__attribute__((weak, used)) void _fini(void) {
    return;
}

__attribute__((weak, used, noreturn)) void _exit(int i) {
    while (1)

M platforms/chibios/timer.c => platforms/chibios/timer.c +10 -4
@@ 73,7 73,9 @@ void timer_clear(void) {
    chSysUnlock();
}

uint16_t timer_read(void) { return (uint16_t)timer_read32(); }
uint16_t timer_read(void) {
    return (uint16_t)timer_read32();
}

uint32_t timer_read32(void) {
    chSysLock();


@@ 90,12 92,16 @@ uint32_t timer_read32(void) {
        ms_offset += OVERFLOW_ADJUST_MS;
    }
    last_ticks              = ticks;
    uint32_t ms_offset_copy = ms_offset;  // read while still holding the lock to ensure a consistent value
    uint32_t ms_offset_copy = ms_offset; // read while still holding the lock to ensure a consistent value
    chSysUnlock();

    return (uint32_t)TIME_I2MS(ticks) + ms_offset_copy;
}

uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }
uint16_t timer_elapsed(uint16_t last) {
    return TIMER_DIFF_16(timer_read(), last);
}

uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }
uint32_t timer_elapsed32(uint32_t last) {
    return TIMER_DIFF_32(timer_read32(), last);
}

M platforms/suspend.c => platforms/suspend.c +6 -2
@@ 18,7 18,9 @@ __attribute__((weak)) void suspend_power_down_user(void) {}
 *
 * FIXME: needs doc
 */
__attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); }
__attribute__((weak)) void suspend_power_down_kb(void) {
    suspend_power_down_user();
}

/** \brief run user level code immediately after wakeup
 *


@@ 30,7 32,9 @@ __attribute__((weak)) void suspend_wakeup_init_user(void) {}
 *
 * FIXME: needs doc
 */
__attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); }
__attribute__((weak)) void suspend_wakeup_init_kb(void) {
    suspend_wakeup_init_user();
}

/** \brief suspend wakeup condition
 *

M platforms/test/eeprom.c => platforms/test/eeprom.c +3 -1
@@ 68,7 68,9 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
    }
}

void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
void eeprom_update_byte(uint8_t *addr, uint8_t value) {
    eeprom_write_byte(addr, value);
}

void eeprom_update_word(uint16_t *addr, uint16_t value) {
    uint8_t *p = (uint8_t *)addr;

M platforms/test/eeprom_stm32_tests.cpp => platforms/test/eeprom_stm32_tests.cpp +28 -26
@@ 60,7 60,9 @@ class EepromStm32Test : public testing::Test {
    ~EepromStm32Test() {}

   protected:
    void SetUp() override { EEPROM_Erase(); }
    void SetUp() override {
        EEPROM_Erase();
    }

    void TearDown() override {
#ifdef EEPROM_DEBUG


@@ 83,7 85,7 @@ TEST_F(EepromStm32Test, TestReadGarbage) {
        garbage += i;
        FlashBuf[i] = garbage;
    }
    EEPROM_Init();  // Just verify we don't crash
    EEPROM_Init(); // Just verify we don't crash
}

TEST_F(EepromStm32Test, TestWriteBadAddress) {


@@ 206,11 208,11 @@ TEST_F(EepromStm32Test, TestReadWord) {

TEST_F(EepromStm32Test, TestWriteWord) {
    /* Direct compacted-area: Address < 0x80 */
    EEPROM_WriteDataWord(0, 0xdead);  // Aligned
    EEPROM_WriteDataWord(3, 0xbeef);  // Unaligned
    EEPROM_WriteDataWord(0, 0xdead); // Aligned
    EEPROM_WriteDataWord(3, 0xbeef); // Unaligned
    /* Direct compacted-area: Address >= 0x80 */
    EEPROM_WriteDataWord(200, 0xabcd);  // Aligned
    EEPROM_WriteDataWord(203, 0x9876);  // Unaligned
    EEPROM_WriteDataWord(200, 0xabcd); // Aligned
    EEPROM_WriteDataWord(203, 0x9876); // Unaligned
    EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234);
    EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678);
    /* Write Log word zero-encoded */


@@ 218,10 220,10 @@ TEST_F(EepromStm32Test, TestWriteWord) {
    /* Write Log word one-encoded */
    EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1);
    /* Write Log word value aligned */
    EEPROM_WriteDataWord(200, 0x4321);  // Aligned
    EEPROM_WriteDataWord(200, 0x4321); // Aligned
    /* Write Log word value unaligned */
    EEPROM_WriteDataByte(202, 0x3c);    // Set neighboring byte
    EEPROM_WriteDataWord(203, 0xcdef);  // Unaligned
    EEPROM_WriteDataByte(202, 0x3c);   // Set neighboring byte
    EEPROM_WriteDataWord(203, 0xcdef); // Unaligned
    /* Check values */
    /* Direct compacted-area */
    EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE], (uint16_t)~0xdead);


@@ 249,11 251,11 @@ TEST_F(EepromStm32Test, TestWriteWord) {

TEST_F(EepromStm32Test, TestWordRoundTrip) {
    /* Direct compacted-area: Address < 0x80 */
    EEPROM_WriteDataWord(0, 0xdead);  // Aligned
    EEPROM_WriteDataWord(3, 0xbeef);  // Unaligned
    EEPROM_WriteDataWord(0, 0xdead); // Aligned
    EEPROM_WriteDataWord(3, 0xbeef); // Unaligned
    /* Direct compacted-area: Address >= 0x80 */
    EEPROM_WriteDataWord(200, 0xabcd);  // Aligned
    EEPROM_WriteDataWord(203, 0x9876);  // Unaligned
    EEPROM_WriteDataWord(200, 0xabcd); // Aligned
    EEPROM_WriteDataWord(203, 0x9876); // Unaligned
    EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234);
    EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678);
    /* Check values */


@@ 270,10 272,10 @@ TEST_F(EepromStm32Test, TestWordRoundTrip) {
    /* Write Log word one-encoded */
    EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1);
    /* Write Log word value aligned */
    EEPROM_WriteDataWord(200, 0x4321);  // Aligned
    EEPROM_WriteDataWord(200, 0x4321); // Aligned
    /* Write Log word value unaligned */
    EEPROM_WriteDataByte(202, 0x3c);    // Set neighboring byte
    EEPROM_WriteDataWord(203, 0xcdef);  // Unaligned
    EEPROM_WriteDataByte(202, 0x3c);   // Set neighboring byte
    EEPROM_WriteDataWord(203, 0xcdef); // Unaligned
    /* Check values */
    EEPROM_Init();
    EXPECT_EQ(EEPROM_ReadDataWord(200), 0x4321);


@@ 324,34 326,34 @@ TEST_F(EepromStm32Test, TestByteWordBoundary) {

TEST_F(EepromStm32Test, TestDWordRoundTrip) {
    /* Direct compacted-area: Address < 0x80 */
    eeprom_write_dword((uint32_t*)0, 0xdeadbeef);  // Aligned
    eeprom_write_dword((uint32_t*)9, 0x12345678);  // Unaligned
    eeprom_write_dword((uint32_t*)0, 0xdeadbeef); // Aligned
    eeprom_write_dword((uint32_t*)9, 0x12345678); // Unaligned
    /* Direct compacted-area: Address >= 0x80 */
    eeprom_write_dword((uint32_t*)200, 0xfacef00d);
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xba5eba11);  // Aligned
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0xcafed00d);  // Unaligned
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xba5eba11); // Aligned
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0xcafed00d); // Unaligned
    /* Check direct values */
    EEPROM_Init();
    EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef);
    EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x12345678);
    EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 0xfacef00d);
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xba5eba11);  // Aligned
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0xcafed00d);  // Unaligned
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xba5eba11); // Aligned
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0xcafed00d); // Unaligned
    /* Write Log byte encoded */
    eeprom_write_dword((uint32_t*)0, 0xdecafbad);
    eeprom_write_dword((uint32_t*)9, 0x87654321);
    /* Write Log word encoded */
    eeprom_write_dword((uint32_t*)200, 1);
    /* Write Log word value aligned */
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xdeadc0de);  // Aligned
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0x6789abcd);  // Unaligned
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xdeadc0de); // Aligned
    eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0x6789abcd); // Unaligned
    /* Check log values */
    EEPROM_Init();
    EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdecafbad);
    EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x87654321);
    EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 1);
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xdeadc0de);  // Aligned
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0x6789abcd);  // Unaligned
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xdeadc0de); // Aligned
    EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0x6789abcd); // Unaligned
}

TEST_F(EepromStm32Test, TestBlockRoundTrip) {

M platforms/test/flash_stm32_mock.c => platforms/test/flash_stm32_mock.c +9 -3
@@ 44,6 44,12 @@ FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) {
    }
}

FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { return FLASH_COMPLETE; }
void         FLASH_Unlock(void) { flash_locked = false; }
void         FLASH_Lock(void) { flash_locked = true; }
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) {
    return FLASH_COMPLETE;
}
void FLASH_Unlock(void) {
    flash_locked = false;
}
void FLASH_Lock(void) {
    flash_locked = true;
}

M platforms/test/timer.c => platforms/test/timer.c +27 -9
@@ 18,16 18,34 @@

static uint32_t current_time = 0;

void timer_init(void) { current_time = 0; }
void timer_init(void) {
    current_time = 0;
}

void timer_clear(void) { current_time = 0; }
void timer_clear(void) {
    current_time = 0;
}

uint16_t timer_read(void) { return current_time & 0xFFFF; }
uint32_t timer_read32(void) { return current_time; }
uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }
uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }
uint16_t timer_read(void) {
    return current_time & 0xFFFF;
}
uint32_t timer_read32(void) {
    return current_time;
}
uint16_t timer_elapsed(uint16_t last) {
    return TIMER_DIFF_16(timer_read(), last);
}
uint32_t timer_elapsed32(uint32_t last) {
    return TIMER_DIFF_32(timer_read32(), last);
}

void set_time(uint32_t t) { current_time = t; }
void advance_time(uint32_t ms) { current_time += ms; }
void set_time(uint32_t t) {
    current_time = t;
}
void advance_time(uint32_t ms) {
    current_time += ms;
}

void wait_ms(uint32_t ms) { advance_time(ms); }
void wait_ms(uint32_t ms) {
    advance_time(ms);
}

M platforms/timer.h => platforms/timer.h +12 -4
@@ 52,14 52,22 @@ uint32_t timer_elapsed32(uint32_t last);
#    define TIMER_DIFF_FAST(a, b) TIMER_DIFF_16(a, b)
#    define timer_expired_fast(current, future) timer_expired(current, future)
typedef uint16_t fast_timer_t;
fast_timer_t inline timer_read_fast(void) { return timer_read(); }
fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed(last); }
fast_timer_t inline timer_read_fast(void) {
    return timer_read();
}
fast_timer_t inline timer_elapsed_fast(fast_timer_t last) {
    return timer_elapsed(last);
}
#else
#    define TIMER_DIFF_FAST(a, b) TIMER_DIFF_32(a, b)
#    define timer_expired_fast(current, future) timer_expired32(current, future)
typedef uint32_t fast_timer_t;
fast_timer_t inline timer_read_fast(void) { return timer_read32(); }
fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed32(last); }
fast_timer_t inline timer_read_fast(void) {
    return timer_read32();
}
fast_timer_t inline timer_elapsed_fast(fast_timer_t last) {
    return timer_elapsed32(last);
}
#endif

#ifdef __cplusplus

M quantum/action.c => quantum/action.c +36 -14
@@ 53,14 53,20 @@ int retro_tapping_counter = 0;
#endif

#ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY
__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) { return false; }
__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) {
    return false;
}
#endif

#ifdef RETRO_TAPPING_PER_KEY
__attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) { return false; }
__attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) {
    return false;
}
#endif

__attribute__((weak)) bool pre_process_record_quantum(keyrecord_t *record) { return true; }
__attribute__((weak)) bool pre_process_record_quantum(keyrecord_t *record) {
    return true;
}

/** \brief Called to execute an action.
 *


@@ 163,10 169,14 @@ void process_record_nocache(keyrecord_t *record) {
    disable_action_cache = false;
}
#else
void process_record_nocache(keyrecord_t *record) { process_record(record); }
void process_record_nocache(keyrecord_t *record) {
    process_record(record);
}
#endif

__attribute__((weak)) bool process_record_quantum(keyrecord_t *record) { return true; }
__attribute__((weak)) bool process_record_quantum(keyrecord_t *record) {
    return true;
}

__attribute__((weak)) void post_process_record_quantum(keyrecord_t *record) {}



@@ 688,7 698,7 @@ void process_action(keyrecord_t *record, action_t action) {
                    /* tap key */
                    if (tap_count > 0) {
                        if (swap_held) {
                            swap_hands = !swap_hands;  // undo hold set up in _tap_hint
                            swap_hands = !swap_hands; // undo hold set up in _tap_hint
                            swap_held  = false;
                        }
                        if (event.pressed) {


@@ 696,11 706,11 @@ void process_action(keyrecord_t *record, action_t action) {
                        } else {
                            wait_ms(TAP_CODE_DELAY);
                            unregister_code(action.swap.code);
                            *record = (keyrecord_t){};  // hack: reset tap mode
                            *record = (keyrecord_t){}; // hack: reset tap mode
                        }
                    } else {
                        if (swap_held && !event.pressed) {
                            swap_hands = !swap_hands;  // undo hold set up in _tap_hint
                            swap_hands = !swap_hands; // undo hold set up in _tap_hint
                            swap_held  = false;
                        }
                    }


@@ 862,9 872,13 @@ __attribute__((weak)) void register_code(uint8_t code) {
        }
#ifdef EXTRAKEY_ENABLE
    else if
        IS_SYSTEM(code) { host_system_send(KEYCODE2SYSTEM(code)); }
        IS_SYSTEM(code) {
            host_system_send(KEYCODE2SYSTEM(code));
        }
    else if
        IS_CONSUMER(code) { host_consumer_send(KEYCODE2CONSUMER(code)); }
        IS_CONSUMER(code) {
            host_consumer_send(KEYCODE2CONSUMER(code));
        }
#endif
#ifdef MOUSEKEY_ENABLE
    else if


@@ 927,9 941,13 @@ __attribute__((weak)) void unregister_code(uint8_t code) {
            send_keyboard_report();
        }
    else if
        IS_SYSTEM(code) { host_system_send(0); }
        IS_SYSTEM(code) {
            host_system_send(0);
        }
    else if
        IS_CONSUMER(code) { host_consumer_send(0); }
        IS_CONSUMER(code) {
            host_consumer_send(0);
        }
#ifdef MOUSEKEY_ENABLE
    else if
        IS_MOUSEKEY(code) {


@@ 956,7 974,9 @@ __attribute__((weak)) void tap_code_delay(uint8_t code, uint16_t delay) {
 *
 * \param code The basic keycode to tap. If `code` is `KC_CAPS_LOCK`, the delay will be `TAP_HOLD_CAPS_DELAY`, otherwise `TAP_CODE_DELAY`, if defined.
 */
__attribute__((weak)) void tap_code(uint8_t code) { tap_code_delay(code, code == KC_CAPS_LOCK ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY); }
__attribute__((weak)) void tap_code(uint8_t code) {
    tap_code_delay(code, code == KC_CAPS_LOCK ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY);
}

/** \brief Adds the given physically pressed modifiers and sends a keyboard report immediately.
 *


@@ 1100,7 1120,9 @@ bool is_tap_action(action_t action) {
 *
 * FIXME: Needs documentation.
 */
void debug_event(keyevent_t event) { dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); }
void debug_event(keyevent_t event) {
    dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time);
}
/** \brief Debug print (FIXME: Needs better description)
 *
 * FIXME: Needs documentation.

M quantum/action_layer.c => quantum/action_layer.c +64 -24
@@ 18,13 18,17 @@ layer_state_t default_layer_state = 0;
 *
 * Run user code on default layer state change
 */
__attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state) { return state; }
__attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state) {
    return state;
}

/** \brief Default Layer State Set At Keyboard Level
 *
 *  Run keyboard code on default layer state change
 */
__attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state) { return default_layer_state_set_user(state); }
__attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state) {
    return default_layer_state_set_user(state);
}

/** \brief Default Layer State Set
 *


@@ 39,9 43,9 @@ static void default_layer_state_set(layer_state_t state) {
    default_layer_debug();
    debug("\n");
#ifdef STRICT_LAYER_RELEASE
    clear_keyboard_but_mods();  // To avoid stuck keys
    clear_keyboard_but_mods(); // To avoid stuck keys
#else
    clear_keyboard_but_mods_and_keys();  // Don't reset held keys
    clear_keyboard_but_mods_and_keys(); // Don't reset held keys
#endif
}



@@ 49,30 53,40 @@ static void default_layer_state_set(layer_state_t state) {
 *
 * Print out the hex value of the 32-bit default layer state, as well as the value of the highest bit.
 */
void default_layer_debug(void) { dprintf("%08lX(%u)", default_layer_state, get_highest_layer(default_layer_state)); }
void default_layer_debug(void) {
    dprintf("%08lX(%u)", default_layer_state, get_highest_layer(default_layer_state));
}

/** \brief Default Layer Set
 *
 * Sets the default layer state.
 */
void default_layer_set(layer_state_t state) { default_layer_state_set(state); }
void default_layer_set(layer_state_t state) {
    default_layer_state_set(state);
}

#ifndef NO_ACTION_LAYER
/** \brief Default Layer Or
 *
 * Turns on the default layer based on matching bits between specifed layer and existing layer state
 */
void default_layer_or(layer_state_t state) { default_layer_state_set(default_layer_state | state); }
void default_layer_or(layer_state_t state) {
    default_layer_state_set(default_layer_state | state);
}
/** \brief Default Layer And
 *
 * Turns on default layer based on matching enabled bits between specifed layer and existing layer state
 */
void default_layer_and(layer_state_t state) { default_layer_state_set(default_layer_state & state); }
void default_layer_and(layer_state_t state) {
    default_layer_state_set(default_layer_state & state);
}
/** \brief Default Layer Xor
 *
 * Turns on default layer based on non-matching bits between specifed layer and existing layer state
 */
void default_layer_xor(layer_state_t state) { default_layer_state_set(default_layer_state ^ state); }
void default_layer_xor(layer_state_t state) {
    default_layer_state_set(default_layer_state ^ state);
}
#endif

#ifndef NO_ACTION_LAYER


@@ 84,13 98,17 @@ layer_state_t layer_state = 0;
 *
 * Runs user code on layer state change
 */
__attribute__((weak)) layer_state_t layer_state_set_user(layer_state_t state) { return state; }
__attribute__((weak)) layer_state_t layer_state_set_user(layer_state_t state) {
    return state;
}

/** \brief Layer state set keyboard
 *
 * Runs keyboard code on layer state change
 */
__attribute__((weak)) layer_state_t layer_state_set_kb(layer_state_t state) { return layer_state_set_user(state); }
__attribute__((weak)) layer_state_t layer_state_set_kb(layer_state_t state) {
    return layer_state_set_user(state);
}

/** \brief Layer state set
 *


@@ 105,9 123,9 @@ void layer_state_set(layer_state_t state) {
    layer_debug();
    dprintln();
#    ifdef STRICT_LAYER_RELEASE
    clear_keyboard_but_mods();  // To avoid stuck keys
    clear_keyboard_but_mods(); // To avoid stuck keys
#    else
    clear_keyboard_but_mods_and_keys();  // Don't reset held keys
    clear_keyboard_but_mods_and_keys(); // Don't reset held keys
#    endif
}



@@ 115,13 133,17 @@ void layer_state_set(layer_state_t state) {
 *
 * Turn off all layers
 */
void layer_clear(void) { layer_state_set(0); }
void layer_clear(void) {
    layer_state_set(0);
}

/** \brief Layer state is
 *
 * Return whether the given state is on (it might still be shadowed by a higher state, though)
 */
bool layer_state_is(uint8_t layer) { return layer_state_cmp(layer_state, layer); }
bool layer_state_is(uint8_t layer) {
    return layer_state_cmp(layer_state, layer);
}

/** \brief Layer state compare
 *


@@ 138,47 160,63 @@ bool layer_state_cmp(layer_state_t cmp_layer_state, uint8_t layer) {
 *
 * Turns on the given layer and turn off all other layers
 */
void layer_move(uint8_t layer) { layer_state_set((layer_state_t)1 << layer); }
void layer_move(uint8_t layer) {
    layer_state_set((layer_state_t)1 << layer);
}

/** \brief Layer on
 *
 * Turns on given layer
 */
void layer_on(uint8_t layer) { layer_state_set(layer_state | ((layer_state_t)1 << layer)); }
void layer_on(uint8_t layer) {
    layer_state_set(layer_state | ((layer_state_t)1 << layer));
}

/** \brief Layer off
 *
 * Turns off given layer
 */
void layer_off(uint8_t layer) { layer_state_set(layer_state & ~((layer_state_t)1 << layer)); }
void layer_off(uint8_t layer) {
    layer_state_set(layer_state & ~((layer_state_t)1 << layer));
}

/** \brief Layer invert
 *
 * Toggle the given layer (set it if it's unset, or unset it if it's set)
 */
void layer_invert(uint8_t layer) { layer_state_set(layer_state ^ ((layer_state_t)1 << layer)); }
void layer_invert(uint8_t layer) {
    layer_state_set(layer_state ^ ((layer_state_t)1 << layer));
}

/** \brief Layer or
 *
 * Turns on layers based on matching bits between specifed layer and existing layer state
 */
void layer_or(layer_state_t state) { layer_state_set(layer_state | state); }
void layer_or(layer_state_t state) {
    layer_state_set(layer_state | state);
}
/** \brief Layer and
 *
 * Turns on layers based on matching enabled bits between specifed layer and existing layer state
 */
void layer_and(layer_state_t state) { layer_state_set(layer_state & state); }
void layer_and(layer_state_t state) {
    layer_state_set(layer_state & state);
}
/** \brief Layer xor
 *
 * Turns on layers based on non-matching bits between specifed layer and existing layer state
 */
void layer_xor(layer_state_t state) { layer_state_set(layer_state ^ state); }
void layer_xor(layer_state_t state) {
    layer_state_set(layer_state ^ state);
}

/** \brief Layer debug printing
 *
 * Print out the hex value of the 32-bit layer state, as well as the value of the highest bit.
 */
void layer_debug(void) { dprintf("%08lX(%u)", layer_state, get_highest_layer(layer_state)); }
void layer_debug(void) {
    dprintf("%08lX(%u)", layer_state, get_highest_layer(layer_state));
}
#endif

#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)


@@ 276,4 314,6 @@ uint8_t layer_switch_get_layer(keypos_t key) {
 *
 * Gets action code based on key position
 */
action_t layer_switch_get_action(keypos_t key) { return action_for_key(layer_switch_get_layer(key), key); }
action_t layer_switch_get_action(keypos_t key) {
    return action_for_key(layer_switch_get_layer(key), key);
}

M quantum/action_tapping.c => quantum/action_tapping.c +12 -4
@@ 26,7 26,9 @@

uint16_t g_tapping_term = TAPPING_TERM;

__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return g_tapping_term; }
__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
    return g_tapping_term;
}

#    ifdef TAPPING_TERM_PER_KEY
#        define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < get_tapping_term(get_record_keycode(&tapping_key, false), &tapping_key))


@@ 35,15 37,21 @@ __attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *r
#    endif

#    ifdef TAPPING_FORCE_HOLD_PER_KEY
__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) { return false; }
__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) {
    return false;
}
#    endif

#    ifdef PERMISSIVE_HOLD_PER_KEY
__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) { return false; }
__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
    return false;
}
#    endif

#    ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY
__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { return false; }
__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
    return false;
}
#    endif

#    if defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)

M quantum/action_util.c => quantum/action_util.c +97 -35
@@ 43,8 43,10 @@ extern inline void clear_keys(void);
#ifndef NO_ACTION_ONESHOT
static uint8_t oneshot_mods        = 0;
static uint8_t oneshot_locked_mods = 0;
uint8_t        get_oneshot_locked_mods(void) { return oneshot_locked_mods; }
void           set_oneshot_locked_mods(uint8_t mods) {
uint8_t        get_oneshot_locked_mods(void) {
    return oneshot_locked_mods;
}
void set_oneshot_locked_mods(uint8_t mods) {
    if (mods != oneshot_locked_mods) {
        oneshot_locked_mods = mods;
        oneshot_locked_mods_changed_kb(oneshot_locked_mods);


@@ 58,9 60,13 @@ void clear_oneshot_locked_mods(void) {
}
#    if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
static uint16_t oneshot_time = 0;
bool            has_oneshot_mods_timed_out(void) { return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT; }
bool            has_oneshot_mods_timed_out(void) {
    return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT;
}
#    else
bool has_oneshot_mods_timed_out(void) { return false; }
bool has_oneshot_mods_timed_out(void) {
    return false;
}
#    endif
#endif



@@ 74,24 80,32 @@ bool has_oneshot_mods_timed_out(void) { return false; }
 */
static int8_t oneshot_layer_data = 0;

inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; }
inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; }
inline uint8_t get_oneshot_layer(void) {
    return oneshot_layer_data >> 3;
}
inline uint8_t get_oneshot_layer_state(void) {
    return oneshot_layer_data & 0b111;
}

#    ifdef SWAP_HANDS_ENABLE
enum {
    SHO_OFF,
    SHO_ACTIVE,   // Swap hands button was pressed, and we didn't send any swapped keys yet
    SHO_PRESSED,  // Swap hands button is currently pressed
    SHO_USED,     // Swap hands button is still pressed, and we already sent swapped keys
    SHO_ACTIVE,  // Swap hands button was pressed, and we didn't send any swapped keys yet
    SHO_PRESSED, // Swap hands button is currently pressed
    SHO_USED,    // Swap hands button is still pressed, and we already sent swapped keys
} swap_hands_oneshot = SHO_OFF;
#    endif

#    if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
static uint16_t oneshot_layer_time = 0;
inline bool     has_oneshot_layer_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT && !(get_oneshot_layer_state() & ONESHOT_TOGGLED); }
inline bool     has_oneshot_layer_timed_out() {
    return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT && !(get_oneshot_layer_state() & ONESHOT_TOGGLED);
}
#        ifdef SWAP_HANDS_ENABLE
static uint16_t oneshot_swaphands_time = 0;
inline bool     has_oneshot_swaphands_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_swaphands_time) >= ONESHOT_TIMEOUT && (swap_hands_oneshot == SHO_ACTIVE); }
inline bool     has_oneshot_swaphands_timed_out() {
    return TIMER_DIFF_16(timer_read(), oneshot_swaphands_time) >= ONESHOT_TIMEOUT && (swap_hands_oneshot == SHO_ACTIVE);
}
#        endif
#    endif



@@ 179,7 193,9 @@ void clear_oneshot_layer_state(oneshot_fullfillment_t state) {
 *
 * FIXME: needs doc
 */
bool is_oneshot_layer_active(void) { return get_oneshot_layer_state(); }
bool is_oneshot_layer_active(void) {
    return get_oneshot_layer_state();
}

/** \brief set oneshot
 *


@@ 198,21 214,29 @@ void oneshot_set(bool active) {
 *
 * FIXME: needs doc
 */
void oneshot_toggle(void) { oneshot_set(!keymap_config.oneshot_disable); }
void oneshot_toggle(void) {
    oneshot_set(!keymap_config.oneshot_disable);
}

/** \brief enable oneshot
 *
 * FIXME: needs doc
 */
void oneshot_enable(void) { oneshot_set(true); }
void oneshot_enable(void) {
    oneshot_set(true);
}

/** \brief disable oneshot
 *
 * FIXME: needs doc
 */
void oneshot_disable(void) { oneshot_set(false); }
void oneshot_disable(void) {
    oneshot_set(false);
}

bool is_oneshot_enabled(void) { return keymap_config.oneshot_disable; }
bool is_oneshot_enabled(void) {
    return keymap_config.oneshot_disable;
}

#endif



@@ 259,68 283,96 @@ void send_keyboard_report(void) {
 *
 * FIXME: needs doc
 */
uint8_t get_mods(void) { return real_mods; }
uint8_t get_mods(void) {
    return real_mods;
}
/** \brief add mods
 *
 * FIXME: needs doc
 */
void add_mods(uint8_t mods) { real_mods |= mods; }
void add_mods(uint8_t mods) {
    real_mods |= mods;
}
/** \brief del mods
 *
 * FIXME: needs doc
 */
void del_mods(uint8_t mods) { real_mods &= ~mods; }
void del_mods(uint8_t mods) {
    real_mods &= ~mods;
}
/** \brief set mods
 *
 * FIXME: needs doc
 */
void set_mods(uint8_t mods) { real_mods = mods; }
void set_mods(uint8_t mods) {
    real_mods = mods;
}
/** \brief clear mods
 *
 * FIXME: needs doc
 */
void clear_mods(void) { real_mods = 0; }
void clear_mods(void) {
    real_mods = 0;
}

/** \brief get weak mods
 *
 * FIXME: needs doc
 */
uint8_t get_weak_mods(void) { return weak_mods; }
uint8_t get_weak_mods(void) {
    return weak_mods;
}
/** \brief add weak mods
 *
 * FIXME: needs doc
 */
void add_weak_mods(uint8_t mods) { weak_mods |= mods; }
void add_weak_mods(uint8_t mods) {
    weak_mods |= mods;
}
/** \brief del weak mods
 *
 * FIXME: needs doc
 */
void del_weak_mods(uint8_t mods) { weak_mods &= ~mods; }
void del_weak_mods(uint8_t mods) {
    weak_mods &= ~mods;
}
/** \brief set weak mods
 *
 * FIXME: needs doc
 */
void set_weak_mods(uint8_t mods) { weak_mods = mods; }
void set_weak_mods(uint8_t mods) {
    weak_mods = mods;
}
/** \brief clear weak mods
 *
 * FIXME: needs doc
 */
void clear_weak_mods(void) { weak_mods = 0; }
void clear_weak_mods(void) {
    weak_mods = 0;
}

#ifdef KEY_OVERRIDE_ENABLE
/** \brief set weak mods used by key overrides. DO not call this manually
 */
void set_weak_override_mods(uint8_t mods) { weak_override_mods = mods; }
void set_weak_override_mods(uint8_t mods) {
    weak_override_mods = mods;
}
/** \brief clear weak mods used by key overrides. DO not call this manually
 */
void clear_weak_override_mods(void) { weak_override_mods = 0; }
void clear_weak_override_mods(void) {
    weak_override_mods = 0;
}

/** \brief set suppressed mods used by key overrides. DO not call this manually
 */
void set_suppressed_override_mods(uint8_t mods) { suppressed_mods = mods; }
void set_suppressed_override_mods(uint8_t mods) {
    suppressed_mods = mods;
}
/** \brief clear suppressed mods used by key overrides. DO not call this manually
 */
void clear_suppressed_override_mods(void) { suppressed_mods = 0; }
void clear_suppressed_override_mods(void) {
    suppressed_mods = 0;
}
#endif

#ifndef NO_ACTION_ONESHOT


@@ 328,7 380,9 @@ void clear_suppressed_override_mods(void) { suppressed_mods = 0; }
 *
 * FIXME: needs doc
 */
uint8_t get_oneshot_mods(void) { return oneshot_mods; }
uint8_t get_oneshot_mods(void) {
    return oneshot_mods;
}

void add_oneshot_mods(uint8_t mods) {
    if ((oneshot_mods & mods) != mods) {


@@ 391,7 445,9 @@ __attribute__((weak)) void oneshot_locked_mods_changed_user(uint8_t mods) {}
 *
 * \param mods Contains the active modifiers active after the change.
 */
__attribute__((weak)) void oneshot_locked_mods_changed_kb(uint8_t mods) { oneshot_locked_mods_changed_user(mods); }
__attribute__((weak)) void oneshot_locked_mods_changed_kb(uint8_t mods) {
    oneshot_locked_mods_changed_user(mods);
}

/** \brief Called when the one shot modifiers have been changed.
 *


@@ 403,7 459,9 @@ __attribute__((weak)) void oneshot_mods_changed_user(uint8_t mods) {}
 *
 * \param mods Contains the active modifiers active after the change.
 */
__attribute__((weak)) void oneshot_mods_changed_kb(uint8_t mods) { oneshot_mods_changed_user(mods); }
__attribute__((weak)) void oneshot_mods_changed_kb(uint8_t mods) {
    oneshot_mods_changed_user(mods);
}

/** \brief Called when the one shot layers have been changed.
 *


@@ 415,10 473,14 @@ __attribute__((weak)) void oneshot_layer_changed_user(uint8_t layer) {}
 *
 * \param layer Contains the layer that is toggled on, or zero when toggled off.
 */
__attribute__((weak)) void oneshot_layer_changed_kb(uint8_t layer) { oneshot_layer_changed_user(layer); }
__attribute__((weak)) void oneshot_layer_changed_kb(uint8_t layer) {
    oneshot_layer_changed_user(layer);
}

/** \brief inspect keyboard state
 *
 * FIXME: needs doc
 */
uint8_t has_anymod(void) { return bitpop(real_mods); }
uint8_t has_anymod(void) {
    return bitpop(real_mods);
}

M quantum/action_util.h => quantum/action_util.h +9 -3
@@ 29,11 29,17 @@ extern report_keyboard_t *keyboard_report;
void send_keyboard_report(void);

/* key */
inline void add_key(uint8_t key) { add_key_to_report(keyboard_report, key); }
inline void add_key(uint8_t key) {
    add_key_to_report(keyboard_report, key);
}

inline void del_key(uint8_t key) { del_key_from_report(keyboard_report, key); }
inline void del_key(uint8_t key) {
    del_key_from_report(keyboard_report, key);
}

inline void clear_keys(void) { clear_keys_from_report(keyboard_report); }
inline void clear_keys(void) {
    clear_keys_from_report(keyboard_report);
}

/* modifier */
uint8_t get_mods(void);

M quantum/audio/audio.c => quantum/audio/audio.c +47 -31
@@ 64,21 64,21 @@
#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
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
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
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


@@ 86,7 86,7 @@ uint16_t last_timestamp               = 0;
#        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
uint8_t  tone_multiplexing_index_shift = 0; // offset used on active-tone array access
#endif

// provided and used by voices.c


@@ 123,12 123,12 @@ void audio_init() {
        eeconfig_init();
    }
    audio_config.raw = eeconfig_read_audio();
#else  // EEPROM settings
#else // EEPROM settings
    audio_config.enable        = true;
#    ifdef AUDIO_CLICKY_ON
    audio_config.clicky_enable = true;
#    endif
#endif  // EEPROM settings
#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};


@@ 181,7 181,9 @@ void audio_off(void) {
    eeconfig_update_audio(audio_config.raw);
}

bool audio_is_on(void) { return (audio_config.enable != 0); }
bool audio_is_on(void) {
    return (audio_config.enable != 0);
}

void audio_stop_all() {
    if (audio_driver_stopped) {


@@ 268,7 270,7 @@ void audio_play_note(float pitch, uint16_t duration) {
                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
            return; // since this frequency played already, the hardware was already started
        }
    }



@@ 286,7 288,7 @@ void audio_play_note(float pitch, uint16_t duration) {
    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
    voices_timer = timer_read(); // reset to zero, for the effects added by voices.c

    if (audio_driver_stopped) {
        audio_driver_start();


@@ 294,7 296,9 @@ void audio_play_note(float pitch, uint16_t duration) {
    }
}

void audio_play_tone(float pitch) { audio_play_note(pitch, 0xffff); }
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) {


@@ 316,7 320,7 @@ void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat) {
    notes_count   = n_count;
    notes_repeat  = n_repeat;

    current_note = 0;  // note in the melody-array/list at note_pointer
    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'


@@ 347,11 351,17 @@ void  audio_play_click(uint16_t delay, float pitch, uint16_t duration) {
    }
}

bool audio_is_playing_note(void) { return playing_note; }
bool audio_is_playing_note(void) {
    return playing_note;
}

bool audio_is_playing_melody(void) { return playing_melody; }
bool audio_is_playing_melody(void) {
    return playing_melody;
}

uint8_t audio_get_number_of_active_tones(void) { return active_tones; }
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) {


@@ 370,7 380,7 @@ float audio_get_processed_frequency(uint8_t tone_index) {

#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
    index = index - tone_multiplexing_index_shift;
    if (index < 0)  // wrap around
    if (index < 0) // wrap around
        index += active_tones;
#endif



@@ 396,7 406,7 @@ bool audio_update_state(void) {
            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
            voices_timer = timer_read(); // reset to zero, for the effects added by voices.c

            if (current_note >= notes_count) {
                if (notes_repeat) {


@@ 466,11 476,11 @@ bool audio_update_state(void) {

        // 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 ((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'
                    audio_stop_tone(tones[i].pitch); // also sets 'state_changed=true'
                }
            }
        }


@@ 487,9 497,15 @@ bool audio_update_state(void) {

// 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_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;

M quantum/audio/audio.h => quantum/audio/audio.h +3 -3
@@ 54,9 54,9 @@ typedef union {
 * "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
    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;

M quantum/audio/song_list.h => quantum/audio/song_list.h +1 -1
@@ 22,7 22,7 @@

#if __has_include("user_song_list.h")
#    include "user_song_list.h"
#endif  // if file exists
#endif // if file exists

#define NO_SOUND


M quantum/audio/voices.c => quantum/audio/voices.c +34 -14
@@ 32,11 32,17 @@ voice_type voice = AUDIO_VOICE_DEFAULT;
voice_type voice = default_voice;
#endif

void set_voice(voice_type v) { voice = v; }
void set_voice(voice_type v) {
    voice = v;
}

void voice_iterate() { voice = (voice + 1) % number_of_voices; }
void voice_iterate() {
    voice = (voice + 1) % number_of_voices;
}

void voice_deiterate() { voice = (voice - 1 + number_of_voices) % number_of_voices; }
void voice_deiterate() {
    voice = (voice - 1 + number_of_voices) % number_of_voices;
}

#ifdef AUDIO_VOICES
float mod(float a, int b) {


@@ 67,8 73,8 @@ 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));
#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?
    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) {


@@ 303,7 309,7 @@ float voice_envelope(float frequency) {
            //         note_timbre = TIMBRE_25;
            //     break;

#endif  // AUDIO_VOICES
#endif // AUDIO_VOICES

        default:
            break;


@@ 318,19 324,31 @@ float voice_envelope(float frequency) {
        // TODO: where to keep track of the start-frequency?
        // frequency = voice_add_glissando(??, frequency);
    }
#endif  // AUDIO_VOICES
#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; }
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



@@ 339,4 357,6 @@ void voice_set_timbre(uint8_t timbre) {
        note_timbre = timbre;
    }
}
uint8_t voice_get_timbre(void) { return note_timbre; }
uint8_t voice_get_timbre(void) {
    return note_timbre;
}

M quantum/audio/voices.h => quantum/audio/voices.h +1 -1
@@ 40,7 40,7 @@ typedef enum {
// duty_third_down,
// duty_fifth_third_down,
#endif
    number_of_voices  // important that this is last
    number_of_voices // important that this is last
} voice_type;

void set_voice(voice_type v);

M quantum/backlight/backlight.c => quantum/backlight/backlight.c +38 -16
@@ 95,10 95,10 @@ void backlight_toggle(void) {
 * FIXME: needs doc
 */
void backlight_enable(void) {
    if (backlight_config.enable) return;  // do nothing if backlight is already on
    if (backlight_config.enable) return; // do nothing if backlight is already on

    backlight_config.enable = true;
    if (backlight_config.raw == 1)  // enabled but level == 0
    if (backlight_config.raw == 1) // enabled but level == 0
        backlight_config.level = 1;
    eeconfig_update_backlight(backlight_config.raw);
    dprintf("backlight enable\n");


@@ 110,7 110,7 @@ void backlight_enable(void) {
 * FIXME: needs doc
 */
void backlight_disable(void) {
    if (!backlight_config.enable) return;  // do nothing if backlight is already off
    if (!backlight_config.enable) return; // do nothing if backlight is already off

    backlight_config.enable = false;
    eeconfig_update_backlight(backlight_config.raw);


@@ 122,7 122,9 @@ void backlight_disable(void) {
 *
 * FIXME: needs doc
 */
bool is_backlight_enabled(void) { return backlight_config.enable; }
bool is_backlight_enabled(void) {
    return backlight_config.enable;
}

/** \brief Backlight step through levels
 *


@@ 158,11 160,17 @@ void backlight_level(uint8_t level) {
    eeconfig_update_backlight(backlight_config.raw);
}

uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT); }
uint8_t eeconfig_read_backlight(void) {
    return eeprom_read_byte(EECONFIG_BACKLIGHT);
}

void eeconfig_update_backlight(uint8_t val) { eeprom_update_byte(EECONFIG_BACKLIGHT, val); }
void eeconfig_update_backlight(uint8_t val) {
    eeprom_update_byte(EECONFIG_BACKLIGHT, val);
}

void eeconfig_update_backlight_current(void) { eeconfig_update_backlight(backlight_config.raw); }
void eeconfig_update_backlight_current(void) {
    eeconfig_update_backlight(backlight_config.raw);
}

void eeconfig_update_backlight_default(void) {
    backlight_config.enable = 1;


@@ 179,7 187,9 @@ void eeconfig_update_backlight_default(void) {
 *
 * FIXME: needs doc
 */
uint8_t get_backlight_level(void) { return backlight_config.level; }
uint8_t get_backlight_level(void) {
    return backlight_config.level;
}

#ifdef BACKLIGHT_BREATHING
/** \brief Backlight breathing toggle


@@ 200,7 210,7 @@ void backlight_toggle_breathing(void) {
 * FIXME: needs doc
 */
void backlight_enable_breathing(void) {
    if (backlight_config.breathing) return;  // do nothing if breathing is already on
    if (backlight_config.breathing) return; // do nothing if breathing is already on

    backlight_config.breathing = true;
    eeconfig_update_backlight(backlight_config.raw);


@@ 213,7 223,7 @@ void backlight_enable_breathing(void) {
 * FIXME: needs doc
 */
void backlight_disable_breathing(void) {
    if (!backlight_config.breathing) return;  // do nothing if breathing is already off
    if (!backlight_config.breathing) return; // do nothing if breathing is already off

    backlight_config.breathing = false;
    eeconfig_update_backlight(backlight_config.raw);


@@ 225,18 235,30 @@ void backlight_disable_breathing(void) {
 *
 * FIXME: needs doc
 */
bool is_backlight_breathing(void) { return backlight_config.breathing; }
bool is_backlight_breathing(void) {
    return backlight_config.breathing;
}

// following are marked as weak purely for backwards compatibility
__attribute__((weak)) void breathing_period_set(uint8_t value) { breathing_period = value ? value : 1; }
__attribute__((weak)) void breathing_period_set(uint8_t value) {
    breathing_period = value ? value : 1;
}

__attribute__((weak)) uint8_t get_breathing_period(void) { return breathing_period; }
__attribute__((weak)) uint8_t get_breathing_period(void) {
    return breathing_period;
}

__attribute__((weak)) void breathing_period_default(void) { breathing_period_set(BREATHING_PERIOD); }
__attribute__((weak)) void breathing_period_default(void) {
    breathing_period_set(BREATHING_PERIOD);
}

__attribute__((weak)) void breathing_period_inc(void) { breathing_period_set(breathing_period + 1); }
__attribute__((weak)) void breathing_period_inc(void) {
    breathing_period_set(breathing_period + 1);
}

__attribute__((weak)) void breathing_period_dec(void) { breathing_period_set(breathing_period - 1); }
__attribute__((weak)) void breathing_period_dec(void) {
    breathing_period_set(breathing_period - 1);
}

__attribute__((weak)) void breathing_toggle(void) {
    if (is_breathing())

M quantum/backlight/backlight.h => quantum/backlight/backlight.h +1 -1
@@ 39,7 39,7 @@ typedef union {
    struct {
        bool    enable : 1;
        bool    breathing : 1;
        uint8_t reserved : 1;  // Reserved for possible future backlight modes
        uint8_t reserved : 1; // Reserved for possible future backlight modes
        uint8_t level : 5;
    };
} backlight_config_t;

M quantum/backlight/backlight_avr.c => quantum/backlight/backlight_avr.c +31 -19
@@ 136,7 136,7 @@
#    define TCCRxB TCCR1B
#    define TIMERx_COMPA_vect TIMER1_COMPA_vect
#    define TIMERx_OVF_vect TIMER1_OVF_vect
#    if defined(__AVR_ATmega32A__)  // This MCU has only one TIMSK register
#    if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
#        define TIMSKx TIMSK
#    else
#        define TIMSKx TIMSK1


@@ 166,7 166,7 @@ error("Please set 'BACKLIGHT_DRIVER = custom' within rules.mk")
error("Please set 'BACKLIGHT_DRIVER = software' within rules.mk")
#endif

#ifndef BACKLIGHT_PWM_TIMER  // pwm through software
#ifndef BACKLIGHT_PWM_TIMER // pwm through software

static inline void enable_pwm(void) {
#    if BACKLIGHT_ON_STATE == 1


@@ 203,7 203,9 @@ static inline void disable_pwm(void) {
// or F_CPU/BACKLIGHT_CUSTOM_RESOLUTION if used.

// Triggered when the counter reaches the OCRx value
ISR(TIMERx_COMPA_vect) { backlight_pins_off(); }
ISR(TIMERx_COMPA_vect) {
    backlight_pins_off();
}

// Triggered when the counter reaches the TOP value
// this one triggers at F_CPU/ICRx = 16MHz/65536 =~ 244 Hz


@@ 232,15 234,15 @@ ISR(TIMERx_OVF_vect) {

// See http://jared.geek.nz/2013/feb/linear-led-pwm
static uint16_t cie_lightness(uint16_t v) {
    if (v <= (uint32_t)ICRx / 12)  // If the value is less than or equal to ~8% of max
    if (v <= (uint32_t)ICRx / 12) // If the value is less than or equal to ~8% of max
    {
        return v / 9;  // Same as dividing by 900%
        return v / 9; // Same as dividing by 900%
    } else {
        // In the next two lines values are bit-shifted. This is to avoid loosing decimals in integer math.
        uint32_t y   = (((uint32_t)v + (uint32_t)ICRx / 6) << 5) / ((uint32_t)ICRx / 6 + ICRx);  // If above 8%, add ~16% of max, and normalize with (max + ~16% max)
        uint32_t out = (y * y * y * ICRx) >> 15;                                                 // Cube it and undo the bit-shifting. (which is now three times as much due to the cubing)
        uint32_t y   = (((uint32_t)v + (uint32_t)ICRx / 6) << 5) / ((uint32_t)ICRx / 6 + ICRx); // If above 8%, add ~16% of max, and normalize with (max + ~16% max)
        uint32_t out = (y * y * y * ICRx) >> 15;                                                // Cube it and undo the bit-shifting. (which is now three times as much due to the cubing)

        if (out > ICRx)  // Avoid overflows
        if (out > ICRx) // Avoid overflows
        {
            out = ICRx;
        }


@@ 249,10 251,14 @@ static uint16_t cie_lightness(uint16_t v) {
}

// rescale the supplied backlight value to be in terms of the value limit	// range for val is [0..ICRx]. PWM pin is high while the timer count is below val.
static uint32_t rescale_limit_val(uint32_t val) { return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; }
static uint32_t rescale_limit_val(uint32_t val) {
    return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256;
}

// range for val is [0..ICRx]. PWM pin is high while the timer count is below val.
static inline void set_pwm(uint16_t val) { OCRxx = val; }
static inline void set_pwm(uint16_t val) {
    OCRxx = val;
}

void backlight_set(uint8_t level) {
    if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS;


@@ 303,7 309,9 @@ static uint16_t breathing_freq_scale_factor = 2;
#    ifdef BACKLIGHT_PWM_TIMER
static bool breathing = false;

bool is_breathing(void) { return breathing; }
bool is_breathing(void) {
    return breathing;
}

#        define breathing_interrupt_enable() \
            do {                             \


@@ 315,7 323,9 @@ bool is_breathing(void) { return breathing; }
            } while (0)
#    else

bool is_breathing(void) { return !!(TIMSKx & _BV(TOIEx)); }
bool is_breathing(void) {
    return !!(TIMSKx & _BV(TOIEx));
}

#        define breathing_interrupt_enable() \
            do {                             \


@@ 370,7 380,9 @@ void breathing_self_disable(void) {
static const uint8_t breathing_table[BREATHING_STEPS] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

// Use this before the cie_lightness function.
static inline uint16_t scale_backlight(uint16_t v) { return v / BACKLIGHT_LEVELS * get_backlight_level(); }
static inline uint16_t scale_backlight(uint16_t v) {
    return v / BACKLIGHT_LEVELS * get_backlight_level();
}

#    ifdef BACKLIGHT_PWM_TIMER
void breathing_task(void)


@@ 403,7 415,7 @@ ISR(TIMERx_OVF_vect)
    set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * ICRx / 255))));
}

#endif  // BACKLIGHT_BREATHING
#endif // BACKLIGHT_BREATHING

void backlight_init_ports(void) {
    // Setup backlight pin as output and output to on state.


@@ 415,10 427,10 @@ void backlight_init_ports(void) {

#ifdef BACKLIGHT_PWM_TIMER
    // TimerX setup, Fast PWM mode count to TOP set in ICRx
    TCCRxA = _BV(WGM11);  // = 0b00000010;
    TCCRxA = _BV(WGM11); // = 0b00000010;
    // clock select clk/1
    TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10);  // = 0b00011001;
#else                                              // hardware PWM
    TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
#else                                             // hardware PWM
    // Pin PB7 = OCR1C (Timer 1, Channel C)
    // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
    // (i.e. start high, go low when counter matches.)


@@ 430,8 442,8 @@ void backlight_init_ports(void) {
    "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]."
    "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)."
    */
    TCCRxA = _BV(COMxx1) | _BV(WGM11);             // = 0b00001010;
    TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10);  // = 0b00011001;
    TCCRxA = _BV(COMxx1) | _BV(WGM11);            // = 0b00001010;
    TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
#endif

#ifdef BACKLIGHT_CUSTOM_RESOLUTION

M quantum/backlight/backlight_chibios.c => quantum/backlight/backlight_chibios.c +10 -6
@@ 53,14 53,14 @@ static PWMConfig pwmCFG = {0xFFFF, /* PWM clock frequency  */

// See http://jared.geek.nz/2013/feb/linear-led-pwm
static uint16_t cie_lightness(uint16_t v) {
    if (v <= 5243)     // if below 8% of max
        return v / 9;  // same as dividing by 900%
    if (v <= 5243)    // if below 8% of max
        return v / 9; // same as dividing by 900%
    else {
        uint32_t y = (((uint32_t)v + 10486) << 8) / (10486 + 0xFFFFUL);  // add 16% of max and compare
        uint32_t y = (((uint32_t)v + 10486) << 8) / (10486 + 0xFFFFUL); // add 16% of max and compare
        // to get a useful result with integer division, we shift left in the expression above
        // and revert what we've done again after squaring.
        y = y * y * y >> 8;
        if (y > 0xFFFFUL)  // prevent overflow
        if (y > 0xFFFFUL) // prevent overflow
            return 0xFFFFU;
        else
            return (uint16_t)y;


@@ 117,7 117,9 @@ static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0,

void breathing_callback(PWMDriver *pwmp);

bool is_breathing(void) { return pwmCFG.callback != NULL; }
bool is_breathing(void) {
    return pwmCFG.callback != NULL;
}

void breathing_enable(void) {
    pwmCFG.callback = breathing_callback;


@@ 133,7 135,9 @@ void breathing_disable(void) {
}

// Use this before the cie_lightness function.
static inline uint16_t scale_backlight(uint16_t v) { return v / BACKLIGHT_LEVELS * get_backlight_level(); }
static inline uint16_t scale_backlight(uint16_t v) {
    return v / BACKLIGHT_LEVELS * get_backlight_level();
}

void breathing_callback(PWMDriver *pwmp) {
    uint8_t  breathing_period = get_breathing_period();

M quantum/backlight/backlight_driver_common.c => quantum/backlight/backlight_driver_common.c +6 -2
@@ 44,6 44,10 @@ void backlight_pins_init(void) {
    FOR_EACH_LED(setPinOutput(backlight_pin); backlight_off(backlight_pin);)
}

void backlight_pins_on(void) { FOR_EACH_LED(backlight_on(backlight_pin);) }
void backlight_pins_on(void) {
    FOR_EACH_LED(backlight_on(backlight_pin);)
}

void backlight_pins_off(void) { FOR_EACH_LED(backlight_off(backlight_pin);) }
void backlight_pins_off(void) {
    FOR_EACH_LED(backlight_off(backlight_pin);)
}

M quantum/backlight/backlight_software.c => quantum/backlight/backlight_software.c +9 -3
@@ 30,11 30,17 @@ static const uint16_t backlight_duty_table[] = {

// clang-format on

static uint8_t scale_backlight(uint8_t v) { return v * (backlight_duty_table_size - 1) / BACKLIGHT_LEVELS; }
static uint8_t scale_backlight(uint8_t v) {
    return v * (backlight_duty_table_size - 1) / BACKLIGHT_LEVELS;
}

void backlight_init_ports(void) { backlight_pins_init(); }
void backlight_init_ports(void) {
    backlight_pins_init();
}

void backlight_set(uint8_t level) { s_duty_pattern = backlight_duty_table[scale_backlight(level)]; }
void backlight_set(uint8_t level) {
    s_duty_pattern = backlight_duty_table[scale_backlight(level)];
}

void backlight_task(void) {
    static uint8_t backlight_tick = 0;

M quantum/backlight/backlight_timer.c => quantum/backlight/backlight_timer.c +22 -10
@@ 14,14 14,14 @@ static uint16_t backlight_timer_get_duty(void);

// See http://jared.geek.nz/2013/feb/linear-led-pwm
static uint16_t cie_lightness(uint16_t v) {
    if (v <= 5243)     // if below 8% of max
        return v / 9;  // same as dividing by 900%
    if (v <= 5243)    // if below 8% of max
        return v / 9; // same as dividing by 900%
    else {
        uint32_t y = (((uint32_t)v + 10486) << 8) / (10486 + 0xFFFFUL);  // add 16% of max and compare
        uint32_t y = (((uint32_t)v + 10486) << 8) / (10486 + 0xFFFFUL); // add 16% of max and compare
        // to get a useful result with integer division, we shift left in the expression above
        // and revert what we've done again after squaring.
        y = y * y * y >> 8;
        if (y > 0xFFFFUL)  // prevent overflow
        if (y > 0xFFFFUL) // prevent overflow
            return 0xFFFFU;
        else
            return (uint16_t)y;


@@ 61,7 61,9 @@ static void backlight_timer_top(void) {
    }
}

static void backlight_timer_cmp(void) { backlight_pins_off(); }
static void backlight_timer_cmp(void) {
    backlight_pins_off();
}

void backlight_task(void) {}



@@ 77,7 79,9 @@ static uint16_t breathing_counter = 0;
static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

// Use this before the cie_lightness function.
static inline uint16_t scale_backlight(uint16_t v) { return v / BACKLIGHT_LEVELS * get_backlight_level(); }
static inline uint16_t scale_backlight(uint16_t v) {
    return v / BACKLIGHT_LEVELS * get_backlight_level();
}

void breathing_task(void) {
    uint8_t  breathing_period = get_breathing_period();


@@ 91,13 95,17 @@ void breathing_task(void) {
    backlight_timer_set_duty(cie_lightness(scale_backlight((uint16_t)breathing_table[index] * 256)));
}

bool is_breathing(void) { return breathing; }
bool is_breathing(void) {
    return breathing;
}

void breathing_enable(void) {
    breathing_counter = 0;
    breathing         = true;
}
void breathing_disable(void) { breathing = false; }
void breathing_disable(void) {
    breathing = false;
}

void breathing_pulse(void) {
    backlight_set(is_backlight_enabled() ? 0 : BACKLIGHT_LEVELS);


@@ 140,8 148,12 @@ static void timerCallback(void) {
    }
}

static void     backlight_timer_set_duty(uint16_t duty) { s_duty = duty; }
static uint16_t backlight_timer_get_duty(void) { return s_duty; }
static void backlight_timer_set_duty(uint16_t duty) {
    s_duty = duty;
}
static uint16_t backlight_timer_get_duty(void) {
    return s_duty;
}

// ChibiOS - Map GPT timer onto Software PWM
static void gptTimerCallback(GPTDriver *gptp) {

M quantum/bitwise.c => quantum/bitwise.c +6 -3
@@ 20,7 20,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 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;
    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 };


@@ 30,13 31,15 @@ __attribute__((noinline)) uint8_t bitpop(uint8_t bits) {

uint8_t bitpop16(uint16_t bits) {
    uint8_t c;
    for (c = 0; bits; c++) bits &= bits - 1;
    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;
    for (c = 0; bits; c++)
        bits &= bits - 1;
    return c;
}


M quantum/bootmagic/bootmagic_lite.c => quantum/bootmagic/bootmagic_lite.c +6 -2
@@ 19,7 19,9 @@
 *
 * ...just incase someone wants to only change the eeprom behaviour
 */
__attribute__((weak)) void bootmagic_lite_reset_eeprom(void) { eeconfig_disable(); }
__attribute__((weak)) void bootmagic_lite_reset_eeprom(void) {
    eeconfig_disable();
}

/** \brief The lite version of TMK's bootmagic based on Wilba.
 *


@@ 57,4 59,6 @@ __attribute__((weak)) void bootmagic_lite(void) {
    }
}

void bootmagic(void) { bootmagic_lite(); }
void bootmagic(void) {
    bootmagic_lite();
}

M quantum/color.c => quantum/color.c +3 -1
@@ 104,7 104,9 @@ RGB hsv_to_rgb(HSV hsv) {
#endif
}

RGB hsv_to_rgb_nocie(HSV hsv) { return hsv_to_rgb_impl(hsv, false); }
RGB hsv_to_rgb_nocie(HSV hsv) {
    return hsv_to_rgb_impl(hsv, false);
}

#ifdef RGBW
#    ifndef MIN

M quantum/command.c => quantum/command.c +1 -1
@@ 446,7 446,7 @@ static bool command_common(uint8_t code) {

        // NKRO toggle
        case MAGIC_KC(MAGIC_KEY_NKRO):
            clear_keyboard();  // clear to prevent stuck keys
            clear_keyboard(); // clear to prevent stuck keys
            keymap_config.nkro = !keymap_config.nkro;
            if (keymap_config.nkro) {
                print("NKRO: on\n");

M quantum/debounce/sym_defer_g.c => quantum/debounce/sym_defer_g.c +1 -1
@@ 45,6 45,6 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool 
}

void debounce_free(void) {}
#else  // no debouncing.
#else // no debouncing.
#    include "none.c"
#endif

M quantum/debounce/sym_defer_pr.c => quantum/debounce/sym_defer_pr.c +3 -1
@@ 69,4 69,6 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool 
    }
}

bool debounce_active(void) { return true; }
bool debounce_active(void) {
    return true;
}

M quantum/debounce/sym_eager_pk.c => quantum/debounce/sym_eager_pk.c +1 -1
@@ 131,7 131,7 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui
                if (*debounce_pointer == DEBOUNCE_ELAPSED) {
                    *debounce_pointer    = DEBOUNCE;
                    counters_need_update = true;
                    existing_row ^= col_mask;  // flip the bit.
                    existing_row ^= col_mask; // flip the bit.
                }
            }
            debounce_pointer++;

M quantum/debounce/tests/debounce_test_common.cpp => quantum/debounce/tests/debounce_test_common.cpp +3 -1
@@ 31,7 31,9 @@ void set_time(uint32_t t);
void advance_time(uint32_t ms);
}

void DebounceTest::addEvents(std::initializer_list<DebounceTestEvent> events) { events_.insert(events_.end(), events.begin(), events.end()); }
void DebounceTest::addEvents(std::initializer_list<DebounceTestEvent> events) {
    events_.insert(events_.end(), events.begin(), events.end());
}

void DebounceTest::runEvents() {
    /* Run the test multiple times, from 1kHz to 10kHz scan rate */

M quantum/deferred_exec.c => quantum/deferred_exec.c +12 -4
@@ 157,7 157,15 @@ void deferred_exec_advanced_task(deferred_executor_t *table, size_t table_count,
static uint32_t            last_deferred_exec_check                = 0;
static deferred_executor_t basic_executors[MAX_DEFERRED_EXECUTORS] = {0};

deferred_token defer_exec(uint32_t delay_ms, deferred_exec_callback callback, void *cb_arg) { return defer_exec_advanced(basic_executors, MAX_DEFERRED_EXECUTORS, delay_ms, callback, cb_arg); }
bool           extend_deferred_exec(deferred_token token, uint32_t delay_ms) { return extend_deferred_exec_advanced(basic_executors, MAX_DEFERRED_EXECUTORS, token, delay_ms); }
bool           cancel_deferred_exec(deferred_token token) { return cancel_deferred_exec_advanced(basic_executors, MAX_DEFERRED_EXECUTORS, token); }
void           deferred_exec_task(void) { deferred_exec_advanced_task(basic_executors, MAX_DEFERRED_EXECUTORS, &last_deferred_exec_check); }
deferred_token defer_exec(uint32_t delay_ms, deferred_exec_callback callback, void *cb_arg) {
    return defer_exec_advanced(basic_executors, MAX_DEFERRED_EXECUTORS, delay_ms, callback, cb_arg);
}
bool extend_deferred_exec(deferred_token token, uint32_t delay_ms) {
    return extend_deferred_exec_advanced(basic_executors, MAX_DEFERRED_EXECUTORS, token, delay_ms);
}
bool cancel_deferred_exec(deferred_token token) {
    return cancel_deferred_exec_advanced(basic_executors, MAX_DEFERRED_EXECUTORS, token);
}
void deferred_exec_task(void) {
    deferred_exec_advanced_task(basic_executors, MAX_DEFERRED_EXECUTORS, &last_deferred_exec_check);
}

M quantum/digitizer.c => quantum/digitizer.c +6 -2
@@ 24,9 24,13 @@ __attribute__((weak)) void digitizer_send(void) {
    }
}

__attribute__((weak)) void digitizer_task(void) { digitizer_send(); }
__attribute__((weak)) void digitizer_task(void) {
    digitizer_send();
}

digitizer_t digitizer_get_report(void) { return digitizerReport; }
digitizer_t digitizer_get_report(void) {
    return digitizerReport;
}

void digitizer_set_report(digitizer_t newDigitizerReport) {
    digitizerReport = newDigitizerReport;

M quantum/dip_switch.c => quantum/dip_switch.c +12 -4
@@ 52,13 52,21 @@ 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)) bool dip_switch_update_user(uint8_t index, bool active) { return true; }
__attribute__((weak)) bool dip_switch_update_user(uint8_t index, bool active) {
    return true;
}

__attribute__((weak)) bool dip_switch_update_kb(uint8_t index, bool active) { return dip_switch_update_user(index, active); }
__attribute__((weak)) bool dip_switch_update_kb(uint8_t index, bool active) {
    return dip_switch_update_user(index, active);
}

__attribute__((weak)) bool dip_switch_update_mask_user(uint32_t state) { return true; }
__attribute__((weak)) bool dip_switch_update_mask_user(uint32_t state) {
    return true;
}

__attribute__((weak)) bool dip_switch_update_mask_kb(uint32_t state) { return dip_switch_update_mask_user(state); }
__attribute__((weak)) bool dip_switch_update_mask_kb(uint32_t state) {
    return dip_switch_update_mask_user(state);
}

void dip_switch_init(void) {
#ifdef DIP_SWITCH_PINS

M quantum/dynamic_keymap.c => quantum/dynamic_keymap.c +13 -7
@@ 14,12 14,12 @@
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "keymap.h"  // to get keymaps[][][]
#include "keymap.h" // to get keymaps[][][]
#include "eeprom.h"
#include "progmem.h"  // to read default from flash
#include "quantum.h"  // for send_string()
#include "progmem.h" // to read default from flash
#include "quantum.h" // for send_string()
#include "dynamic_keymap.h"
#include "via.h"  // for default VIA_EEPROM_ADDR_END
#include "via.h" // for default VIA_EEPROM_ADDR_END

#ifndef DYNAMIC_KEYMAP_LAYER_COUNT
#    define DYNAMIC_KEYMAP_LAYER_COUNT 4


@@ 79,7 79,9 @@
#    define DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + 1)
#endif

uint8_t dynamic_keymap_get_layer_count(void) { return DYNAMIC_KEYMAP_LAYER_COUNT; }
uint8_t dynamic_keymap_get_layer_count(void) {
    return DYNAMIC_KEYMAP_LAYER_COUNT;
}

void *dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column) {
    // TODO: optimize this with some left shifts


@@ 151,9 153,13 @@ uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
    }
}

uint8_t dynamic_keymap_macro_get_count(void) { return DYNAMIC_KEYMAP_MACRO_COUNT; }
uint8_t dynamic_keymap_macro_get_count(void) {
    return DYNAMIC_KEYMAP_MACRO_COUNT;
}

uint16_t dynamic_keymap_macro_get_buffer_size(void) { return DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE; }
uint16_t dynamic_keymap_macro_get_buffer_size(void) {
    return DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE;
}

void dynamic_keymap_macro_get_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
    void *   source = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + offset);

M quantum/eeconfig.c => quantum/eeconfig.c +52 -18
@@ 49,7 49,7 @@ void eeconfig_init_quantum(void) {
    eeprom_update_byte(EECONFIG_KEYMAP_UPPER_BYTE, 0);
    eeprom_update_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
    eeprom_update_byte(EECONFIG_BACKLIGHT, 0);
    eeprom_update_byte(EECONFIG_AUDIO, 0xFF);  // On by default
    eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default
    eeprom_update_dword(EECONFIG_RGBLIGHT, 0);
    eeprom_update_byte(EECONFIG_STENOMODE, 0);
    eeprom_update_dword(EECONFIG_HAPTIC, 0);


@@ 90,13 90,17 @@ void eeconfig_init_quantum(void) {
 *
 * FIXME: needs doc
 */
void eeconfig_init(void) { eeconfig_init_quantum(); }
void eeconfig_init(void) {
    eeconfig_init_quantum();
}

/** \brief eeconfig enable
 *
 * FIXME: needs doc
 */
void eeconfig_enable(void) { eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); }
void eeconfig_enable(void) {
    eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
}

/** \brief eeconfig disable
 *


@@ 141,29 145,39 @@ bool eeconfig_is_disabled(void) {
 *
 * FIXME: needs doc
 */
uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG); }
uint8_t eeconfig_read_debug(void) {
    return eeprom_read_byte(EECONFIG_DEBUG);
}
/** \brief eeconfig update debug
 *
 * FIXME: needs doc
 */
void eeconfig_update_debug(uint8_t val) { eeprom_update_byte(EECONFIG_DEBUG, val); }
void eeconfig_update_debug(uint8_t val) {
    eeprom_update_byte(EECONFIG_DEBUG, val);
}

/** \brief eeconfig read default layer
 *
 * FIXME: needs doc
 */
uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); }
uint8_t eeconfig_read_default_layer(void) {
    return eeprom_read_byte(EECONFIG_DEFAULT_LAYER);
}
/** \brief eeconfig update default layer
 *
 * FIXME: needs doc
 */
void eeconfig_update_default_layer(uint8_t val) { eeprom_update_byte(EECONFIG_DEFAULT_LAYER, val); }
void eeconfig_update_default_layer(uint8_t val) {
    eeprom_update_byte(EECONFIG_DEFAULT_LAYER, val);
}

/** \brief eeconfig read keymap
 *
 * FIXME: needs doc
 */
uint16_t eeconfig_read_keymap(void) { return (eeprom_read_byte(EECONFIG_KEYMAP_LOWER_BYTE) | (eeprom_read_byte(EECONFIG_KEYMAP_UPPER_BYTE) << 8)); }
uint16_t eeconfig_read_keymap(void) {
    return (eeprom_read_byte(EECONFIG_KEYMAP_LOWER_BYTE) | (eeprom_read_byte(EECONFIG_KEYMAP_UPPER_BYTE) << 8));
}
/** \brief eeconfig update keymap
 *
 * FIXME: needs doc


@@ 177,53 191,73 @@ void eeconfig_update_keymap(uint16_t val) {
 *
 * FIXME: needs doc
 */
uint8_t eeconfig_read_audio(void) { return eeprom_read_byte(EECONFIG_AUDIO); }
uint8_t eeconfig_read_audio(void) {
    return eeprom_read_byte(EECONFIG_AUDIO);
}
/** \brief eeconfig update audio
 *
 * FIXME: needs doc
 */
void eeconfig_update_audio(uint8_t val) { eeprom_update_byte(EECONFIG_AUDIO, val); }
void eeconfig_update_audio(uint8_t val) {
    eeprom_update_byte(EECONFIG_AUDIO, val);
}

/** \brief eeconfig read kb
 *
 * FIXME: needs doc
 */
uint32_t eeconfig_read_kb(void) { return eeprom_read_dword(EECONFIG_KEYBOARD); }
uint32_t eeconfig_read_kb(void) {
    return eeprom_read_dword(EECONFIG_KEYBOARD);
}
/** \brief eeconfig update kb
 *
 * FIXME: needs doc
 */
void eeconfig_update_kb(uint32_t val) { eeprom_update_dword(EECONFIG_KEYBOARD, val); }
void eeconfig_update_kb(uint32_t val) {
    eeprom_update_dword(EECONFIG_KEYBOARD, val);
}

/** \brief eeconfig read user
 *
 * FIXME: needs doc
 */
uint32_t eeconfig_read_user(void) { return eeprom_read_dword(EECONFIG_USER); }
uint32_t eeconfig_read_user(void) {
    return eeprom_read_dword(EECONFIG_USER);
}
/** \brief eeconfig update user
 *
 * FIXME: needs doc
 */
void eeconfig_update_user(uint32_t val) { eeprom_update_dword(EECONFIG_USER, val); }
void eeconfig_update_user(uint32_t val) {
    eeprom_update_dword(EECONFIG_USER, val);
}

/** \brief eeconfig read haptic
 *
 * FIXME: needs doc
 */
uint32_t eeconfig_read_haptic(void) { return eeprom_read_dword(EECONFIG_HAPTIC); }
uint32_t eeconfig_read_haptic(void) {
    return eeprom_read_dword(EECONFIG_HAPTIC);
}
/** \brief eeconfig update haptic
 *
 * FIXME: needs doc
 */
void eeconfig_update_haptic(uint32_t val) { eeprom_update_dword(EECONFIG_HAPTIC, val); }
void eeconfig_update_haptic(uint32_t val) {
    eeprom_update_dword(EECONFIG_HAPTIC, val);
}

/** \brief eeconfig read split handedness
 *
 * FIXME: needs doc
 */
bool eeconfig_read_handedness(void) { return !!eeprom_read_byte(EECONFIG_HANDEDNESS); }
bool eeconfig_read_handedness(void) {
    return !!eeprom_read_byte(EECONFIG_HANDEDNESS);
}
/** \brief eeconfig update split handedness
 *
 * FIXME: needs doc
 */
void eeconfig_update_handedness(bool val) { eeprom_update_byte(EECONFIG_HANDEDNESS, !!val); }
void eeconfig_update_handedness(bool val) {
    eeprom_update_byte(EECONFIG_HANDEDNESS, !!val);
}

M quantum/eeconfig.h => quantum/eeconfig.h +27 -25
@@ 21,7 21,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include <stdbool.h>

#ifndef EECONFIG_MAGIC_NUMBER
#    define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEE9  // When changing, decrement this value to avoid future re-init issues
#    define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEE9 // When changing, decrement this value to avoid future re-init issues
#endif
#define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF



@@ 112,28 112,30 @@ void     eeconfig_update_haptic(uint32_t val);
bool eeconfig_read_handedness(void);
void eeconfig_update_handedness(bool val);

#define EECONFIG_DEBOUNCE_HELPER(name, offset, config)                     \
    static uint8_t dirty_##name = false;                                   \
                                                                           \
    static inline void eeconfig_init_##name(void) {                        \
        eeprom_read_block(&config, offset, sizeof(config));                \
        dirty_##name = false;                                              \
    }                                                                      \
    static inline void eeconfig_flush_##name(bool force) {                 \
        if (force || dirty_##name) {                                       \
            eeprom_update_block(&config, offset, sizeof(config));          \
            dirty_##name = false;                                          \
        }                                                                  \
    }                                                                      \
    static inline void eeconfig_flush_##name##_task(uint16_t timeout) {    \
        static uint16_t flush_timer = 0;                                   \
        if (timer_elapsed(flush_timer) > timeout) {                        \
            eeconfig_flush_##name(false);                                  \
            flush_timer = timer_read();                                    \
        }                                                                  \
    }                                                                      \
    static inline void eeconfig_flag_##name(bool v) { dirty_##name |= v; } \
    static inline void eeconfig_write_##name(typeof(config) conf) {        \
        memcpy(&config, &conf, sizeof(config));                            \
        eeconfig_flag_##name(true);                                        \
#define EECONFIG_DEBOUNCE_HELPER(name, offset, config)                  \
    static uint8_t dirty_##name = false;                                \
                                                                        \
    static inline void eeconfig_init_##name(void) {                     \
        eeprom_read_block(&config, offset, sizeof(config));             \
        dirty_##name = false;                                           \
    }                                                                   \
    static inline void eeconfig_flush_##name(bool force) {              \
        if (force || dirty_##name) {                                    \
            eeprom_update_block(&config, offset, sizeof(config));       \
            dirty_##name = false;                                       \
        }                                                               \
    }                                                                   \
    static inline void eeconfig_flush_##name##_task(uint16_t timeout) { \
        static uint16_t flush_timer = 0;                                \
        if (timer_elapsed(flush_timer) > timeout) {                     \
            eeconfig_flush_##name(false);                               \
            flush_timer = timer_read();                                 \
        }                                                               \
    }                                                                   \
    static inline void eeconfig_flag_##name(bool v) {                   \
        dirty_##name |= v;                                              \
    }                                                                   \
    static inline void eeconfig_write_##name(typeof(config) conf) {     \
        memcpy(&config, &conf, sizeof(config));                         \
        eeconfig_flag_##name(true);                                     \
    }

M quantum/encoder.c => quantum/encoder.c +10 -4
@@ 59,9 59,13 @@ static uint8_t thisHand, thatHand;
static uint8_t encoder_value[NUMBER_OF_ENCODERS] = {0};
#endif

__attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { return true; }
__attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) {
    return true;
}

__attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) { return encoder_update_user(index, clockwise); }
__attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) {
    return encoder_update_user(index, clockwise);
}

void encoder_init(void) {
#if defined(SPLIT_KEYBOARD) && defined(ENCODERS_PAD_A_RIGHT) && defined(ENCODERS_PAD_B_RIGHT)


@@ 113,7 117,7 @@ static bool encoder_update(uint8_t index, uint8_t state) {
        changed = true;
        encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
    }
    if (encoder_pulses[i] <= -resolution) {  // direction is arbitrary here, but this clockwise
    if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise
        encoder_value[index]--;
        changed = true;
        encoder_update_kb(index, ENCODER_CLOCKWISE);


@@ 140,7 144,9 @@ bool encoder_read(void) {
#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_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;

M quantum/encoder/tests/mock.c => quantum/encoder/tests/mock.c +3 -1
@@ 26,7 26,9 @@ uint8_t mockSetPinInputHigh(pin_t pin) {
    return 0;
}

bool mockReadPin(pin_t pin) { return pins[pin]; }
bool mockReadPin(pin_t pin) {
    return pins[pin];
}

bool setPin(pin_t pin, bool val) {
    pins[pin] = val;

M quantum/encoder/tests/mock_split.c => quantum/encoder/tests/mock_split.c +3 -1
@@ 26,7 26,9 @@ uint8_t mockSetPinInputHigh(pin_t pin) {
    return 0;
}

bool mockReadPin(pin_t pin) { return pins[pin]; }
bool mockReadPin(pin_t pin) {
    return pins[pin];
}

bool setPin(pin_t pin, bool val) {
    pins[pin] = val;

M quantum/haptic.c => quantum/haptic.c +3 -1
@@ 247,7 247,9 @@ void haptic_set_dwell(uint8_t dwell) {
    xprintf("haptic_config.dwell = %u\n", haptic_config.dwell);
}

uint8_t haptic_get_enable(void) { return haptic_config.enable; }
uint8_t haptic_get_enable(void) {
    return haptic_config.enable;
}

uint8_t haptic_get_mode(void) {
    if (!haptic_config.enable) {

M quantum/keyboard.c => quantum/keyboard.c +43 -15
@@ 110,18 110,34 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#endif

static uint32_t last_input_modification_time = 0;
uint32_t        last_input_activity_time(void) { return last_input_modification_time; }
uint32_t        last_input_activity_elapsed(void) { return timer_elapsed32(last_input_modification_time); }
uint32_t        last_input_activity_time(void) {
    return last_input_modification_time;
}
uint32_t last_input_activity_elapsed(void) {
    return timer_elapsed32(last_input_modification_time);
}

static uint32_t last_matrix_modification_time = 0;
uint32_t        last_matrix_activity_time(void) { return last_matrix_modification_time; }
uint32_t        last_matrix_activity_elapsed(void) { return timer_elapsed32(last_matrix_modification_time); }
void            last_matrix_activity_trigger(void) { last_matrix_modification_time = last_input_modification_time = timer_read32(); }
uint32_t        last_matrix_activity_time(void) {
    return last_matrix_modification_time;
}
uint32_t last_matrix_activity_elapsed(void) {
    return timer_elapsed32(last_matrix_modification_time);
}
void last_matrix_activity_trigger(void) {
    last_matrix_modification_time = last_input_modification_time = timer_read32();
}

static uint32_t last_encoder_modification_time = 0;
uint32_t        last_encoder_activity_time(void) { return last_encoder_modification_time; }
uint32_t        last_encoder_activity_elapsed(void) { return timer_elapsed32(last_encoder_modification_time); }
void            last_encoder_activity_trigger(void) { last_encoder_modification_time = last_input_modification_time = timer_read32(); }
uint32_t        last_encoder_activity_time(void) {
    return last_encoder_modification_time;
}
uint32_t last_encoder_activity_elapsed(void) {
    return timer_elapsed32(last_encoder_modification_time);
}
void last_encoder_activity_trigger(void) {
    last_encoder_modification_time = last_input_modification_time = timer_read32();
}

// Only enable this if console is enabled to print to
#if defined(DEBUG_MATRIX_SCAN_RATE)


@@ 143,7 159,9 @@ void matrix_scan_perf_task(void) {
    }
}

uint32_t get_matrix_scan_rate(void) { return last_matrix_scan_count; }
uint32_t get_matrix_scan_rate(void) {
    return last_matrix_scan_count;
}
#else
#    define matrix_scan_perf_task()
#endif


@@ 163,7 181,7 @@ static matrix_row_t   get_real_keys(uint8_t row, matrix_row_t rowdata) {
}

static inline bool popcount_more_than_one(matrix_row_t rowdata) {
    rowdata &= rowdata - 1;  // if there are less than two bits (keys) set, rowdata will become zero
    rowdata &= rowdata - 1; // if there are less than two bits (keys) set, rowdata will become zero
    return rowdata;
}



@@ 220,7 238,9 @@ __attribute__((weak)) void keyboard_pre_init_user(void) {}
 *
 * FIXME: needs doc
 */
__attribute__((weak)) void keyboard_pre_init_kb(void) { keyboard_pre_init_user(); }
__attribute__((weak)) void keyboard_pre_init_kb(void) {
    keyboard_pre_init_user();
}

/** \brief keyboard_post_init_user
 *


@@ 234,7 254,9 @@ __attribute__((weak)) void keyboard_post_init_user() {}
 * FIXME: needs doc
 */

__attribute__((weak)) void keyboard_post_init_kb(void) { keyboard_post_init_user(); }
__attribute__((weak)) void keyboard_post_init_kb(void) {
    keyboard_post_init_user();
}

/** \brief keyboard_setup
 *


@@ 258,13 280,17 @@ void keyboard_setup(void) {
 *
 * FIXME: needs doc
 */
__attribute__((weak)) bool is_keyboard_master(void) { return true; }
__attribute__((weak)) bool is_keyboard_master(void) {
    return true;
}

/** \brief is_keyboard_left
 *
 * FIXME: needs doc
 */
__attribute__((weak)) bool is_keyboard_left(void) { return true; }
__attribute__((weak)) bool is_keyboard_left(void) {
    return true;
}

#endif



@@ 273,7 299,9 @@ __attribute__((weak)) bool is_keyboard_left(void) { return true; }
 * Override this function if you have a condition where keypresses processing should change:
 *   - splits where the slave side needs to process for rgb/oled functionality
 */
__attribute__((weak)) bool should_process_keypress(void) { return is_keyboard_master(); }
__attribute__((weak)) bool should_process_keypress(void) {
    return is_keyboard_master();
}

/** \brief housekeeping_task_kb
 *

M quantum/keyboard.h => quantum/keyboard.h +22 -14
@@ 44,13 44,21 @@ typedef struct {
 * 1) (time == 0) to handle (keyevent_t){} as empty event
 * 2) Matrix(255, 255) to make TICK event available
 */
static inline bool IS_NOEVENT(keyevent_t event) { return event.time == 0 || (event.key.row == 255 && event.key.col == 255); }
static inline bool IS_PRESSED(keyevent_t event) { return (!IS_NOEVENT(event) && event.pressed); }
static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) && !event.pressed); }
static inline bool IS_NOEVENT(keyevent_t event) {
    return event.time == 0 || (event.key.row == 255 && event.key.col == 255);
}
static inline bool IS_PRESSED(keyevent_t event) {
    return (!IS_NOEVENT(event) && event.pressed);
}
static inline bool IS_RELEASED(keyevent_t event) {
    return (!IS_NOEVENT(event) && !event.pressed);
}

/* Tick event */
#define TICK \
    (keyevent_t) { .key = (keypos_t){.row = 255, .col = 255}, .pressed = false, .time = (timer_read() | 1) }
#define TICK                                                                                    \
    (keyevent_t) {                                                                              \
        .key = (keypos_t){.row = 255, .col = 255}, .pressed = false, .time = (timer_read() | 1) \
    }

/* it runs once at early stage of startup before keyboard_init. */
void keyboard_setup(void);


@@ 68,18 76,18 @@ void keyboard_pre_init_user(void);
void keyboard_post_init_kb(void);
void keyboard_post_init_user(void);

void housekeeping_task(void);       // To be executed by the main loop in each backend TMK protocol
void housekeeping_task_kb(void);    // To be overridden by keyboard-level code
void housekeeping_task_user(void);  // To be overridden by user/keymap-level code
void housekeeping_task(void);      // To be executed by the main loop in each backend TMK protocol
void housekeeping_task_kb(void);   // To be overridden by keyboard-level code
void housekeeping_task_user(void); // To be overridden by user/keymap-level code

uint32_t last_input_activity_time(void);     // Timestamp of the last matrix or encoder activity
uint32_t last_input_activity_elapsed(void);  // Number of milliseconds since the last matrix or encoder activity
uint32_t last_input_activity_time(void);    // Timestamp of the last matrix or encoder activity
uint32_t last_input_activity_elapsed(void); // Number of milliseconds since the last matrix or encoder activity

uint32_t last_matrix_activity_time(void);     // Timestamp of the last matrix activity
uint32_t last_matrix_activity_elapsed(void);  // Number of milliseconds since the last matrix activity
uint32_t last_matrix_activity_time(void);    // Timestamp of the last matrix activity
uint32_t last_matrix_activity_elapsed(void); // Number of milliseconds since the last matrix activity

uint32_t last_encoder_activity_time(void);     // Timestamp of the last encoder activity
uint32_t last_encoder_activity_elapsed(void);  // Number of milliseconds since the last encoder activity
uint32_t last_encoder_activity_time(void);    // Timestamp of the last encoder activity
uint32_t last_encoder_activity_elapsed(void); // Number of milliseconds since the last encoder activity

uint32_t get_matrix_scan_rate(void);


M quantum/keycode.h => quantum/keycode.h +13 -13
@@ 251,7 251,7 @@ enum hid_keyboard_keypad_usage {
    KC_J,
    KC_K,
    KC_L,
    KC_M,  // 0x10
    KC_M, // 0x10
    KC_N,
    KC_O,
    KC_P,


@@ 267,7 267,7 @@ enum hid_keyboard_keypad_usage {
    KC_Z,
    KC_1,
    KC_2,
    KC_3,  // 0x20
    KC_3, // 0x20
    KC_4,
    KC_5,
    KC_6,


@@ 283,7 283,7 @@ enum hid_keyboard_keypad_usage {
    KC_MINUS,
    KC_EQUAL,
    KC_LEFT_BRACKET,
    KC_RIGHT_BRACKET,  // 0x30
    KC_RIGHT_BRACKET, // 0x30
    KC_BACKSLASH,
    KC_NONUS_HASH,
    KC_SEMICOLON,


@@ 299,7 299,7 @@ enum hid_keyboard_keypad_usage {
    KC_F4,
    KC_F5,
    KC_F6,
    KC_F7,  // 0x40
    KC_F7, // 0x40
    KC_F8,
    KC_F9,
    KC_F10,


@@ 315,7 315,7 @@ enum hid_keyboard_keypad_usage {
    KC_END,
    KC_PAGE_DOWN,
    KC_RIGHT,
    KC_LEFT,  // 0x50
    KC_LEFT, // 0x50
    KC_DOWN,
    KC_UP,
    KC_NUM_LOCK,


@@ 331,7 331,7 @@ enum hid_keyboard_keypad_usage {
    KC_KP_5,
    KC_KP_6,
    KC_KP_7,
    KC_KP_8,  // 0x60
    KC_KP_8, // 0x60
    KC_KP_9,
    KC_KP_0,
    KC_KP_DOT,


@@ 347,7 347,7 @@ enum hid_keyboard_keypad_usage {
    KC_F18,
    KC_F19,
    KC_F20,
    KC_F21,  // 0x70
    KC_F21, // 0x70
    KC_F22,
    KC_F23,
    KC_F24,


@@ 363,7 363,7 @@ enum hid_keyboard_keypad_usage {
    KC_PASTE,
    KC_FIND,
    KC_KB_MUTE,
    KC_KB_VOLUME_UP,  // 0x80
    KC_KB_VOLUME_UP, // 0x80
    KC_KB_VOLUME_DOWN,
    KC_LOCKING_CAPS_LOCK,
    KC_LOCKING_NUM_LOCK,


@@ 379,7 379,7 @@ enum hid_keyboard_keypad_usage {
    KC_INTERNATIONAL_7,
    KC_INTERNATIONAL_8,
    KC_INTERNATIONAL_9,
    KC_LANGUAGE_1,  // 0x90
    KC_LANGUAGE_1, // 0x90
    KC_LANGUAGE_2,
    KC_LANGUAGE_3,
    KC_LANGUAGE_4,


@@ 395,7 395,7 @@ enum hid_keyboard_keypad_usage {
    KC_PRIOR,
    KC_RETURN,
    KC_SEPARATOR,
    KC_OUT,  // 0xA0
    KC_OUT, // 0xA0
    KC_OPER,
    KC_CLEAR_AGAIN,
    KC_CRSEL,


@@ 488,7 488,7 @@ enum internal_special_keycodes {
    KC_MEDIA_STOP,
    KC_MEDIA_PLAY_PAUSE,
    KC_MEDIA_SELECT,
    KC_MEDIA_EJECT,  // 0xB0
    KC_MEDIA_EJECT, // 0xB0
    KC_MAIL,
    KC_CALCULATOR,
    KC_MY_COMPUTER,


@@ 514,7 514,7 @@ enum mouse_keys {
#endif
    KC_MS_DOWN,
    KC_MS_LEFT,
    KC_MS_RIGHT,  // 0xF0
    KC_MS_RIGHT, // 0xF0
    KC_MS_BTN1,
    KC_MS_BTN2,
    KC_MS_BTN3,


@@ 539,7 539,7 @@ enum mouse_keys {
    /* Acceleration */
    KC_MS_ACCEL0,
    KC_MS_ACCEL1,
    KC_MS_ACCEL2  // 0xFF
    KC_MS_ACCEL2 // 0xFF
};

#include "keycode_legacy.h"

M quantum/keymap_common.c => quantum/keymap_common.c +1 -1
@@ 77,7 77,7 @@ action_t action_for_keycode(uint16_t keycode) {
        case QK_MODS ... QK_MODS_MAX:;
            // Has a modifier
            // Split it up
            action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF);  // adds modifier to key
            action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key
            break;
#ifndef NO_ACTION_LAYER
        case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:

M quantum/keymap_extras/keymap_nordic.h => quantum/keymap_extras/keymap_nordic.h +1 -1
@@ 24,7 24,7 @@
#define NO_ACUT KC_EQL

#define NO_AM KC_LBRC
#define NO_QUOT KC_RBRC  // this is the "umlaut" char on Nordic keyboards, Apple layout
#define NO_QUOT KC_RBRC // this is the "umlaut" char on Nordic keyboards, Apple layout
#define NO_AE KC_SCLN
#define NO_OSLH KC_QUOT
#define NO_APOS KC_NUHS

M quantum/keymap_extras/keymap_steno.h => quantum/keymap_extras/keymap_steno.h +1 -1
@@ 70,7 70,7 @@ enum steno_keycodes {
    STN_NB,
    STN_NC,
    STN_ZR,
    STN__MAX = STN_ZR,  // must be less than QK_STENO_BOLT
    STN__MAX = STN_ZR, // must be less than QK_STENO_BOLT
};

#ifdef STENO_COMBINEDMAP

M quantum/led.c => quantum/led.c +9 -3
@@ 64,13 64,17 @@ __attribute__((weak)) void led_set_user(uint8_t usb_led) {}
 *
 * \deprecated Use led_update_kb() instead.
 */
__attribute__((weak)) void led_set_kb(uint8_t usb_led) { led_set_user(usb_led); }
__attribute__((weak)) void led_set_kb(uint8_t usb_led) {
    led_set_user(usb_led);
}

/** \brief Lock LED update callback - keymap/user level
 *
 * \return True if led_update_kb() should run its own code, false otherwise.
 */
__attribute__((weak)) bool led_update_user(led_t led_state) { return true; }
__attribute__((weak)) bool led_update_user(led_t led_state) {
    return true;
}

/** \brief Lock LED update callback - keyboard level
 *


@@ 156,7 160,9 @@ void led_suspend(void) {

/** \brief Trigger behaviour on transition from suspend
 */
void led_wakeup(void) { led_set(host_keyboard_leds()); }
void led_wakeup(void) {
    led_set(host_keyboard_leds());
}

/** \brief set host led state
 *

M quantum/led_matrix/animations/alpha_mods_anim.h => quantum/led_matrix/animations/alpha_mods_anim.h +2 -2
@@ 20,5 20,5 @@ bool ALPHAS_MODS(effect_params_t* params) {
    return led_matrix_check_finished_leds(led_max);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_ALPHAS_MODS
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_ALPHAS_MODS

M quantum/led_matrix/animations/band_anim.h => quantum/led_matrix/animations/band_anim.h +5 -3
@@ 7,7 7,9 @@ static uint8_t BAND_math(uint8_t val, uint8_t i, uint8_t time) {
    return scale8(v < 0 ? 0 : v, val);
}

bool BAND(effect_params_t* params) { return effect_runner_i(params, &BAND_math); }
bool BAND(effect_params_t* params) {
    return effect_runner_i(params, &BAND_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_BAND
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_BAND

M quantum/led_matrix/animations/band_pinwheel_anim.h => quantum/led_matrix/animations/band_pinwheel_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(BAND_PINWHEEL)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t BAND_PINWHEEL_math(uint8_t val, int16_t dx, int16_t dy, uint8_t time) { return scale8(val - time - atan2_8(dy, dx) * 3, val); }
static uint8_t BAND_PINWHEEL_math(uint8_t val, int16_t dx, int16_t dy, uint8_t time) {
    return scale8(val - time - atan2_8(dy, dx) * 3, val);
}

bool BAND_PINWHEEL(effect_params_t* params) { return effect_runner_dx_dy(params, &BAND_PINWHEEL_math); }
bool BAND_PINWHEEL(effect_params_t* params) {
    return effect_runner_dx_dy(params, &BAND_PINWHEEL_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_BAND_PINWHEEL
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_BAND_PINWHEEL

M quantum/led_matrix/animations/band_spiral_anim.h => quantum/led_matrix/animations/band_spiral_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(BAND_SPIRAL)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t BAND_SPIRAL_math(uint8_t val, int16_t dx, int16_t dy, uint8_t dist, uint8_t time) { return scale8(val + dist - time - atan2_8(dy, dx), val); }
static uint8_t BAND_SPIRAL_math(uint8_t val, int16_t dx, int16_t dy, uint8_t dist, uint8_t time) {
    return scale8(val + dist - time - atan2_8(dy, dx), val);
}

bool BAND_SPIRAL(effect_params_t* params) { return effect_runner_dx_dy_dist(params, &BAND_SPIRAL_math); }
bool BAND_SPIRAL(effect_params_t* params) {
    return effect_runner_dx_dy_dist(params, &BAND_SPIRAL_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_BAND_SPIRAL
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_BAND_SPIRAL

M quantum/led_matrix/animations/breathing_anim.h => quantum/led_matrix/animations/breathing_anim.h +2 -2
@@ 15,5 15,5 @@ bool BREATHING(effect_params_t* params) {
    return led_matrix_check_finished_leds(led_max);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_BREATHING
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_BREATHING

M quantum/led_matrix/animations/cycle_left_right_anim.h => quantum/led_matrix/animations/cycle_left_right_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(CYCLE_LEFT_RIGHT)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t CYCLE_LEFT_RIGHT_math(uint8_t val, uint8_t i, uint8_t time) { return scale8(g_led_config.point[i].x - time, val); }
static uint8_t CYCLE_LEFT_RIGHT_math(uint8_t val, uint8_t i, uint8_t time) {
    return scale8(g_led_config.point[i].x - time, val);
}

bool CYCLE_LEFT_RIGHT(effect_params_t* params) { return effect_runner_i(params, &CYCLE_LEFT_RIGHT_math); }
bool CYCLE_LEFT_RIGHT(effect_params_t* params) {
    return effect_runner_i(params, &CYCLE_LEFT_RIGHT_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_CYCLE_LEFT_RIGHT
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_CYCLE_LEFT_RIGHT

M quantum/led_matrix/animations/cycle_out_in_anim.h => quantum/led_matrix/animations/cycle_out_in_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(CYCLE_OUT_IN)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t CYCLE_OUT_IN_math(uint8_t val, int16_t dx, int16_t dy, uint8_t dist, uint8_t time) { return scale8(3 * dist / 2 + time, val); }
static uint8_t CYCLE_OUT_IN_math(uint8_t val, int16_t dx, int16_t dy, uint8_t dist, uint8_t time) {
    return scale8(3 * dist / 2 + time, val);
}

bool CYCLE_OUT_IN(effect_params_t* params) { return effect_runner_dx_dy_dist(params, &CYCLE_OUT_IN_math); }
bool CYCLE_OUT_IN(effect_params_t* params) {
    return effect_runner_dx_dy_dist(params, &CYCLE_OUT_IN_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_CYCLE_OUT_IN
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_CYCLE_OUT_IN

M quantum/led_matrix/animations/cycle_up_down_anim.h => quantum/led_matrix/animations/cycle_up_down_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(CYCLE_UP_DOWN)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t CYCLE_UP_DOWN_math(uint8_t val, uint8_t i, uint8_t time) { return scale8(g_led_config.point[i].y - time, val); }
static uint8_t CYCLE_UP_DOWN_math(uint8_t val, uint8_t i, uint8_t time) {
    return scale8(g_led_config.point[i].y - time, val);
}

bool CYCLE_UP_DOWN(effect_params_t* params) { return effect_runner_i(params, &CYCLE_UP_DOWN_math); }
bool CYCLE_UP_DOWN(effect_params_t* params) {
    return effect_runner_i(params, &CYCLE_UP_DOWN_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_CYCLE_UP_DOWN
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_CYCLE_UP_DOWN

M quantum/led_matrix/animations/dual_beacon_anim.h => quantum/led_matrix/animations/dual_beacon_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(DUAL_BEACON)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t DUAL_BEACON_math(uint8_t val, int8_t sin, int8_t cos, uint8_t i, uint8_t time) { return scale8(((g_led_config.point[i].y - k_led_matrix_center.y) * cos + (g_led_config.point[i].x - k_led_matrix_center.x) * sin) / 128, val); }
static uint8_t DUAL_BEACON_math(uint8_t val, int8_t sin, int8_t cos, uint8_t i, uint8_t time) {
    return scale8(((g_led_config.point[i].y - k_led_matrix_center.y) * cos + (g_led_config.point[i].x - k_led_matrix_center.x) * sin) / 128, val);
}

bool DUAL_BEACON(effect_params_t* params) { return effect_runner_sin_cos_i(params, &DUAL_BEACON_math); }
bool DUAL_BEACON(effect_params_t* params) {
    return effect_runner_sin_cos_i(params, &DUAL_BEACON_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_DUAL_BEACON
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_DUAL_BEACON

M quantum/led_matrix/animations/runners/effect_runner_reactive.h => quantum/led_matrix/animations/runners/effect_runner_reactive.h +1 -1
@@ 25,4 25,4 @@ bool effect_runner_reactive(effect_params_t* params, reactive_f effect_func) {
    return led_matrix_check_finished_leds(led_max);
}

#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

M quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h => quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h +1 -1
@@ 23,4 23,4 @@ bool effect_runner_reactive_splash(uint8_t start, effect_params_t* params, react
    return led_matrix_check_finished_leds(led_max);
}

#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

M quantum/led_matrix/animations/solid_anim.h => quantum/led_matrix/animations/solid_anim.h +1 -1
@@ 12,4 12,4 @@ bool SOLID(effect_params_t* params) {
    return led_matrix_check_finished_leds(led_max);
}

#endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS

M quantum/led_matrix/animations/solid_reactive_cross.h => quantum/led_matrix/animations/solid_reactive_cross.h +9 -5
@@ 23,13 23,17 @@ static uint8_t SOLID_REACTIVE_CROSS_math(uint8_t val, int16_t dx, int16_t dy, ui
}

#            ifdef ENABLE_LED_MATRIX_SOLID_REACTIVE_CROSS
bool SOLID_REACTIVE_CROSS(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_CROSS_math); }
bool SOLID_REACTIVE_CROSS(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_CROSS_math);
}
#            endif

#            ifdef ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTICROSS
bool SOLID_REACTIVE_MULTICROSS(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_CROSS_math); }
bool SOLID_REACTIVE_MULTICROSS(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_CROSS_math);
}
#            endif

#        endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_CROSS) || defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTICROSS)
#endif          // LED_MATRIX_KEYREACTIVE_ENABLED
#        endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_CROSS) || defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTICROSS)
#endif         // LED_MATRIX_KEYREACTIVE_ENABLED

M quantum/led_matrix/animations/solid_reactive_nexus.h => quantum/led_matrix/animations/solid_reactive_nexus.h +9 -5
@@ 20,13 20,17 @@ static uint8_t SOLID_REACTIVE_NEXUS_math(uint8_t val, int16_t dx, int16_t dy, ui
}

#            ifdef ENABLE_LED_MATRIX_SOLID_REACTIVE_NEXUS
bool SOLID_REACTIVE_NEXUS(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_NEXUS_math); }
bool SOLID_REACTIVE_NEXUS(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_NEXUS_math);
}
#            endif

#            ifdef ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTINEXUS
bool SOLID_REACTIVE_MULTINEXUS(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_NEXUS_math); }
bool SOLID_REACTIVE_MULTINEXUS(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_NEXUS_math);
}
#            endif

#        endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_NEXUS) || defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTINEXUS)
#endif          // LED_MATRIX_KEYREACTIVE_ENABLED
#        endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_NEXUS) || defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTINEXUS)
#endif         // LED_MATRIX_KEYREACTIVE_ENABLED

M quantum/led_matrix/animations/solid_reactive_simple_anim.h => quantum/led_matrix/animations/solid_reactive_simple_anim.h +9 -5
@@ 3,10 3,14 @@
LED_MATRIX_EFFECT(SOLID_REACTIVE_SIMPLE)
#        ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t SOLID_REACTIVE_SIMPLE_math(uint8_t val, uint16_t offset) { return scale8(255 - offset, val); }
static uint8_t SOLID_REACTIVE_SIMPLE_math(uint8_t val, uint16_t offset) {
    return scale8(255 - offset, val);
}

bool SOLID_REACTIVE_SIMPLE(effect_params_t* params) { return effect_runner_reactive(params, &SOLID_REACTIVE_SIMPLE_math); }
bool SOLID_REACTIVE_SIMPLE(effect_params_t* params) {
    return effect_runner_reactive(params, &SOLID_REACTIVE_SIMPLE_math);
}

#        endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // ENABLE_LED_MATRIX_SOLID_REACTIVE_SIMPLE
#endif          // LED_MATRIX_KEYREACTIVE_ENABLED
#        endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // ENABLE_LED_MATRIX_SOLID_REACTIVE_SIMPLE
#endif         // LED_MATRIX_KEYREACTIVE_ENABLED

M quantum/led_matrix/animations/solid_reactive_wide.h => quantum/led_matrix/animations/solid_reactive_wide.h +9 -5
@@ 18,13 18,17 @@ static uint8_t SOLID_REACTIVE_WIDE_math(uint8_t val, int16_t dx, int16_t dy, uin
}

#            ifdef ENABLE_LED_MATRIX_SOLID_REACTIVE_WIDE
bool SOLID_REACTIVE_WIDE(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_WIDE_math); }
bool SOLID_REACTIVE_WIDE(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_WIDE_math);
}
#            endif

#            ifdef ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTIWIDE
bool SOLID_REACTIVE_MULTIWIDE(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_WIDE_math); }
bool SOLID_REACTIVE_MULTIWIDE(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_WIDE_math);
}
#            endif

#        endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // !defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_WIDE) || !defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTIWIDE)
#endif          // LED_MATRIX_KEYREACTIVE_ENABLED
#        endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // !defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_WIDE) || !defined(ENABLE_LED_MATRIX_SOLID_REACTIVE_MULTIWIDE)
#endif         // LED_MATRIX_KEYREACTIVE_ENABLED

M quantum/led_matrix/animations/solid_splash_anim.h => quantum/led_matrix/animations/solid_splash_anim.h +9 -5
@@ 18,13 18,17 @@ uint8_t SOLID_SPLASH_math(uint8_t val, int16_t dx, int16_t dy, uint8_t dist, uin
}

#            ifdef ENABLE_LED_MATRIX_SOLID_SPLASH
bool SOLID_SPLASH(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_SPLASH_math); }
bool SOLID_SPLASH(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_SPLASH_math);
}
#            endif

#            ifdef ENABLE_LED_MATRIX_SOLID_MULTISPLASH
bool SOLID_MULTISPLASH(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_SPLASH_math); }
bool SOLID_MULTISPLASH(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_SPLASH_math);
}
#            endif

#        endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // defined(ENABLE_LED_MATRIX_SPLASH) || defined(ENABLE_LED_MATRIX_MULTISPLASH)
#endif          // LED_MATRIX_KEYREACTIVE_ENABLED
#        endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // defined(ENABLE_LED_MATRIX_SPLASH) || defined(ENABLE_LED_MATRIX_MULTISPLASH)
#endif         // LED_MATRIX_KEYREACTIVE_ENABLED

M quantum/led_matrix/animations/wave_left_right_anim.h => quantum/led_matrix/animations/wave_left_right_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(WAVE_LEFT_RIGHT)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t WAVE_LEFT_RIGHT_math(uint8_t val, uint8_t i, uint8_t time) { return scale8(sin8(g_led_config.point[i].x - time), val); }
static uint8_t WAVE_LEFT_RIGHT_math(uint8_t val, uint8_t i, uint8_t time) {
    return scale8(sin8(g_led_config.point[i].x - time), val);
}

bool WAVE_LEFT_RIGHT(effect_params_t* params) { return effect_runner_i(params, &WAVE_LEFT_RIGHT_math); }
bool WAVE_LEFT_RIGHT(effect_params_t* params) {
    return effect_runner_i(params, &WAVE_LEFT_RIGHT_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_WAVE_LEFT_RIGHT
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_WAVE_LEFT_RIGHT

M quantum/led_matrix/animations/wave_up_down_anim.h => quantum/led_matrix/animations/wave_up_down_anim.h +8 -4
@@ 2,9 2,13 @@
LED_MATRIX_EFFECT(WAVE_UP_DOWN)
#    ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS

static uint8_t WAVE_UP_DOWN_math(uint8_t val, uint8_t i, uint8_t time) { return scale8(sin8(g_led_config.point[i].y - time), val); }
static uint8_t WAVE_UP_DOWN_math(uint8_t val, uint8_t i, uint8_t time) {
    return scale8(sin8(g_led_config.point[i].y - time), val);
}

bool WAVE_UP_DOWN(effect_params_t* params) { return effect_runner_i(params, &WAVE_UP_DOWN_math); }
bool WAVE_UP_DOWN(effect_params_t* params) {
    return effect_runner_i(params, &WAVE_UP_DOWN_math);
}

#    endif  // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_LED_MATRIX_WAVE_UP_DOWN
#    endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_LED_MATRIX_WAVE_UP_DOWN

M quantum/led_matrix/led_matrix.c => quantum/led_matrix/led_matrix.c +124 -55
@@ 88,14 88,14 @@ const led_point_t k_led_matrix_center = LED_MATRIX_CENTER;
#endif

// globals
led_eeconfig_t led_matrix_eeconfig;  // TODO: would like to prefix this with g_ for global consistancy, do this in another pr
led_eeconfig_t led_matrix_eeconfig; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr
uint32_t       g_led_timer;
#ifdef LED_MATRIX_FRAMEBUFFER_EFFECTS
uint8_t g_led_frame_buffer[MATRIX_ROWS][MATRIX_COLS] = {{0}};
#endif  // LED_MATRIX_FRAMEBUFFER_EFFECTS
#endif // LED_MATRIX_FRAMEBUFFER_EFFECTS
#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
last_hit_t g_last_hit_tracker;
#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

// internals
static bool            suspend_state     = false;


@@ 105,13 105,13 @@ static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false};
static led_task_states led_task_state    = SYNCING;
#if LED_DISABLE_TIMEOUT > 0
static uint32_t led_anykey_timer;
#endif  // LED_DISABLE_TIMEOUT > 0
#endif // LED_DISABLE_TIMEOUT > 0

// double buffers
static uint32_t led_timer_buffer;
#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
static last_hit_t last_hit_buffer;
#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

// split led matrix
#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)


@@ 120,7 120,9 @@ const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT;

EECONFIG_DEBOUNCE_HELPER(led_matrix, EECONFIG_LED_MATRIX, led_matrix_eeconfig);

void eeconfig_update_led_matrix(void) { eeconfig_flush_led_matrix(true); }
void eeconfig_update_led_matrix(void) {
    eeconfig_flush_led_matrix(true);
}

void eeconfig_update_led_matrix_default(void) {
    dprintf("eeconfig_update_led_matrix_default\n");


@@ 141,7 143,9 @@ void eeconfig_debug_led_matrix(void) {
    dprintf("led_matrix_eeconfig.flags = %d\n", led_matrix_eeconfig.flags);
}

__attribute__((weak)) uint8_t led_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) { return 0; }
__attribute__((weak)) uint8_t led_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) {
    return 0;
}

uint8_t led_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) {
    uint8_t led_count = led_matrix_map_row_column_to_led_kb(row, column, led_i);


@@ 153,7 157,9 @@ uint8_t led_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *l
    return led_count;
}

void led_matrix_update_pwm_buffers(void) { led_matrix_driver.flush(); }
void led_matrix_update_pwm_buffers(void) {
    led_matrix_driver.flush();
}

void led_matrix_set_value(int index, uint8_t value) {
#ifdef USE_CIE1931_CURVE


@@ 164,7 170,8 @@ void led_matrix_set_value(int index, uint8_t value) {

void led_matrix_set_value_all(uint8_t value) {
#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
    for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) led_matrix_set_value(i, value);
    for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++)
        led_matrix_set_value(i, value);
#else
#    ifdef USE_CIE1931_CURVE
    led_matrix_driver.set_value_all(pgm_read_byte(&CIE1931_CURVE[value]));


@@ 180,7 187,7 @@ void process_led_matrix(uint8_t row, uint8_t col, bool pressed) {
#endif
#if LED_DISABLE_TIMEOUT > 0
    led_anykey_timer = 0;
#endif  // LED_DISABLE_TIMEOUT > 0
#endif // LED_DISABLE_TIMEOUT > 0

#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
    uint8_t led[LED_HITS_TO_REMEMBER];


@@ 190,7 197,7 @@ void process_led_matrix(uint8_t row, uint8_t col, bool pressed) {
    if (!pressed)
#    elif defined(LED_MATRIX_KEYPRESSES)
    if (pressed)
#    endif  // defined(LED_MATRIX_KEYRELEASES)
#    endif // defined(LED_MATRIX_KEYRELEASES)
    {
        led_count = led_matrix_map_row_column_to_led(row, col, led);
    }


@@ 198,7 205,7 @@ void process_led_matrix(uint8_t row, uint8_t col, bool pressed) {
    if (last_hit_buffer.count + led_count > LED_HITS_TO_REMEMBER) {
        memcpy(&last_hit_buffer.x[0], &last_hit_buffer.x[led_count], LED_HITS_TO_REMEMBER - led_count);
        memcpy(&last_hit_buffer.y[0], &last_hit_buffer.y[led_count], LED_HITS_TO_REMEMBER - led_count);
        memcpy(&last_hit_buffer.tick[0], &last_hit_buffer.tick[led_count], (LED_HITS_TO_REMEMBER - led_count) * 2);  // 16 bit
        memcpy(&last_hit_buffer.tick[0], &last_hit_buffer.tick[led_count], (LED_HITS_TO_REMEMBER - led_count) * 2); // 16 bit
        memcpy(&last_hit_buffer.index[0], &last_hit_buffer.index[led_count], LED_HITS_TO_REMEMBER - led_count);
        last_hit_buffer.count = LED_HITS_TO_REMEMBER - led_count;
    }


@@ 211,13 218,13 @@ void process_led_matrix(uint8_t row, uint8_t col, bool pressed) {
        last_hit_buffer.tick[index]  = 0;
        last_hit_buffer.count++;
    }
#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

#if defined(LED_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_LED_MATRIX_TYPING_HEATMAP)
    if (led_matrix_eeconfig.mode == LED_MATRIX_TYPING_HEATMAP) {
        process_led_matrix_typing_heatmap(row, col);
    }
#endif  // defined(LED_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_LED_MATRIX_TYPING_HEATMAP)
#endif // defined(LED_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_LED_MATRIX_TYPING_HEATMAP)
}

static bool led_matrix_none(effect_params_t *params) {


@@ 232,7 239,7 @@ static bool led_matrix_none(effect_params_t *params) {
static void led_task_timers(void) {
#if defined(LED_MATRIX_KEYREACTIVE_ENABLED) || LED_DISABLE_TIMEOUT > 0
    uint32_t deltaTime = sync_timer_elapsed32(led_timer_buffer);
#endif  // defined(LED_MATRIX_KEYREACTIVE_ENABLED) || LED_DISABLE_TIMEOUT > 0
#endif // defined(LED_MATRIX_KEYREACTIVE_ENABLED) || LED_DISABLE_TIMEOUT > 0
    led_timer_buffer = sync_timer_read32();

    // Update double buffer timers


@@ 244,7 251,7 @@ static void led_task_timers(void) {
            led_anykey_timer += deltaTime;
        }
    }
#endif  // LED_DISABLE_TIMEOUT > 0
#endif // LED_DISABLE_TIMEOUT > 0

    // Update double buffer last hit timers
#ifdef LED_MATRIX_KEYREACTIVE_ENABLED


@@ 256,7 263,7 @@ static void led_task_timers(void) {
        }
        last_hit_buffer.tick[i] += deltaTime;
    }
#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED
}

static void led_task_sync(void) {


@@ 273,7 280,7 @@ static void led_task_start(void) {
    g_led_timer = led_timer_buffer;
#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
    g_last_hit_tracker = last_hit_buffer;
#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

    // next task
    led_task_state = RENDERING;


@@ 352,7 359,7 @@ void led_matrix_task(void) {
    bool suspend_backlight = suspend_state ||
#if LED_DISABLE_TIMEOUT > 0
                             (led_anykey_timer > (uint32_t)LED_DISABLE_TIMEOUT) ||
#endif  // LED_DISABLE_TIMEOUT > 0
#endif // LED_DISABLE_TIMEOUT > 0
                             false;

    uint8_t effect = suspend_backlight || !led_matrix_eeconfig.enable ? 0 : led_matrix_eeconfig.mode;


@@ 421,7 428,7 @@ void led_matrix_init(void) {
    for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) {
        last_hit_buffer.tick[i] = UINT16_MAX;
    }
#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

    if (!eeconfig_is_enabled()) {
        dprintf("led_matrix_init_drivers eeconfig is not enabled.\n");


@@ 434,20 441,22 @@ void led_matrix_init(void) {
        dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n");
        eeconfig_update_led_matrix_default();
    }
    eeconfig_debug_led_matrix();  // display current eeprom values
    eeconfig_debug_led_matrix(); // display current eeprom values
}

void led_matrix_set_suspend_state(bool state) {
#ifdef LED_DISABLE_WHEN_USB_SUSPENDED
    if (state && !suspend_state && is_keyboard_master()) {  // only run if turning off, and only once
        led_task_render(0);                                 // turn off all LEDs when suspending
        led_task_flush(0);                                  // and actually flash led state to LEDs
    if (state && !suspend_state && is_keyboard_master()) { // only run if turning off, and only once
        led_task_render(0);                                // turn off all LEDs when suspending
        led_task_flush(0);                                 // and actually flash led state to LEDs
    }
    suspend_state = state;
#endif
}

bool led_matrix_get_suspend_state(void) { return suspend_state; }
bool led_matrix_get_suspend_state(void) {
    return suspend_state;
}

void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
    led_matrix_eeconfig.enable ^= 1;


@@ 455,8 464,12 @@ void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
    eeconfig_flag_led_matrix(write_to_eeprom);
    dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable);
}
void led_matrix_toggle_noeeprom(void) { led_matrix_toggle_eeprom_helper(false); }
void led_matrix_toggle(void) { led_matrix_toggle_eeprom_helper(true); }
void led_matrix_toggle_noeeprom(void) {
    led_matrix_toggle_eeprom_helper(false);
}
void led_matrix_toggle(void) {
    led_matrix_toggle_eeprom_helper(true);
}

void led_matrix_enable(void) {
    led_matrix_enable_noeeprom();


@@ 478,7 491,9 @@ void led_matrix_disable_noeeprom(void) {
    led_matrix_eeconfig.enable = 0;
}

uint8_t led_matrix_is_enabled(void) { return led_matrix_eeconfig.enable; }
uint8_t led_matrix_is_enabled(void) {
    return led_matrix_eeconfig.enable;
}

void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
    if (!led_matrix_eeconfig.enable) {


@@ 495,24 510,38 @@ void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
    eeconfig_flag_led_matrix(write_to_eeprom);
    dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.mode);
}
void led_matrix_mode_noeeprom(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, false); }
void led_matrix_mode(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, true); }
void led_matrix_mode_noeeprom(uint8_t mode) {
    led_matrix_mode_eeprom_helper(mode, false);
}
void led_matrix_mode(uint8_t mode) {
    led_matrix_mode_eeprom_helper(mode, true);
}

uint8_t led_matrix_get_mode(void) { return led_matrix_eeconfig.mode; }
uint8_t led_matrix_get_mode(void) {
    return led_matrix_eeconfig.mode;
}

void led_matrix_step_helper(bool write_to_eeprom) {
    uint8_t mode = led_matrix_eeconfig.mode + 1;
    led_matrix_mode_eeprom_helper((mode < LED_MATRIX_EFFECT_MAX) ? mode : 1, write_to_eeprom);
}
void led_matrix_step_noeeprom(void) { led_matrix_step_helper(false); }
void led_matrix_step(void) { led_matrix_step_helper(true); }
void led_matrix_step_noeeprom(void) {
    led_matrix_step_helper(false);
}
void led_matrix_step(void) {
    led_matrix_step_helper(true);
}

void led_matrix_step_reverse_helper(bool write_to_eeprom) {
    uint8_t mode = led_matrix_eeconfig.mode - 1;
    led_matrix_mode_eeprom_helper((mode < 1) ? LED_MATRIX_EFFECT_MAX - 1 : mode, write_to_eeprom);
}
void led_matrix_step_reverse_noeeprom(void) { led_matrix_step_reverse_helper(false); }
void led_matrix_step_reverse(void) { led_matrix_step_reverse_helper(true); }
void led_matrix_step_reverse_noeeprom(void) {
    led_matrix_step_reverse_helper(false);
}
void led_matrix_step_reverse(void) {
    led_matrix_step_reverse_helper(true);
}

void led_matrix_set_val_eeprom_helper(uint8_t val, bool write_to_eeprom) {
    if (!led_matrix_eeconfig.enable) {


@@ 522,37 551,77 @@ void led_matrix_set_val_eeprom_helper(uint8_t val, bool write_to_eeprom) {
    eeconfig_flag_led_matrix(write_to_eeprom);
    dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val);
}
void led_matrix_set_val_noeeprom(uint8_t val) { led_matrix_set_val_eeprom_helper(val, false); }
void led_matrix_set_val(uint8_t val) { led_matrix_set_val_eeprom_helper(val, true); }
void led_matrix_set_val_noeeprom(uint8_t val) {
    led_matrix_set_val_eeprom_helper(val, false);
}
void led_matrix_set_val(uint8_t val) {
    led_matrix_set_val_eeprom_helper(val, true);
}

uint8_t led_matrix_get_val(void) { return led_matrix_eeconfig.val; }
uint8_t led_matrix_get_val(void) {
    return led_matrix_eeconfig.val;
}

void led_matrix_increase_val_helper(bool write_to_eeprom) { led_matrix_set_val_eeprom_helper(qadd8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom); }
void led_matrix_increase_val_noeeprom(void) { led_matrix_increase_val_helper(false); }
void led_matrix_increase_val(void) { led_matrix_increase_val_helper(true); }
void led_matrix_increase_val_helper(bool write_to_eeprom) {
    led_matrix_set_val_eeprom_helper(qadd8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom);
}
void led_matrix_increase_val_noeeprom(void) {
    led_matrix_increase_val_helper(false);
}
void led_matrix_increase_val(void) {
    led_matrix_increase_val_helper(true);
}

void led_matrix_decrease_val_helper(bool write_to_eeprom) { led_matrix_set_val_eeprom_helper(qsub8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom); }
void led_matrix_decrease_val_noeeprom(void) { led_matrix_decrease_val_helper(false); }
void led_matrix_decrease_val(void) { led_matrix_decrease_val_helper(true); }
void led_matrix_decrease_val_helper(bool write_to_eeprom) {
    led_matrix_set_val_eeprom_helper(qsub8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom);
}
void led_matrix_decrease_val_noeeprom(void) {
    led_matrix_decrease_val_helper(false);
}
void led_matrix_decrease_val(void) {
    led_matrix_decrease_val_helper(true);
}

void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
    led_matrix_eeconfig.speed = speed;
    eeconfig_flag_led_matrix(write_to_eeprom);
    dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed);
}
void led_matrix_set_speed_noeeprom(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, false); }
void led_matrix_set_speed(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, true); }
void led_matrix_set_speed_noeeprom(uint8_t speed) {
    led_matrix_set_speed_eeprom_helper(speed, false);
}
void led_matrix_set_speed(uint8_t speed) {
    led_matrix_set_speed_eeprom_helper(speed, true);
}

uint8_t led_matrix_get_speed(void) { return led_matrix_eeconfig.speed; }
uint8_t led_matrix_get_speed(void) {
    return led_matrix_eeconfig.speed;
}

void led_matrix_increase_speed_helper(bool write_to_eeprom) { led_matrix_set_speed_eeprom_helper(qadd8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom); }
void led_matrix_increase_speed_noeeprom(void) { led_matrix_increase_speed_helper(false); }
void led_matrix_increase_speed(void) { led_matrix_increase_speed_helper(true); }
void led_matrix_increase_speed_helper(bool write_to_eeprom) {
    led_matrix_set_speed_eeprom_helper(qadd8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom);
}
void led_matrix_increase_speed_noeeprom(void) {
    led_matrix_increase_speed_helper(false);
}
void led_matrix_increase_speed(void) {
    led_matrix_increase_speed_helper(true);
}

void led_matrix_decrease_speed_helper(bool write_to_eeprom) { led_matrix_set_speed_eeprom_helper(qsub8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom); }
void led_matrix_decrease_speed_noeeprom(void) { led_matrix_decrease_speed_helper(false); }
void led_matrix_decrease_speed(void) { led_matrix_decrease_speed_helper(true); }
void led_matrix_decrease_speed_helper(bool write_to_eeprom) {
    led_matrix_set_speed_eeprom_helper(qsub8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom);
}
void led_matrix_decrease_speed_noeeprom(void) {
    led_matrix_decrease_speed_helper(false);
}
void led_matrix_decrease_speed(void) {
    led_matrix_decrease_speed_helper(true);
}

led_flags_t led_matrix_get_flags(void) { return led_matrix_eeconfig.flags; }
led_flags_t led_matrix_get_flags(void) {
    return led_matrix_eeconfig.flags;
}

void led_matrix_set_flags(led_flags_t flags) { led_matrix_eeconfig.flags = flags; }
void led_matrix_set_flags(led_flags_t flags) {
    led_matrix_eeconfig.flags = flags;
}

M quantum/led_matrix/led_matrix_types.h => quantum/led_matrix/led_matrix_types.h +3 -3
@@ 36,7 36,7 @@
// Last led hit
#ifndef LED_HITS_TO_REMEMBER
#    define LED_HITS_TO_REMEMBER 8
#endif  // LED_HITS_TO_REMEMBER
#endif // LED_HITS_TO_REMEMBER

#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
typedef struct PACKED {


@@ 46,7 46,7 @@ typedef struct PACKED {
    uint8_t  index[LED_HITS_TO_REMEMBER];
    uint16_t tick[LED_HITS_TO_REMEMBER];
} last_hit_t;
#endif  // LED_MATRIX_KEYREACTIVE_ENABLED
#endif // LED_MATRIX_KEYREACTIVE_ENABLED

typedef enum led_task_states { STARTING, RENDERING, FLUSHING, SYNCING } led_task_states;



@@ 87,7 87,7 @@ typedef union {
        uint8_t     mode : 6;
        uint16_t    reserved;
        uint8_t     val;
        uint8_t     speed;  // EECONFIG needs to be increased to support this
        uint8_t     speed; // EECONFIG needs to be increased to support this
        led_flags_t flags;
    };
} led_eeconfig_t;

M quantum/logging/debug.c => quantum/logging/debug.c +5 -5
@@ 17,9 17,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include "debug.h"

debug_config_t debug_config = {
    .enable   = false,  //
    .matrix   = false,  //
    .keyboard = false,  //
    .mouse    = false,  //
    .reserved = 0       //
    .enable   = false, //
    .matrix   = false, //
    .keyboard = false, //
    .mouse    = false, //
    .reserved = 0      //
};

M quantum/logging/print.c => quantum/logging/print.c +9 -3
@@ 19,9 19,15 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

// bind lib/printf to console interface - sendchar

static int8_t          null_sendchar_func(uint8_t c) { return 0; }
static int8_t null_sendchar_func(uint8_t c) {
    return 0;
}
static sendchar_func_t func = null_sendchar_func;

void print_set_sendchar(sendchar_func_t send) { func = send; }
void print_set_sendchar(sendchar_func_t send) {
    func = send;
}

void _putchar(char character) { func(character); }
void _putchar(char character) {
    func(character);
}

M quantum/logging/print.h => quantum/logging/print.h +1 -1
@@ 37,7 37,7 @@ void print_set_sendchar(sendchar_func_t func);
#        include_next "_print.h" /* Include the platforms print.h */
#    else
// Fall back to lib/printf
#        include "printf.h"  // lib/printf/printf.h
#        include "printf.h" // lib/printf/printf.h

// Create user & normal print defines
#        define print(s) printf(s)

M quantum/logging/sendchar.c => quantum/logging/sendchar.c +3 -1
@@ 17,4 17,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include "sendchar.h"

/* default noop "null" implementation */
__attribute__((weak)) int8_t sendchar(uint8_t c) { return 0; }
__attribute__((weak)) int8_t sendchar(uint8_t c) {
    return 0;
}

M quantum/main.c => quantum/main.c +2 -2
@@ 45,7 45,7 @@ void protocol_task(void) {

#ifdef DEFERRED_EXEC_ENABLE
void deferred_exec_task(void);
#endif  // DEFERRED_EXEC_ENABLE
#endif // DEFERRED_EXEC_ENABLE

/** \brief Main
 *


@@ 66,7 66,7 @@ int main(void) {
#ifdef DEFERRED_EXEC_ENABLE
        // Run deferred executions
        deferred_exec_task();
#endif  // DEFERRED_EXEC_ENABLE
#endif // DEFERRED_EXEC_ENABLE

        housekeeping_task();
    }

M quantum/matrix.c => quantum/matrix.c +15 -13
@@ 51,15 51,15 @@ static SPLIT_MUTABLE pin_t direct_pins[ROWS_PER_HAND][MATRIX_COLS] = DIRECT_PINS
#elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
#    ifdef MATRIX_ROW_PINS
static SPLIT_MUTABLE_ROW pin_t row_pins[ROWS_PER_HAND] = MATRIX_ROW_PINS;
#    endif  // MATRIX_ROW_PINS
#    endif // MATRIX_ROW_PINS
#    ifdef MATRIX_COL_PINS
static SPLIT_MUTABLE_COL pin_t col_pins[MATRIX_COLS]   = MATRIX_COL_PINS;
#    endif  // MATRIX_COL_PINS
#    endif // MATRIX_COL_PINS
#endif

/* matrix state(1:on, 0:off) */
extern matrix_row_t raw_matrix[MATRIX_ROWS];  // raw values
extern matrix_row_t matrix[MATRIX_ROWS];      // debounced values
extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
extern matrix_row_t matrix[MATRIX_ROWS];     // debounced values

#ifdef SPLIT_KEYBOARD
// row offsets for each hand


@@ 86,7 86,9 @@ static inline void setPinOutput_writeHigh(pin_t pin) {
}

static inline void setPinInputHigh_atomic(pin_t pin) {
    ATOMIC_BLOCK_FORCEON { setPinInputHigh(pin); }
    ATOMIC_BLOCK_FORCEON {
        setPinInputHigh(pin);
    }
}

static inline uint8_t readMatrixPin(pin_t pin) {


@@ 171,8 173,8 @@ __attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[]
    // Start with a clear matrix row
    matrix_row_t current_row_value = 0;

    if (!select_row(current_row)) {  // Select row
        return;                      // skip NO_PIN row
    if (!select_row(current_row)) { // Select row
        return;                     // skip NO_PIN row
    }
    matrix_output_select_delay();



@@ 187,7 189,7 @@ __attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[]

    // Unselect row
    unselect_row(current_row);
    matrix_output_unselect_delay(current_row, current_row_value != 0);  // wait for all Col signals to go HIGH
    matrix_output_unselect_delay(current_row, current_row_value != 0); // wait for all Col signals to go HIGH

    // Update the matrix
    current_matrix[current_row] = current_row_value;


@@ 234,8 236,8 @@ __attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[]
    bool key_pressed = false;

    // Select col
    if (!select_col(current_col)) {  // select col
        return;                      // skip NO_PIN col
    if (!select_col(current_col)) { // select col
        return;                     // skip NO_PIN col
    }
    matrix_output_select_delay();



@@ 254,13 256,13 @@ __attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[]

    // Unselect col
    unselect_col(current_col);
    matrix_output_unselect_delay(current_col, key_pressed);  // wait for all Row signals to go HIGH
    matrix_output_unselect_delay(current_col, key_pressed); // wait for all Row signals to go HIGH
}

#        else
#            error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
#        endif
#    endif  // defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
#    endif // defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
#else
#    error DIODE_DIRECTION is not defined!
#endif


@@ 311,7 313,7 @@ void matrix_init(void) {
// Fallback implementation for keyboards not using the standard split_util.c
__attribute__((weak)) bool transport_master_if_connected(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
    transport_master(master_matrix, slave_matrix);
    return true;  // Treat the transport as always connected
    return true; // Treat the transport as always connected
}
#endif


M quantum/matrix_common.c => quantum/matrix_common.c +33 -11
@@ 33,9 33,13 @@ extern const matrix_row_t matrix_mask[];

// user-defined overridable functions

__attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
__attribute__((weak)) void matrix_init_kb(void) {
    matrix_init_user();
}

__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
__attribute__((weak)) void matrix_scan_kb(void) {
    matrix_scan_user();
}

__attribute__((weak)) void matrix_init_user(void) {}



@@ 43,11 47,17 @@ __attribute__((weak)) void matrix_scan_user(void) {}

// helper functions

inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
inline uint8_t matrix_rows(void) {
    return MATRIX_ROWS;
}

inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
inline uint8_t matrix_cols(void) {
    return MATRIX_COLS;
}

inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); }
inline bool matrix_is_on(uint8_t row, uint8_t col) {
    return (matrix[row] & ((matrix_row_t)1 << col));
}

inline matrix_row_t matrix_get_row(uint8_t row) {
    // Matrix mask lets you disable switches in the returned matrix data. For example, if you have a


@@ 124,16 134,26 @@ bool matrix_post_scan(void) {
#endif

/* `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(uint8_t line, bool key_pressed) { matrix_io_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(uint8_t line, bool key_pressed) {
    matrix_io_delay();
}

// CUSTOM MATRIX 'LITE'
__attribute__((weak)) void matrix_init_custom(void) {}
__attribute__((weak)) bool matrix_scan_custom(matrix_row_t current_matrix[]) { return true; }
__attribute__((weak)) bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    return true;
}

#ifdef SPLIT_KEYBOARD
__attribute__((weak)) void matrix_slave_scan_kb(void) { matrix_slave_scan_user(); }
__attribute__((weak)) void matrix_slave_scan_kb(void) {
    matrix_slave_scan_user();
}
__attribute__((weak)) void matrix_slave_scan_user(void) {}
#endif



@@ 170,4 190,6 @@ __attribute__((weak)) uint8_t matrix_scan(void) {
    return changed;
}

__attribute__((weak)) bool peek_matrix(uint8_t row_index, uint8_t col_index, bool raw) { return 0 != ((raw ? raw_matrix[row_index] : matrix[row_index]) & (MATRIX_ROW_SHIFTER << col_index)); }
__attribute__((weak)) bool peek_matrix(uint8_t row_index, uint8_t col_index, bool raw) {
    return 0 != ((raw ? raw_matrix[row_index] : matrix[row_index]) & (MATRIX_ROW_SHIFTER << col_index));
}

M quantum/mousekey.c => quantum/mousekey.c +3 -1
@@ 487,4 487,6 @@ static void mousekey_debug(void) {
    print(")\n");
}

report_mouse_t mousekey_get_report(void) { return mouse_report; }
report_mouse_t mousekey_get_report(void) {
    return mouse_report;
}

M quantum/pointing_device.c => quantum/pointing_device.c +29 -11
@@ 39,7 39,9 @@ uint16_t       shared_cpi          = 0;
 *
 * @param[in] new_mouse_report report_mouse_t
 */
void pointing_device_set_shared_report(report_mouse_t new_mouse_report) { shared_mouse_report = new_mouse_report; }
void pointing_device_set_shared_report(report_mouse_t new_mouse_report) {
    shared_mouse_report = new_mouse_report;
}

/**
 * @brief Gets current pointing device CPI if supported


@@ 50,7 52,9 @@ void pointing_device_set_shared_report(report_mouse_t new_mouse_report) { shared
 *
 * @return cpi value as uint16_t
 */
uint16_t pointing_device_get_shared_cpi(void) { return shared_cpi; }
uint16_t pointing_device_get_shared_cpi(void) {
    return shared_cpi;
}

#    if defined(POINTING_DEVICE_LEFT)
#        define POINTING_DEVICE_THIS_SIDE is_keyboard_left()


@@ 60,7 64,7 @@ uint16_t pointing_device_get_shared_cpi(void) { return shared_cpi; }
#        define POINTING_DEVICE_THIS_SIDE true
#    endif

#endif  // defined(SPLIT_POINTING_ENABLE)
#endif // defined(SPLIT_POINTING_ENABLE)

static report_mouse_t local_mouse_report = {};



@@ 73,7 77,9 @@ extern const pointing_device_driver_t pointing_device_driver;
 * @param[in] old report_mouse_t
 * @return bool result
 */
__attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return memcmp(&new, &old, sizeof(new)); }
__attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) {
    return memcmp(&new, &old, sizeof(new));
}

/**
 * @brief Keyboard level code pointing device initialisation


@@ 95,7 101,9 @@ __attribute__((weak)) void pointing_device_init_user(void) {}
 * @param[in] mouse_report report_mouse_t
 * @return report_mouse_t
 */
__attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { return pointing_device_task_user(mouse_report); }
__attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
    return pointing_device_task_user(mouse_report);
}

/**
 * @brief Weak function allowing for user level mouse report modification


@@ 105,7 113,9 @@ __attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mous
 * @param[in] mouse_report report_mouse_t
 * @return report_mouse_t
 */
__attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { return mouse_report; }
__attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
    return mouse_report;
}

/**
 * @brief Handles pointing device buttons


@@ 246,7 256,7 @@ __attribute__((weak)) void pointing_device_task(void) {
#    endif
#else
    local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
#endif  // defined(SPLIT_POINTING_ENABLE)
#endif // defined(SPLIT_POINTING_ENABLE)

    // allow kb to intercept and modify report
#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED)


@@ 275,14 285,18 @@ __attribute__((weak)) void pointing_device_task(void) {
 *
 * @return report_mouse_t
 */
report_mouse_t pointing_device_get_report(void) { return local_mouse_report; }
report_mouse_t pointing_device_get_report(void) {
    return local_mouse_report;
}

/**
 * @brief Sets mouse report used be pointing device task
 *
 * @param[in] new_mouse_report
 */
void pointing_device_set_report(report_mouse_t new_mouse_report) { local_mouse_report = new_mouse_report; }
void pointing_device_set_report(report_mouse_t new_mouse_report) {
    local_mouse_report = new_mouse_report;
}

/**
 * @brief Gets current pointing device CPI if supported


@@ 422,7 436,9 @@ report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_repo
 * @param[in] right_report report_mouse_t
 * @return pointing_device_task_combined_user(left_report, right_report) by default
 */
__attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report) { return pointing_device_task_combined_user(left_report, right_report); }
__attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report) {
    return pointing_device_task_combined_user(left_report, right_report);
}

/**
 * @brief Weak function allowing for user level mouse report modification


@@ 435,5 451,7 @@ __attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mou
 * @param[in] right_report report_mouse_t
 * @return pointing_device_combine_reports(left_report, right_report) by default
 */
__attribute__((weak)) report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) { return pointing_device_combine_reports(left_report, right_report); }
__attribute__((weak)) report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) {
    return pointing_device_combine_reports(left_report, right_report);
}
#endif

M quantum/pointing_device.h => quantum/pointing_device.h +2 -2
@@ 103,5 103,5 @@ report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, repor
report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report);
report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report);
report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report);
#    endif  // defined(POINTING_DEVICE_COMBINED)
#endif      // defined(SPLIT_POINTING_ENABLE)
#    endif // defined(POINTING_DEVICE_COMBINED)
#endif     // defined(SPLIT_POINTING_ENABLE)

M quantum/pointing_device_drivers.c => quantum/pointing_device_drivers.c +16 -8
@@ 120,7 120,7 @@ report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) {
    int8_t          report_x = 0, report_y = 0;
    static bool     is_z_down = false;

    cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale());  // Scale coordinates to arbitrary X, Y resolution
    cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); // Scale coordinates to arbitrary X, Y resolution

    if (x && y && touchData.xValue && touchData.yValue) {
        report_x = (int8_t)(touchData.xValue - x);


@@ 207,11 207,13 @@ const pointing_device_driver_t pointing_device_driver = {
};
// clang-format on
#elif defined(POINTING_DEVICE_DRIVER_pmw3360)
static void pmw3360_device_init(void) { pmw3360_init(); }
static void pmw3360_device_init(void) {
    pmw3360_init();
}

report_mouse_t pmw3360_get_report(report_mouse_t mouse_report) {
    report_pmw3360_t data        = pmw3360_read_burst();
    static uint16_t  MotionStart = 0;  // Timer for accel, 0 is resting state
    static uint16_t  MotionStart = 0; // Timer for accel, 0 is resting state

    if (data.isOnSurface && data.isMotion) {
        // Reset timer if stopped moving


@@ 243,11 245,13 @@ const pointing_device_driver_t pointing_device_driver = {
};
// clang-format on
#elif defined(POINTING_DEVICE_DRIVER_pmw3389)
static void pmw3389_device_init(void) { pmw3389_init(); }
static void pmw3389_device_init(void) {
    pmw3389_init();
}

report_mouse_t pmw3389_get_report(report_mouse_t mouse_report) {
    report_pmw3389_t data        = pmw3389_read_burst();
    static uint16_t  MotionStart = 0;  // Timer for accel, 0 is resting state
    static uint16_t  MotionStart = 0; // Timer for accel, 0 is resting state

    if (data.isOnSurface && data.isMotion) {
        // Reset timer if stopped moving


@@ 280,9 284,13 @@ const pointing_device_driver_t pointing_device_driver = {
// clang-format on
#else
__attribute__((weak)) void           pointing_device_driver_init(void) {}
__attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) { return mouse_report; }
__attribute__((weak)) uint16_t       pointing_device_driver_get_cpi(void) { return 0; }
__attribute__((weak)) void           pointing_device_driver_set_cpi(uint16_t cpi) {}
__attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) {
    return mouse_report;
}
__attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) {
    return 0;
}
__attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) {}

// clang-format off
const pointing_device_driver_t pointing_device_driver = {

M quantum/process_keycode/process_audio.c => quantum/process_keycode/process_audio.c +9 -3
@@ 50,11 50,17 @@ bool process_audio(uint16_t keycode, keyrecord_t *record) {
    return true;
}

void process_audio_noteon(uint8_t note) { play_note(compute_freq_for_midi_note(note), 0xF); }
void process_audio_noteon(uint8_t note) {
    play_note(compute_freq_for_midi_note(note), 0xF);
}

void process_audio_noteoff(uint8_t note) { stop_note(compute_freq_for_midi_note(note)); }
void process_audio_noteoff(uint8_t note) {
    stop_note(compute_freq_for_midi_note(note));
}

void process_audio_all_notes_off(void) { stop_all_notes(); }
void process_audio_all_notes_off(void) {
    stop_all_notes();
}

__attribute__((weak)) void audio_on_user() {}
__attribute__((weak)) void audio_off_user() {}

M quantum/process_keycode/process_auto_shift.c => quantum/process_keycode/process_auto_shift.c +27 -9
@@ 62,7 62,9 @@ static struct {
// clang-format on

/** \brief Called on physical press, returns whether key should be added to Auto Shift */
__attribute__((weak)) bool get_custom_auto_shifted_key(uint16_t keycode, keyrecord_t *record) { return false; }
__attribute__((weak)) bool get_custom_auto_shifted_key(uint16_t keycode, keyrecord_t *record) {
    return false;
}

/** \brief Called on physical press, returns whether is Auto Shift key */
__attribute__((weak)) bool get_auto_shifted_key(uint16_t keycode, keyrecord_t *record) {


@@ 82,8 84,12 @@ __attribute__((weak)) bool get_auto_shifted_key(uint16_t keycode, keyrecord_t *r
}

/** \brief Called to check whether defines should apply if PER_KEY is set for it */
__attribute__((weak)) bool get_auto_shift_repeat(uint16_t keycode, keyrecord_t *record) { return true; }
__attribute__((weak)) bool get_auto_shift_no_auto_repeat(uint16_t keycode, keyrecord_t *record) { return true; }
__attribute__((weak)) bool get_auto_shift_repeat(uint16_t keycode, keyrecord_t *record) {
    return true;
}
__attribute__((weak)) bool get_auto_shift_no_auto_repeat(uint16_t keycode, keyrecord_t *record) {
    return true;
}

/** \brief Called when an Auto Shift key needs to be pressed */
__attribute__((weak)) void autoshift_press_user(uint16_t keycode, bool shifted, keyrecord_t *record) {


@@ 94,7 100,9 @@ __attribute__((weak)) void autoshift_press_user(uint16_t keycode, bool shifted, 
}

/** \brief Called when an Auto Shift key needs to be released */
__attribute__((weak)) void autoshift_release_user(uint16_t keycode, bool shifted, keyrecord_t *record) { unregister_code16((IS_RETRO(keycode)) ? keycode & 0xFF : keycode); }
__attribute__((weak)) void autoshift_release_user(uint16_t keycode, bool shifted, keyrecord_t *record) {
    unregister_code16((IS_RETRO(keycode)) ? keycode & 0xFF : keycode);
}

/** \brief Sets the shift state to use when keyrepeating, required by custom shifts */
void set_autoshift_shift_state(uint16_t keycode, bool shifted) {


@@ 311,7 319,9 @@ void autoshift_toggle(void) {
    autoshift_flush_shift();
}

void autoshift_enable(void) { autoshift_flags.enabled = true; }
void autoshift_enable(void) {
    autoshift_flags.enabled = true;
}

void autoshift_disable(void) {
    autoshift_flags.enabled = false;


@@ 328,12 338,20 @@ void autoshift_timer_report(void) {
}
#    endif

bool get_autoshift_state(void) { return autoshift_flags.enabled; }
bool get_autoshift_state(void) {
    return autoshift_flags.enabled;
}

uint16_t                       get_generic_autoshift_timeout() { return autoshift_timeout; }
__attribute__((weak)) uint16_t get_autoshift_timeout(uint16_t keycode, keyrecord_t *record) { return autoshift_timeout; }
uint16_t get_generic_autoshift_timeout() {
    return autoshift_timeout;
}
__attribute__((weak)) uint16_t get_autoshift_timeout(uint16_t keycode, keyrecord_t *record) {
    return autoshift_timeout;
}

void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; }
void set_autoshift_timeout(uint16_t timeout) {
    autoshift_timeout = timeout;
}

bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
    // Note that record->event.time isn't reliable, see:

M quantum/process_keycode/process_clicky.c => quantum/process_keycode/process_clicky.c +18 -14
@@ 5,40 5,40 @@

#    ifndef AUDIO_CLICKY_DELAY_DURATION
#        define AUDIO_CLICKY_DELAY_DURATION 1
#    endif  // !AUDIO_CLICKY_DELAY_DURATION
#    endif // !AUDIO_CLICKY_DELAY_DURATION
#    ifndef AUDIO_CLICKY_FREQ_DEFAULT
#        define AUDIO_CLICKY_FREQ_DEFAULT 440.0f
#    endif  // !AUDIO_CLICKY_FREQ_DEFAULT
#    endif // !AUDIO_CLICKY_FREQ_DEFAULT
#    ifndef AUDIO_CLICKY_FREQ_MIN
#        define AUDIO_CLICKY_FREQ_MIN 65.0f
#    endif  // !AUDIO_CLICKY_FREQ_MIN
#    endif // !AUDIO_CLICKY_FREQ_MIN
#    ifndef AUDIO_CLICKY_FREQ_MAX
#        define AUDIO_CLICKY_FREQ_MAX 1500.0f
#    endif  // !AUDIO_CLICKY_FREQ_MAX
#    endif // !AUDIO_CLICKY_FREQ_MAX
#    ifndef AUDIO_CLICKY_FREQ_FACTOR
#        define AUDIO_CLICKY_FREQ_FACTOR 1.18921f
#    endif  // !AUDIO_CLICKY_FREQ_FACTOR
#    endif // !AUDIO_CLICKY_FREQ_FACTOR
#    ifndef AUDIO_CLICKY_FREQ_RANDOMNESS
#        define AUDIO_CLICKY_FREQ_RANDOMNESS 0.05f
#    endif  // !AUDIO_CLICKY_FREQ_RANDOMNESS
#    endif // !AUDIO_CLICKY_FREQ_RANDOMNESS

float clicky_freq = AUDIO_CLICKY_FREQ_DEFAULT;
float clicky_rand = AUDIO_CLICKY_FREQ_RANDOMNESS;

// the first "note" is an intentional delay; the 2nd and 3rd notes are the "clicky"
float clicky_song[][2] = {{AUDIO_CLICKY_FREQ_MIN, AUDIO_CLICKY_DELAY_DURATION}, {AUDIO_CLICKY_FREQ_DEFAULT, 3}, {AUDIO_CLICKY_FREQ_DEFAULT, 1}};  // 3 and 1 --> durations
float clicky_song[][2] = {{AUDIO_CLICKY_FREQ_MIN, AUDIO_CLICKY_DELAY_DURATION}, {AUDIO_CLICKY_FREQ_DEFAULT, 3}, {AUDIO_CLICKY_FREQ_DEFAULT, 1}}; // 3 and 1 --> durations

extern audio_config_t audio_config;

#    ifndef NO_MUSIC_MODE
extern bool music_activated;
extern bool midi_activated;
#    endif  // !NO_MUSIC_MODE
#    endif // !NO_MUSIC_MODE

void clicky_play(void) {
#    ifndef NO_MUSIC_MODE
    if (music_activated || midi_activated || !audio_config.enable) return;
#    endif  // !NO_MUSIC_MODE
#    endif // !NO_MUSIC_MODE
    clicky_song[1][0] = 2.0f * clicky_freq * (1.0f + clicky_rand * (((float)rand()) / ((float)(RAND_MAX))));
    clicky_song[2][0] = clicky_freq * (1.0f + clicky_rand * (((float)rand()) / ((float)(RAND_MAX))));
    PLAY_SONG(clicky_song);


@@ 58,7 58,9 @@ void clicky_freq_down(void) {
    }
}

void clicky_freq_reset(void) { clicky_freq = AUDIO_CLICKY_FREQ_DEFAULT; }
void clicky_freq_reset(void) {
    clicky_freq = AUDIO_CLICKY_FREQ_DEFAULT;
}

void clicky_toggle(void) {
    audio_config.clicky_enable ^= 1;


@@ 75,7 77,9 @@ void clicky_off(void) {
    eeconfig_update_audio(audio_config.raw);
}

bool is_clicky_on(void) { return (audio_config.clicky_enable != 0); }
bool is_clicky_on(void) {
    return (audio_config.clicky_enable != 0);
}

bool process_clicky(uint16_t keycode, keyrecord_t *record) {
    if (keycode == CLICKY_TOGGLE && record->event.pressed) {


@@ 101,8 105,8 @@ bool process_clicky(uint16_t keycode, keyrecord_t *record) {
    }

    if (audio_config.enable && audio_config.clicky_enable) {
        if (record->event.pressed) {                       // Leave this separate so it's easier to add upstroke sound
            if (keycode != AU_OFF && keycode != AU_TOG) {  // DO NOT PLAY if audio will be disabled, and causes issuse on ARM
        if (record->event.pressed) {                      // Leave this separate so it's easier to add upstroke sound
            if (keycode != AU_OFF && keycode != AU_TOG) { // DO NOT PLAY if audio will be disabled, and causes issuse on ARM
                clicky_play();
            }
        }


@@ 110,4 114,4 @@ bool process_clicky(uint16_t keycode, keyrecord_t *record) {
    return true;
}

#endif  // AUDIO_CLICKY
#endif // AUDIO_CLICKY

M quantum/process_keycode/process_combo.c => quantum/process_keycode/process_combo.c +28 -12
@@ 30,33 30,45 @@ extern uint16_t COMBO_LEN;
__attribute__((weak)) void process_combo_event(uint16_t combo_index, bool pressed) {}

#ifdef COMBO_MUST_HOLD_PER_COMBO
__attribute__((weak)) bool get_combo_must_hold(uint16_t index, combo_t *combo) { return false; }
__attribute__((weak)) bool get_combo_must_hold(uint16_t index, combo_t *combo) {
    return false;
}
#endif

#ifdef COMBO_MUST_TAP_PER_COMBO
__attribute__((weak)) bool get_combo_must_tap(uint16_t index, combo_t *combo) { return false; }
__attribute__((weak)) bool get_combo_must_tap(uint16_t index, combo_t *combo) {
    return false;
}
#endif

#ifdef COMBO_TERM_PER_COMBO
__attribute__((weak)) uint16_t get_combo_term(uint16_t index, combo_t *combo) { return COMBO_TERM; }
__attribute__((weak)) uint16_t get_combo_term(uint16_t index, combo_t *combo) {
    return COMBO_TERM;
}
#endif

#ifdef COMBO_MUST_PRESS_IN_ORDER_PER_COMBO
__attribute__((weak)) bool get_combo_must_press_in_order(uint16_t combo_index, combo_t *combo) { return true; }
__attribute__((weak)) bool get_combo_must_press_in_order(uint16_t combo_index, combo_t *combo) {
    return true;
}
#endif

#ifdef COMBO_PROCESS_KEY_RELEASE
__attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) { return false; }
__attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) {
    return false;
}
#endif

#ifdef COMBO_SHOULD_TRIGGER
__attribute__((weak)) bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) { return true; }
__attribute__((weak)) bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) {
    return true;
}
#endif

#ifndef COMBO_NO_TIMER
static uint16_t timer = 0;
#endif
static bool     b_combo_enable = true;  // defaults to enabled
static bool     b_combo_enable = true; // defaults to enabled
static uint16_t longest_term   = 0;

typedef struct {


@@ 462,7 474,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
                    // get possible longer waiting time for tap-/hold-only combos.
                    longest_term = _get_wait_time(combo_index, combo);
                }
            }  // if timer elapsed end
            } // if timer elapsed end
        }
    } else {
        // chord releases


@@ 477,7 489,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
            else if (get_combo_must_tap(combo_index, combo)) {
                // immediately apply tap-only combo
                apply_combo(combo_index, combo);
                apply_combos();  // also apply other prepared combos and dump key buffer
                apply_combos(); // also apply other prepared combos and dump key buffer
#    ifdef COMBO_PROCESS_KEY_RELEASE
                if (process_combo_key_release(combo_index, combo, key_index, keycode)) {
                    release_combo(combo_index, combo);


@@ 559,7 571,7 @@ bool process_combo(uint16_t keycode, keyrecord_t *record) {
            key_buffer[key_buffer_size++] = (queued_record_t){
                .record      = *record,
                .keycode     = keycode,
                .combo_index = -1,  // this will be set when applying combos
                .combo_index = -1, // this will be set when applying combos
            };
        }
    } else {


@@ 598,7 610,9 @@ void combo_task(void) {
#endif
}

void combo_enable(void) { b_combo_enable = true; }
void combo_enable(void) {
    b_combo_enable = true;
}

void combo_disable(void) {
#ifndef COMBO_NO_TIMER


@@ 618,4 632,6 @@ void combo_toggle(void) {
    }
}

bool is_combo_enabled(void) { return b_combo_enable; }
bool is_combo_enabled(void) {
    return b_combo_enable;
}

M quantum/process_keycode/process_dynamic_macro.c => quantum/process_keycode/process_dynamic_macro.c +12 -4
@@ 29,13 29,21 @@ void dynamic_macro_led_blink(void) {

/* User hooks for Dynamic Macros */

__attribute__((weak)) void dynamic_macro_record_start_user(void) { dynamic_macro_led_blink(); }
__attribute__((weak)) void dynamic_macro_record_start_user(void) {
    dynamic_macro_led_blink();
}

__attribute__((weak)) void dynamic_macro_play_user(int8_t direction) { dynamic_macro_led_blink(); }
__attribute__((weak)) void dynamic_macro_play_user(int8_t direction) {
    dynamic_macro_led_blink();
}

__attribute__((weak)) void dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record) { dynamic_macro_led_blink(); }
__attribute__((weak)) void dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record) {
    dynamic_macro_led_blink();
}

__attribute__((weak)) void dynamic_macro_record_end_user(int8_t direction) { dynamic_macro_led_blink(); }
__attribute__((weak)) void dynamic_macro_record_end_user(int8_t direction) {
    dynamic_macro_led_blink();
}

/* Convenience macros used for retrieving the debug info. All of them
 * need a `direction` variable accessible at the call site.

M quantum/process_keycode/process_joystick.c => quantum/process_keycode/process_joystick.c +3 -1
@@ 74,7 74,9 @@ void restorePinState(pin_t pin, uint16_t restoreState) {
#endif
}

__attribute__((weak)) bool process_joystick_analogread() { return process_joystick_analogread_quantum(); }
__attribute__((weak)) bool process_joystick_analogread() {
    return process_joystick_analogread_quantum();
}

bool process_joystick_analogread_quantum() {
#if JOYSTICK_AXES_COUNT > 0

M quantum/process_keycode/process_key_override.c => quantum/process_keycode/process_key_override.c +13 -11
@@ 106,7 106,9 @@ void key_override_toggle(void) {
    }
}

bool key_override_is_enabled(void) { return enabled; }
bool key_override_is_enabled(void) {
    return enabled;
}

// Returns whether the modifiers that are pressed are such that the override should activate
static bool key_override_matches_active_modifiers(const key_override_t *override, const uint8_t mods) {


@@ 150,7 152,7 @@ static void schedule_deferred_register(const uint16_t keycode) {
    } else {
        // Wait a very short time when a modifier event triggers the override to avoid false activations when e.g. a modifier is pressed just before a key is released (with the intention of pairing the modifier with a different key), or a modifier is lifted shortly before the trigger key is lifted. Operating systems by default reject modifier-events that happen very close to a non-modifier event.
        defer_reference_time = timer_read32();
        defer_delay          = 50;  // 50ms
        defer_delay          = 50; // 50ms
    }
    deferred_register = keycode;
}


@@ 174,8 176,8 @@ const key_override_t *clear_active_override(const bool allow_reregister) {

    const uint8_t mod_free_replacement = clear_mods_from(active_override->replacement);

    bool unregister_replacement = mod_free_replacement != KC_NO &&    // KC_NO is never registered
                                  mod_free_replacement < SAFE_RANGE;  // Custom keycodes are never registered
    bool unregister_replacement = mod_free_replacement != KC_NO &&   // KC_NO is never registered
                                  mod_free_replacement < SAFE_RANGE; // Custom keycodes are never registered

    // Try firing the custom handler
    if (active_override->custom_action != NULL) {


@@ 195,11 197,11 @@ const key_override_t *clear_active_override(const bool allow_reregister) {

    const uint16_t trigger = active_override->trigger;

    const bool reregister_trigger = allow_reregister &&                                                   // Check if allowed from caller
                                    (active_override->options & ko_option_no_reregister_trigger) == 0 &&  // Check if override allows
                                    active_override_trigger_is_down &&                                    // Check if trigger is even down
                                    trigger != KC_NO &&                                                   // KC_NO is never registered
                                    trigger < SAFE_RANGE;                                                 // A custom keycode should not be registered
    const bool reregister_trigger = allow_reregister &&                                                  // Check if allowed from caller
                                    (active_override->options & ko_option_no_reregister_trigger) == 0 && // Check if override allows
                                    active_override_trigger_is_down &&                                   // Check if trigger is even down
                                    trigger != KC_NO &&                                                  // KC_NO is never registered
                                    trigger < SAFE_RANGE;                                                // A custom keycode should not be registered

    // Optionally re-register the trigger if it is still down
    if (reregister_trigger) {


@@ 336,8 338,8 @@ static bool try_activating_override(const uint16_t keycode, const uint8_t layer,

        const uint16_t mod_free_replacement = clear_mods_from(override->replacement);

        bool register_replacement = mod_free_replacement != KC_NO &&    // KC_NO is never registered
                                    mod_free_replacement < SAFE_RANGE;  // Custom keycodes are never registered
        bool register_replacement = mod_free_replacement != KC_NO &&   // KC_NO is never registered
                                    mod_free_replacement < SAFE_RANGE; // Custom keycodes are never registered

        // Try firing the custom handler
        if (override->custom_action != NULL) {

M quantum/process_keycode/process_leader.c => quantum/process_keycode/process_leader.c +2 -2
@@ 51,13 51,13 @@ bool process_leader(uint16_t keycode, keyrecord_t *record) {
        if (leading) {
#    ifndef LEADER_NO_TIMEOUT
            if (timer_elapsed(leader_time) < LEADER_TIMEOUT)
#    endif  // LEADER_NO_TIMEOUT
#    endif // LEADER_NO_TIMEOUT
            {
#    ifndef LEADER_KEY_STRICT_KEY_PROCESSING
                if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
                    keycode = keycode & 0xFF;
                }
#    endif  // LEADER_KEY_STRICT_KEY_PROCESSING
#    endif // LEADER_KEY_STRICT_KEY_PROCESSING
                if (leader_sequence_size < (sizeof(leader_sequence) / sizeof(leader_sequence[0]))) {
                    leader_sequence[leader_sequence_size] = keycode;
                    leader_sequence_size++;

M quantum/process_keycode/process_magic.c => quantum/process_keycode/process_magic.c +4 -4
@@ 76,7 76,7 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) {
                        keymap_config.swap_backslash_backspace = true;
                        break;
                    case MAGIC_HOST_NKRO:
                        clear_keyboard();  // clear first buffer to prevent stuck keys
                        clear_keyboard(); // clear first buffer to prevent stuck keys
                        keymap_config.nkro = true;
                        break;
                    case MAGIC_SWAP_ALT_GUI:


@@ 119,7 119,7 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) {
                        keymap_config.swap_backslash_backspace = false;
                        break;
                    case MAGIC_UNHOST_NKRO:
                        clear_keyboard();  // clear first buffer to prevent stuck keys
                        clear_keyboard(); // clear first buffer to prevent stuck keys
                        keymap_config.nkro = false;
                        break;
                    case MAGIC_UNSWAP_ALT_GUI:


@@ 157,7 157,7 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) {
#endif
                        break;
                    case MAGIC_TOGGLE_NKRO:
                        clear_keyboard();  // clear first buffer to prevent stuck keys
                        clear_keyboard(); // clear first buffer to prevent stuck keys
                        keymap_config.nkro = !keymap_config.nkro;
                        break;
                    case MAGIC_EE_HANDS_LEFT:


@@ 175,7 175,7 @@ bool process_magic(uint16_t keycode, keyrecord_t *record) {
                }

                eeconfig_update_keymap(keymap_config.raw);
                clear_keyboard();  // clear to prevent stuck keys
                clear_keyboard(); // clear to prevent stuck keys

                return false;
        }

M quantum/process_keycode/process_midi.c => quantum/process_keycode/process_midi.c +18 -8
@@ 22,13 22,19 @@

#    ifdef MIDI_BASIC

void process_midi_basic_noteon(uint8_t note) { midi_send_noteon(&midi_device, 0, note, 127); }
void process_midi_basic_noteon(uint8_t note) {
    midi_send_noteon(&midi_device, 0, note, 127);
}

void process_midi_basic_noteoff(uint8_t note) { midi_send_noteoff(&midi_device, 0, note, 0); }
void process_midi_basic_noteoff(uint8_t note) {
    midi_send_noteoff(&midi_device, 0, note, 0);
}

void process_midi_all_notes_off(void) { midi_send_cc(&midi_device, 0, 0x7B, 0); }
void process_midi_all_notes_off(void) {
    midi_send_cc(&midi_device, 0, 0x7B, 0);
}

#    endif  // MIDI_BASIC
#    endif // MIDI_BASIC

#    ifdef MIDI_ADVANCED



@@ 41,7 47,9 @@ static int8_t   midi_modulation_step;
static uint16_t midi_modulation_timer;
midi_config_t   midi_config;

inline uint8_t compute_velocity(uint8_t setting) { return setting * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN)); }
inline uint8_t compute_velocity(uint8_t setting) {
    return setting * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN));
}

void midi_init(void) {
    midi_config.octave              = MI_OCT_2 - MIDI_OCTAVE_MIN;


@@ 60,7 68,9 @@ void midi_init(void) {
    midi_modulation_timer = 0;
}

uint8_t midi_compute_note(uint16_t keycode) { return 12 * midi_config.octave + (keycode - MIDI_TONE_MIN) + midi_config.transpose; }
uint8_t midi_compute_note(uint16_t keycode) {
    return 12 * midi_config.octave + (keycode - MIDI_TONE_MIN) + midi_config.transpose;
}

bool process_midi(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {


@@ 238,7 248,7 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) {
    return true;
}

#    endif  // MIDI_ADVANCED
#    endif // MIDI_ADVANCED

void midi_task(void) {
    midi_device_process(&midi_device);


@@ 263,4 273,4 @@ void midi_task(void) {
#    endif
}

#endif  // MIDI_ENABLE
#endif // MIDI_ENABLE

M quantum/process_keycode/process_midi.h => quantum/process_keycode/process_midi.h +2 -2
@@ 49,6 49,6 @@ bool process_midi(uint16_t keycode, keyrecord_t *record);
#        define MIDI_TONE_COUNT (MIDI_TONE_MAX - MIDI_TONE_MIN + 1)

uint8_t midi_compute_note(uint16_t keycode);
#    endif  // MIDI_ADVANCED
#    endif // MIDI_ADVANCED

#endif  // MIDI_ENABLE
#endif // MIDI_ENABLE

M quantum/process_keycode/process_music.c => quantum/process_keycode/process_music.c +17 -9
@@ 146,7 146,7 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {

    if (music_activated || midi_activated) {
        if (record->event.pressed) {
            if (keycode == KC_LEFT_CTRL) {  // Start recording
            if (keycode == KC_LEFT_CTRL) { // Start recording
                music_all_notes_off();
                music_sequence_recording = true;
                music_sequence_recorded  = false;


@@ 155,9 155,9 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {
                return false;
            }

            if (keycode == KC_LEFT_ALT) {  // Stop recording/playing
            if (keycode == KC_LEFT_ALT) { // Stop recording/playing
                music_all_notes_off();
                if (music_sequence_recording) {  // was recording
                if (music_sequence_recording) { // was recording
                    music_sequence_recorded = true;
                }
                music_sequence_recording = false;


@@ 165,7 165,7 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {
                return false;
            }

            if (keycode == KC_LEFT_GUI && music_sequence_recorded) {  // Start playing
            if (keycode == KC_LEFT_GUI && music_sequence_recorded) { // Start playing
                music_all_notes_off();
                music_sequence_recording = false;
                music_sequence_playing   = true;


@@ 230,11 230,17 @@ bool music_mask(uint16_t keycode) {
#    endif
}

__attribute__((weak)) bool music_mask_kb(uint16_t keycode) { return music_mask_user(keycode); }
__attribute__((weak)) bool music_mask_kb(uint16_t keycode) {
    return music_mask_user(keycode);
}

__attribute__((weak)) bool music_mask_user(uint16_t keycode) { return keycode < 0xFF; }
__attribute__((weak)) bool music_mask_user(uint16_t keycode) {
    return keycode < 0xFF;
}

bool is_music_on(void) { return (music_activated != 0); }
bool is_music_on(void) {
    return (music_activated != 0);
}

void music_toggle(void) {
    if (!music_activated) {


@@ 260,7 266,9 @@ void music_off(void) {
#    endif
}

bool is_midi_on(void) { return (midi_activated != 0); }
bool is_midi_on(void) {
    return (midi_activated != 0);
}

void midi_toggle(void) {
    if (!midi_activated) {


@@ 315,4 323,4 @@ __attribute__((weak)) void midi_on_user() {}

__attribute__((weak)) void music_scale_user() {}

#endif  // defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))
#endif // defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))

M quantum/process_keycode/process_music.h => quantum/process_keycode/process_music.h +5 -3
@@ 51,8 51,10 @@ bool music_mask_kb(uint16_t keycode);
bool music_mask_user(uint16_t keycode);

#    ifndef SCALE
#        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), }
#        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), \
            }
#    endif

#endif  // defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))
#endif // defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))

M quantum/process_keycode/process_printer.c => quantum/process_keycode/process_printer.c +5 -2
@@ 26,7 26,9 @@ void enable_printing(void) {
    uart_init(19200);
}

void disable_printing(void) { printing_enabled = false; }
void disable_printing(void) {
    printing_enabled = false;
}

uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29};



@@ 41,7 43,8 @@ void print_char(char c) {
}

void print_string(char c[]) {
    for (uint8_t i = 0; i < strlen(c); i++) print_char(c[i]);
    for (uint8_t i = 0; i < strlen(c); i++)
        print_char(c[i]);
}

void print_box_string(const char text[]) {

M quantum/process_keycode/process_printer_bb.c => quantum/process_keycode/process_printer_bb.c +17 -6
@@ 25,13 25,21 @@ uint8_t character_shift  = 0;
#define SERIAL_PIN_MASK _BV(PD3)
#define SERIAL_DELAY 52

inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); }
inline static void serial_delay(void) {
    _delay_us(SERIAL_DELAY);
}

inline static void serial_high(void) { SERIAL_PIN_PORT |= SERIAL_PIN_MASK; }
inline static void serial_high(void) {
    SERIAL_PIN_PORT |= SERIAL_PIN_MASK;
}

inline static void serial_low(void) { SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK; }
inline static void serial_low(void) {
    SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK;
}

inline static void serial_output(void) { SERIAL_PIN_DDR |= SERIAL_PIN_MASK; }
inline static void serial_output(void) {
    SERIAL_PIN_DDR |= SERIAL_PIN_MASK;
}

void enable_printing() {
    printing_enabled = true;


@@ 39,7 47,9 @@ void enable_printing() {
    serial_high();
}

void disable_printing() { printing_enabled = false; }
void disable_printing() {
    printing_enabled = false;
}

uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29};



@@ 61,7 71,8 @@ void print_char(char c) {
}

void print_string(char c[]) {
    for (uint8_t i = 0; i < strlen(c); i++) print_char(c[i]);
    for (uint8_t i = 0; i < strlen(c); i++)
        print_char(c[i]);
}

bool process_printer(uint16_t keycode, keyrecord_t *record) {

M quantum/process_keycode/process_steno.c => quantum/process_keycode/process_steno.c +17 -7
@@ 102,11 102,17 @@ void steno_set_mode(steno_mode_t new_mode) {
/* override to intercept chords right before they get sent.
 * return zero to suppress normal sending behavior.
 */
__attribute__((weak)) bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { return true; }
__attribute__((weak)) bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) {
    return true;
}

__attribute__((weak)) bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed) { return true; }
__attribute__((weak)) bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed) {
    return true;
}

__attribute__((weak)) bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; }
__attribute__((weak)) bool process_steno_user(uint16_t keycode, keyrecord_t *record) {
    return true;
}

static void send_steno_chord(void) {
    if (send_steno_chord_user(mode, chord)) {


@@ 114,11 120,11 @@ static void send_steno_chord(void) {
            case STENO_MODE_BOLT:
                send_steno_state(BOLT_STATE_SIZE, false);
#ifdef VIRTSER_ENABLE
                virtser_send(0);  // terminating byte
                virtser_send(0); // terminating byte
#endif
                break;
            case STENO_MODE_GEMINI:
                chord[0] |= 0x80;  // Indicate start of packet
                chord[0] |= 0x80; // Indicate start of packet
                send_steno_state(GEMINI_STATE_SIZE, true);
                break;
        }


@@ 126,9 132,13 @@ static void send_steno_chord(void) {
    steno_clear_state();
}

uint8_t *steno_get_state(void) { return &state[0]; }
uint8_t *steno_get_state(void) {
    return &state[0];
}

uint8_t *steno_get_chord(void) { return &chord[0]; }
uint8_t *steno_get_chord(void) {
    return &chord[0];
}

static bool update_state_bolt(uint8_t key, bool press) {
    uint8_t boltcode = pgm_read_byte(boltmap + key);

M quantum/process_keycode/process_tap_dance.c => quantum/process_keycode/process_tap_dance.c +3 -1
@@ 86,7 86,9 @@ static inline void _process_tap_dance_action_fn(qk_tap_dance_state_t *state, voi
    }
}

static inline void process_tap_dance_action_on_each_tap(qk_tap_dance_action_t *action) { _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_each_tap); }
static inline void process_tap_dance_action_on_each_tap(qk_tap_dance_action_t *action) {
    _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_each_tap);
}

static inline void process_tap_dance_action_on_dance_finished(qk_tap_dance_action_t *action) {
    if (action->state.finished) return;

M quantum/process_keycode/process_terminal.c => quantum/process_keycode/process_terminal.c +18 -16
@@ 27,12 27,12 @@
bool terminal_enabled = false;
char buffer[80]       = "";
char cmd_buffer[CMD_BUFF_SIZE][80];
bool cmd_buffer_enabled = true;  // replace with ifdef?
bool cmd_buffer_enabled = true; // replace with ifdef?
char newline[2]         = "\n";
char arguments[6][20];
bool firstTime = true;

short int current_cmd_buffer_pos = 0;  // used for up/down arrows - keeps track of where you are in the command buffer
short int current_cmd_buffer_pos = 0; // used for up/down arrows - keeps track of where you are in the command buffer

__attribute__((weak)) const char terminal_prompt[8] = "> ";



@@ 59,7 59,8 @@ void enable_terminal(void) {
    terminal_enabled = true;
    strcpy(buffer, "");
    memset(cmd_buffer, 0, CMD_BUFF_SIZE * 80);
    for (int i = 0; i < 6; i++) strcpy(arguments[i], "");
    for (int i = 0; i < 6; i++)
        strcpy(arguments[i], "");
    // select all text to start over
    // SEND_STRING(SS_LCTL("a"));
    send_string(terminal_prompt);


@@ 160,7 161,7 @@ void print_cmd_buff(void) {
    for (int i = 0; i < CMD_BUFF_SIZE; i++) {
        char tmpChar = ' ';
        itoa(i, &tmpChar, 10);
        const char *tmpCnstCharStr = &tmpChar;  // because sned_string wont take a normal char *
        const char *tmpCnstCharStr = &tmpChar; // because sned_string wont take a normal char *
        send_string(tmpCnstCharStr);
        SEND_STRING(". ");
        send_string(cmd_buffer[i]);


@@ 185,7 186,7 @@ void terminal_help(void) {
}

void command_not_found(void) {
    wait_ms(50);  // sometimes buffer isnt grabbed quick enough
    wait_ms(50); // sometimes buffer isnt grabbed quick enough
    SEND_STRING("command \"");
    send_string(buffer);
    SEND_STRING("\" not found\n");


@@ 217,15 218,16 @@ void process_terminal_command(void) {

    if (terminal_enabled) {
        strcpy(buffer, "");
        for (int i = 0; i < 6; i++) strcpy(arguments[i], "");
        for (int i = 0; i < 6; i++)
            strcpy(arguments[i], "");
        SEND_STRING(SS_TAP(X_HOME));
        send_string(terminal_prompt);
    }
}
void check_pos(void) {
    if (current_cmd_buffer_pos >= CMD_BUFF_SIZE) {  // if over the top, move it back down to the top of the buffer so you can climb back down...
    if (current_cmd_buffer_pos >= CMD_BUFF_SIZE) { // if over the top, move it back down to the top of the buffer so you can climb back down...
        current_cmd_buffer_pos = CMD_BUFF_SIZE - 1;
    } else if (current_cmd_buffer_pos < 0) {  //...and if you fall under the bottom of the buffer, reset back to 0 so you can climb back up
    } else if (current_cmd_buffer_pos < 0) { //...and if you fall under the bottom of the buffer, reset back to 0 so you can climb back up
        current_cmd_buffer_pos = 0;
    }
}


@@ 278,33 280,33 @@ bool process_terminal(uint16_t keycode, keyrecord_t *record) {
                case KC_RIGHT:
                    return false;
                    break;
                case KC_UP:                                             // 0 = recent
                    check_pos();                                        // check our current buffer position is valid
                    if (current_cmd_buffer_pos <= CMD_BUFF_SIZE - 1) {  // once we get to the top, dont do anything
                case KC_UP:                                            // 0 = recent
                    check_pos();                                       // check our current buffer position is valid
                    if (current_cmd_buffer_pos <= CMD_BUFF_SIZE - 1) { // once we get to the top, dont do anything
                        str_len = strlen(buffer);
                        for (int i = 0; i < str_len; ++i) {
                            send_string(SS_TAP(X_BSPACE));  // clear w/e is on the line already
                            send_string(SS_TAP(X_BSPACE)); // clear w/e is on the line already
                            // process_terminal(KC_BACKSPACE,record);
                        }
                        strncpy(buffer, cmd_buffer[current_cmd_buffer_pos], 80);

                        send_string(buffer);
                        ++current_cmd_buffer_pos;  // get ready to access the above cmd if up/down is pressed again
                        ++current_cmd_buffer_pos; // get ready to access the above cmd if up/down is pressed again
                    }
                    return false;
                    break;
                case KC_DOWN:
                    check_pos();
                    if (current_cmd_buffer_pos >= 0) {  // once we get to the bottom, dont do anything
                    if (current_cmd_buffer_pos >= 0) { // once we get to the bottom, dont do anything
                        str_len = strlen(buffer);
                        for (int i = 0; i < str_len; ++i) {
                            send_string(SS_TAP(X_BSPACE));  // clear w/e is on the line already
                            send_string(SS_TAP(X_BSPACE)); // clear w/e is on the line already
                            // process_terminal(KC_BACKSPACE,record);
                        }
                        strncpy(buffer, cmd_buffer[current_cmd_buffer_pos], 79);

                        send_string(buffer);
                        --current_cmd_buffer_pos;  // get ready to access the above cmd if down/up is pressed again
                        --current_cmd_buffer_pos; // get ready to access the above cmd if down/up is pressed again
                    }
                    return false;
                    break;

M quantum/process_keycode/process_ucis.c => quantum/process_keycode/process_ucis.c +1 -1
@@ 27,7 27,7 @@ void qk_ucis_start(void) {

__attribute__((weak)) void qk_ucis_start_user(void) {
    unicode_input_start();
    register_hex(0x2328);  // ⌨
    register_hex(0x2328); // ⌨
    unicode_input_finish();
}


M quantum/process_keycode/process_unicode_common.c => quantum/process_keycode/process_unicode_common.c +14 -10
@@ 54,7 54,9 @@ void unicode_input_mode_init(void) {
    dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode);
}

uint8_t get_unicode_input_mode(void) { return unicode_config.input_mode; }
uint8_t get_unicode_input_mode(void) {
    return unicode_config.input_mode;
}

void set_unicode_input_mode(uint8_t mode) {
    unicode_config.input_mode = mode;


@@ 76,7 78,9 @@ void cycle_unicode_input_mode(int8_t offset) {
#endif
}

void persist_unicode_input_mode(void) { eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode); }
void persist_unicode_input_mode(void) {
    eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode);
}

__attribute__((weak)) void unicode_input_start(void) {
    unicode_saved_caps_lock = host_keyboard_led_state().caps_lock;


@@ 90,8 94,8 @@ __attribute__((weak)) void unicode_input_start(void) {
        tap_code(KC_CAPS_LOCK);
    }

    unicode_saved_mods = get_mods();  // Save current mods
    clear_mods();                     // Unregister mods to start from a clean state
    unicode_saved_mods = get_mods(); // Save current mods
    clear_mods();                    // Unregister mods to start from a clean state

    switch (unicode_config.input_mode) {
        case UC_MAC:


@@ 140,7 144,7 @@ __attribute__((weak)) void unicode_input_finish(void) {
            break;
    }

    set_mods(unicode_saved_mods);  // Reregister previously set mods
    set_mods(unicode_saved_mods); // Reregister previously set mods
}

__attribute__((weak)) void unicode_input_cancel(void) {


@@ 165,7 169,7 @@ __attribute__((weak)) void unicode_input_cancel(void) {
            break;
    }

    set_mods(unicode_saved_mods);  // Reregister previously set mods
    set_mods(unicode_saved_mods); // Reregister previously set mods
}

// clang-format off


@@ 262,16 266,16 @@ void send_unicode_hex_string(const char *str) {
static const char *decode_utf8(const char *str, int32_t *code_point) {
    const char *next;

    if (str[0] < 0x80) {  // U+0000-007F
    if (str[0] < 0x80) { // U+0000-007F
        *code_point = str[0];
        next        = str + 1;
    } else if ((str[0] & 0xE0) == 0xC0) {  // U+0080-07FF
    } else if ((str[0] & 0xE0) == 0xC0) { // U+0080-07FF
        *code_point = ((int32_t)(str[0] & 0x1F) << 6) | ((int32_t)(str[1] & 0x3F) << 0);
        next        = str + 2;
    } else if ((str[0] & 0xF0) == 0xE0) {  // U+0800-FFFF
    } else if ((str[0] & 0xF0) == 0xE0) { // U+0800-FFFF
        *code_point = ((int32_t)(str[0] & 0x0F) << 12) | ((int32_t)(str[1] & 0x3F) << 6) | ((int32_t)(str[2] & 0x3F) << 0);
        next        = str + 3;
    } else if ((str[0] & 0xF8) == 0xF0 && (str[0] <= 0xF4)) {  // U+10000-10FFFF
    } else if ((str[0] & 0xF8) == 0xF0 && (str[0] <= 0xF4)) { // U+10000-10FFFF
        *code_point = ((int32_t)(str[0] & 0x07) << 18) | ((int32_t)(str[1] & 0x3F) << 12) | ((int32_t)(str[2] & 0x3F) << 6) | ((int32_t)(str[3] & 0x3F) << 0);
        next        = str + 4;
    } else {

M quantum/process_keycode/process_unicode_common.h => quantum/process_keycode/process_unicode_common.h +6 -6
@@ 59,12 59,12 @@
#define UC_OSX UC_MAC

enum unicode_input_modes {
    UC_MAC,    // macOS using Unicode Hex Input
    UC_LNX,    // Linux using IBus
    UC_WIN,    // Windows using EnableHexNumpad
    UC_BSD,    // BSD (not implemented)
    UC_WINC,   // Windows using WinCompose (https://github.com/samhocevar/wincompose)
    UC__COUNT  // Number of available input modes (always leave at the end)
    UC_MAC,   // macOS using Unicode Hex Input
    UC_LNX,   // Linux using IBus
    UC_WIN,   // Windows using EnableHexNumpad
    UC_BSD,   // BSD (not implemented)
    UC_WINC,  // Windows using WinCompose (https://github.com/samhocevar/wincompose)
    UC__COUNT // Number of available input modes (always leave at the end)
};

typedef union {

M quantum/programmable_button.c => quantum/programmable_button.c +21 -7
@@ 22,16 22,30 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

static uint32_t programmable_button_report = 0;

void programmable_button_clear(void) { programmable_button_report = 0; }
void programmable_button_clear(void) {
    programmable_button_report = 0;
}

void programmable_button_send(void) { host_programmable_button_send(programmable_button_report); }
void programmable_button_send(void) {
    host_programmable_button_send(programmable_button_report);
}

void programmable_button_on(uint8_t index) { programmable_button_report |= REPORT_BIT(index); }
void programmable_button_on(uint8_t index) {
    programmable_button_report |= REPORT_BIT(index);
}

void programmable_button_off(uint8_t index) { programmable_button_report &= ~REPORT_BIT(index); }
void programmable_button_off(uint8_t index) {
    programmable_button_report &= ~REPORT_BIT(index);
}

bool programmable_button_is_on(uint8_t index) { return !!(programmable_button_report & REPORT_BIT(index)); };
bool programmable_button_is_on(uint8_t index) {
    return !!(programmable_button_report & REPORT_BIT(index));
};

uint32_t programmable_button_get_report(void) { return programmable_button_report; };
uint32_t programmable_button_get_report(void) {
    return programmable_button_report;
};

void programmable_button_set_report(uint32_t report) { programmable_button_report = report; }
void programmable_button_set_report(uint32_t report) {
    programmable_button_report = report;
}

M quantum/quantum.c => quantum/quantum.c +28 -11
@@ 56,7 56,7 @@ uint8_t extract_mod_bits(uint16_t code) {

    uint8_t mods_to_send = 0;

    if (code & QK_RMODS_MIN) {  // Right mod flag is set
    if (code & QK_RMODS_MIN) { // Right mod flag is set
        if (code & QK_LCTL) mods_to_send |= MOD_BIT(KC_RIGHT_CTRL);
        if (code & QK_LSFT) mods_to_send |= MOD_BIT(KC_RIGHT_SHIFT);
        if (code & QK_LALT) mods_to_send |= MOD_BIT(KC_RIGHT_ALT);


@@ 71,7 71,9 @@ uint8_t extract_mod_bits(uint16_t code) {
    return mods_to_send;
}

void do_code16(uint16_t code, void (*f)(uint8_t)) { f(extract_mod_bits(code)); }
void do_code16(uint16_t code, void (*f)(uint8_t)) {
    f(extract_mod_bits(code));
}

__attribute__((weak)) void register_code16(uint16_t code) {
    if (IS_MOD(code) || code == KC_NO) {


@@ 101,13 103,21 @@ __attribute__((weak)) void tap_code16(uint16_t code) {
    unregister_code16(code);
}

__attribute__((weak)) bool process_action_kb(keyrecord_t *record) { return true; }
__attribute__((weak)) bool process_action_kb(keyrecord_t *record) {
    return true;
}

__attribute__((weak)) bool process_record_kb(uint16_t keycode, keyrecord_t *record) { return process_record_user(keycode, record); }
__attribute__((weak)) bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
    return process_record_user(keycode, record);
}

__attribute__((weak)) bool process_record_user(uint16_t keycode, keyrecord_t *record) { return true; }
__attribute__((weak)) bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    return true;
}

__attribute__((weak)) void post_process_record_kb(uint16_t keycode, keyrecord_t *record) { post_process_record_user(keycode, record); }
__attribute__((weak)) void post_process_record_kb(uint16_t keycode, keyrecord_t *record) {
    post_process_record_user(keycode, record);
}

__attribute__((weak)) void post_process_record_user(uint16_t keycode, keyrecord_t *record) {}



@@ 123,7 133,8 @@ void reset_keyboard(void) {
    uint16_t timer_start = timer_read();
    PLAY_SONG(goodbye_song);
    shutdown_user();
    while (timer_elapsed(timer_start) < 250) wait_ms(1);
    while (timer_elapsed(timer_start) < 250)
        wait_ms(1);
    stop_all_notes();
#else
    shutdown_user();


@@ 178,7 189,7 @@ bool pre_process_record_quantum(keyrecord_t *record) {
            true)) {
        return false;
    }
    return true;  // continue processing
    return true; // continue processing
}

/* Get keycode, and then call keyboard function */


@@ 367,11 378,17 @@ layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_
    return (state & mask12) == mask12 ? (state | mask3) : (state & ~mask3);
}

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 update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
    layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3));
}

// TODO: remove legacy api
void matrix_init_quantum() { matrix_init_kb(); }
void matrix_scan_quantum() { matrix_scan_kb(); }
void matrix_init_quantum() {
    matrix_init_kb();
}
void matrix_scan_quantum() {
    matrix_scan_kb();
}

//------------------------------------------------------------------------------
// Override these functions in your keymap file to play different tunes on

M quantum/quantum_keycodes.h => quantum/quantum_keycodes.h +357 -357
@@ 77,421 77,421 @@ enum quantum_keycodes {

    // Loose keycodes - to be used directly
    QK_BOOTLOADER = 0x5C00,
    QK_DEBUG_TOGGLE,  // 5C01
    QK_DEBUG_TOGGLE, // 5C01

    // Magic
    MAGIC_SWAP_CONTROL_CAPSLOCK,       // 5C02
    MAGIC_CAPSLOCK_TO_CONTROL,         // 5C03
    MAGIC_SWAP_LALT_LGUI,              // 5C04
    MAGIC_SWAP_RALT_RGUI,              // 5C05
    MAGIC_NO_GUI,                      // 5C06
    MAGIC_SWAP_GRAVE_ESC,              // 5C07
    MAGIC_SWAP_BACKSLASH_BACKSPACE,    // 5C08
    MAGIC_HOST_NKRO,                   // 5C09
    MAGIC_SWAP_ALT_GUI,                // 5C0A
    MAGIC_UNSWAP_CONTROL_CAPSLOCK,     // 5C0B
    MAGIC_UNCAPSLOCK_TO_CONTROL,       // 5C0C
    MAGIC_UNSWAP_LALT_LGUI,            // 5C0D
    MAGIC_UNSWAP_RALT_RGUI,            // 5C0E
    MAGIC_UNNO_GUI,                    // 5C0F
    MAGIC_UNSWAP_GRAVE_ESC,            // 5C10
    MAGIC_UNSWAP_BACKSLASH_BACKSPACE,  // 5C11
    MAGIC_UNHOST_NKRO,                 // 5C12
    MAGIC_UNSWAP_ALT_GUI,              // 5C13
    MAGIC_TOGGLE_NKRO,                 // 5C14
    MAGIC_TOGGLE_ALT_GUI,              // 5C15
    MAGIC_SWAP_CONTROL_CAPSLOCK,      // 5C02
    MAGIC_CAPSLOCK_TO_CONTROL,        // 5C03
    MAGIC_SWAP_LALT_LGUI,             // 5C04
    MAGIC_SWAP_RALT_RGUI,             // 5C05
    MAGIC_NO_GUI,                     // 5C06
    MAGIC_SWAP_GRAVE_ESC,             // 5C07
    MAGIC_SWAP_BACKSLASH_BACKSPACE,   // 5C08
    MAGIC_HOST_NKRO,                  // 5C09
    MAGIC_SWAP_ALT_GUI,               // 5C0A
    MAGIC_UNSWAP_CONTROL_CAPSLOCK,    // 5C0B
    MAGIC_UNCAPSLOCK_TO_CONTROL,      // 5C0C
    MAGIC_UNSWAP_LALT_LGUI,           // 5C0D
    MAGIC_UNSWAP_RALT_RGUI,           // 5C0E
    MAGIC_UNNO_GUI,                   // 5C0F
    MAGIC_UNSWAP_GRAVE_ESC,           // 5C10
    MAGIC_UNSWAP_BACKSLASH_BACKSPACE, // 5C11
    MAGIC_UNHOST_NKRO,                // 5C12
    MAGIC_UNSWAP_ALT_GUI,             // 5C13
    MAGIC_TOGGLE_NKRO,                // 5C14
    MAGIC_TOGGLE_ALT_GUI,             // 5C15

    // Grave Escape
    QK_GRAVE_ESCAPE,  // 5C16
    QK_GRAVE_ESCAPE, // 5C16

    // Auto Shift
    KC_ASUP,   // 5C17
    KC_ASDN,   // 5C18
    KC_ASRP,   // 5C19
    KC_ASTG,   // 5C1A
    KC_ASON,   // 5C1B
    KC_ASOFF,  // 5C1C
    KC_ASUP,  // 5C17
    KC_ASDN,  // 5C18
    KC_ASRP,  // 5C19
    KC_ASTG,  // 5C1A
    KC_ASON,  // 5C1B
    KC_ASOFF, // 5C1C

    // Audio
    AU_ON,   // 5C1D
    AU_OFF,  // 5C1E
    AU_TOG,  // 5C1F
    AU_ON,  // 5C1D
    AU_OFF, // 5C1E
    AU_TOG, // 5C1F

    // Audio Clicky
    CLICKY_TOGGLE,   // 5C20
    CLICKY_ENABLE,   // 5C21
    CLICKY_DISABLE,  // 5C22
    CLICKY_UP,       // 5C23
    CLICKY_DOWN,     // 5C24
    CLICKY_RESET,    // 5C25
    CLICKY_TOGGLE,  // 5C20
    CLICKY_ENABLE,  // 5C21
    CLICKY_DISABLE, // 5C22
    CLICKY_UP,      // 5C23
    CLICKY_DOWN,    // 5C24
    CLICKY_RESET,   // 5C25

    // Music mode
    MU_ON,   // 5C26
    MU_OFF,  // 5C27
    MU_TOG,  // 5C28
    MU_MOD,  // 5C29
    MUV_IN,  // 5C2A
    MUV_DE,  // 5C2B
    MU_ON,  // 5C26
    MU_OFF, // 5C27
    MU_TOG, // 5C28
    MU_MOD, // 5C29
    MUV_IN, // 5C2A
    MUV_DE, // 5C2B

    // MIDI
    MI_ON,   // 5C2C
    MI_OFF,  // 5C2D
    MI_TOG,  // 5C2E
    MI_ON,  // 5C2C
    MI_OFF, // 5C2D
    MI_TOG, // 5C2E

    MI_C,   // 5C2F
    MI_Cs,  // 5C30
    MI_C,  // 5C2F
    MI_Cs, // 5C30
    MI_Db = MI_Cs,
    MI_D,   // 5C31
    MI_Ds,  // 5C32
    MI_D,  // 5C31
    MI_Ds, // 5C32
    MI_Eb = MI_Ds,
    MI_E,   // 5C33
    MI_F,   // 5C34
    MI_Fs,  // 5C35
    MI_E,  // 5C33
    MI_F,  // 5C34
    MI_Fs, // 5C35
    MI_Gb = MI_Fs,
    MI_G,   // 5C36
    MI_Gs,  // 5C37
    MI_G,  // 5C36
    MI_Gs, // 5C37
    MI_Ab = MI_Gs,
    MI_A,   // 5C38
    MI_As,  // 5C39
    MI_A,  // 5C38
    MI_As, // 5C39
    MI_Bb = MI_As,
    MI_B,  // 5C3A
    MI_B, // 5C3A

    MI_C_1,   // 5C3B
    MI_Cs_1,  // 5C3C
    MI_C_1,  // 5C3B
    MI_Cs_1, // 5C3C
    MI_Db_1 = MI_Cs_1,
    MI_D_1,   // 5C3D
    MI_Ds_1,  // 5C3E
    MI_D_1,  // 5C3D
    MI_Ds_1, // 5C3E
    MI_Eb_1 = MI_Ds_1,
    MI_E_1,   // 5C3F
    MI_F_1,   // 5C40
    MI_Fs_1,  // 5C41
    MI_E_1,  // 5C3F
    MI_F_1,  // 5C40
    MI_Fs_1, // 5C41
    MI_Gb_1 = MI_Fs_1,
    MI_G_1,   // 5C42
    MI_Gs_1,  // 5C43
    MI_G_1,  // 5C42
    MI_Gs_1, // 5C43
    MI_Ab_1 = MI_Gs_1,
    MI_A_1,   // 5C44
    MI_As_1,  // 5C45
    MI_A_1,  // 5C44
    MI_As_1, // 5C45
    MI_Bb_1 = MI_As_1,
    MI_B_1,  // 5C46
    MI_B_1, // 5C46

    MI_C_2,   // 5C47
    MI_Cs_2,  // 5C48
    MI_C_2,  // 5C47
    MI_Cs_2, // 5C48
    MI_Db_2 = MI_Cs_2,
    MI_D_2,   // 5C49
    MI_Ds_2,  // 5C4A
    MI_D_2,  // 5C49
    MI_Ds_2, // 5C4A
    MI_Eb_2 = MI_Ds_2,
    MI_E_2,   // 5C4B
    MI_F_2,   // 5C4C
    MI_Fs_2,  // 5C4D
    MI_E_2,  // 5C4B
    MI_F_2,  // 5C4C
    MI_Fs_2, // 5C4D
    MI_Gb_2 = MI_Fs_2,
    MI_G_2,   // 5C4E
    MI_Gs_2,  // 5C4F
    MI_G_2,  // 5C4E
    MI_Gs_2, // 5C4F
    MI_Ab_2 = MI_Gs_2,
    MI_A_2,   // 5C50
    MI_As_2,  // 5C51
    MI_A_2,  // 5C50
    MI_As_2, // 5C51
    MI_Bb_2 = MI_As_2,
    MI_B_2,  // 5C52
    MI_B_2, // 5C52

    MI_C_3,   // 5C53
    MI_Cs_3,  // 5C54
    MI_C_3,  // 5C53
    MI_Cs_3, // 5C54
    MI_Db_3 = MI_Cs_3,
    MI_D_3,   // 5C55
    MI_Ds_3,  // 5C56
    MI_D_3,  // 5C55
    MI_Ds_3, // 5C56
    MI_Eb_3 = MI_Ds_3,
    MI_E_3,   // 5C57
    MI_F_3,   // 5C58
    MI_Fs_3,  // 5C59
    MI_E_3,  // 5C57
    MI_F_3,  // 5C58
    MI_Fs_3, // 5C59
    MI_Gb_3 = MI_Fs_3,
    MI_G_3,   // 5C5A
    MI_Gs_3,  // 5C5B
    MI_G_3,  // 5C5A
    MI_Gs_3, // 5C5B
    MI_Ab_3 = MI_Gs_3,
    MI_A_3,   // 5C5C
    MI_As_3,  // 5C5D
    MI_A_3,  // 5C5C
    MI_As_3, // 5C5D
    MI_Bb_3 = MI_As_3,
    MI_B_3,  // 5C5E
    MI_B_3, // 5C5E

    MI_C_4,   // 5C5F
    MI_Cs_4,  // 5C60
    MI_C_4,  // 5C5F
    MI_Cs_4, // 5C60
    MI_Db_4 = MI_Cs_4,
    MI_D_4,   // 5C61
    MI_Ds_4,  // 5C62
    MI_D_4,  // 5C61
    MI_Ds_4, // 5C62
    MI_Eb_4 = MI_Ds_4,
    MI_E_4,   // 5C63
    MI_F_4,   // 5C64
    MI_Fs_4,  // 5C65
    MI_E_4,  // 5C63
    MI_F_4,  // 5C64
    MI_Fs_4, // 5C65
    MI_Gb_4 = MI_Fs_4,
    MI_G_4,   // 5C66
    MI_Gs_4,  // 5C67
    MI_G_4,  // 5C66
    MI_Gs_4, // 5C67
    MI_Ab_4 = MI_Gs_4,
    MI_A_4,   // 5C68
    MI_As_4,  // 5C69
    MI_A_4,  // 5C68
    MI_As_4, // 5C69
    MI_Bb_4 = MI_As_4,
    MI_B_4,  // 5C6A
    MI_B_4, // 5C6A

    MI_C_5,   // 5C6B
    MI_Cs_5,  // 5C6C
    MI_C_5,  // 5C6B
    MI_Cs_5, // 5C6C
    MI_Db_5 = MI_Cs_5,
    MI_D_5,   // 5C6D
    MI_Ds_5,  // 5C6E
    MI_D_5,  // 5C6D
    MI_Ds_5, // 5C6E
    MI_Eb_5 = MI_Ds_5,
    MI_E_5,   // 5C6F
    MI_F_5,   // 5C70
    MI_Fs_5,  // 5C71
    MI_E_5,  // 5C6F
    MI_F_5,  // 5C70
    MI_Fs_5, // 5C71
    MI_Gb_5 = MI_Fs_5,
    MI_G_5,   // 5C72
    MI_Gs_5,  // 5C73
    MI_G_5,  // 5C72
    MI_Gs_5, // 5C73
    MI_Ab_5 = MI_Gs_5,
    MI_A_5,   // 5C74
    MI_As_5,  // 5C75
    MI_A_5,  // 5C74
    MI_As_5, // 5C75
    MI_Bb_5 = MI_As_5,
    MI_B_5,  // 5C76

    MI_OCT_N2,  // 5C77
    MI_OCT_N1,  // 5C78
    MI_OCT_0,   // 5C79
    MI_OCT_1,   // 5C7A
    MI_OCT_2,   // 5C7B
    MI_OCT_3,   // 5C7C
    MI_OCT_4,   // 5C7D
    MI_OCT_5,   // 5C7E
    MI_OCT_6,   // 5C7F
    MI_OCT_7,   // 5C80
    MI_OCTD,    // 5C81
    MI_OCTU,    // 5C82

    MI_TRNS_N6,  // 5C83
    MI_TRNS_N5,  // 5C84
    MI_TRNS_N4,  // 5C85
    MI_TRNS_N3,  // 5C86
    MI_TRNS_N2,  // 5C87
    MI_TRNS_N1,  // 5C88
    MI_TRNS_0,   // 5C89
    MI_TRNS_1,   // 5C8A
    MI_TRNS_2,   // 5C8B
    MI_TRNS_3,   // 5C8C
    MI_TRNS_4,   // 5C8D
    MI_TRNS_5,   // 5C8E
    MI_TRNS_6,   // 5C8F
    MI_TRNSD,    // 5C90
    MI_TRNSU,    // 5C91

    MI_VEL_0,  // 5C92
    MI_B_5, // 5C76

    MI_OCT_N2, // 5C77
    MI_OCT_N1, // 5C78
    MI_OCT_0,  // 5C79
    MI_OCT_1,  // 5C7A
    MI_OCT_2,  // 5C7B
    MI_OCT_3,  // 5C7C
    MI_OCT_4,  // 5C7D
    MI_OCT_5,  // 5C7E
    MI_OCT_6,  // 5C7F
    MI_OCT_7,  // 5C80
    MI_OCTD,   // 5C81
    MI_OCTU,   // 5C82

    MI_TRNS_N6, // 5C83
    MI_TRNS_N5, // 5C84
    MI_TRNS_N4, // 5C85
    MI_TRNS_N3, // 5C86
    MI_TRNS_N2, // 5C87
    MI_TRNS_N1, // 5C88
    MI_TRNS_0,  // 5C89
    MI_TRNS_1,  // 5C8A
    MI_TRNS_2,  // 5C8B
    MI_TRNS_3,  // 5C8C
    MI_TRNS_4,  // 5C8D
    MI_TRNS_5,  // 5C8E
    MI_TRNS_6,  // 5C8F
    MI_TRNSD,   // 5C90
    MI_TRNSU,   // 5C91

    MI_VEL_0, // 5C92
#ifdef VIA_ENABLE
    MI_VEL_1 = MI_VEL_0,
#else
    MI_VEL_1,  // 5C93
    MI_VEL_1, // 5C93
#endif
    MI_VEL_2,   // 5C94
    MI_VEL_3,   // 5C95
    MI_VEL_4,   // 5C96
    MI_VEL_5,   // 5C97
    MI_VEL_6,   // 5C98
    MI_VEL_7,   // 5C99
    MI_VEL_8,   // 5C9A
    MI_VEL_9,   // 5C9B
    MI_VEL_10,  // 5C9C
    MI_VELD,    // 5C9D
    MI_VELU,    // 5C9E

    MI_CH1,   // 5C9F
    MI_CH2,   // 5CA0
    MI_CH3,   // 5CA1
    MI_CH4,   // 5CA2
    MI_CH5,   // 5CA3
    MI_CH6,   // 5CA4
    MI_CH7,   // 5CA5
    MI_CH8,   // 5CA6
    MI_CH9,   // 5CA7
    MI_CH10,  // 5CA8
    MI_CH11,  // 5CA9
    MI_CH12,  // 5CAA
    MI_CH13,  // 5CAB
    MI_CH14,  // 5CAC
    MI_CH15,  // 5CAD
    MI_CH16,  // 5CAE
    MI_CHD,   // 5CAF
    MI_CHU,   // 5CB0

    MI_ALLOFF,  // 5CB1

    MI_SUS,   // 5CB2
    MI_PORT,  // 5CB3
    MI_SOST,  // 5CB4
    MI_SOFT,  // 5CB5
    MI_LEG,   // 5CB6

    MI_MOD,    // 5CB7
    MI_MODSD,  // 5CB8
    MI_MODSU,  // 5CB9

    MI_BENDD,  // 5CBA
    MI_BENDU,  // 5CBB
    MI_VEL_2,  // 5C94
    MI_VEL_3,  // 5C95
    MI_VEL_4,  // 5C96
    MI_VEL_5,  // 5C97
    MI_VEL_6,  // 5C98
    MI_VEL_7,  // 5C99
    MI_VEL_8,  // 5C9A
    MI_VEL_9,  // 5C9B
    MI_VEL_10, // 5C9C
    MI_VELD,   // 5C9D
    MI_VELU,   // 5C9E

    MI_CH1,  // 5C9F
    MI_CH2,  // 5CA0
    MI_CH3,  // 5CA1
    MI_CH4,  // 5CA2
    MI_CH5,  // 5CA3
    MI_CH6,  // 5CA4
    MI_CH7,  // 5CA5
    MI_CH8,  // 5CA6
    MI_CH9,  // 5CA7
    MI_CH10, // 5CA8
    MI_CH11, // 5CA9
    MI_CH12, // 5CAA
    MI_CH13, // 5CAB
    MI_CH14, // 5CAC
    MI_CH15, // 5CAD
    MI_CH16, // 5CAE
    MI_CHD,  // 5CAF
    MI_CHU,  // 5CB0

    MI_ALLOFF, // 5CB1

    MI_SUS,  // 5CB2
    MI_PORT, // 5CB3
    MI_SOST, // 5CB4
    MI_SOFT, // 5CB5
    MI_LEG,  // 5CB6

    MI_MOD,   // 5CB7
    MI_MODSD, // 5CB8
    MI_MODSU, // 5CB9

    MI_BENDD, // 5CBA
    MI_BENDU, // 5CBB

    // Backlight
    BL_ON,    // 5CBC
    BL_OFF,   // 5CBD
    BL_DEC,   // 5CBE
    BL_INC,   // 5CBF
    BL_TOGG,  // 5CC0
    BL_STEP,  // 5CC1
    BL_BRTG,  // 5CC2
    BL_ON,   // 5CBC
    BL_OFF,  // 5CBD
    BL_DEC,  // 5CBE
    BL_INC,  // 5CBF
    BL_TOGG, // 5CC0
    BL_STEP, // 5CC1
    BL_BRTG, // 5CC2

    // RGB underglow/matrix
    RGB_TOG,            // 5CC3
    RGB_MODE_FORWARD,   // 5CC4
    RGB_MODE_REVERSE,   // 5CC5
    RGB_HUI,            // 5CC6
    RGB_HUD,            // 5CC7
    RGB_SAI,            // 5CC8
    RGB_SAD,            // 5CC9
    RGB_VAI,            // 5CCA
    RGB_VAD,            // 5CCB
    RGB_SPI,            // 5CCC
    RGB_SPD,            // 5CCD
    RGB_MODE_PLAIN,     // 5CCE
    RGB_MODE_BREATHE,   // 5CCF
    RGB_MODE_RAINBOW,   // 5CD0
    RGB_MODE_SWIRL,     // 5CD1
    RGB_MODE_SNAKE,     // 5CD2
    RGB_MODE_KNIGHT,    // 5CD3
    RGB_MODE_XMAS,      // 5CD4
    RGB_MODE_GRADIENT,  // 5CD5
    RGB_MODE_RGBTEST,   // 5CD6
    RGB_TOG,           // 5CC3
    RGB_MODE_FORWARD,  // 5CC4
    RGB_MODE_REVERSE,  // 5CC5
    RGB_HUI,           // 5CC6
    RGB_HUD,           // 5CC7
    RGB_SAI,           // 5CC8
    RGB_SAD,           // 5CC9
    RGB_VAI,           // 5CCA
    RGB_VAD,           // 5CCB
    RGB_SPI,           // 5CCC
    RGB_SPD,           // 5CCD
    RGB_MODE_PLAIN,    // 5CCE
    RGB_MODE_BREATHE,  // 5CCF
    RGB_MODE_RAINBOW,  // 5CD0
    RGB_MODE_SWIRL,    // 5CD1
    RGB_MODE_SNAKE,    // 5CD2
    RGB_MODE_KNIGHT,   // 5CD3
    RGB_MODE_XMAS,     // 5CD4
    RGB_MODE_GRADIENT, // 5CD5
    RGB_MODE_RGBTEST,  // 5CD6

    // Velocikey
    VLK_TOG,  // 5CD7
    VLK_TOG, // 5CD7

    // Space Cadet
    KC_LSPO,    // 5CD8
    KC_RSPC,    // 5CD9
    KC_SFTENT,  // 5CDA
    KC_LSPO,   // 5CD8
    KC_RSPC,   // 5CD9
    KC_SFTENT, // 5CDA

    // Thermal Printer
    PRINT_ON,   // 5CDB
    PRINT_OFF,  // 5CDC
    PRINT_ON,  // 5CDB
    PRINT_OFF, // 5CDC

    // Bluetooth: output selection
    OUT_AUTO,  // 5CDD
    OUT_USB,   // 5CDE
    OUT_AUTO, // 5CDD
    OUT_USB,  // 5CDE

    // Clear EEPROM
    QK_CLEAR_EEPROM,  // 5CDF
    QK_CLEAR_EEPROM, // 5CDF

    // Unicode
    UNICODE_MODE_FORWARD,  // 5CE0
    UNICODE_MODE_REVERSE,  // 5CE1
    UNICODE_MODE_MAC,      // 5CE2
    UNICODE_MODE_LNX,      // 5CE3
    UNICODE_MODE_WIN,      // 5CE4
    UNICODE_MODE_BSD,      // 5CE5
    UNICODE_MODE_WINC,     // 5CE6
    UNICODE_MODE_FORWARD, // 5CE0
    UNICODE_MODE_REVERSE, // 5CE1
    UNICODE_MODE_MAC,     // 5CE2
    UNICODE_MODE_LNX,     // 5CE3
    UNICODE_MODE_WIN,     // 5CE4
    UNICODE_MODE_BSD,     // 5CE5
    UNICODE_MODE_WINC,    // 5CE6

    // Haptic
    HPT_ON,    // 5CE7
    HPT_OFF,   // 5CE8
    HPT_TOG,   // 5CE9
    HPT_RST,   // 5CEA
    HPT_FBK,   // 5CEB
    HPT_BUZ,   // 5CEC
    HPT_MODI,  // 5CED
    HPT_MODD,  // 5CEE
    HPT_CONT,  // 5CEF
    HPT_CONI,  // 5CF0
    HPT_COND,  // 5CF1
    HPT_DWLI,  // 5CF2
    HPT_DWLD,  // 5CF3
    HPT_ON,   // 5CE7
    HPT_OFF,  // 5CE8
    HPT_TOG,  // 5CE9
    HPT_RST,  // 5CEA
    HPT_FBK,  // 5CEB
    HPT_BUZ,  // 5CEC
    HPT_MODI, // 5CED
    HPT_MODD, // 5CEE
    HPT_CONT, // 5CEF
    HPT_CONI, // 5CF0
    HPT_COND, // 5CF1
    HPT_DWLI, // 5CF2
    HPT_DWLD, // 5CF3

    // Space Cadet (continued)
    KC_LCPO,  // 5CF4
    KC_RCPC,  // 5CF5
    KC_LAPO,  // 5CF6
    KC_RAPC,  // 5CF7
    KC_LCPO, // 5CF4
    KC_RCPC, // 5CF5
    KC_LAPO, // 5CF6
    KC_RAPC, // 5CF7

    // Combos
    CMB_ON,   // 5CF8
    CMB_OFF,  // 5CF9
    CMB_TOG,  // 5CFA
    CMB_ON,  // 5CF8
    CMB_OFF, // 5CF9
    CMB_TOG, // 5CFA

    // Magic (continued)
    MAGIC_SWAP_LCTL_LGUI,    // 5CFB
    MAGIC_SWAP_RCTL_RGUI,    // 5CFC
    MAGIC_UNSWAP_LCTL_LGUI,  // 5CFD
    MAGIC_UNSWAP_RCTL_RGUI,  // 5CFE
    MAGIC_SWAP_CTL_GUI,      // 5CFF
    MAGIC_UNSWAP_CTL_GUI,    // 5D00
    MAGIC_TOGGLE_CTL_GUI,    // 5D01
    MAGIC_EE_HANDS_LEFT,     // 5D02
    MAGIC_EE_HANDS_RIGHT,    // 5D03
    MAGIC_SWAP_LCTL_LGUI,   // 5CFB
    MAGIC_SWAP_RCTL_RGUI,   // 5CFC
    MAGIC_UNSWAP_LCTL_LGUI, // 5CFD
    MAGIC_UNSWAP_RCTL_RGUI, // 5CFE
    MAGIC_SWAP_CTL_GUI,     // 5CFF
    MAGIC_UNSWAP_CTL_GUI,   // 5D00
    MAGIC_TOGGLE_CTL_GUI,   // 5D01
    MAGIC_EE_HANDS_LEFT,    // 5D02
    MAGIC_EE_HANDS_RIGHT,   // 5D03

    // Dynamic Macros
    DYN_REC_START1,   // 5D04
    DYN_REC_START2,   // 5D05
    DYN_REC_STOP,     // 5D06
    DYN_MACRO_PLAY1,  // 5D07
    DYN_MACRO_PLAY2,  // 5D08
    DYN_REC_START1,  // 5D04
    DYN_REC_START2,  // 5D05
    DYN_REC_STOP,    // 5D06
    DYN_MACRO_PLAY1, // 5D07
    DYN_MACRO_PLAY2, // 5D08

    // Joystick
    JS_BUTTON0,   // 5D09
    JS_BUTTON1,   // 5D0A
    JS_BUTTON2,   // 5D0B
    JS_BUTTON3,   // 5D0C
    JS_BUTTON4,   // 5D0D
    JS_BUTTON5,   // 5D0E
    JS_BUTTON6,   // 5D0F
    JS_BUTTON7,   // 5D10
    JS_BUTTON8,   // 5D11
    JS_BUTTON9,   // 5D12
    JS_BUTTON10,  // 5D13
    JS_BUTTON11,  // 5D14
    JS_BUTTON12,  // 5D15
    JS_BUTTON13,  // 5D16
    JS_BUTTON14,  // 5D17
    JS_BUTTON15,  // 5D18
    JS_BUTTON16,  // 5D19
    JS_BUTTON17,  // 5D1A
    JS_BUTTON18,  // 5D1B
    JS_BUTTON19,  // 5D1C
    JS_BUTTON20,  // 5D1D
    JS_BUTTON21,  // 5D1E
    JS_BUTTON22,  // 5D1F
    JS_BUTTON23,  // 5D20
    JS_BUTTON24,  // 5D21
    JS_BUTTON25,  // 5D22
    JS_BUTTON26,  // 5D23
    JS_BUTTON27,  // 5D24
    JS_BUTTON28,  // 5D25
    JS_BUTTON29,  // 5D26
    JS_BUTTON30,  // 5D27
    JS_BUTTON31,  // 5D28
    JS_BUTTON0,  // 5D09
    JS_BUTTON1,  // 5D0A
    JS_BUTTON2,  // 5D0B
    JS_BUTTON3,  // 5D0C
    JS_BUTTON4,  // 5D0D
    JS_BUTTON5,  // 5D0E
    JS_BUTTON6,  // 5D0F
    JS_BUTTON7,  // 5D10
    JS_BUTTON8,  // 5D11
    JS_BUTTON9,  // 5D12
    JS_BUTTON10, // 5D13
    JS_BUTTON11, // 5D14
    JS_BUTTON12, // 5D15
    JS_BUTTON13, // 5D16
    JS_BUTTON14, // 5D17
    JS_BUTTON15, // 5D18
    JS_BUTTON16, // 5D19
    JS_BUTTON17, // 5D1A
    JS_BUTTON18, // 5D1B
    JS_BUTTON19, // 5D1C
    JS_BUTTON20, // 5D1D
    JS_BUTTON21, // 5D1E
    JS_BUTTON22, // 5D1F
    JS_BUTTON23, // 5D20
    JS_BUTTON24, // 5D21
    JS_BUTTON25, // 5D22
    JS_BUTTON26, // 5D23
    JS_BUTTON27, // 5D24
    JS_BUTTON28, // 5D25
    JS_BUTTON29, // 5D26
    JS_BUTTON30, // 5D27
    JS_BUTTON31, // 5D28

    // Leader Key
    KC_LEAD,  // 5D29
    KC_LEAD, // 5D29

    // Bluetooth: output selection (continued)
    OUT_BT,  // 5D2A
    OUT_BT, // 5D2A

    // Lock Key
    KC_LOCK,  // 5D2B
    KC_LOCK, // 5D2B

    // Terminal
    TERM_ON,   // 5D2C
    TERM_OFF,  // 5D2D
    TERM_ON,  // 5D2C
    TERM_OFF, // 5D2D

    // Sequencer
    SQ_ON,   // 5D2E
    SQ_OFF,  // 5D2F
    SQ_TOG,  // 5D30
    SQ_ON,  // 5D2E
    SQ_OFF, // 5D2F
    SQ_TOG, // 5D30

    SQ_TMPD,  // 5D31
    SQ_TMPU,  // 5D32
    SQ_TMPD, // 5D31
    SQ_TMPU, // 5D32

    SQ_RESD,  // 5D33
    SQ_RESU,  // 5D34
    SQ_RESD, // 5D33
    SQ_RESU, // 5D34

    SQ_SALL,  // 5D35
    SQ_SCLR,  // 5D36
    SQ_SALL, // 5D35
    SQ_SCLR, // 5D36

    SEQUENCER_STEP_MIN,  // 5D37
    SEQUENCER_STEP_MIN, // 5D37
    SEQUENCER_STEP_MAX = SEQUENCER_STEP_MIN + SEQUENCER_STEPS,

    SEQUENCER_RESOLUTION_MIN,


@@ 636,69 636,69 @@ enum quantum_keycodes {
#define MOD_MEH 0x7

// US ANSI shifted keycode aliases
#define KC_TILDE LSFT(KC_GRAVE)  // ~
#define KC_TILDE LSFT(KC_GRAVE) // ~
#define KC_TILD KC_TILDE

#define KC_EXCLAIM LSFT(KC_1)  // !
#define KC_EXCLAIM LSFT(KC_1) // !
#define KC_EXLM KC_EXCLAIM

#define KC_AT LSFT(KC_2)  // @
#define KC_AT LSFT(KC_2) // @

#define KC_HASH LSFT(KC_3)  // #
#define KC_HASH LSFT(KC_3) // #

#define KC_DOLLAR LSFT(KC_4)  // $
#define KC_DOLLAR LSFT(KC_4) // $
#define KC_DLR KC_DOLLAR

#define KC_PERCENT LSFT(KC_5)  // %
#define KC_PERCENT LSFT(KC_5) // %
#define KC_PERC KC_PERCENT

#define KC_CIRCUMFLEX LSFT(KC_6)  // ^
#define KC_CIRCUMFLEX LSFT(KC_6) // ^
#define KC_CIRC KC_CIRCUMFLEX

#define KC_AMPERSAND LSFT(KC_7)  // &
#define KC_AMPERSAND LSFT(KC_7) // &
#define KC_AMPR KC_AMPERSAND

#define KC_ASTERISK LSFT(KC_8)  // *
#define KC_ASTERISK LSFT(KC_8) // *
#define KC_ASTR KC_ASTERISK

#define KC_LEFT_PAREN LSFT(KC_9)  // (
#define KC_LEFT_PAREN LSFT(KC_9) // (
#define KC_LPRN KC_LEFT_PAREN

#define KC_RIGHT_PAREN LSFT(KC_0)  // )
#define KC_RIGHT_PAREN LSFT(KC_0) // )
#define KC_RPRN KC_RIGHT_PAREN

#define KC_UNDERSCORE LSFT(KC_MINUS)  // _
#define KC_UNDERSCORE LSFT(KC_MINUS) // _
#define KC_UNDS KC_UNDERSCORE

#define KC_PLUS LSFT(KC_EQUAL)  // +
#define KC_PLUS LSFT(KC_EQUAL) // +

#define KC_LEFT_CURLY_BRACE LSFT(KC_LEFT_BRACKET)  // {
#define KC_LEFT_CURLY_BRACE LSFT(KC_LEFT_BRACKET) // {
#define KC_LCBR KC_LEFT_CURLY_BRACE

#define KC_RIGHT_CURLY_BRACE LSFT(KC_RIGHT_BRACKET)  // }
#define KC_RIGHT_CURLY_BRACE LSFT(KC_RIGHT_BRACKET) // }
#define KC_RCBR KC_RIGHT_CURLY_BRACE

#define KC_LEFT_ANGLE_BRACKET LSFT(KC_COMMA)  // <
#define KC_LEFT_ANGLE_BRACKET LSFT(KC_COMMA) // <
#define KC_LABK KC_LEFT_ANGLE_BRACKET
#define KC_LT KC_LEFT_ANGLE_BRACKET

#define KC_RIGHT_ANGLE_BRACKET LSFT(KC_DOT)  // >
#define KC_RIGHT_ANGLE_BRACKET LSFT(KC_DOT) // >
#define KC_RABK KC_RIGHT_ANGLE_BRACKET
#define KC_GT KC_RIGHT_ANGLE_BRACKET

#define KC_COLON LSFT(KC_SEMICOLON)  // :
#define KC_COLON LSFT(KC_SEMICOLON) // :
#define KC_COLN KC_COLON

#define KC_PIPE LSFT(KC_BACKSLASH)  // |
#define KC_PIPE LSFT(KC_BACKSLASH) // |

#define KC_QUESTION LSFT(KC_SLASH)  // ?
#define KC_QUESTION LSFT(KC_SLASH) // ?
#define KC_QUES KC_QUESTION

#define KC_DOUBLE_QUOTE LSFT(KC_QUOTE)  // "
#define KC_DOUBLE_QUOTE LSFT(KC_QUOTE) // "
#define KC_DQUO KC_DOUBLE_QUOTE
#define KC_DQT KC_DOUBLE_QUOTE

#define KC_DELT KC_DELETE  // Del key (four letter code)
#define KC_DELT KC_DELETE // Del key (four letter code)

// Modified keycode aliases
#define C(kc) LCTL(kc)


@@ 841,22 841,22 @@ enum quantum_keycodes {
#define CMD_T(kc) LCMD_T(kc)
#define WIN_T(kc) LWIN_T(kc)

#define C_S_T(kc) MT(MOD_LCTL | MOD_LSFT, kc)                         // Left Control + Shift e.g. for gnome-terminal
#define MEH_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT, kc)              // Meh is a less hyper version of the Hyper key -- doesn't include GUI, so just Left Control + Shift + Alt
#define LCAG_T(kc) MT(MOD_LCTL | MOD_LALT | MOD_LGUI, kc)             // Left Control + Alt + GUI
#define RCAG_T(kc) MT(MOD_RCTL | MOD_RALT | MOD_RGUI, kc)             // Right Control + Alt + GUI
#define HYPR_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI, kc)  // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
#define LSG_T(kc) MT(MOD_LSFT | MOD_LGUI, kc)                         // Left Shift + GUI
#define C_S_T(kc) MT(MOD_LCTL | MOD_LSFT, kc)                        // Left Control + Shift e.g. for gnome-terminal
#define MEH_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT, kc)             // Meh is a less hyper version of the Hyper key -- doesn't include GUI, so just Left Control + Shift + Alt
#define LCAG_T(kc) MT(MOD_LCTL | MOD_LALT | MOD_LGUI, kc)            // Left Control + Alt + GUI
#define RCAG_T(kc) MT(MOD_RCTL | MOD_RALT | MOD_RGUI, kc)            // Right Control + Alt + GUI
#define HYPR_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI, kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
#define LSG_T(kc) MT(MOD_LSFT | MOD_LGUI, kc)                        // Left Shift + GUI
#define SGUI_T(kc) LSG_T(kc)
#define SCMD_T(kc) LSG_T(kc)
#define SWIN_T(kc) LSG_T(kc)
#define LAG_T(kc) MT(MOD_LALT | MOD_LGUI, kc)  // Left Alt + GUI
#define RSG_T(kc) MT(MOD_RSFT | MOD_RGUI, kc)  // Right Shift + GUI
#define RAG_T(kc) MT(MOD_RALT | MOD_RGUI, kc)  // Right Alt + GUI
#define LCA_T(kc) MT(MOD_LCTL | MOD_LALT, kc)  // Left Control + Alt
#define LSA_T(kc) MT(MOD_LSFT | MOD_LALT, kc)  // Left Shift + Alt
#define RSA_T(kc) MT(MOD_RSFT | MOD_RALT, kc)  // Right Shift + Alt
#define RCS_T(kc) MT(MOD_RCTL | MOD_RSFT, kc)  // Right Control + Shift
#define LAG_T(kc) MT(MOD_LALT | MOD_LGUI, kc) // Left Alt + GUI
#define RSG_T(kc) MT(MOD_RSFT | MOD_RGUI, kc) // Right Shift + GUI
#define RAG_T(kc) MT(MOD_RALT | MOD_RGUI, kc) // Right Alt + GUI
#define LCA_T(kc) MT(MOD_LCTL | MOD_LALT, kc) // Left Control + Alt
#define LSA_T(kc) MT(MOD_LSFT | MOD_LALT, kc) // Left Shift + Alt
#define RSA_T(kc) MT(MOD_RSFT | MOD_RALT, kc) // Right Shift + Alt
#define RCS_T(kc) MT(MOD_RCTL | MOD_RSFT, kc) // Right Control + Shift
#define SAGR_T(kc) RSA_T(kc)

#define ALL_T(kc) HYPR_T(kc)


@@ 870,14 870,14 @@ enum quantum_keycodes {
#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 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

#define UC_M_MA UNICODE_MODE_MAC
#define UNICODE_MODE_OSX UNICODE_MODE_MAC  // Deprecated alias
#define UC_M_OS UNICODE_MODE_MAC           // Deprecated alias
#define UNICODE_MODE_OSX UNICODE_MODE_MAC // Deprecated alias
#define UC_M_OS UNICODE_MODE_MAC          // Deprecated alias
#define UC_M_LN UNICODE_MODE_LNX
#define UC_M_WI UNICODE_MODE_WIN
#define UC_M_BS UNICODE_MODE_BSD

M quantum/rgb_matrix/animations/alpha_mods_anim.h => quantum/rgb_matrix/animations/alpha_mods_anim.h +2 -2
@@ 22,5 22,5 @@ bool ALPHAS_MODS(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_ALPHAS_MODS
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_ALPHAS_MODS

M quantum/rgb_matrix/animations/breathing_anim.h => quantum/rgb_matrix/animations/breathing_anim.h +2 -2
@@ 16,5 16,5 @@ bool BREATHING(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_BREATHING
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_BREATHING

M quantum/rgb_matrix/animations/colorband_pinwheel_sat_anim.h => quantum/rgb_matrix/animations/colorband_pinwheel_sat_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV BAND_PINWHEEL_SAT_math(HSV hsv, int16_t dx, int16_t dy, uint8_t time)
    return hsv;
}

bool BAND_PINWHEEL_SAT(effect_params_t* params) { return effect_runner_dx_dy(params, &BAND_PINWHEEL_SAT_math); }
bool BAND_PINWHEEL_SAT(effect_params_t* params) {
    return effect_runner_dx_dy(params, &BAND_PINWHEEL_SAT_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT

M quantum/rgb_matrix/animations/colorband_pinwheel_val_anim.h => quantum/rgb_matrix/animations/colorband_pinwheel_val_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV BAND_PINWHEEL_VAL_math(HSV hsv, int16_t dx, int16_t dy, uint8_t time)
    return hsv;
}

bool BAND_PINWHEEL_VAL(effect_params_t* params) { return effect_runner_dx_dy(params, &BAND_PINWHEEL_VAL_math); }
bool BAND_PINWHEEL_VAL(effect_params_t* params) {
    return effect_runner_dx_dy(params, &BAND_PINWHEEL_VAL_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL

M quantum/rgb_matrix/animations/colorband_sat_anim.h => quantum/rgb_matrix/animations/colorband_sat_anim.h +5 -3
@@ 8,7 8,9 @@ static HSV BAND_SAT_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool BAND_SAT(effect_params_t* params) { return effect_runner_i(params, &BAND_SAT_math); }
bool BAND_SAT(effect_params_t* params) {
    return effect_runner_i(params, &BAND_SAT_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_BAND_SAT
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_BAND_SAT

M quantum/rgb_matrix/animations/colorband_spiral_sat_anim.h => quantum/rgb_matrix/animations/colorband_spiral_sat_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV BAND_SPIRAL_SAT_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, u
    return hsv;
}

bool BAND_SPIRAL_SAT(effect_params_t* params) { return effect_runner_dx_dy_dist(params, &BAND_SPIRAL_SAT_math); }
bool BAND_SPIRAL_SAT(effect_params_t* params) {
    return effect_runner_dx_dy_dist(params, &BAND_SPIRAL_SAT_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT

M quantum/rgb_matrix/animations/colorband_spiral_val_anim.h => quantum/rgb_matrix/animations/colorband_spiral_val_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV BAND_SPIRAL_VAL_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, u
    return hsv;
}

bool BAND_SPIRAL_VAL(effect_params_t* params) { return effect_runner_dx_dy_dist(params, &BAND_SPIRAL_VAL_math); }
bool BAND_SPIRAL_VAL(effect_params_t* params) {
    return effect_runner_dx_dy_dist(params, &BAND_SPIRAL_VAL_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL

M quantum/rgb_matrix/animations/colorband_val_anim.h => quantum/rgb_matrix/animations/colorband_val_anim.h +5 -3
@@ 8,7 8,9 @@ static HSV BAND_VAL_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool BAND_VAL(effect_params_t* params) { return effect_runner_i(params, &BAND_VAL_math); }
bool BAND_VAL(effect_params_t* params) {
    return effect_runner_i(params, &BAND_VAL_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_BAND_VAL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_BAND_VAL

M quantum/rgb_matrix/animations/cycle_all_anim.h => quantum/rgb_matrix/animations/cycle_all_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV CYCLE_ALL_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool CYCLE_ALL(effect_params_t* params) { return effect_runner_i(params, &CYCLE_ALL_math); }
bool CYCLE_ALL(effect_params_t* params) {
    return effect_runner_i(params, &CYCLE_ALL_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_CYCLE_ALL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_CYCLE_ALL

M quantum/rgb_matrix/animations/cycle_left_right_anim.h => quantum/rgb_matrix/animations/cycle_left_right_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV CYCLE_LEFT_RIGHT_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool CYCLE_LEFT_RIGHT(effect_params_t* params) { return effect_runner_i(params, &CYCLE_LEFT_RIGHT_math); }
bool CYCLE_LEFT_RIGHT(effect_params_t* params) {
    return effect_runner_i(params, &CYCLE_LEFT_RIGHT_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT

M quantum/rgb_matrix/animations/cycle_out_in_anim.h => quantum/rgb_matrix/animations/cycle_out_in_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV CYCLE_OUT_IN_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint
    return hsv;
}

bool CYCLE_OUT_IN(effect_params_t* params) { return effect_runner_dx_dy_dist(params, &CYCLE_OUT_IN_math); }
bool CYCLE_OUT_IN(effect_params_t* params) {
    return effect_runner_dx_dy_dist(params, &CYCLE_OUT_IN_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_CYCLE_OUT_IN
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_CYCLE_OUT_IN

M quantum/rgb_matrix/animations/cycle_out_in_dual_anim.h => quantum/rgb_matrix/animations/cycle_out_in_dual_anim.h +5 -3
@@ 9,7 9,9 @@ static HSV CYCLE_OUT_IN_DUAL_math(HSV hsv, int16_t dx, int16_t dy, uint8_t time)
    return hsv;
}

bool CYCLE_OUT_IN_DUAL(effect_params_t* params) { return effect_runner_dx_dy(params, &CYCLE_OUT_IN_DUAL_math); }
bool CYCLE_OUT_IN_DUAL(effect_params_t* params) {
    return effect_runner_dx_dy(params, &CYCLE_OUT_IN_DUAL_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL

M quantum/rgb_matrix/animations/cycle_pinwheel_anim.h => quantum/rgb_matrix/animations/cycle_pinwheel_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV CYCLE_PINWHEEL_math(HSV hsv, int16_t dx, int16_t dy, uint8_t time) {
    return hsv;
}

bool CYCLE_PINWHEEL(effect_params_t* params) { return effect_runner_dx_dy(params, &CYCLE_PINWHEEL_math); }
bool CYCLE_PINWHEEL(effect_params_t* params) {
    return effect_runner_dx_dy(params, &CYCLE_PINWHEEL_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_CYCLE_PINWHEEL

M quantum/rgb_matrix/animations/cycle_spiral_anim.h => quantum/rgb_matrix/animations/cycle_spiral_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV CYCLE_SPIRAL_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint
    return hsv;
}

bool CYCLE_SPIRAL(effect_params_t* params) { return effect_runner_dx_dy_dist(params, &CYCLE_SPIRAL_math); }
bool CYCLE_SPIRAL(effect_params_t* params) {
    return effect_runner_dx_dy_dist(params, &CYCLE_SPIRAL_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_CYCLE_SPIRAL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_CYCLE_SPIRAL

M quantum/rgb_matrix/animations/cycle_up_down_anim.h => quantum/rgb_matrix/animations/cycle_up_down_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV CYCLE_UP_DOWN_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool CYCLE_UP_DOWN(effect_params_t* params) { return effect_runner_i(params, &CYCLE_UP_DOWN_math); }
bool CYCLE_UP_DOWN(effect_params_t* params) {
    return effect_runner_i(params, &CYCLE_UP_DOWN_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_CYCLE_UP_DOWN

M quantum/rgb_matrix/animations/digital_rain_anim.h => quantum/rgb_matrix/animations/digital_rain_anim.h +2 -2
@@ 71,5 71,5 @@ bool DIGITAL_RAIN(effect_params_t* params) {
    return false;
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(ENABLE_RGB_MATRIX_DIGITAL_RAIN)
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(ENABLE_RGB_MATRIX_DIGITAL_RAIN)

M quantum/rgb_matrix/animations/dual_beacon_anim.h => quantum/rgb_matrix/animations/dual_beacon_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV DUAL_BEACON_math(HSV hsv, int8_t sin, int8_t cos, uint8_t i, uint8_t 
    return hsv;
}

bool DUAL_BEACON(effect_params_t* params) { return effect_runner_sin_cos_i(params, &DUAL_BEACON_math); }
bool DUAL_BEACON(effect_params_t* params) {
    return effect_runner_sin_cos_i(params, &DUAL_BEACON_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_DUAL_BEACON
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_DUAL_BEACON

M quantum/rgb_matrix/animations/gradient_left_right_anim.h => quantum/rgb_matrix/animations/gradient_left_right_anim.h +2 -2
@@ 18,5 18,5 @@ bool GRADIENT_LEFT_RIGHT(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT

M quantum/rgb_matrix/animations/gradient_up_down_anim.h => quantum/rgb_matrix/animations/gradient_up_down_anim.h +2 -2
@@ 18,5 18,5 @@ bool GRADIENT_UP_DOWN(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN

M quantum/rgb_matrix/animations/hue_breathing_anim.h => quantum/rgb_matrix/animations/hue_breathing_anim.h +2 -2
@@ 18,5 18,5 @@ bool HUE_BREATHING(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // DISABLE_RGB_HUE_BREATHING
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // DISABLE_RGB_HUE_BREATHING

M quantum/rgb_matrix/animations/hue_pendulum_anim.h => quantum/rgb_matrix/animations/hue_pendulum_anim.h +5 -3
@@ 11,7 11,9 @@ static HSV HUE_PENDULUM_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool HUE_PENDULUM(effect_params_t* params) { return effect_runner_i(params, &HUE_PENDULUM_math); }
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
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // DISABLE_RGB_HUE_PENDULUM

M quantum/rgb_matrix/animations/hue_wave_anim.h => quantum/rgb_matrix/animations/hue_wave_anim.h +5 -3
@@ 11,7 11,9 @@ static HSV HUE_WAVE_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool HUE_WAVE(effect_params_t* params) { return effect_runner_i(params, &HUE_WAVE_math); }
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
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // DISABLE_RGB_HUE_WAVE

M quantum/rgb_matrix/animations/jellybean_raindrops_anim.h => quantum/rgb_matrix/animations/jellybean_raindrops_anim.h +2 -2
@@ 25,5 25,5 @@ bool JELLYBEAN_RAINDROPS(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS

M quantum/rgb_matrix/animations/pixel_flow_anim.h => quantum/rgb_matrix/animations/pixel_flow_anim.h +5 -3
@@ 14,7 14,9 @@ static bool PIXEL_FLOW(effect_params_t* params) {
        return false;
    }

    inline uint32_t interval(void) { return 3000 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16); }
    inline uint32_t interval(void) {
        return 3000 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16);
    }

    if (params->init) {
        // Clear LEDs and fill the state array


@@ 45,5 47,5 @@ static bool PIXEL_FLOW(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_PIXEL_FLOW
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_PIXEL_FLOW

M quantum/rgb_matrix/animations/pixel_fractal_anim.h => quantum/rgb_matrix/animations/pixel_fractal_anim.h +7 -5
@@ 29,7 29,9 @@ static bool PIXEL_FRACTAL(effect_params_t* params) {
        return false;
    }

    inline uint32_t interval(void) { return 3000 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16); }
    inline uint32_t interval(void) {
        return 3000 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16);
    }

    if (params->init) {
        rgb_matrix_set_color_all(0, 0, 0);


@@ 37,7 39,7 @@ static bool PIXEL_FRACTAL(effect_params_t* params) {

    RGB rgb = rgb_matrix_hsv_to_rgb(rgb_matrix_config.hsv);
    for (uint8_t h = 0; h < MATRIX_ROWS; ++h) {
        for (uint8_t l = 0; l < MID_COL - 1; ++l) {  // Light and move left columns outwards
        for (uint8_t l = 0; l < MID_COL - 1; ++l) { // Light and move left columns outwards
            if (led[h][l]) {
                rgb_matrix_set_color(g_led_config.matrix_co[h][l], rgb.r, rgb.g, rgb.b);
            } else {


@@ 46,7 48,7 @@ static bool PIXEL_FRACTAL(effect_params_t* params) {
            led[h][l] = led[h][l + 1];
        }

        for (uint8_t r = MATRIX_COLS - 1; r > MID_COL; --r) {  // Light and move right columns outwards
        for (uint8_t r = MATRIX_COLS - 1; r > MID_COL; --r) { // Light and move right columns outwards
            if (led[h][r]) {
                rgb_matrix_set_color(g_led_config.matrix_co[h][r], rgb.r, rgb.g, rgb.b);
            } else {


@@ 74,5 76,5 @@ static bool PIXEL_FRACTAL(effect_params_t* params) {
    wait_timer = g_rgb_timer + interval();
    return false;
}
#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_PIXEL_FRACTAL
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_PIXEL_FRACTAL

M quantum/rgb_matrix/animations/pixel_rain_anim.h => quantum/rgb_matrix/animations/pixel_rain_anim.h +5 -3
@@ 24,7 24,9 @@ static bool PIXEL_RAIN(effect_params_t* params) {
        return false;
    }

    inline uint32_t interval(void) { return 500 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16); }
    inline uint32_t interval(void) {
        return 500 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16);
    }

    bool rain_pixel(uint8_t i, effect_params_t * params, bool off) {
        if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) {


@@ 44,5 46,5 @@ static bool PIXEL_RAIN(effect_params_t* params) {
    return rain_pixel(mod8(random8(), DRIVER_LED_TOTAL), params, random8() & 2);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_PIXEL_RAIN
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_PIXEL_RAIN

M quantum/rgb_matrix/animations/rainbow_beacon_anim.h => quantum/rgb_matrix/animations/rainbow_beacon_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV RAINBOW_BEACON_math(HSV hsv, int8_t sin, int8_t cos, uint8_t i, uint8
    return hsv;
}

bool RAINBOW_BEACON(effect_params_t* params) { return effect_runner_sin_cos_i(params, &RAINBOW_BEACON_math); }
bool RAINBOW_BEACON(effect_params_t* params) {
    return effect_runner_sin_cos_i(params, &RAINBOW_BEACON_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_RAINBOW_BEACON
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_RAINBOW_BEACON

M quantum/rgb_matrix/animations/rainbow_moving_chevron_anim.h => quantum/rgb_matrix/animations/rainbow_moving_chevron_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV RAINBOW_MOVING_CHEVRON_math(HSV hsv, uint8_t i, uint8_t time) {
    return hsv;
}

bool RAINBOW_MOVING_CHEVRON(effect_params_t* params) { return effect_runner_i(params, &RAINBOW_MOVING_CHEVRON_math); }
bool RAINBOW_MOVING_CHEVRON(effect_params_t* params) {
    return effect_runner_i(params, &RAINBOW_MOVING_CHEVRON_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON

M quantum/rgb_matrix/animations/rainbow_pinwheels_anim.h => quantum/rgb_matrix/animations/rainbow_pinwheels_anim.h +5 -3
@@ 7,7 7,9 @@ static HSV RAINBOW_PINWHEELS_math(HSV hsv, int8_t sin, int8_t cos, uint8_t i, ui
    return hsv;
}

bool RAINBOW_PINWHEELS(effect_params_t* params) { return effect_runner_sin_cos_i(params, &RAINBOW_PINWHEELS_math); }
bool RAINBOW_PINWHEELS(effect_params_t* params) {
    return effect_runner_sin_cos_i(params, &RAINBOW_PINWHEELS_math);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS

M quantum/rgb_matrix/animations/raindrops_anim.h => quantum/rgb_matrix/animations/raindrops_anim.h +2 -2
@@ 35,5 35,5 @@ bool RAINDROPS(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // ENABLE_RGB_MATRIX_RAINDROPS
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // ENABLE_RGB_MATRIX_RAINDROPS

M quantum/rgb_matrix/animations/runners/effect_runner_reactive.h => quantum/rgb_matrix/animations/runners/effect_runner_reactive.h +1 -1
@@ 26,4 26,4 @@ bool effect_runner_reactive(effect_params_t* params, reactive_f effect_func) {
    return rgb_matrix_check_finished_leds(led_max);
}

#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h => quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h +1 -1
@@ 26,4 26,4 @@ bool effect_runner_reactive_splash(uint8_t start, effect_params_t* params, react
    return rgb_matrix_check_finished_leds(led_max);
}

#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/solid_color_anim.h => quantum/rgb_matrix/animations/solid_color_anim.h +1 -1
@@ 12,4 12,4 @@ bool SOLID_COLOR(effect_params_t* params) {
    return rgb_matrix_check_finished_leds(led_max);
}

#endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS

M quantum/rgb_matrix/animations/solid_reactive_anim.h => quantum/rgb_matrix/animations/solid_reactive_anim.h +6 -4
@@ 8,8 8,10 @@ static HSV SOLID_REACTIVE_math(HSV hsv, uint16_t offset) {
    return hsv;
}

bool SOLID_REACTIVE(effect_params_t* params) { return effect_runner_reactive(params, &SOLID_REACTIVE_math); }
bool SOLID_REACTIVE(effect_params_t* params) {
    return effect_runner_reactive(params, &SOLID_REACTIVE_math);
}

#        endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // ENABLE_RGB_MATRIX_SOLID_REACTIVE
#endif          // RGB_MATRIX_KEYREACTIVE_ENABLED
#        endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // ENABLE_RGB_MATRIX_SOLID_REACTIVE
#endif         // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/solid_reactive_cross.h => quantum/rgb_matrix/animations/solid_reactive_cross.h +9 -5
@@ 24,13 24,17 @@ static HSV SOLID_REACTIVE_CROSS_math(HSV hsv, int16_t dx, int16_t dy, uint8_t di
}

#            ifdef ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
bool SOLID_REACTIVE_CROSS(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_CROSS_math); }
bool SOLID_REACTIVE_CROSS(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_CROSS_math);
}
#            endif

#            ifdef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
bool SOLID_REACTIVE_MULTICROSS(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_CROSS_math); }
bool SOLID_REACTIVE_MULTICROSS(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_CROSS_math);
}
#            endif

#        endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS) || defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS)
#endif          // RGB_MATRIX_KEYREACTIVE_ENABLED
#        endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS) || defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS)
#endif         // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/solid_reactive_nexus.h => quantum/rgb_matrix/animations/solid_reactive_nexus.h +9 -5
@@ 22,13 22,17 @@ static HSV SOLID_REACTIVE_NEXUS_math(HSV hsv, int16_t dx, int16_t dy, uint8_t di
}

#            ifdef ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
bool SOLID_REACTIVE_NEXUS(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_NEXUS_math); }
bool SOLID_REACTIVE_NEXUS(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_NEXUS_math);
}
#            endif

#            ifdef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
bool SOLID_REACTIVE_MULTINEXUS(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_NEXUS_math); }
bool SOLID_REACTIVE_MULTINEXUS(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_NEXUS_math);
}
#            endif

#        endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS) || !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS)
#endif          // RGB_MATRIX_KEYREACTIVE_ENABLED
#        endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS) || !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS)
#endif         // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/solid_reactive_simple_anim.h => quantum/rgb_matrix/animations/solid_reactive_simple_anim.h +6 -4
@@ 8,8 8,10 @@ static HSV SOLID_REACTIVE_SIMPLE_math(HSV hsv, uint16_t offset) {
    return hsv;
}

bool SOLID_REACTIVE_SIMPLE(effect_params_t* params) { return effect_runner_reactive(params, &SOLID_REACTIVE_SIMPLE_math); }
bool SOLID_REACTIVE_SIMPLE(effect_params_t* params) {
    return effect_runner_reactive(params, &SOLID_REACTIVE_SIMPLE_math);
}

#        endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
#endif          // RGB_MATRIX_KEYREACTIVE_ENABLED
#        endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
#endif         // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/solid_reactive_wide.h => quantum/rgb_matrix/animations/solid_reactive_wide.h +9 -5
@@ 19,13 19,17 @@ static HSV SOLID_REACTIVE_WIDE_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dis
}

#            ifdef ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
bool SOLID_REACTIVE_WIDE(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_WIDE_math); }
bool SOLID_REACTIVE_WIDE(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_REACTIVE_WIDE_math);
}
#            endif

#            ifdef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
bool SOLID_REACTIVE_MULTIWIDE(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_WIDE_math); }
bool SOLID_REACTIVE_MULTIWIDE(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_REACTIVE_WIDE_math);
}
#            endif

#        endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE) || !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE)
#endif          // RGB_MATRIX_KEYREACTIVE_ENABLED
#        endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE) || !defined(ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE)
#endif         // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/solid_splash_anim.h => quantum/rgb_matrix/animations/solid_splash_anim.h +9 -5
@@ 19,13 19,17 @@ HSV SOLID_SPLASH_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint16_t ti
}

#            ifdef ENABLE_RGB_MATRIX_SOLID_SPLASH
bool SOLID_SPLASH(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_SPLASH_math); }
bool SOLID_SPLASH(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SOLID_SPLASH_math);
}
#            endif

#            ifdef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH
bool SOLID_MULTISPLASH(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SOLID_SPLASH_math); }
bool SOLID_MULTISPLASH(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SOLID_SPLASH_math);
}
#            endif

#        endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // !defined(ENABLE_RGB_MATRIX_SPLASH) && !defined(ENABLE_RGB_MATRIX_MULTISPLASH)
#endif          // RGB_MATRIX_KEYREACTIVE_ENABLED
#        endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // !defined(ENABLE_RGB_MATRIX_SPLASH) && !defined(ENABLE_RGB_MATRIX_MULTISPLASH)
#endif         // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/splash_anim.h => quantum/rgb_matrix/animations/splash_anim.h +9 -5
@@ 20,13 20,17 @@ HSV SPLASH_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint16_t tick) {
}

#            ifdef ENABLE_RGB_MATRIX_SPLASH
bool SPLASH(effect_params_t* params) { return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SPLASH_math); }
bool SPLASH(effect_params_t* params) {
    return effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SPLASH_math);
}
#            endif

#            ifdef ENABLE_RGB_MATRIX_MULTISPLASH
bool MULTISPLASH(effect_params_t* params) { return effect_runner_reactive_splash(0, params, &SPLASH_math); }
bool MULTISPLASH(effect_params_t* params) {
    return effect_runner_reactive_splash(0, params, &SPLASH_math);
}
#            endif

#        endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif      // !defined(ENABLE_RGB_MATRIX_SPLASH) || !defined(ENABLE_RGB_MATRIX_MULTISPLASH)
#endif          // RGB_MATRIX_KEYREACTIVE_ENABLED
#        endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#    endif     // !defined(ENABLE_RGB_MATRIX_SPLASH) || !defined(ENABLE_RGB_MATRIX_MULTISPLASH)
#endif         // RGB_MATRIX_KEYREACTIVE_ENABLED

M quantum/rgb_matrix/animations/typing_heatmap_anim.h => quantum/rgb_matrix/animations/typing_heatmap_anim.h +2 -2
@@ 82,5 82,5 @@ bool TYPING_HEATMAP(effect_params_t* params) {
    return led_max < sizeof(g_rgb_frame_buffer);
}

#    endif  // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif      // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP)
#    endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
#endif     // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP)

M quantum/rgb_matrix/rgb_matrix.c => quantum/rgb_matrix/rgb_matrix.c +176 -73
@@ 31,7 31,9 @@ const led_point_t k_rgb_matrix_center = {112, 32};
const led_point_t k_rgb_matrix_center = RGB_MATRIX_CENTER;
#endif

__attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); }
__attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) {
    return hsv_to_rgb(hsv);
}

// Generic effect runners
#include "rgb_matrix_runners.inc"


@@ 109,14 111,14 @@ __attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv
#endif

// globals
rgb_config_t rgb_matrix_config;  // TODO: would like to prefix this with g_ for global consistancy, do this in another pr
rgb_config_t rgb_matrix_config; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr
uint32_t     g_rgb_timer;
#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
uint8_t g_rgb_frame_buffer[MATRIX_ROWS][MATRIX_COLS] = {{0}};
#endif  // RGB_MATRIX_FRAMEBUFFER_EFFECTS
#endif // RGB_MATRIX_FRAMEBUFFER_EFFECTS
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
last_hit_t g_last_hit_tracker;
#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

// internals
static bool            suspend_state     = false;


@@ 126,13 128,13 @@ static effect_params_t rgb_effect_params = {0, LED_FLAG_ALL, false};
static rgb_task_states rgb_task_state    = SYNCING;
#if RGB_DISABLE_TIMEOUT > 0
static uint32_t rgb_anykey_timer;
#endif  // RGB_DISABLE_TIMEOUT > 0
#endif // RGB_DISABLE_TIMEOUT > 0

// double buffers
static uint32_t rgb_timer_buffer;
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
static last_hit_t last_hit_buffer;
#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

// split rgb matrix
#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)


@@ 141,7 143,9 @@ const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;

EECONFIG_DEBOUNCE_HELPER(rgb_matrix, EECONFIG_RGB_MATRIX, rgb_matrix_config);

void eeconfig_update_rgb_matrix(void) { eeconfig_flush_rgb_matrix(true); }
void eeconfig_update_rgb_matrix(void) {
    eeconfig_flush_rgb_matrix(true);
}

void eeconfig_update_rgb_matrix_default(void) {
    dprintf("eeconfig_update_rgb_matrix_default\n");


@@ 168,13 172,15 @@ void rgb_matrix_reload_from_eeprom(void) {
    rgb_matrix_disable_noeeprom();
    /* Reset back to what we have in eeprom */
    eeconfig_init_rgb_matrix();
    eeconfig_debug_rgb_matrix();  // display current eeprom values
    eeconfig_debug_rgb_matrix(); // display current eeprom values
    if (rgb_matrix_config.enable) {
        rgb_matrix_mode_noeeprom(rgb_matrix_config.mode);
    }
}

__attribute__((weak)) uint8_t rgb_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) { return 0; }
__attribute__((weak)) uint8_t rgb_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) {
    return 0;
}

uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) {
    uint8_t led_count = rgb_matrix_map_row_column_to_led_kb(row, column, led_i);


@@ 186,13 192,18 @@ uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *l
    return led_count;
}

void rgb_matrix_update_pwm_buffers(void) { rgb_matrix_driver.flush(); }
void rgb_matrix_update_pwm_buffers(void) {
    rgb_matrix_driver.flush();
}

void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { rgb_matrix_driver.set_color(index, red, green, blue); }
void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
    rgb_matrix_driver.set_color(index, red, green, blue);
}

void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
    for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) rgb_matrix_set_color(i, red, green, blue);
    for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++)
        rgb_matrix_set_color(i, red, green, blue);
#else
    rgb_matrix_driver.set_color_all(red, green, blue);
#endif


@@ 204,7 215,7 @@ void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) {
#endif
#if RGB_DISABLE_TIMEOUT > 0
    rgb_anykey_timer = 0;
#endif  // RGB_DISABLE_TIMEOUT > 0
#endif // RGB_DISABLE_TIMEOUT > 0

#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
    uint8_t led[LED_HITS_TO_REMEMBER];


@@ 214,7 225,7 @@ void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) {
    if (!pressed)
#    elif defined(RGB_MATRIX_KEYPRESSES)
    if (pressed)
#    endif  // defined(RGB_MATRIX_KEYRELEASES)
#    endif // defined(RGB_MATRIX_KEYRELEASES)
    {
        led_count = rgb_matrix_map_row_column_to_led(row, col, led);
    }


@@ 222,7 233,7 @@ void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) {
    if (last_hit_buffer.count + led_count > LED_HITS_TO_REMEMBER) {
        memcpy(&last_hit_buffer.x[0], &last_hit_buffer.x[led_count], LED_HITS_TO_REMEMBER - led_count);
        memcpy(&last_hit_buffer.y[0], &last_hit_buffer.y[led_count], LED_HITS_TO_REMEMBER - led_count);
        memcpy(&last_hit_buffer.tick[0], &last_hit_buffer.tick[led_count], (LED_HITS_TO_REMEMBER - led_count) * 2);  // 16 bit
        memcpy(&last_hit_buffer.tick[0], &last_hit_buffer.tick[led_count], (LED_HITS_TO_REMEMBER - led_count) * 2); // 16 bit
        memcpy(&last_hit_buffer.index[0], &last_hit_buffer.index[led_count], LED_HITS_TO_REMEMBER - led_count);
        last_hit_buffer.count = LED_HITS_TO_REMEMBER - led_count;
    }


@@ 235,13 246,13 @@ void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) {
        last_hit_buffer.tick[index]  = 0;
        last_hit_buffer.count++;
    }
#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP)
    if (rgb_matrix_config.mode == RGB_MATRIX_TYPING_HEATMAP) {
        process_rgb_matrix_typing_heatmap(row, col);
    }
#endif  // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP)
#endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP)
}

void rgb_matrix_test(void) {


@@ 280,7 291,7 @@ 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 = sync_timer_elapsed32(rgb_timer_buffer);
#endif  // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
    rgb_timer_buffer = sync_timer_read32();

    // Update double buffer timers


@@ 288,7 299,7 @@ static void rgb_task_timers(void) {
    if (rgb_anykey_timer + deltaTime <= UINT32_MAX) {
        rgb_anykey_timer += deltaTime;
    }
#endif  // RGB_DISABLE_TIMEOUT > 0
#endif // RGB_DISABLE_TIMEOUT > 0

    // Update double buffer last hit timers
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED


@@ 300,7 311,7 @@ static void rgb_task_timers(void) {
        }
        last_hit_buffer.tick[i] += deltaTime;
    }
#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED
}

static void rgb_task_sync(void) {


@@ 317,7 328,7 @@ static void rgb_task_start(void) {
    g_rgb_timer = rgb_timer_buffer;
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
    g_last_hit_tracker = last_hit_buffer;
#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

    // next task
    rgb_task_state = RENDERING;


@@ 403,7 414,7 @@ void rgb_matrix_task(void) {
    bool suspend_backlight = suspend_state ||
#if RGB_DISABLE_TIMEOUT > 0
                             (rgb_anykey_timer > (uint32_t)RGB_DISABLE_TIMEOUT) ||
#endif  // RGB_DISABLE_TIMEOUT > 0
#endif // RGB_DISABLE_TIMEOUT > 0
                             false;

    uint8_t effect = suspend_backlight || !rgb_matrix_config.enable ? 0 : rgb_matrix_config.mode;


@@ 472,7 483,7 @@ void rgb_matrix_init(void) {
    for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) {
        last_hit_buffer.tick[i] = UINT16_MAX;
    }
#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

    if (!eeconfig_is_enabled()) {
        dprintf("rgb_matrix_init_drivers eeconfig is not enabled.\n");


@@ 485,20 496,22 @@ void rgb_matrix_init(void) {
        dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n");
        eeconfig_update_rgb_matrix_default();
    }
    eeconfig_debug_rgb_matrix();  // display current eeprom values
    eeconfig_debug_rgb_matrix(); // display current eeprom values
}

void rgb_matrix_set_suspend_state(bool state) {
#ifdef RGB_DISABLE_WHEN_USB_SUSPENDED
    if (state && !suspend_state) {  // only run if turning off, and only once
        rgb_task_render(0);         // turn off all LEDs when suspending
        rgb_task_flush(0);          // and actually flash led state to LEDs
    if (state && !suspend_state) { // only run if turning off, and only once
        rgb_task_render(0);        // turn off all LEDs when suspending
        rgb_task_flush(0);         // and actually flash led state to LEDs
    }
    suspend_state = state;
#endif
}

bool rgb_matrix_get_suspend_state(void) { return suspend_state; }
bool rgb_matrix_get_suspend_state(void) {
    return suspend_state;
}

void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
    rgb_matrix_config.enable ^= 1;


@@ 506,8 519,12 @@ void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
    eeconfig_flag_rgb_matrix(write_to_eeprom);
    dprintf("rgb matrix toggle [%s]: rgb_matrix_config.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.enable);
}
void rgb_matrix_toggle_noeeprom(void) { rgb_matrix_toggle_eeprom_helper(false); }
void rgb_matrix_toggle(void) { rgb_matrix_toggle_eeprom_helper(true); }
void rgb_matrix_toggle_noeeprom(void) {
    rgb_matrix_toggle_eeprom_helper(false);
}
void rgb_matrix_toggle(void) {
    rgb_matrix_toggle_eeprom_helper(true);
}

void rgb_matrix_enable(void) {
    rgb_matrix_enable_noeeprom();


@@ 529,7 546,9 @@ void rgb_matrix_disable_noeeprom(void) {
    rgb_matrix_config.enable = 0;
}

uint8_t rgb_matrix_is_enabled(void) { return rgb_matrix_config.enable; }
uint8_t rgb_matrix_is_enabled(void) {
    return rgb_matrix_config.enable;
}

void rgb_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
    if (!rgb_matrix_config.enable) {


@@ 546,24 565,38 @@ void rgb_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
    eeconfig_flag_rgb_matrix(write_to_eeprom);
    dprintf("rgb matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.mode);
}
void rgb_matrix_mode_noeeprom(uint8_t mode) { rgb_matrix_mode_eeprom_helper(mode, false); }
void rgb_matrix_mode(uint8_t mode) { rgb_matrix_mode_eeprom_helper(mode, true); }
void rgb_matrix_mode_noeeprom(uint8_t mode) {
    rgb_matrix_mode_eeprom_helper(mode, false);
}
void rgb_matrix_mode(uint8_t mode) {
    rgb_matrix_mode_eeprom_helper(mode, true);
}

uint8_t rgb_matrix_get_mode(void) { return rgb_matrix_config.mode; }
uint8_t rgb_matrix_get_mode(void) {
    return rgb_matrix_config.mode;
}

void rgb_matrix_step_helper(bool write_to_eeprom) {
    uint8_t mode = rgb_matrix_config.mode + 1;
    rgb_matrix_mode_eeprom_helper((mode < RGB_MATRIX_EFFECT_MAX) ? mode : 1, write_to_eeprom);
}
void rgb_matrix_step_noeeprom(void) { rgb_matrix_step_helper(false); }
void rgb_matrix_step(void) { rgb_matrix_step_helper(true); }
void rgb_matrix_step_noeeprom(void) {
    rgb_matrix_step_helper(false);
}
void rgb_matrix_step(void) {
    rgb_matrix_step_helper(true);
}

void rgb_matrix_step_reverse_helper(bool write_to_eeprom) {
    uint8_t mode = rgb_matrix_config.mode - 1;
    rgb_matrix_mode_eeprom_helper((mode < 1) ? RGB_MATRIX_EFFECT_MAX - 1 : mode, write_to_eeprom);
}
void rgb_matrix_step_reverse_noeeprom(void) { rgb_matrix_step_reverse_helper(false); }
void rgb_matrix_step_reverse(void) { rgb_matrix_step_reverse_helper(true); }
void rgb_matrix_step_reverse_noeeprom(void) {
    rgb_matrix_step_reverse_helper(false);
}
void rgb_matrix_step_reverse(void) {
    rgb_matrix_step_reverse_helper(true);
}

void rgb_matrix_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
    if (!rgb_matrix_config.enable) {


@@ 575,56 608,126 @@ void rgb_matrix_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, boo
    eeconfig_flag_rgb_matrix(write_to_eeprom);
    dprintf("rgb matrix set hsv [%s]: %u,%u,%u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v);
}
void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) { rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false); }
void rgb_matrix_sethsv(uint16_t hue, uint8_t sat, uint8_t val) { rgb_matrix_sethsv_eeprom_helper(hue, sat, val, true); }
void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
    rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false);
}
void rgb_matrix_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
    rgb_matrix_sethsv_eeprom_helper(hue, sat, val, true);
}

HSV     rgb_matrix_get_hsv(void) { return rgb_matrix_config.hsv; }
uint8_t rgb_matrix_get_hue(void) { return rgb_matrix_config.hsv.h; }
uint8_t rgb_matrix_get_sat(void) { return rgb_matrix_config.hsv.s; }
uint8_t rgb_matrix_get_val(void) { return rgb_matrix_config.hsv.v; }
HSV rgb_matrix_get_hsv(void) {
    return rgb_matrix_config.hsv;
}
uint8_t rgb_matrix_get_hue(void) {
    return rgb_matrix_config.hsv.h;
}
uint8_t rgb_matrix_get_sat(void) {
    return rgb_matrix_config.hsv.s;
}
uint8_t rgb_matrix_get_val(void) {
    return rgb_matrix_config.hsv.v;
}

void rgb_matrix_increase_hue_helper(bool write_to_eeprom) { rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h + RGB_MATRIX_HUE_STEP, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v, write_to_eeprom); }
void rgb_matrix_increase_hue_noeeprom(void) { rgb_matrix_increase_hue_helper(false); }
void rgb_matrix_increase_hue(void) { rgb_matrix_increase_hue_helper(true); }
void rgb_matrix_increase_hue_helper(bool write_to_eeprom) {
    rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h + RGB_MATRIX_HUE_STEP, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v, write_to_eeprom);
}
void rgb_matrix_increase_hue_noeeprom(void) {
    rgb_matrix_increase_hue_helper(false);
}
void rgb_matrix_increase_hue(void) {
    rgb_matrix_increase_hue_helper(true);
}

void rgb_matrix_decrease_hue_helper(bool write_to_eeprom) { rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h - RGB_MATRIX_HUE_STEP, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v, write_to_eeprom); }
void rgb_matrix_decrease_hue_noeeprom(void) { rgb_matrix_decrease_hue_helper(false); }
void rgb_matrix_decrease_hue(void) { rgb_matrix_decrease_hue_helper(true); }
void rgb_matrix_decrease_hue_helper(bool write_to_eeprom) {
    rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h - RGB_MATRIX_HUE_STEP, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v, write_to_eeprom);
}
void rgb_matrix_decrease_hue_noeeprom(void) {
    rgb_matrix_decrease_hue_helper(false);
}
void rgb_matrix_decrease_hue(void) {
    rgb_matrix_decrease_hue_helper(true);
}

void rgb_matrix_increase_sat_helper(bool write_to_eeprom) { rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, qadd8(rgb_matrix_config.hsv.s, RGB_MATRIX_SAT_STEP), rgb_matrix_config.hsv.v, write_to_eeprom); }
void rgb_matrix_increase_sat_noeeprom(void) { rgb_matrix_increase_sat_helper(false); }
void rgb_matrix_increase_sat(void) { rgb_matrix_increase_sat_helper(true); }
void rgb_matrix_increase_sat_helper(bool write_to_eeprom) {
    rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, qadd8(rgb_matrix_config.hsv.s, RGB_MATRIX_SAT_STEP), rgb_matrix_config.hsv.v, write_to_eeprom);
}
void rgb_matrix_increase_sat_noeeprom(void) {
    rgb_matrix_increase_sat_helper(false);
}
void rgb_matrix_increase_sat(void) {
    rgb_matrix_increase_sat_helper(true);
}

void rgb_matrix_decrease_sat_helper(bool write_to_eeprom) { rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, qsub8(rgb_matrix_config.hsv.s, RGB_MATRIX_SAT_STEP), rgb_matrix_config.hsv.v, write_to_eeprom); }
void rgb_matrix_decrease_sat_noeeprom(void) { rgb_matrix_decrease_sat_helper(false); }
void rgb_matrix_decrease_sat(void) { rgb_matrix_decrease_sat_helper(true); }
void rgb_matrix_decrease_sat_helper(bool write_to_eeprom) {
    rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, qsub8(rgb_matrix_config.hsv.s, RGB_MATRIX_SAT_STEP), rgb_matrix_config.hsv.v, write_to_eeprom);
}
void rgb_matrix_decrease_sat_noeeprom(void) {
    rgb_matrix_decrease_sat_helper(false);
}
void rgb_matrix_decrease_sat(void) {
    rgb_matrix_decrease_sat_helper(true);
}

void rgb_matrix_increase_val_helper(bool write_to_eeprom) { rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, qadd8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP), write_to_eeprom); }
void rgb_matrix_increase_val_noeeprom(void) { rgb_matrix_increase_val_helper(false); }
void rgb_matrix_increase_val(void) { rgb_matrix_increase_val_helper(true); }
void rgb_matrix_increase_val_helper(bool write_to_eeprom) {
    rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, qadd8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP), write_to_eeprom);
}
void rgb_matrix_increase_val_noeeprom(void) {
    rgb_matrix_increase_val_helper(false);
}
void rgb_matrix_increase_val(void) {
    rgb_matrix_increase_val_helper(true);
}

void rgb_matrix_decrease_val_helper(bool write_to_eeprom) { rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, qsub8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP), write_to_eeprom); }
void rgb_matrix_decrease_val_noeeprom(void) { rgb_matrix_decrease_val_helper(false); }
void rgb_matrix_decrease_val(void) { rgb_matrix_decrease_val_helper(true); }
void rgb_matrix_decrease_val_helper(bool write_to_eeprom) {
    rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, qsub8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP), write_to_eeprom);
}
void rgb_matrix_decrease_val_noeeprom(void) {
    rgb_matrix_decrease_val_helper(false);
}
void rgb_matrix_decrease_val(void) {
    rgb_matrix_decrease_val_helper(true);
}

void rgb_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
    rgb_matrix_config.speed = speed;
    eeconfig_flag_rgb_matrix(write_to_eeprom);
    dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.speed);
}
void rgb_matrix_set_speed_noeeprom(uint8_t speed) { rgb_matrix_set_speed_eeprom_helper(speed, false); }
void rgb_matrix_set_speed(uint8_t speed) { rgb_matrix_set_speed_eeprom_helper(speed, true); }
void rgb_matrix_set_speed_noeeprom(uint8_t speed) {
    rgb_matrix_set_speed_eeprom_helper(speed, false);
}
void rgb_matrix_set_speed(uint8_t speed) {
    rgb_matrix_set_speed_eeprom_helper(speed, true);
}

uint8_t rgb_matrix_get_speed(void) { return rgb_matrix_config.speed; }
uint8_t rgb_matrix_get_speed(void) {
    return rgb_matrix_config.speed;
}

void rgb_matrix_increase_speed_helper(bool write_to_eeprom) { rgb_matrix_set_speed_eeprom_helper(qadd8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP), write_to_eeprom); }
void rgb_matrix_increase_speed_noeeprom(void) { rgb_matrix_increase_speed_helper(false); }
void rgb_matrix_increase_speed(void) { rgb_matrix_increase_speed_helper(true); }
void rgb_matrix_increase_speed_helper(bool write_to_eeprom) {
    rgb_matrix_set_speed_eeprom_helper(qadd8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP), write_to_eeprom);
}
void rgb_matrix_increase_speed_noeeprom(void) {
    rgb_matrix_increase_speed_helper(false);
}
void rgb_matrix_increase_speed(void) {
    rgb_matrix_increase_speed_helper(true);
}

void rgb_matrix_decrease_speed_helper(bool write_to_eeprom) { rgb_matrix_set_speed_eeprom_helper(qsub8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP), write_to_eeprom); }
void rgb_matrix_decrease_speed_noeeprom(void) { rgb_matrix_decrease_speed_helper(false); }
void rgb_matrix_decrease_speed(void) { rgb_matrix_decrease_speed_helper(true); }
void rgb_matrix_decrease_speed_helper(bool write_to_eeprom) {
    rgb_matrix_set_speed_eeprom_helper(qsub8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP), write_to_eeprom);
}
void rgb_matrix_decrease_speed_noeeprom(void) {
    rgb_matrix_decrease_speed_helper(false);
}
void rgb_matrix_decrease_speed(void) {
    rgb_matrix_decrease_speed_helper(true);
}

led_flags_t rgb_matrix_get_flags(void) { return rgb_matrix_config.flags; }
led_flags_t rgb_matrix_get_flags(void) {
    return rgb_matrix_config.flags;
}

void rgb_matrix_set_flags(led_flags_t flags) { rgb_matrix_config.flags = flags; }
void rgb_matrix_set_flags(led_flags_t flags) {
    rgb_matrix_config.flags = flags;
}

M quantum/rgb_matrix/rgb_matrix_types.h => quantum/rgb_matrix/rgb_matrix_types.h +3 -3
@@ 37,7 37,7 @@
// Last led hit
#ifndef LED_HITS_TO_REMEMBER
#    define LED_HITS_TO_REMEMBER 8
#endif  // LED_HITS_TO_REMEMBER
#endif // LED_HITS_TO_REMEMBER

#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
typedef struct PACKED {


@@ 47,7 47,7 @@ typedef struct PACKED {
    uint8_t  index[LED_HITS_TO_REMEMBER];
    uint16_t tick[LED_HITS_TO_REMEMBER];
} last_hit_t;
#endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
#endif // RGB_MATRIX_KEYREACTIVE_ENABLED

typedef enum rgb_task_states { STARTING, RENDERING, FLUSHING, SYNCING } rgb_task_states;



@@ 88,7 88,7 @@ typedef union {
        uint8_t     enable : 2;
        uint8_t     mode : 6;
        HSV         hsv;
        uint8_t     speed;  // EECONFIG needs to be increased to support this
        uint8_t     speed; // EECONFIG needs to be increased to support this
        led_flags_t flags;
    };
} rgb_config_t;

M quantum/rgblight/rgblight.c => quantum/rgblight/rgblight.c +160 -66
@@ 72,7 72,7 @@ static uint8_t static_effect_table[] = {
#define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##msym,
#define _RGBM_TMP_DYNAMIC(sym, msym) RGBLIGHT_MODE_##msym,
static uint8_t mode_base_table[] = {
    0,  // RGBLIGHT_MODE_zero
    0, // RGBLIGHT_MODE_zero
#include "rgblight_modes.h"
};



@@ 96,7 96,9 @@ static uint8_t mode_base_table[] = {
#    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; }
static inline int is_static_effect(uint8_t mode) {
    return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL;
}

#ifdef RGBLIGHT_LED_MAP
const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP;


@@ 143,7 145,9 @@ void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) {
    rgblight_ranges.effect_num_leds  = num_leds;
}

__attribute__((weak)) RGB rgblight_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); }
__attribute__((weak)) RGB rgblight_hsv_to_rgb(HSV hsv) {
    return hsv_to_rgb(hsv);
}

void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
    HSV hsv = {hue, sat, val};


@@ 151,7 155,9 @@ void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
    setrgb(rgb.r, rgb.g, rgb.b, led1);
}

void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { sethsv_raw(hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val, led1); }
void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
    sethsv_raw(hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val, led1);
}

void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
    led1->r = r;


@@ 191,7 197,9 @@ void eeconfig_update_rgblight(uint32_t val) {
#endif
}

void eeconfig_update_rgblight_current(void) { eeconfig_update_rgblight(rgblight_config.raw); }
void eeconfig_update_rgblight_current(void) {
    eeconfig_update_rgblight(rgblight_config.raw);
}

void eeconfig_update_rgblight_default(void) {
    rgblight_config.enable = 1;


@@ 238,9 246,9 @@ void rgblight_init(void) {
    }
    rgblight_check_config();

    eeconfig_debug_rgblight();  // display current eeprom values
    eeconfig_debug_rgblight(); // display current eeprom values

    rgblight_timer_init();  // setup the timer
    rgblight_timer_init(); // setup the timer

    if (rgblight_config.enable) {
        rgblight_mode_noeeprom(rgblight_config.mode);


@@ 254,13 262,15 @@ void rgblight_reload_from_eeprom(void) {
    rgblight_config.raw = eeconfig_read_rgblight();
    RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
    rgblight_check_config();
    eeconfig_debug_rgblight();  // display current eeprom values
    eeconfig_debug_rgblight(); // display current eeprom values
    if (rgblight_config.enable) {
        rgblight_mode_noeeprom(rgblight_config.mode);
    }
}

uint32_t rgblight_read_dword(void) { return rgblight_config.raw; }
uint32_t rgblight_read_dword(void) {
    return rgblight_config.raw;
}

void rgblight_update_dword(uint32_t dword) {
    RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;


@@ 296,8 306,12 @@ void rgblight_step_helper(bool write_to_eeprom) {
    }
    rgblight_mode_eeprom_helper(mode, write_to_eeprom);
}
void rgblight_step_noeeprom(void) { rgblight_step_helper(false); }
void rgblight_step(void) { rgblight_step_helper(true); }
void rgblight_step_noeeprom(void) {
    rgblight_step_helper(false);
}
void rgblight_step(void) {
    rgblight_step_helper(true);
}
void rgblight_step_reverse_helper(bool write_to_eeprom) {
    uint8_t mode = 0;
    mode         = rgblight_config.mode - 1;


@@ 306,8 320,12 @@ void rgblight_step_reverse_helper(bool write_to_eeprom) {
    }
    rgblight_mode_eeprom_helper(mode, write_to_eeprom);
}
void rgblight_step_reverse_noeeprom(void) { rgblight_step_reverse_helper(false); }
void rgblight_step_reverse(void) { rgblight_step_reverse_helper(true); }
void rgblight_step_reverse_noeeprom(void) {
    rgblight_step_reverse_helper(false);
}
void rgblight_step_reverse(void) {
    rgblight_step_reverse_helper(true);
}

uint8_t rgblight_get_mode(void) {
    if (!rgblight_config.enable) {


@@ 346,9 364,13 @@ void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
    rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
}

void rgblight_mode(uint8_t mode) { rgblight_mode_eeprom_helper(mode, true); }
void rgblight_mode(uint8_t mode) {
    rgblight_mode_eeprom_helper(mode, true);
}

void rgblight_mode_noeeprom(uint8_t mode) { rgblight_mode_eeprom_helper(mode, false); }
void rgblight_mode_noeeprom(uint8_t mode) {
    rgblight_mode_eeprom_helper(mode, false);
}

void rgblight_toggle(void) {
    dprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);


@@ 401,64 423,98 @@ void rgblight_disable_noeeprom(void) {
    rgblight_set();
}

bool rgblight_is_enabled(void) { return rgblight_config.enable; }
bool rgblight_is_enabled(void) {
    return rgblight_config.enable;
}

void rgblight_increase_hue_helper(bool write_to_eeprom) {
    uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP;
    rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
}
void rgblight_increase_hue_noeeprom(void) { rgblight_increase_hue_helper(false); }
void rgblight_increase_hue(void) { rgblight_increase_hue_helper(true); }
void rgblight_increase_hue_noeeprom(void) {
    rgblight_increase_hue_helper(false);
}
void rgblight_increase_hue(void) {
    rgblight_increase_hue_helper(true);
}
void rgblight_decrease_hue_helper(bool write_to_eeprom) {
    uint8_t hue = rgblight_config.hue - RGBLIGHT_HUE_STEP;
    rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
}
void rgblight_decrease_hue_noeeprom(void) { rgblight_decrease_hue_helper(false); }
void rgblight_decrease_hue(void) { rgblight_decrease_hue_helper(true); }
void rgblight_decrease_hue_noeeprom(void) {
    rgblight_decrease_hue_helper(false);
}
void rgblight_decrease_hue(void) {
    rgblight_decrease_hue_helper(true);
}
void rgblight_increase_sat_helper(bool write_to_eeprom) {
    uint8_t sat = qadd8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
    rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
}
void rgblight_increase_sat_noeeprom(void) { rgblight_increase_sat_helper(false); }
void rgblight_increase_sat(void) { rgblight_increase_sat_helper(true); }
void rgblight_increase_sat_noeeprom(void) {
    rgblight_increase_sat_helper(false);
}
void rgblight_increase_sat(void) {
    rgblight_increase_sat_helper(true);
}
void rgblight_decrease_sat_helper(bool write_to_eeprom) {
    uint8_t sat = qsub8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
    rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
}
void rgblight_decrease_sat_noeeprom(void) { rgblight_decrease_sat_helper(false); }
void rgblight_decrease_sat(void) { rgblight_decrease_sat_helper(true); }
void rgblight_decrease_sat_noeeprom(void) {
    rgblight_decrease_sat_helper(false);
}
void rgblight_decrease_sat(void) {
    rgblight_decrease_sat_helper(true);
}
void rgblight_increase_val_helper(bool write_to_eeprom) {
    uint8_t val = qadd8(rgblight_config.val, RGBLIGHT_VAL_STEP);
    rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
}
void rgblight_increase_val_noeeprom(void) { rgblight_increase_val_helper(false); }
void rgblight_increase_val(void) { rgblight_increase_val_helper(true); }
void rgblight_increase_val_noeeprom(void) {
    rgblight_increase_val_helper(false);
}
void rgblight_increase_val(void) {
    rgblight_increase_val_helper(true);
}
void rgblight_decrease_val_helper(bool write_to_eeprom) {
    uint8_t val = qsub8(rgblight_config.val, RGBLIGHT_VAL_STEP);
    rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
}
void rgblight_decrease_val_noeeprom(void) { rgblight_decrease_val_helper(false); }
void rgblight_decrease_val(void) { rgblight_decrease_val_helper(true); }
void rgblight_decrease_val_noeeprom(void) {
    rgblight_decrease_val_helper(false);
}
void rgblight_decrease_val(void) {
    rgblight_decrease_val_helper(true);
}

void rgblight_increase_speed_helper(bool write_to_eeprom) {
    if (rgblight_config.speed < 3) rgblight_config.speed++;
    // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?
    if (write_to_eeprom) {
        eeconfig_update_rgblight(rgblight_config.raw);  // EECONFIG needs to be increased to support this
        eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this
    }
}
void rgblight_increase_speed(void) { rgblight_increase_speed_helper(true); }
void rgblight_increase_speed_noeeprom(void) { rgblight_increase_speed_helper(false); }
void rgblight_increase_speed(void) {
    rgblight_increase_speed_helper(true);
}
void rgblight_increase_speed_noeeprom(void) {
    rgblight_increase_speed_helper(false);
}

void rgblight_decrease_speed_helper(bool write_to_eeprom) {
    if (rgblight_config.speed > 0) rgblight_config.speed--;
    // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED??
    if (write_to_eeprom) {
        eeconfig_update_rgblight(rgblight_config.raw);  // EECONFIG needs to be increased to support this
        eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this
    }
}
void rgblight_decrease_speed(void) { rgblight_decrease_speed_helper(true); }
void rgblight_decrease_speed_noeeprom(void) { rgblight_decrease_speed_helper(false); }
void rgblight_decrease_speed(void) {
    rgblight_decrease_speed_helper(true);
}
void rgblight_decrease_speed_noeeprom(void) {
    rgblight_decrease_speed_helper(false);
}

void rgblight_sethsv_noeeprom_old(uint8_t hue, uint8_t sat, uint8_t val) {
    if (rgblight_config.enable) {


@@ 478,7 534,7 @@ void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool w
            rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
        } else {
            // all LEDs in same color
            if (1 == 0) {  // dummy
            if (1 == 0) { // dummy
            }
#ifdef RGBLIGHT_EFFECT_BREATHING
            else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) {


@@ 540,33 596,51 @@ void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool w
    }
}

void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, true); }
void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val) {
    rgblight_sethsv_eeprom_helper(hue, sat, val, true);
}

void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, false); }
void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val) {
    rgblight_sethsv_eeprom_helper(hue, sat, val, false);
}

uint8_t rgblight_get_speed(void) { return rgblight_config.speed; }
uint8_t rgblight_get_speed(void) {
    return rgblight_config.speed;
}

void rgblight_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
    rgblight_config.speed = speed;
    if (write_to_eeprom) {
        eeconfig_update_rgblight(rgblight_config.raw);  // EECONFIG needs to be increased to support this
        eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this
        dprintf("rgblight set speed [EEPROM]: %u\n", rgblight_config.speed);
    } else {
        dprintf("rgblight set speed [NOEEPROM]: %u\n", rgblight_config.speed);
    }
}

void rgblight_set_speed(uint8_t speed) { rgblight_set_speed_eeprom_helper(speed, true); }
void rgblight_set_speed(uint8_t speed) {
    rgblight_set_speed_eeprom_helper(speed, true);
}

void rgblight_set_speed_noeeprom(uint8_t speed) { rgblight_set_speed_eeprom_helper(speed, false); }
void rgblight_set_speed_noeeprom(uint8_t speed) {
    rgblight_set_speed_eeprom_helper(speed, false);
}

uint8_t rgblight_get_hue(void) { return rgblight_config.hue; }
uint8_t rgblight_get_hue(void) {
    return rgblight_config.hue;
}

uint8_t rgblight_get_sat(void) { return rgblight_config.sat; }
uint8_t rgblight_get_sat(void) {
    return rgblight_config.sat;
}

uint8_t rgblight_get_val(void) { return rgblight_config.val; }
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) {


@@ 648,14 722,22 @@ void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start,
}

#ifndef RGBLIGHT_SPLIT
void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLED_NUM / 2); }
void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) {
    rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLED_NUM / 2);
}

void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); }
void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) {
    rgblight_setrgb_range(r, g, b, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM);
}

void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLED_NUM / 2); }
void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) {
    rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLED_NUM / 2);
}

void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); }
#endif  // ifndef RGBLIGHT_SPLIT
void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) {
    rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM);
}
#endif // ifndef RGBLIGHT_SPLIT

#ifdef RGBLIGHT_LAYERS
void rgblight_set_layer_state(uint8_t layer, bool enabled) {


@@ 693,18 775,18 @@ static void rgblight_layers_write(void) {
    // For each layer
    for (const rgblight_segment_t *const *layer_ptr = rgblight_layers; i < RGBLIGHT_MAX_LAYERS; layer_ptr++, i++) {
        if (!rgblight_get_layer_state(i)) {
            continue;  // Layer is disabled
            continue; // Layer is disabled
        }
        const rgblight_segment_t *segment_ptr = pgm_read_ptr(layer_ptr);
        if (segment_ptr == NULL) {
            break;  // No more layers
            break; // No more layers
        }
        // For each segment
        while (1) {
            rgblight_segment_t segment;
            memcpy_P(&segment, segment_ptr, sizeof(rgblight_segment_t));
            if (segment.index == RGBLIGHT_END_SEGMENT_INDEX) {
                break;  // No more segments
                break; // No more segments
            }
            // Write segment.count LEDs
            LED_TYPE *const limit = &led[MIN(segment.index + segment.count, RGBLED_NUM)];


@@ 726,7 808,9 @@ static uint16_t       _repeat_timer;
static uint8_t        _times_remaining;
static uint16_t       _dur;

void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { rgblight_blink_layer_repeat(layer, duration_ms, 1); }
void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
    rgblight_blink_layer_repeat(layer, duration_ms, 1);
}

void rgblight_blink_layer_repeat(uint8_t layer, uint16_t duration_ms, uint8_t times) {
    _times_remaining = times * 2;


@@ 796,7 880,9 @@ void rgblight_wakeup(void) {

#endif

__attribute__((weak)) void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { ws2812_setleds(start_led, num_leds); }
__attribute__((weak)) void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) {
    ws2812_setleds(start_led, num_leds);
}

#ifndef RGBLIGHT_CUSTOM_DRIVER



@@ 848,9 934,13 @@ void rgblight_set(void) {

#ifdef RGBLIGHT_SPLIT
/* for split keyboard master side */
uint8_t rgblight_get_change_flags(void) { return rgblight_status.change_flags; }
uint8_t rgblight_get_change_flags(void) {
    return rgblight_status.change_flags;
}

void rgblight_clear_change_flags(void) { rgblight_status.change_flags = 0; }
void rgblight_clear_change_flags(void) {
    rgblight_status.change_flags = 0;
}

void rgblight_get_syncinfo(rgblight_syncinfo_t *syncinfo) {
    syncinfo->config = rgblight_config;


@@ 866,7 956,7 @@ void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
#    endif
    if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) {
        if (syncinfo->config.enable) {
            rgblight_config.enable = 1;  // == rgblight_enable_noeeprom();
            rgblight_config.enable = 1; // == rgblight_enable_noeeprom();
            rgblight_mode_eeprom_helper(syncinfo->config.mode, write_to_eeprom);
        } else {
            rgblight_disable_noeeprom();


@@ 945,12 1035,12 @@ static void rgblight_effect_dummy(animation_status_t *anim) {
void rgblight_task(void) {
    if (rgblight_status.timer_enabled) {
        effect_func_t effect_func   = rgblight_effect_dummy;
        uint16_t      interval_time = 2000;  // dummy interval
        uint16_t      interval_time = 2000; // dummy interval
        uint8_t       delta         = rgblight_config.mode - rgblight_status.base_mode;
        animation_status.delta      = delta;

        // static light mode, do nothing here
        if (1 == 0) {  // dummy
        if (1 == 0) { // dummy
        }
#    ifdef RGBLIGHT_EFFECT_BREATHING
        else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) {


@@ 1016,7 1106,7 @@ void rgblight_task(void) {
        if (animation_status.restart) {
            animation_status.restart    = false;
            animation_status.last_timer = sync_timer_read();
            animation_status.pos16      = 0;  // restart signal to local each effect
            animation_status.pos16      = 0; // restart signal to local each effect
        }
        uint16_t now = sync_timer_read();
        if (timer_expired(now, animation_status.last_timer)) {


@@ 1055,7 1145,7 @@ void rgblight_task(void) {

#    ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
#        ifndef RGBLIGHT_BREATHE_TABLE_SIZE
#            define RGBLIGHT_BREATHE_TABLE_SIZE 256  // 256 or 128 or 64
#            define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256 or 128 or 64
#        endif
#        include <rgblight_breathe_table.h>
#    endif


@@ 1131,7 1221,7 @@ void rgblight_effect_snake(animation_status_t *anim) {
    }

#    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    if (anim->pos == 0) {  // restart signal
    if (anim->pos == 0) { // restart signal
        if (increment == 1) {
            pos = rgblight_ranges.effect_num_leds - 1;
        } else {


@@ 1194,7 1284,7 @@ void rgblight_effect_knight(animation_status_t *anim) {
    uint8_t       i, cur;

#    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    if (anim->pos == 0) {  // restart signal
    if (anim->pos == 0) { // restart signal
        anim->pos  = 1;
        low_bound  = 0;
        high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;


@@ 1347,8 1437,12 @@ void rgblight_effect_twinkle(animation_status_t *anim) {
    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; }
    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]);

M quantum/rgblight/rgblight.h => quantum/rgblight/rgblight.h +5 -5
@@ 119,7 119,7 @@ enum RGBLIGHT_EFFECT_MODE {
// sample: #define RGBLIGHT_EFFECT_BREATHE_CENTER   1.85

#ifndef RGBLIGHT_EFFECT_BREATHE_MAX
#    define RGBLIGHT_EFFECT_BREATHE_MAX 255  // 0-255
#    define RGBLIGHT_EFFECT_BREATHE_MAX 255 // 0-255
#endif

#ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH


@@ 177,8 177,8 @@ enum RGBLIGHT_EFFECT_MODE {

#ifdef RGBLIGHT_LAYERS
typedef struct {
    uint8_t index;  // The first LED to light
    uint8_t count;  // The number of LEDs to light
    uint8_t index; // The first LED to light
    uint8_t count; // The number of LEDs to light
    uint8_t hue;
    uint8_t sat;
    uint8_t val;


@@ 241,7 241,7 @@ typedef union {
        uint8_t hue : 8;
        uint8_t sat : 8;
        uint8_t val : 8;
        uint8_t speed : 8;  // EECONFIG needs to be increased to support this
        uint8_t speed : 8; // EECONFIG needs to be increased to support this
    };
} rgblight_config_t;



@@ 271,7 271,7 @@ extern rgblight_ranges_t rgblight_ranges;

/* === Utility Functions ===*/
void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1);
void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1);  // without RGBLIGHT_LIMIT_VAL check
void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1); // without RGBLIGHT_LIMIT_VAL check
void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1);

/* === Low level Functions === */

M quantum/ring_buffer.h => quantum/ring_buffer.h +6 -2
@@ 36,9 36,13 @@ static inline uint8_t rbuf_dequeue(void) {
}
static inline bool rbuf_has_data(void) {
    bool has_data;
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { has_data = (rbuf_head != rbuf_tail); }
    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; }
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        rbuf_head = rbuf_tail = 0;
    }
}

M quantum/send_string.c => quantum/send_string.c +15 -7
@@ 142,9 142,13 @@ __attribute__((weak)) const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
// 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(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_P(const char *str) {
    send_string_with_delay_P(str, 0);
}

void send_string_with_delay(const char *str, uint8_t interval) {
    while (1) {


@@ 173,7 177,8 @@ void send_string_with_delay(const char *str, uint8_t interval) {
                    ms += keycode - '0';
                    keycode = *(++str);
                }
                while (ms--) wait_ms(1);
                while (ms--)
                    wait_ms(1);
            }
        } else {
            send_char(ascii_code);


@@ 182,7 187,8 @@ void send_string_with_delay(const char *str, uint8_t interval) {
        // interval
        {
            uint8_t ms = interval;
            while (ms--) wait_ms(1);
            while (ms--)
                wait_ms(1);
        }
    }
}


@@ 214,7 220,8 @@ void send_string_with_delay_P(const char *str, uint8_t interval) {
                    ms += keycode - '0';
                    keycode = pgm_read_byte(++str);
                }
                while (ms--) wait_ms(1);
                while (ms--)
                    wait_ms(1);
            }
        } else {
            send_char(ascii_code);


@@ 223,14 230,15 @@ void send_string_with_delay_P(const char *str, uint8_t interval) {
        // interval
        {
            uint8_t ms = interval;
            while (ms--) wait_ms(1);
            while (ms--)
                wait_ms(1);
        }
    }
}

void send_char(char ascii_code) {
#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL)
    if (ascii_code == '\a') {  // BEL
    if (ascii_code == '\a') { // BEL
        PLAY_SONG(bell_song);
        return;
    }

M quantum/sequencer/sequencer.c => quantum/sequencer/sequencer.c +44 -18
@@ 25,16 25,18 @@
#endif

sequencer_config_t sequencer_config = {
    false,     // enabled
    {false},   // steps
    {0},       // track notes
    60,        // tempo
    SQ_RES_4,  // resolution
    false,    // enabled
    {false},  // steps
    {0},      // track notes
    60,       // tempo
    SQ_RES_4, // resolution
};

sequencer_state_t sequencer_internal_state = {0, 0, 0, 0, SEQUENCER_PHASE_ATTACK};

bool is_sequencer_on(void) { return sequencer_config.enabled; }
bool is_sequencer_on(void) {
    return sequencer_config.enabled;
}

void sequencer_on(void) {
    dprintln("sequencer on");


@@ 65,7 67,9 @@ void sequencer_set_track_notes(const uint16_t track_notes[SEQUENCER_TRACKS]) {
    }
}

bool is_sequencer_track_active(uint8_t track) { return (sequencer_internal_state.active_tracks >> track) & true; }
bool is_sequencer_track_active(uint8_t track) {
    return (sequencer_internal_state.active_tracks >> track) & true;
}

void sequencer_set_track_activation(uint8_t track, bool value) {
    if (value) {


@@ 76,7 80,9 @@ void sequencer_set_track_activation(uint8_t track, bool value) {
    dprintf("sequencer: track %d is %s\n", track, value ? "active" : "inactive");
}

void sequencer_toggle_track_activation(uint8_t track) { sequencer_set_track_activation(track, !is_sequencer_track_active(track)); }
void sequencer_toggle_track_activation(uint8_t track) {
    sequencer_set_track_activation(track, !is_sequencer_track_active(track));
}

void sequencer_toggle_single_active_track(uint8_t track) {
    if (is_sequencer_track_active(track)) {


@@ 86,9 92,13 @@ void sequencer_toggle_single_active_track(uint8_t track) {
    }
}

bool is_sequencer_step_on(uint8_t step) { return step < SEQUENCER_STEPS && (sequencer_config.steps[step] & sequencer_internal_state.active_tracks) > 0; }
bool is_sequencer_step_on(uint8_t step) {
    return step < SEQUENCER_STEPS && (sequencer_config.steps[step] & sequencer_internal_state.active_tracks) > 0;
}

bool is_sequencer_step_on_for_track(uint8_t step, uint8_t track) { return step < SEQUENCER_STEPS && (sequencer_config.steps[step] >> track) & true; }
bool is_sequencer_step_on_for_track(uint8_t step, uint8_t track) {
    return step < SEQUENCER_STEPS && (sequencer_config.steps[step] >> track) & true;
}

void sequencer_set_step(uint8_t step, bool value) {
    if (step < SEQUENCER_STEPS) {


@@ 122,7 132,9 @@ void sequencer_set_all_steps(bool value) {
    dprintf("sequencer: all steps are %s\n", value ? "on" : "off");
}

uint8_t sequencer_get_tempo(void) { return sequencer_config.tempo; }
uint8_t sequencer_get_tempo(void) {
    return sequencer_config.tempo;
}

void sequencer_set_tempo(uint8_t tempo) {
    if (tempo > 0) {


@@ 142,9 154,13 @@ void sequencer_increase_tempo(void) {
    }
}

void sequencer_decrease_tempo(void) { sequencer_set_tempo(sequencer_config.tempo - 1); }
void sequencer_decrease_tempo(void) {
    sequencer_set_tempo(sequencer_config.tempo - 1);
}

sequencer_resolution_t sequencer_get_resolution(void) { return sequencer_config.resolution; }
sequencer_resolution_t sequencer_get_resolution(void) {
    return sequencer_config.resolution;
}

void sequencer_set_resolution(sequencer_resolution_t resolution) {
    if (resolution >= 0 && resolution < SEQUENCER_RESOLUTIONS) {


@@ 155,11 171,17 @@ void sequencer_set_resolution(sequencer_resolution_t resolution) {
    }
}

void sequencer_increase_resolution(void) { sequencer_set_resolution(sequencer_config.resolution + 1); }
void sequencer_increase_resolution(void) {
    sequencer_set_resolution(sequencer_config.resolution + 1);
}

void sequencer_decrease_resolution(void) { sequencer_set_resolution(sequencer_config.resolution - 1); }
void sequencer_decrease_resolution(void) {
    sequencer_set_resolution(sequencer_config.resolution - 1);
}

uint8_t sequencer_get_current_step(void) { return sequencer_internal_state.current_step; }
uint8_t sequencer_get_current_step(void) {
    return sequencer_internal_state.current_step;
}

void sequencer_phase_attack(void) {
    dprintf("sequencer: step %d\n", sequencer_internal_state.current_step);


@@ 229,9 251,13 @@ void sequencer_task(void) {
    }
}

uint16_t sequencer_get_beat_duration(void) { return get_beat_duration(sequencer_config.tempo); }
uint16_t sequencer_get_beat_duration(void) {
    return get_beat_duration(sequencer_config.tempo);
}

uint16_t sequencer_get_step_duration(void) { return get_step_duration(sequencer_config.tempo, sequencer_config.resolution); }
uint16_t sequencer_get_step_duration(void) {
    return get_step_duration(sequencer_config.tempo, sequencer_config.resolution);
}

uint16_t get_beat_duration(uint8_t tempo) {
    // Don’t crash in the unlikely case where the given tempo is 0

M quantum/sequencer/sequencer.h => quantum/sequencer/sequencer.h +4 -4
@@ 48,7 48,7 @@ typedef struct {
    bool                   enabled;
    uint8_t                steps[SEQUENCER_STEPS];
    uint16_t               track_notes[SEQUENCER_TRACKS];
    uint8_t                tempo;  // Is a maximum tempo of 255 reasonable?
    uint8_t                tempo; // Is a maximum tempo of 255 reasonable?
    sequencer_resolution_t resolution;
} sequencer_config_t;



@@ 57,9 57,9 @@ typedef struct {
 * We use a "phase" state machine to delay some of the events.
 */
typedef enum sequencer_phase_t {
    SEQUENCER_PHASE_ATTACK,   // t=0ms, send the MIDI note on signal
    SEQUENCER_PHASE_RELEASE,  // t=SEQUENCER_PHASE_RELEASE_TIMEOUT ms, send the MIDI note off signal
    SEQUENCER_PHASE_PAUSE     // t=step duration ms, loop
    SEQUENCER_PHASE_ATTACK,  // t=0ms, send the MIDI note on signal
    SEQUENCER_PHASE_RELEASE, // t=SEQUENCER_PHASE_RELEASE_TIMEOUT ms, send the MIDI note off signal
    SEQUENCER_PHASE_PAUSE    // t=step duration ms, loop
} sequencer_phase_t;

typedef struct {

M quantum/sequencer/tests/midi_mock.c => quantum/sequencer/tests/midi_mock.c +9 -3
@@ 19,8 19,14 @@
uint16_t last_noteon  = 0;
uint16_t last_noteoff = 0;

uint16_t midi_compute_note(uint16_t keycode) { return keycode; }
uint16_t midi_compute_note(uint16_t keycode) {
    return keycode;
}

void process_midi_basic_noteon(uint16_t note) { last_noteon = note; }
void process_midi_basic_noteon(uint16_t note) {
    last_noteon = note;
}

void process_midi_basic_noteoff(uint16_t note) { last_noteoff = note; }
void process_midi_basic_noteoff(uint16_t note) {
    last_noteoff = note;
}

M quantum/sequencer/tests/sequencer_tests.cpp => quantum/sequencer/tests/sequencer_tests.cpp +3 -1
@@ 78,7 78,9 @@ class SequencerTest : public ::testing::Test {
    sequencer_state_t  state_copy;
};

TEST_F(SequencerTest, TestOffByDefault) { EXPECT_EQ(is_sequencer_on(), false); }
TEST_F(SequencerTest, TestOffByDefault) {
    EXPECT_EQ(is_sequencer_on(), false);
}

TEST_F(SequencerTest, TestOn) {
    sequencer_config.enabled = false;

M quantum/split_common/post_config.h => quantum/split_common/post_config.h +1 -1
@@ 5,6 5,6 @@
#    endif

#    ifndef F_SCL
#        define F_SCL 100000UL  // SCL frequency
#        define F_SCL 100000UL // SCL frequency
#    endif
#endif

M quantum/split_common/split_util.c => quantum/split_common/split_util.c +12 -8
@@ 43,14 43,14 @@
// Set to 0 to disable the disconnection check altogether.
#ifndef SPLIT_MAX_CONNECTION_ERRORS
#    define SPLIT_MAX_CONNECTION_ERRORS 10
#endif  // SPLIT_MAX_CONNECTION_ERRORS
#endif // SPLIT_MAX_CONNECTION_ERRORS

// How long (in milliseconds) to block all connection attempts after the communication has been flagged as disconnected.
// One communication attempt will be allowed everytime this amount of time has passed since the last attempt. If that attempt succeeds, the communication is seen as working again.
// Set to 0 to disable communication throttling while disconnected
#ifndef SPLIT_CONNECTION_CHECK_TIMEOUT
#    define SPLIT_CONNECTION_CHECK_TIMEOUT 500
#endif  // SPLIT_CONNECTION_CHECK_TIMEOUT
#endif // SPLIT_CONNECTION_CHECK_TIMEOUT

static uint8_t connection_errors = 0;



@@ 68,7 68,9 @@ static bool usbIsActive(void) {
    return false;
}
#else
static inline bool usbIsActive(void) { return usb_vbus_state(); }
static inline bool usbIsActive(void) {
    return usb_vbus_state();
}
#endif

#ifdef SPLIT_HAND_MATRIX_GRID


@@ 83,7 85,7 @@ static uint8_t peek_matrix_intersection(pin_t out_pin, pin_t in_pin) {
    uint8_t pin_state = readPin(in_pin);
    // Set out_pin to a setting that is less susceptible to noise.
    setPinInputHigh(out_pin);
    matrix_io_delay();  // Wait for the pull-up to go HIGH.
    matrix_io_delay(); // Wait for the pull-up to go HIGH.
    return pin_state;
}
#endif


@@ 158,7 160,9 @@ void split_post_init(void) {
    }
}

bool is_transport_connected(void) { return connection_errors < SPLIT_MAX_CONNECTION_ERRORS; }
bool is_transport_connected(void) {
    return connection_errors < SPLIT_MAX_CONNECTION_ERRORS;
}

bool transport_master_if_connected(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
#if SPLIT_MAX_CONNECTION_ERRORS > 0 && SPLIT_CONNECTION_CHECK_TIMEOUT > 0


@@ 169,7 173,7 @@ bool transport_master_if_connected(matrix_row_t master_matrix[], matrix_row_t sl
    if (is_disconnected && timer_elapsed(connection_check_timer) < SPLIT_CONNECTION_CHECK_TIMEOUT) {
        return false;
    }
#endif  // SPLIT_MAX_CONNECTION_ERRORS > 0 && SPLIT_CONNECTION_CHECK_TIMEOUT > 0
#endif // SPLIT_MAX_CONNECTION_ERRORS > 0 && SPLIT_CONNECTION_CHECK_TIMEOUT > 0

    __attribute__((unused)) bool okay = transport_master(master_matrix, slave_matrix);
#if SPLIT_MAX_CONNECTION_ERRORS > 0


@@ 186,10 190,10 @@ bool transport_master_if_connected(matrix_row_t master_matrix[], matrix_row_t sl
        return connected;
    } else if (is_disconnected) {
        dprintln("Target connected");
#    endif  // SPLIT_CONNECTION_CHECK_TIMEOUT > 0
#    endif // SPLIT_CONNECTION_CHECK_TIMEOUT > 0
    }

    connection_errors = 0;
#endif  // SPLIT_MAX_CONNECTION_ERRORS > 0
#endif // SPLIT_MAX_CONNECTION_ERRORS > 0
    return true;
}

M quantum/split_common/transaction_id_define.h => quantum/split_common/transaction_id_define.h +18 -18
@@ 19,87 19,87 @@
enum serial_transaction_id {
#ifdef USE_I2C
    I2C_EXECUTE_CALLBACK,
#endif  // USE_I2C
#endif // USE_I2C

    GET_SLAVE_MATRIX_CHECKSUM,
    GET_SLAVE_MATRIX_DATA,

#ifdef SPLIT_TRANSPORT_MIRROR
    PUT_MASTER_MATRIX,
#endif  // SPLIT_TRANSPORT_MIRROR
#endif // SPLIT_TRANSPORT_MIRROR

#ifdef ENCODER_ENABLE
    GET_ENCODERS_CHECKSUM,
    GET_ENCODERS_DATA,
#endif  // ENCODER_ENABLE
#endif // ENCODER_ENABLE

#ifndef DISABLE_SYNC_TIMER
    PUT_SYNC_TIMER,
#endif  // DISABLE_SYNC_TIMER
#endif // DISABLE_SYNC_TIMER

#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
    PUT_LAYER_STATE,
    PUT_DEFAULT_LAYER_STATE,
#endif  // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)

#ifdef SPLIT_LED_STATE_ENABLE
    PUT_LED_STATE,
#endif  // SPLIT_LED_STATE_ENABLE
#endif // SPLIT_LED_STATE_ENABLE

#ifdef SPLIT_MODS_ENABLE
    PUT_MODS,
#endif  // SPLIT_MODS_ENABLE
#endif // SPLIT_MODS_ENABLE

#ifdef BACKLIGHT_ENABLE
    PUT_BACKLIGHT,
#endif  // BACKLIGHT_ENABLE
#endif // BACKLIGHT_ENABLE

#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
    PUT_RGBLIGHT,
#endif  // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)

#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
    PUT_LED_MATRIX,
#endif  // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)

#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
    PUT_RGB_MATRIX,
#endif  // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)

#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
    PUT_WPM,
#endif  // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)

#if defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
    PUT_OLED,
#endif  // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
#endif // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)

#if defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
    PUT_ST7565,
#endif  // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
#endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)

#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
    GET_POINTING_CHECKSUM,
    GET_POINTING_DATA,
    PUT_POINTING_CPI,
#endif  // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)

#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
    PUT_RPC_INFO,
    PUT_RPC_REQ_DATA,
    EXECUTE_RPC,
    GET_RPC_RESP_DATA,
#endif  // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)

// keyboard-specific
#ifdef SPLIT_TRANSACTION_IDS_KB
    SPLIT_TRANSACTION_IDS_KB,
#endif  // SPLIT_TRANSACTION_IDS_KB
#endif // SPLIT_TRANSACTION_IDS_KB

// user/keymap-specific
#ifdef SPLIT_TRANSACTION_IDS_USER
    SPLIT_TRANSACTION_IDS_USER,
#endif  // SPLIT_TRANSACTION_IDS_USER
#endif // SPLIT_TRANSACTION_IDS_USER

    NUM_TOTAL_TRANSACTIONS
};

M quantum/split_common/transactions.c => quantum/split_common/transactions.c +51 -43
@@ 30,7 30,7 @@

#ifndef FORCED_SYNC_THROTTLE_MS
#    define FORCED_SYNC_THROTTLE_MS 100
#endif  // FORCED_SYNC_THROTTLE_MS
#endif // FORCED_SYNC_THROTTLE_MS

#define sizeof_member(type, member) sizeof(((type *)NULL)->member)



@@ 49,7 49,7 @@
// Forward-declare the RPC callback handlers
void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
#endif  // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)

////////////////////////////////////////////////////
// Helpers


@@ 63,7 63,9 @@ static bool transaction_handler_master(matrix_row_t master_matrix[], matrix_row_
            }
        }
        bool this_okay = true;
        ATOMIC_BLOCK_FORCEON { this_okay = handler(master_matrix, slave_matrix); };
        ATOMIC_BLOCK_FORCEON {
            this_okay = handler(master_matrix, slave_matrix);
        };
        if (this_okay) return true;
    }
    dprintf("Failed to execute %s\n", prefix);


@@ 75,9 77,11 @@ static bool transaction_handler_master(matrix_row_t master_matrix[], matrix_row_
        if (!transaction_handler_master(master_matrix, slave_matrix, #prefix, &prefix##_handlers_master)) return false; \
    } while (0)

#define TRANSACTION_HANDLER_SLAVE(prefix)                                               \
    do {                                                                                \
        ATOMIC_BLOCK_FORCEON { prefix##_handlers_slave(master_matrix, slave_matrix); }; \
#define TRANSACTION_HANDLER_SLAVE(prefix)                         \
    do {                                                          \
        ATOMIC_BLOCK_FORCEON {                                    \
            prefix##_handlers_slave(master_matrix, slave_matrix); \
        };                                                        \
    } while (0)

inline static bool read_if_checksum_mismatch(int8_t trans_id_checksum, int8_t trans_id_retrieve, uint32_t *last_update, void *destination, const void *equiv_shmem, size_t length) {


@@ 116,8 120,8 @@ inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update,

static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
    static uint32_t     last_update                    = 0;
    static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0};  // last successfully-read matrix, so we can replicate if there are checksum errors
    matrix_row_t        temp_matrix[(MATRIX_ROWS) / 2];        // holding area while we test whether or not checksum is correct
    static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors
    matrix_row_t        temp_matrix[(MATRIX_ROWS) / 2];       // holding area while we test whether or not checksum is correct

    bool okay = read_if_checksum_mismatch(GET_SLAVE_MATRIX_CHECKSUM, GET_SLAVE_MATRIX_DATA, &last_update, temp_matrix, split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
    if (okay) {


@@ 161,13 165,13 @@ static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_ro
#    define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix)
#    define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),

#else  // SPLIT_TRANSPORT_MIRROR
#else // SPLIT_TRANSPORT_MIRROR

#    define TRANSACTIONS_MASTER_MATRIX_MASTER()
#    define TRANSACTIONS_MASTER_MATRIX_SLAVE()
#    define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS

#endif  // SPLIT_TRANSPORT_MIRROR
#endif // SPLIT_TRANSPORT_MIRROR

////////////////////////////////////////////////////
// Encoders


@@ 200,13 204,13 @@ static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sl
    [GET_ENCODERS_DATA]     = trans_target2initiator_initializer(encoders.state),
// clang-format on

#else  // ENCODER_ENABLE
#else // ENCODER_ENABLE

#    define TRANSACTIONS_ENCODERS_MASTER()
#    define TRANSACTIONS_ENCODERS_SLAVE()
#    define TRANSACTIONS_ENCODERS_REGISTRATIONS

#endif  // ENCODER_ENABLE
#endif // ENCODER_ENABLE

////////////////////////////////////////////////////
// Sync timer


@@ 239,13 243,13 @@ static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
#    define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer)
#    define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),

#else  // DISABLE_SYNC_TIMER
#else // DISABLE_SYNC_TIMER

#    define TRANSACTIONS_SYNC_TIMER_MASTER()
#    define TRANSACTIONS_SYNC_TIMER_SLAVE()
#    define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS

#endif  // DISABLE_SYNC_TIMER
#endif // DISABLE_SYNC_TIMER

////////////////////////////////////////////////////
// Layer state


@@ 276,13 280,13 @@ static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_
    [PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state),
// clang-format on

#else  // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
#else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)

#    define TRANSACTIONS_LAYER_STATE_MASTER()
#    define TRANSACTIONS_LAYER_STATE_SLAVE()
#    define TRANSACTIONS_LAYER_STATE_REGISTRATIONS

#endif  // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)

////////////////////////////////////////////////////
// LED state


@@ 304,13 308,13 @@ static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t 
#    define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state)
#    define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),

#else  // SPLIT_LED_STATE_ENABLE
#else // SPLIT_LED_STATE_ENABLE

#    define TRANSACTIONS_LED_STATE_MASTER()
#    define TRANSACTIONS_LED_STATE_SLAVE()
#    define TRANSACTIONS_LED_STATE_REGISTRATIONS

#endif  // SPLIT_LED_STATE_ENABLE
#endif // SPLIT_LED_STATE_ENABLE

////////////////////////////////////////////////////
// Mods


@@ 336,7 340,7 @@ static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slav
    if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) {
        mods_need_sync = true;
    }
#    endif  // NO_ACTION_ONESHOT
#    endif // NO_ACTION_ONESHOT

    bool okay = true;
    if (mods_need_sync) {


@@ 361,13 365,13 @@ static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave
#    define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods)
#    define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),

#else  // SPLIT_MODS_ENABLE
#else // SPLIT_MODS_ENABLE

#    define TRANSACTIONS_MODS_MASTER()
#    define TRANSACTIONS_MODS_SLAVE()
#    define TRANSACTIONS_MODS_REGISTRATIONS

#endif  // SPLIT_MODS_ENABLE
#endif // SPLIT_MODS_ENABLE

////////////////////////////////////////////////////
// Backlight


@@ 380,19 384,21 @@ static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t
    return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level));
}

static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); }
static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
    backlight_set(split_shmem->backlight_level);
}

#    define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight)
#    define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight)
#    define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),

#else  // BACKLIGHT_ENABLE
#else // BACKLIGHT_ENABLE

#    define TRANSACTIONS_BACKLIGHT_MASTER()
#    define TRANSACTIONS_BACKLIGHT_SLAVE()
#    define TRANSACTIONS_BACKLIGHT_REGISTRATIONS

#endif  // BACKLIGHT_ENABLE
#endif // BACKLIGHT_ENABLE

////////////////////////////////////////////////////
// RGBLIGHT


@@ 423,13 429,13 @@ static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t s
#    define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight)
#    define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),

#else  // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
#else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)

#    define TRANSACTIONS_RGBLIGHT_MASTER()
#    define TRANSACTIONS_RGBLIGHT_SLAVE()
#    define TRANSACTIONS_RGBLIGHT_REGISTRATIONS

#endif  // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)

////////////////////////////////////////////////////
// LED Matrix


@@ 453,13 459,13 @@ static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
#    define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix)
#    define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),

#else  // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
#else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)

#    define TRANSACTIONS_LED_MATRIX_MASTER()
#    define TRANSACTIONS_LED_MATRIX_SLAVE()
#    define TRANSACTIONS_LED_MATRIX_REGISTRATIONS

#endif  // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)

////////////////////////////////////////////////////
// RGB Matrix


@@ 483,13 489,13 @@ static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
#    define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix)
#    define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),

#else  // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
#else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)

#    define TRANSACTIONS_RGB_MATRIX_MASTER()
#    define TRANSACTIONS_RGB_MATRIX_SLAVE()
#    define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS

#endif  // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)

////////////////////////////////////////////////////
// WPM


@@ 502,19 508,21 @@ static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave
    return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), &current_wpm, sizeof(current_wpm));
}

static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); }
static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
    set_current_wpm(split_shmem->current_wpm);
}

#    define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm)
#    define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm)
#    define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),

#else  // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
#else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)

#    define TRANSACTIONS_WPM_MASTER()
#    define TRANSACTIONS_WPM_SLAVE()
#    define TRANSACTIONS_WPM_REGISTRATIONS

#endif  // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)

////////////////////////////////////////////////////
// OLED


@@ 539,13 547,13 @@ static void oled_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave
#    define TRANSACTIONS_OLED_SLAVE() TRANSACTION_HANDLER_SLAVE(oled)
#    define TRANSACTIONS_OLED_REGISTRATIONS [PUT_OLED] = trans_initiator2target_initializer(current_oled_state),

#else  // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
#else // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)

#    define TRANSACTIONS_OLED_MASTER()
#    define TRANSACTIONS_OLED_SLAVE()
#    define TRANSACTIONS_OLED_REGISTRATIONS

#endif  // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
#endif // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)

////////////////////////////////////////////////////
// ST7565


@@ 570,13 578,13 @@ static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sla
#    define TRANSACTIONS_ST7565_SLAVE() TRANSACTION_HANDLER_SLAVE(st7565)
#    define TRANSACTIONS_ST7565_REGISTRATIONS [PUT_ST7565] = trans_initiator2target_initializer(current_st7565_state),

#else  // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
#else // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)

#    define TRANSACTIONS_ST7565_MASTER()
#    define TRANSACTIONS_ST7565_SLAVE()
#    define TRANSACTIONS_ST7565_REGISTRATIONS

#endif  // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
#endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)

////////////////////////////////////////////////////
// POINTING


@@ 631,7 639,7 @@ static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t s
    }
    last_exec = timer_read32();
#    endif
    temp_cpi = !pointing_device_driver.get_cpi ? 0 : pointing_device_driver.get_cpi();  // check for NULL
    temp_cpi = !pointing_device_driver.get_cpi ? 0 : pointing_device_driver.get_cpi(); // check for NULL
    if (split_shmem->pointing.cpi && memcmp(&split_shmem->pointing.cpi, &temp_cpi, sizeof(temp_cpi)) != 0) {
        if (pointing_device_driver.set_cpi) {
            pointing_device_driver.set_cpi(split_shmem->pointing.cpi);


@@ 648,13 656,13 @@ static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t s
#    define TRANSACTIONS_POINTING_SLAVE() TRANSACTION_HANDLER_SLAVE(pointing)
#    define TRANSACTIONS_POINTING_REGISTRATIONS [GET_POINTING_CHECKSUM] = trans_target2initiator_initializer(pointing.checksum), [GET_POINTING_DATA] = trans_target2initiator_initializer(pointing.report), [PUT_POINTING_CPI] = trans_initiator2target_initializer(pointing.cpi),

#else  // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#else // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)

#    define TRANSACTIONS_POINTING_MASTER()
#    define TRANSACTIONS_POINTING_SLAVE()
#    define TRANSACTIONS_POINTING_REGISTRATIONS

#endif  // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)

////////////////////////////////////////////////////



@@ 664,7 672,7 @@ split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {

#ifdef USE_I2C
    [I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id),
#endif  // USE_I2C
#endif // USE_I2C

    // clang-format off
    TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS


@@ 689,7 697,7 @@ split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {
    [PUT_RPC_REQ_DATA]  = trans_initiator2target_initializer(rpc_m2s_buffer),
    [EXECUTE_RPC]       = trans_initiator2target_initializer_cb(rpc_info.transaction_id, slave_rpc_exec_callback),
    [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer),
#endif  // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
};

bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {


@@ 800,4 808,4 @@ void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *i
    }
}

#endif  // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)

M quantum/split_common/transport.c => quantum/split_common/transport.c +21 -9
@@ 26,7 26,7 @@

#    ifndef SLAVE_I2C_TIMEOUT
#        define SLAVE_I2C_TIMEOUT 100
#    endif  // SLAVE_I2C_TIMEOUT
#    endif // SLAVE_I2C_TIMEOUT

#    ifndef SLAVE_I2C_ADDRESS
#        define SLAVE_I2C_ADDRESS 0x32


@@ 40,8 40,12 @@ _Static_assert(sizeof(split_shared_memory_t) <= I2C_SLAVE_REG_COUNT, "split_shar

split_shared_memory_t *const split_shmem = (split_shared_memory_t *)i2c_slave_reg;

void transport_master_init(void) { i2c_init(); }
void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); }
void transport_master_init(void) {
    i2c_init();
}
void transport_slave_init(void) {
    i2c_slave_init(SLAVE_I2C_ADDRESS);
}

i2c_status_t transport_trigger_callback(int8_t id) {
    // If there's no callback, indicate that we were successful


@@ 82,15 86,19 @@ bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, 
    return true;
}

#else  // USE_I2C
#else // USE_I2C

#    include "serial.h"

static split_shared_memory_t shared_memory;
split_shared_memory_t *const split_shmem = &shared_memory;

void transport_master_init(void) { soft_serial_initiator_init(); }
void transport_slave_init(void) { soft_serial_target_init(); }
void transport_master_init(void) {
    soft_serial_initiator_init();
}
void transport_slave_init(void) {
    soft_serial_target_init();
}

bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
    split_transaction_desc_t *trans = &split_transaction_table[id];


@@ 111,8 119,12 @@ bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, 
    return true;
}

#endif  // USE_I2C
#endif // USE_I2C

bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { return transactions_master(master_matrix, slave_matrix); }
bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
    return transactions_master(master_matrix, slave_matrix);
}

void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { transactions_slave(master_matrix, slave_matrix); }
void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
    transactions_slave(master_matrix, slave_matrix);
}

M quantum/split_common/transport.h => quantum/split_common/transport.h +30 -30
@@ 25,11 25,11 @@

#ifndef RPC_M2S_BUFFER_SIZE
#    define RPC_M2S_BUFFER_SIZE 32
#endif  // RPC_M2S_BUFFER_SIZE
#endif // RPC_M2S_BUFFER_SIZE

#ifndef RPC_S2M_BUFFER_SIZE
#    define RPC_S2M_BUFFER_SIZE 32
#endif  // RPC_S2M_BUFFER_SIZE
#endif // RPC_S2M_BUFFER_SIZE

void transport_master_init(void);
void transport_slave_init(void);


@@ 43,15 43,15 @@ bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, 
#ifdef ENCODER_ENABLE
#    include "encoder.h"
#    define NUMBER_OF_ENCODERS (sizeof((pin_t[])ENCODERS_PAD_A) / sizeof(pin_t))
#endif  // ENCODER_ENABLE
#endif // ENCODER_ENABLE

#ifdef BACKLIGHT_ENABLE
#    include "backlight.h"
#endif  // BACKLIGHT_ENABLE
#endif // BACKLIGHT_ENABLE

#ifdef RGBLIGHT_ENABLE
#    include "rgblight.h"
#endif  // RGBLIGHT_ENABLE
#endif // RGBLIGHT_ENABLE

typedef struct _split_slave_matrix_sync_t {
    uint8_t      checksum;


@@ 62,21 62,21 @@ typedef struct _split_slave_matrix_sync_t {
typedef struct _split_master_matrix_sync_t {
    matrix_row_t matrix[(MATRIX_ROWS) / 2];
} split_master_matrix_sync_t;
#endif  // SPLIT_TRANSPORT_MIRROR
#endif // SPLIT_TRANSPORT_MIRROR

#ifdef ENCODER_ENABLE
typedef struct _split_slave_encoder_sync_t {
    uint8_t checksum;
    uint8_t state[NUMBER_OF_ENCODERS];
} split_slave_encoder_sync_t;
#endif  // ENCODER_ENABLE
#endif // ENCODER_ENABLE

#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
typedef struct _split_layers_sync_t {
    layer_state_t layer_state;
    layer_state_t default_layer_state;
} split_layers_sync_t;
#endif  // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)

#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
#    include "led_matrix.h"


@@ 85,7 85,7 @@ typedef struct _led_matrix_sync_t {
    led_eeconfig_t led_matrix;
    bool           led_suspend_state;
} led_matrix_sync_t;
#endif  // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)

#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
#    include "rgb_matrix.h"


@@ 94,7 94,7 @@ typedef struct _rgb_matrix_sync_t {
    rgb_config_t rgb_matrix;
    bool         rgb_suspend_state;
} rgb_matrix_sync_t;
#endif  // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)

#ifdef SPLIT_MODS_ENABLE
typedef struct _split_mods_sync_t {


@@ 102,9 102,9 @@ typedef struct _split_mods_sync_t {
    uint8_t weak_mods;
#    ifndef NO_ACTION_ONESHOT
    uint8_t oneshot_mods;
#    endif  // NO_ACTION_ONESHOT
#    endif // NO_ACTION_ONESHOT
} split_mods_sync_t;
#endif  // SPLIT_MODS_ENABLE
#endif // SPLIT_MODS_ENABLE

#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#    include "pointing_device.h"


@@ 113,7 113,7 @@ typedef struct _split_slave_pointing_sync_t {
    report_mouse_t report;
    uint16_t       cpi;
} split_slave_pointing_sync_t;
#endif  // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)

#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
typedef struct _rpc_sync_info_t {


@@ 121,76 121,76 @@ typedef struct _rpc_sync_info_t {
    uint8_t m2s_length;
    uint8_t s2m_length;
} rpc_sync_info_t;
#endif  // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)

typedef struct _split_shared_memory_t {
#ifdef USE_I2C
    int8_t transaction_id;
#endif  // USE_I2C
#endif // USE_I2C

    split_slave_matrix_sync_t smatrix;

#ifdef SPLIT_TRANSPORT_MIRROR
    split_master_matrix_sync_t mmatrix;
#endif  // SPLIT_TRANSPORT_MIRROR
#endif // SPLIT_TRANSPORT_MIRROR

#ifdef ENCODER_ENABLE
    split_slave_encoder_sync_t encoders;
#endif  // ENCODER_ENABLE
#endif // ENCODER_ENABLE

#ifndef DISABLE_SYNC_TIMER
    uint32_t sync_timer;
#endif  // DISABLE_SYNC_TIMER
#endif // DISABLE_SYNC_TIMER

#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
    split_layers_sync_t layers;
#endif  // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)

#ifdef SPLIT_LED_STATE_ENABLE
    uint8_t led_state;
#endif  // SPLIT_LED_STATE_ENABLE
#endif // SPLIT_LED_STATE_ENABLE

#ifdef SPLIT_MODS_ENABLE
    split_mods_sync_t mods;
#endif  // SPLIT_MODS_ENABLE
#endif // SPLIT_MODS_ENABLE

#ifdef BACKLIGHT_ENABLE
    uint8_t backlight_level;
#endif  // BACKLIGHT_ENABLE
#endif // BACKLIGHT_ENABLE

#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
    rgblight_syncinfo_t rgblight_sync;
#endif  // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)

#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
    led_matrix_sync_t led_matrix_sync;
#endif  // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)

#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
    rgb_matrix_sync_t rgb_matrix_sync;
#endif  // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)

#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
    uint8_t current_wpm;
#endif  // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)

#if defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
    uint8_t current_oled_state;
#endif  // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
#endif // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)

#if defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
    uint8_t current_st7565_state;
#endif  // ST7565_ENABLE(OLED_ENABLE) && defined(SPLIT_ST7565_ENABLE)
#endif // ST7565_ENABLE(OLED_ENABLE) && defined(SPLIT_ST7565_ENABLE)

#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
    split_slave_pointing_sync_t pointing;
#endif  // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)

#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
    rpc_sync_info_t rpc_info;
    uint8_t         rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE];
    uint8_t         rpc_s2m_buffer[RPC_S2M_BUFFER_SIZE];
#endif  // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
} split_shared_memory_t;

extern split_shared_memory_t *const split_shmem;

M quantum/sync_timer.c => quantum/sync_timer.c +3 -1
@@ 29,7 29,9 @@ SOFTWARE.
#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
volatile int32_t sync_timer_ms;

void sync_timer_init(void) { sync_timer_ms = 0; }
void sync_timer_init(void) {
    sync_timer_ms = 0;
}

void sync_timer_update(uint32_t time) {
    if (is_keyboard_master()) return;

M quantum/velocikey.c => quantum/velocikey.c +6 -2
@@ 13,7 13,9 @@
#define TYPING_SPEED_MAX_VALUE 200
uint8_t typing_speed = 0;

bool velocikey_enabled(void) { return eeprom_read_byte(EECONFIG_VELOCIKEY) == 1; }
bool velocikey_enabled(void) {
    return eeprom_read_byte(EECONFIG_VELOCIKEY) == 1;
}

void velocikey_toggle(void) {
    if (velocikey_enabled())


@@ 39,4 41,6 @@ void velocikey_decelerate(void) {
    }
}

uint8_t velocikey_match_speed(uint8_t minValue, uint8_t maxValue) { return MAX(minValue, maxValue - (maxValue - minValue) * ((float)typing_speed / TYPING_SPEED_MAX_VALUE)); }
uint8_t velocikey_match_speed(uint8_t minValue, uint8_t maxValue) {
    return MAX(minValue, maxValue - (maxValue - minValue) * ((float)typing_speed / TYPING_SPEED_MAX_VALUE));
}

M quantum/via.c => quantum/via.c +9 -9
@@ 45,7 45,7 @@
#include "raw_hid.h"
#include "dynamic_keymap.h"
#include "eeprom.h"
#include "version.h"  // for QMK_BUILDDATE used in EEPROM magic
#include "version.h" // for QMK_BUILDDATE used in EEPROM magic
#include "via_ensure_keycode.h"

// Forward declare some helpers.


@@ 62,7 62,7 @@ void via_qmk_rgblight_get_value(uint8_t *data);
// Can be called in an overriding via_init_kb() to test if keyboard level code usage of
// EEPROM is invalid and use/save defaults.
bool via_eeprom_is_valid(void) {
    char *  p      = QMK_BUILDDATE;  // e.g. "2019-11-05-11:29:54"
    char *  p      = QMK_BUILDDATE; // e.g. "2019-11-05-11:29:54"
    uint8_t magic0 = ((p[2] & 0x0F) << 4) | (p[3] & 0x0F);
    uint8_t magic1 = ((p[5] & 0x0F) << 4) | (p[6] & 0x0F);
    uint8_t magic2 = ((p[8] & 0x0F) << 4) | (p[9] & 0x0F);


@@ 73,7 73,7 @@ bool via_eeprom_is_valid(void) {
// Sets VIA/keyboard level usage of EEPROM to valid/invalid
// Keyboard level code (eg. via_init_kb()) should not call this
void via_eeprom_set_valid(bool valid) {
    char *  p      = QMK_BUILDDATE;  // e.g. "2019-11-05-11:29:54"
    char *  p      = QMK_BUILDDATE; // e.g. "2019-11-05-11:29:54"
    uint8_t magic0 = ((p[2] & 0x0F) << 4) | (p[3] & 0x0F);
    uint8_t magic1 = ((p[5] & 0x0F) << 4) | (p[6] & 0x0F);
    uint8_t magic2 = ((p[8] & 0x0F) << 4) | (p[9] & 0x0F);


@@ 347,13 347,13 @@ void raw_hid_receive(uint8_t *data, uint8_t length) {
        }
        case id_dynamic_keymap_macro_get_buffer: {
            uint16_t offset = (command_data[0] << 8) | command_data[1];
            uint16_t size   = command_data[2];  // size <= 28
            uint16_t size   = command_data[2]; // size <= 28
            dynamic_keymap_macro_get_buffer(offset, size, &command_data[3]);
            break;
        }
        case id_dynamic_keymap_macro_set_buffer: {
            uint16_t offset = (command_data[0] << 8) | command_data[1];
            uint16_t size   = command_data[2];  // size <= 28
            uint16_t size   = command_data[2]; // size <= 28
            dynamic_keymap_macro_set_buffer(offset, size, &command_data[3]);
            break;
        }


@@ 367,13 367,13 @@ void raw_hid_receive(uint8_t *data, uint8_t length) {
        }
        case id_dynamic_keymap_get_buffer: {
            uint16_t offset = (command_data[0] << 8) | command_data[1];
            uint16_t size   = command_data[2];  // size <= 28
            uint16_t size   = command_data[2]; // size <= 28
            dynamic_keymap_get_buffer(offset, size, &command_data[3]);
            break;
        }
        case id_dynamic_keymap_set_buffer: {
            uint16_t offset = (command_data[0] << 8) | command_data[1];
            uint16_t size   = command_data[2];  // size <= 28
            uint16_t size   = command_data[2]; // size <= 28
            dynamic_keymap_set_buffer(offset, size, &command_data[3]);
            break;
        }


@@ 438,7 438,7 @@ void via_qmk_backlight_set_value(uint8_t *data) {
    }
}

#endif  // #if defined(VIA_QMK_BACKLIGHT_ENABLE)
#endif // #if defined(VIA_QMK_BACKLIGHT_ENABLE)

#if defined(VIA_QMK_RGBLIGHT_ENABLE)



@@ 494,4 494,4 @@ void via_qmk_rgblight_set_value(uint8_t *data) {
    }
}

#endif  // #if defined(VIA_QMK_RGBLIGHT_ENABLE)
#endif // #if defined(VIA_QMK_RGBLIGHT_ENABLE)

M quantum/via.h => quantum/via.h +3 -3
@@ 16,7 16,7 @@

#pragma once

#include "eeconfig.h"  // for EECONFIG_SIZE
#include "eeconfig.h" // for EECONFIG_SIZE

// Keyboard level code can change where VIA stores the magic.
// The magic is the build date YYMMDD encoded as BCD in 3 bytes,


@@ 59,7 59,7 @@
#define VIA_PROTOCOL_VERSION 0x0009

enum via_command_id {
    id_get_protocol_version                 = 0x01,  // always 0x01
    id_get_protocol_version                 = 0x01, // always 0x01
    id_get_keyboard_value                   = 0x02,
    id_set_keyboard_value                   = 0x03,
    id_dynamic_keymap_get_keycode           = 0x04,


@@ 82,7 82,7 @@ enum via_command_id {
};

enum via_keyboard_value_id {
    id_uptime              = 0x01,  //
    id_uptime              = 0x01, //
    id_layout_options      = 0x02,
    id_switch_matrix_state = 0x03
};

M quantum/wpm.c => quantum/wpm.c +15 -7
@@ 55,12 55,20 @@ static uint8_t  prev_wpm        = 0;
static uint8_t  next_wpm        = 0;
#endif

void    set_current_wpm(uint8_t new_wpm) { current_wpm = new_wpm; }
uint8_t get_current_wpm(void) { return current_wpm; }
void set_current_wpm(uint8_t new_wpm) {
    current_wpm = new_wpm;
}
uint8_t get_current_wpm(void) {
    return current_wpm;
}

bool wpm_keycode(uint16_t keycode) { return wpm_keycode_kb(keycode); }
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_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)) {


@@ 122,7 130,7 @@ void decay_wpm(void) {
    uint32_t duration = (((periods)*PERIOD_DURATION) + elapsed);
    int32_t  wpm_now  = (60000 * presses) / (duration * WPM_ESTIMATED_WORD_SIZE);

    if (wpm_now < 0)  // set some reasonable WPM measurement limits
    if (wpm_now < 0) // set some reasonable WPM measurement limits
        wpm_now = 0;
    if (wpm_now > 240) wpm_now = 240;



@@ 133,7 141,7 @@ void decay_wpm(void) {
        elapsed                        = 0;
        wpm_timer                      = timer_read32();
    }
    if (presses < 2)  // don't guess high WPM based on a single keypress.
    if (presses < 2) // don't guess high WPM based on a single keypress.
        wpm_now = 0;

#if defined(WPM_LAUNCH_CONTROL)


@@ 150,7 158,7 @@ void decay_wpm(void) {
        wpm_now           = 0;
        period_presses[0] = 0;
    }
#endif  // WPM_LAUNCH_CONTROL
#endif // WPM_LAUNCH_CONTROL

#if defined(WPM_UNFILTERED)
    current_wpm = wpm_now;

M tests/test_common/keyboard_report_util.cpp => tests/test_common/keyboard_report_util.cpp +10 -4
@@ 36,7 36,7 @@ std::vector<uint8_t> get_keys(const report_keyboard_t& report) {
    std::sort(result.begin(), result.end());
    return result;
}
}  // namespace
} // namespace

bool operator==(const report_keyboard_t& lhs, const report_keyboard_t& rhs) {
    auto lhskeys = get_keys(lhs);


@@ 72,8 72,14 @@ KeyboardReportMatcher::KeyboardReportMatcher(const std::vector<uint8_t>& keys) {
    }
}

bool KeyboardReportMatcher::MatchAndExplain(report_keyboard_t& report, MatchResultListener* listener) const { return m_report == report; }
bool KeyboardReportMatcher::MatchAndExplain(report_keyboard_t& report, MatchResultListener* listener) const {
    return m_report == report;
}

void KeyboardReportMatcher::DescribeTo(::std::ostream* os) const { *os << "is equal to " << m_report; }
void KeyboardReportMatcher::DescribeTo(::std::ostream* os) const {
    *os << "is equal to " << m_report;
}

void KeyboardReportMatcher::DescribeNegationTo(::std::ostream* os) const { *os << "is not equal to " << m_report; }
void KeyboardReportMatcher::DescribeNegationTo(::std::ostream* os) const {
    *os << "is not equal to " << m_report;
}

M tests/test_common/matrix.c => tests/test_common/matrix.c +12 -4
@@ 30,7 30,9 @@ uint8_t matrix_scan(void) {
    return 1;
}

matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
matrix_row_t matrix_get_row(uint8_t row) {
    return matrix[row];
}

void matrix_print(void) {}



@@ 38,10 40,16 @@ void matrix_init_kb(void) {}

void matrix_scan_kb(void) {}

void press_key(uint8_t col, uint8_t row) { matrix[row] |= 1 << col; }
void press_key(uint8_t col, uint8_t row) {
    matrix[row] |= 1 << col;
}

void release_key(uint8_t col, uint8_t row) { matrix[row] &= ~(1 << col); }
void release_key(uint8_t col, uint8_t row) {
    matrix[row] &= ~(1 << col);
}

void clear_all_keys(void) { memset(matrix, 0, sizeof(matrix)); }
void clear_all_keys(void) {
    memset(matrix, 0, sizeof(matrix));
}

void led_set(uint8_t usb_led) {}

M tests/test_common/test_driver.cpp => tests/test_common/test_driver.cpp +15 -5
@@ 23,17 23,27 @@ TestDriver::TestDriver() : m_driver{&TestDriver::keyboard_leds, &TestDriver::sen
    m_this = this;
}

TestDriver::~TestDriver() { m_this = nullptr; }
TestDriver::~TestDriver() {
    m_this = nullptr;
}

uint8_t TestDriver::keyboard_leds(void) { return m_this->m_leds; }
uint8_t TestDriver::keyboard_leds(void) {
    return m_this->m_leds;
}

void TestDriver::send_keyboard(report_keyboard_t* report) {
    test_logger.trace() << *report;
    m_this->send_keyboard_mock(*report);
}

void TestDriver::send_mouse(report_mouse_t* report) { m_this->send_mouse_mock(*report); }
void TestDriver::send_mouse(report_mouse_t* report) {
    m_this->send_mouse_mock(*report);
}

void TestDriver::send_system(uint16_t data) { m_this->send_system_mock(data); }
void TestDriver::send_system(uint16_t data) {
    m_this->send_system_mock(data);
}

void TestDriver::send_consumer(uint16_t data) { m_this->send_consumer(data); }
void TestDriver::send_consumer(uint16_t data) {
    m_this->send_consumer(data);
}

M tests/test_common/test_fixture.cpp => tests/test_common/test_fixture.cpp +3 -1
@@ 55,7 55,9 @@ void TestFixture::SetUpTestCase() {

void TestFixture::TearDownTestCase() {}

TestFixture::TestFixture() { m_this = this; }
TestFixture::TestFixture() {
    m_this = this;
}

TestFixture::~TestFixture() {
    test_logger.info() << "TestFixture clean-up start." << std::endl;

M tests/test_common/test_logger.cpp => tests/test_common/test_logger.cpp +6 -2
@@ 34,6 34,10 @@ TestLogger& TestLogger::error() {
    return *this;
}

void TestLogger::reset() { this->m_log.str(""); };
void TestLogger::reset() {
    this->m_log.str("");
};

void TestLogger::print_log() { std::cerr << this->m_log.str(); }
void TestLogger::print_log() {
    std::cerr << this->m_log.str();
}

M tmk_core/protocol/arm_atsam/adc.c => tmk_core/protocol/arm_atsam/adc.c +13 -13
@@ 27,10 27,10 @@ uint16_t v_con_2_boot;
void ADC0_clock_init(void) {
    DBGC(DC_ADC0_CLOCK_INIT_BEGIN);

    MCLK->APBDMASK.bit.ADC0_ = 1;  // ADC0 Clock Enable
    MCLK->APBDMASK.bit.ADC0_ = 1; // ADC0 Clock Enable

    GCLK->PCHCTRL[ADC0_GCLK_ID].bit.GEN  = GEN_OSC0;  // Select generator clock
    GCLK->PCHCTRL[ADC0_GCLK_ID].bit.CHEN = 1;         // Enable peripheral clock
    GCLK->PCHCTRL[ADC0_GCLK_ID].bit.GEN  = GEN_OSC0; // Select generator clock
    GCLK->PCHCTRL[ADC0_GCLK_ID].bit.CHEN = 1;        // Enable peripheral clock

    DBGC(DC_ADC0_CLOCK_INIT_COMPLETE);
}


@@ 39,15 39,15 @@ void ADC0_init(void) {
    DBGC(DC_ADC0_INIT_BEGIN);

    // MCU
    PORT->Group[1].DIRCLR.reg           = 1 << 0;  // PB00 as input 5V
    PORT->Group[1].DIRCLR.reg           = 1 << 1;  // PB01 as input CON2
    PORT->Group[1].DIRCLR.reg           = 1 << 2;  // PB02 as input CON1
    PORT->Group[1].PMUX[0].bit.PMUXE    = 1;       // PB00 mux select B ADC 5V
    PORT->Group[1].PMUX[0].bit.PMUXO    = 1;       // PB01 mux select B ADC CON2
    PORT->Group[1].PMUX[1].bit.PMUXE    = 1;       // PB02 mux select B ADC CON1
    PORT->Group[1].PINCFG[0].bit.PMUXEN = 1;       // PB01 mux ADC Enable 5V
    PORT->Group[1].PINCFG[1].bit.PMUXEN = 1;       // PB01 mux ADC Enable CON2
    PORT->Group[1].PINCFG[2].bit.PMUXEN = 1;       // PB02 mux ADC Enable CON1
    PORT->Group[1].DIRCLR.reg           = 1 << 0; // PB00 as input 5V
    PORT->Group[1].DIRCLR.reg           = 1 << 1; // PB01 as input CON2
    PORT->Group[1].DIRCLR.reg           = 1 << 2; // PB02 as input CON1
    PORT->Group[1].PMUX[0].bit.PMUXE    = 1;      // PB00 mux select B ADC 5V
    PORT->Group[1].PMUX[0].bit.PMUXO    = 1;      // PB01 mux select B ADC CON2
    PORT->Group[1].PMUX[1].bit.PMUXE    = 1;      // PB02 mux select B ADC CON1
    PORT->Group[1].PINCFG[0].bit.PMUXEN = 1;      // PB01 mux ADC Enable 5V
    PORT->Group[1].PINCFG[1].bit.PMUXEN = 1;      // PB01 mux ADC Enable CON2
    PORT->Group[1].PINCFG[2].bit.PMUXEN = 1;      // PB02 mux ADC Enable CON1

    // ADC
    ADC0->CTRLA.bit.SWRST = 1;


@@ 81,7 81,7 @@ void ADC0_init(void) {
    }

    // Settling
    ADC0->SAMPCTRL.bit.SAMPLEN = 45;  // Sampling Time Length: 1-63, 1 ADC CLK per
    ADC0->SAMPCTRL.bit.SAMPLEN = 45; // Sampling Time Length: 1-63, 1 ADC CLK per
    while (ADC0->SYNCBUSY.bit.SAMPCTRL) {
        DBGC(DC_ADC0_SAMPCTRL_SYNCING_1);
    }

M tmk_core/protocol/arm_atsam/adc.h => tmk_core/protocol/arm_atsam/adc.h +1 -1
@@ 34,4 34,4 @@ extern uint16_t v_con_2_boot;
void ADC0_clock_init(void);
void ADC0_init(void);

#endif  //_ADC_H_
#endif //_ADC_H_

M tmk_core/protocol/arm_atsam/arm_atsam_protocol.h => tmk_core/protocol/arm_atsam/arm_atsam_protocol.h +2 -2
@@ 42,6 42,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#    include "./usb/udc.h"
#    include "./usb/udi_cdc.h"

#endif  // MD_BOOTLOADER
#endif // MD_BOOTLOADER

#endif  //_ARM_ATSAM_PROTOCOL_H_
#endif //_ARM_ATSAM_PROTOCOL_H_

M tmk_core/protocol/arm_atsam/clks.c => tmk_core/protocol/arm_atsam/clks.c +21 -21
@@ 22,7 22,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
volatile clk_t    system_clks;
volatile uint64_t ms_clk;
uint32_t          usec_delay_mult;
#define USEC_DELAY_LOOP_CYCLES 3  // Sum of instruction cycles in us delay loop
#define USEC_DELAY_LOOP_CYCLES 3 // Sum of instruction cycles in us delay loop

const uint32_t sercom_apbbase[] = {(uint32_t)SERCOM0, (uint32_t)SERCOM1, (uint32_t)SERCOM2, (uint32_t)SERCOM3, (uint32_t)SERCOM4, (uint32_t)SERCOM5};
const uint8_t  sercom_pchan[]   = {7, 8, 23, 24, 34, 35};


@@ 59,9 59,9 @@ void CLK_oscctrl_init(void) {
    while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.ENABLE) {
        DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_DISABLE);
    }
    posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.REFCLK = 2;          // select XOSC0 (16MHz)
    posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.DIV    = 7;          // 16 MHz / (2 * (7 + 1)) = 1 MHz
    posctrl->Dpll[USE_DPLL_IND].DPLLRATIO.bit.LDR    = PLL_RATIO;  // 1 MHz * (PLL_RATIO(47) + 1) = 48MHz
    posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.REFCLK = 2;         // select XOSC0 (16MHz)
    posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.DIV    = 7;         // 16 MHz / (2 * (7 + 1)) = 1 MHz
    posctrl->Dpll[USE_DPLL_IND].DPLLRATIO.bit.LDR    = PLL_RATIO; // 1 MHz * (PLL_RATIO(47) + 1) = 48MHz
    while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.DPLLRATIO) {
        DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_RATIO);
    }


@@ 87,7 87,7 @@ void CLK_oscctrl_init(void) {
    system_clks.freq_gclk[0] = system_clks.freq_dpll[0];

    usec_delay_mult = system_clks.freq_gclk[0] / (USEC_DELAY_LOOP_CYCLES * 1000000);
    if (usec_delay_mult < 1) usec_delay_mult = 1;  // Never allow a multiplier of zero
    if (usec_delay_mult < 1) usec_delay_mult = 1; // Never allow a multiplier of zero

    DBGC(DC_CLK_OSC_INIT_COMPLETE);
}


@@ 240,7 240,7 @@ uint32_t CLK_enable_timebase(void) {
    // ptc4->COUNT16.DBGCTRL.bit.DBGRUN = 1;

    // wave mode
    ptc4->COUNT16.WAVE.bit.WAVEGEN = 1;  // MFRQ match frequency mode, toggle each CC match
    ptc4->COUNT16.WAVE.bit.WAVEGEN = 1; // MFRQ match frequency mode, toggle each CC match
    // generate event for next stage
    ptc4->COUNT16.EVCTRL.bit.MCEO0 = 1;



@@ 272,9 272,9 @@ uint32_t CLK_enable_timebase(void) {
        DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_2);
    }
    // CTRLA as default
    ptc0->COUNT32.CTRLA.bit.MODE   = 2;  // 32 bit mode
    ptc0->COUNT32.EVCTRL.bit.TCEI  = 1;  // enable incoming events
    ptc0->COUNT32.EVCTRL.bit.EVACT = 2;  // count events
    ptc0->COUNT32.CTRLA.bit.MODE   = 2; // 32 bit mode
    ptc0->COUNT32.EVCTRL.bit.TCEI  = 1; // enable incoming events
    ptc0->COUNT32.EVCTRL.bit.EVACT = 2; // count events

    DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_COMPLETE);



@@ 284,10 284,10 @@ uint32_t CLK_enable_timebase(void) {
    pmclk->APBBMASK.bit.EVSYS_               = 1;
    pgclk->PCHCTRL[EVSYS_GCLK_ID_0].bit.GEN  = GEN_TC45;
    pgclk->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 1;
    pevsys->USER[44].reg                     = EVSYS_ID_USER_PORT_EV_0;               // TC0 will get event channel 0
    pevsys->Channel[0].CHANNEL.bit.EDGSEL    = EVSYS_CHANNEL_EDGSEL_RISING_EDGE_Val;  // Rising edge
    pevsys->Channel[0].CHANNEL.bit.PATH      = EVSYS_CHANNEL_PATH_SYNCHRONOUS_Val;    // Synchronous
    pevsys->Channel[0].CHANNEL.bit.EVGEN     = EVSYS_ID_GEN_TC4_MCX_0;                // TC4 MC0
    pevsys->USER[44].reg                     = EVSYS_ID_USER_PORT_EV_0;              // TC0 will get event channel 0
    pevsys->Channel[0].CHANNEL.bit.EDGSEL    = EVSYS_CHANNEL_EDGSEL_RISING_EDGE_Val; // Rising edge
    pevsys->Channel[0].CHANNEL.bit.PATH      = EVSYS_CHANNEL_PATH_SYNCHRONOUS_Val;   // Synchronous
    pevsys->Channel[0].CHANNEL.bit.EVGEN     = EVSYS_ID_GEN_TC4_MCX_0;               // TC4 MC0

    DBGC(DC_CLK_ENABLE_TIMEBASE_EVSYS_COMPLETE);



@@ 301,15 301,15 @@ uint32_t CLK_enable_timebase(void) {
}

void CLK_delay_us(uint32_t usec) {
    asm("CBZ R0, return\n\t"  // If usec == 0, branch to return label
    asm("CBZ R0, return\n\t" // If usec == 0, branch to return label
    );
    asm("MULS R0, %0\n\t"        // Multiply R0(usec) by usec_delay_mult and store in R0
        ".balign 16\n\t"         // Ensure loop is aligned for fastest performance
        "loop: SUBS R0, #1\n\t"  // Subtract 1 from R0 and update flags (1 cycle)
        "BNE loop\n\t"           // Branch if non-zero to loop label (2 cycles)  NOTE: USEC_DELAY_LOOP_CYCLES is the sum of loop cycles
        "return:\n\t"            // Return label
        :                        // No output registers
        : "r"(usec_delay_mult)   // For %0
    asm("MULS R0, %0\n\t"       // Multiply R0(usec) by usec_delay_mult and store in R0
        ".balign 16\n\t"        // Ensure loop is aligned for fastest performance
        "loop: SUBS R0, #1\n\t" // Subtract 1 from R0 and update flags (1 cycle)
        "BNE loop\n\t"          // Branch if non-zero to loop label (2 cycles)  NOTE: USEC_DELAY_LOOP_CYCLES is the sum of loop cycles
        "return:\n\t"           // Return label
        :                       // No output registers
        : "r"(usec_delay_mult)  // For %0
    );
    // Note: BX LR generated
}

M tmk_core/protocol/arm_atsam/clks.h => tmk_core/protocol/arm_atsam/clks.h +12 -12
@@ 24,14 24,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#    include "config_led.h"
#    include "config.h"

#endif  // MD_BOOTLOADER
#endif // MD_BOOTLOADER

#define PLL_RATIO 47                // mcu frequency ((X+1)MHz)
#define FREQ_DFLL_DEFAULT 48000000  // DFLL frequency / usb clock
#define FREQ_SPI_DEFAULT 1000000    // spi to 595 shift regs
#define FREQ_I2C0_DEFAULT 100000    // i2c to hub
#define FREQ_I2C1_DEFAULT I2C_HZ    // i2c to LED drivers
#define FREQ_TC45_DEFAULT 1000000   // 1 usec resolution
#define PLL_RATIO 47               // mcu frequency ((X+1)MHz)
#define FREQ_DFLL_DEFAULT 48000000 // DFLL frequency / usb clock
#define FREQ_SPI_DEFAULT 1000000   // spi to 595 shift regs
#define FREQ_I2C0_DEFAULT 100000   // i2c to hub
#define FREQ_I2C1_DEFAULT I2C_HZ   // i2c to LED drivers
#define FREQ_TC45_DEFAULT 1000000  // 1 usec resolution

// I2C1 Set      ~Result     PWM Time (2x Drivers)
//     1000000  1090000


@@ 44,10 44,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

#define FREQ_XOSC0 16000000

#define CHAN_SERCOM_SPI 2   // shift regs
#define CHAN_SERCOM_I2C0 0  // hub
#define CHAN_SERCOM_I2C1 1  // led drivers
#define CHAN_SERCOM_UART 3  // debug util
#define CHAN_SERCOM_SPI 2  // shift regs
#define CHAN_SERCOM_I2C0 0 // hub
#define CHAN_SERCOM_I2C1 1 // led drivers
#define CHAN_SERCOM_UART 3 // debug util

// Generator clock channels
#define GEN_DPLL0 0


@@ 86,4 86,4 @@ uint32_t CLK_set_i2c0_freq(uint8_t sercomn, uint32_t freq);
uint32_t CLK_set_i2c1_freq(uint8_t sercomn, uint32_t freq);
void     CLK_init(void);

#endif  // _CLKS_H_
#endif // _CLKS_H_

M tmk_core/protocol/arm_atsam/d51_util.c => tmk_core/protocol/arm_atsam/d51_util.c +18 -16
@@ 34,7 34,8 @@ void dbg_print(uint32_t x) {
    while (t >= 0) {
        p2 = t;
        p  = 1;
        while (p2--) p *= 10;
        while (p2--)
            p *= 10;
        n = x / p;
        x -= n * p;
        if (!n) {


@@ 55,7 56,7 @@ void dbg_print(uint32_t x) {
    }

    for (w = DBG_PAUSE; w; w--)
        ;  // Long pause after number is complete
        ; // Long pause after number is complete
}

// Display unsigned 32-bit number through debug led


@@ 91,7 92,8 @@ void dled_print(uint32_t x, uint8_t long_pause) {
    while (t >= 0) {
        p2 = t;
        p  = 1;
        while (p2--) p *= 10;
        while (p2--)
            p *= 10;
        n = x / p;
        x -= n * p;
        if (!n) {


@@ 188,12 190,12 @@ void debug_code_init(void) {
    DBGC(DC_UNSET);

    // Configure Ports for EIC
    PORT->Group[DEBUG_BOOT_TRACING_PORT].DIRCLR.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN;  // Input
    PORT->Group[DEBUG_BOOT_TRACING_PORT].OUTSET.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN;  // High
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.INEN    = 1;                            // Input Enable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PULLEN  = 1;                            // Pull Enable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PMUXEN  = 1;                            // Mux Enable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PMUX[DEBUG_BOOT_TRACING_PIN / 2].bit.PMUXO = 0;                            // Mux A
    PORT->Group[DEBUG_BOOT_TRACING_PORT].DIRCLR.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN; // Input
    PORT->Group[DEBUG_BOOT_TRACING_PORT].OUTSET.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN; // High
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.INEN    = 1;                           // Input Enable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PULLEN  = 1;                           // Pull Enable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PMUXEN  = 1;                           // Mux Enable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PMUX[DEBUG_BOOT_TRACING_PIN / 2].bit.PMUXO = 0;                           // Mux A

    // Enable CLK_EIC_APB
    MCLK->APBAMASK.bit.EIC_ = 1;


@@ 223,12 225,12 @@ void debug_code_disable(void) {
    }

    // Default port configuration
    PORT->Group[DEBUG_BOOT_TRACING_PORT].DIRCLR.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN;  // Input
    PORT->Group[DEBUG_BOOT_TRACING_PORT].OUTCLR.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN;  // Low
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.INEN    = 0;                            // Input Disable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PULLEN  = 0;                            // Pull Disable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PMUXEN  = 0;                            // Mux Disable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PMUX[DEBUG_BOOT_TRACING_PIN / 2].bit.PMUXO = 0;                            // Mux A
    PORT->Group[DEBUG_BOOT_TRACING_PORT].DIRCLR.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN; // Input
    PORT->Group[DEBUG_BOOT_TRACING_PORT].OUTCLR.reg                                 = 1 << DEBUG_BOOT_TRACING_PIN; // Low
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.INEN    = 0;                           // Input Disable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PULLEN  = 0;                           // Pull Disable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PINCFG[DEBUG_BOOT_TRACING_PIN].bit.PMUXEN  = 0;                           // Mux Disable
    PORT->Group[DEBUG_BOOT_TRACING_PORT].PMUX[DEBUG_BOOT_TRACING_PIN / 2].bit.PMUXO = 0;                           // Mux A

    // Disable CLK_EIC_APB
    MCLK->APBAMASK.bit.EIC_ = 0;


@@ 239,4 241,4 @@ void debug_code_disable(void) {
void debug_code_init(void) {}
void debug_code_disable(void) {}

#endif  // DEBUG_BOOT_TRACING_ENABLE
#endif // DEBUG_BOOT_TRACING_ENABLE

M tmk_core/protocol/arm_atsam/d51_util.h => tmk_core/protocol/arm_atsam/d51_util.h +2 -2
@@ 219,6 219,6 @@ enum debug_code_list {
#    define DBGC(n) \
        {}

#endif  // DEBUG_BOOT_TRACING_ENABLE
#endif // DEBUG_BOOT_TRACING_ENABLE

#endif  //_D51_UTIL_H_
#endif //_D51_UTIL_H_

M tmk_core/protocol/arm_atsam/i2c_master.c => tmk_core/protocol/arm_atsam/i2c_master.c +68 -64
@@ 26,21 26,21 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#    include "config_led.h"
#    include "matrix.h"

#    define I2C_LED_USE_DMA 1  // Set 1 to use background DMA transfers for leds, Set 0 to use inline software transfers
#    define I2C_LED_USE_DMA 1 // Set 1 to use background DMA transfers for leds, Set 0 to use inline software transfers

DmacDescriptor dmac_desc;
DmacDescriptor dmac_desc_wb;

static uint8_t i2c_led_q[I2C_Q_SIZE];  // I2C queue circular buffer
static uint8_t i2c_led_q_s;            // Start of circular buffer
static uint8_t i2c_led_q_e;            // End of circular buffer
static uint8_t i2c_led_q_full;         // Queue full counter for reset
static uint8_t i2c_led_q[I2C_Q_SIZE]; // I2C queue circular buffer
static uint8_t i2c_led_q_s;           // Start of circular buffer
static uint8_t i2c_led_q_e;           // End of circular buffer
static uint8_t i2c_led_q_full;        // Queue full counter for reset

static uint8_t dma_sendbuf[I2C_DMA_MAX_SEND];  // Data being written to I2C
static uint8_t dma_sendbuf[I2C_DMA_MAX_SEND]; // Data being written to I2C

volatile uint8_t i2c_led_q_running;

#endif  // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)
#endif // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)

void i2c0_init(void) {
    DBGC(DC_I2C0_INIT_BEGIN);


@@ 56,23 56,23 @@ void i2c0_init(void) {
    // I2C
    // Note: SW Reset handled in CLK_set_i2c0_freq clks.c

    SERCOM0->I2CM.CTRLA.bit.MODE = 5;  // Set master mode
    SERCOM0->I2CM.CTRLA.bit.MODE = 5; // Set master mode

    SERCOM0->I2CM.CTRLA.bit.SPEED    = 0;  // Set to 1 for Fast-mode Plus (FM+) up to 1 MHz
    SERCOM0->I2CM.CTRLA.bit.RUNSTDBY = 1;  // Enabled
    SERCOM0->I2CM.CTRLA.bit.SPEED    = 0; // Set to 1 for Fast-mode Plus (FM+) up to 1 MHz
    SERCOM0->I2CM.CTRLA.bit.RUNSTDBY = 1; // Enabled

    SERCOM0->I2CM.CTRLA.bit.ENABLE = 1;  // Enable the device
    SERCOM0->I2CM.CTRLA.bit.ENABLE = 1; // Enable the device
    while (SERCOM0->I2CM.SYNCBUSY.bit.ENABLE) {
        DBGC(DC_I2C0_INIT_SYNC_ENABLING);
    }  // Wait for SYNCBUSY.ENABLE to clear
    } // Wait for SYNCBUSY.ENABLE to clear

    SERCOM0->I2CM.STATUS.bit.BUSSTATE = 1;  // Force into IDLE state
    SERCOM0->I2CM.STATUS.bit.BUSSTATE = 1; // Force into IDLE state
    while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) {
        DBGC(DC_I2C0_INIT_SYNC_SYSOP);
    }
    while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1) {
        DBGC(DC_I2C0_INIT_WAIT_IDLE);
    }  // Wait while not idle
    } // Wait while not idle

    DBGC(DC_I2C0_INIT_COMPLETE);
}


@@ 139,27 139,27 @@ void i2c1_init(void) {
    /* I2C */
    // Note: SW Reset handled in CLK_set_i2c1_freq clks.c

    SERCOM1->I2CM.CTRLA.bit.MODE     = 5;  // MODE: Set master mode (No sync)
    SERCOM1->I2CM.CTRLA.bit.SPEED    = 1;  // SPEED: Fm+ up to 1MHz (No sync)
    SERCOM1->I2CM.CTRLA.bit.RUNSTDBY = 1;  // RUNSTBY: Enabled (No sync)
    SERCOM1->I2CM.CTRLA.bit.MODE     = 5; // MODE: Set master mode (No sync)
    SERCOM1->I2CM.CTRLA.bit.SPEED    = 1; // SPEED: Fm+ up to 1MHz (No sync)
    SERCOM1->I2CM.CTRLA.bit.RUNSTDBY = 1; // RUNSTBY: Enabled (No sync)

    SERCOM1->I2CM.CTRLB.bit.SMEN = 1;  // SMEN: Smart mode enabled (For DMA)(No sync)
    SERCOM1->I2CM.CTRLB.bit.SMEN = 1; // SMEN: Smart mode enabled (For DMA)(No sync)

    NVIC_EnableIRQ(SERCOM1_0_IRQn);
    SERCOM1->I2CM.INTENSET.bit.ERROR = 1;

    SERCOM1->I2CM.CTRLA.bit.ENABLE = 1;  // ENABLE: Enable the device (sync SYNCBUSY.ENABLE)
    SERCOM1->I2CM.CTRLA.bit.ENABLE = 1; // ENABLE: Enable the device (sync SYNCBUSY.ENABLE)
    while (SERCOM1->I2CM.SYNCBUSY.bit.ENABLE) {
        DBGC(DC_I2C1_INIT_SYNC_ENABLING);
    }  // Wait for SYNCBUSY.ENABLE to clear
    } // Wait for SYNCBUSY.ENABLE to clear

    SERCOM1->I2CM.STATUS.bit.BUSSTATE = 1;  // BUSSTATE: Force into IDLE state (sync SYNCBUSY.SYSOP)
    SERCOM1->I2CM.STATUS.bit.BUSSTATE = 1; // BUSSTATE: Force into IDLE state (sync SYNCBUSY.SYSOP)
    while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) {
        DBGC(DC_I2C1_INIT_SYNC_SYSOP);
    }
    while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1) {
        DBGC(DC_I2C1_INIT_WAIT_IDLE);
    }  // Wait while not idle
    } // Wait while not idle

    DBGC(DC_I2C1_INIT_COMPLETE);
}


@@ 240,7 240,7 @@ void i2c_led_send_onoff(uint8_t drvid) {
    }
#    endif

    *issidrv[drvid].onoff = 0;  // Force start location offset to zero
    *issidrv[drvid].onoff = 0; // Force start location offset to zero
    i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].onoff, ISSI3733_PG0_BYTES, 0);
}



@@ 265,7 265,7 @@ void i2c_led_send_pwm(uint8_t drvid) {
    }
#    endif

    *issidrv[drvid].pwm = 0;  // Force start location offset to zero
    *issidrv[drvid].pwm = 0; // Force start location offset to zero
    i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].pwm, ISSI3733_PG1_BYTES, 0);
}



@@ 300,12 300,12 @@ uint8_t I2C3733_Init_Drivers(void) {
    // Set up master device
    i2c_led_send_CRWL(0);
    i2c_led_select_page(0, 3);
    i2c_led_send_mode_op_gcr(0, 0, ISSI3733_CR_SSD_NORMAL);  // No SYNC due to brightness mismatch with second driver
    i2c_led_send_mode_op_gcr(0, 0, ISSI3733_CR_SSD_NORMAL); // No SYNC due to brightness mismatch with second driver

    // Set up slave device
    i2c_led_send_CRWL(1);
    i2c_led_select_page(1, 3);
    i2c_led_send_mode_op_gcr(1, 0, ISSI3733_CR_SSD_NORMAL);  // No SYNC due to brightness mismatch with first driver and slight flicker at rgb values 1,2
    i2c_led_send_mode_op_gcr(1, 0, ISSI3733_CR_SSD_NORMAL); // No SYNC due to brightness mismatch with first driver and slight flicker at rgb values 1,2

    i2c_led_send_CRWL(0);
    i2c_led_select_page(0, 3);


@@ 326,41 326,41 @@ void I2C_DMAC_LED_Init(void) {
    DBGC(DC_I2C_DMAC_LED_INIT_BEGIN);

    // Disable device
    dmac->CTRL.bit.DMAENABLE = 0;  // Disable DMAC
    dmac->CTRL.bit.DMAENABLE = 0; // Disable DMAC
    while (dmac->CTRL.bit.DMAENABLE) {
    }                          // Wait for disabled state in case of ongoing transfers
    dmac->CTRL.bit.SWRST = 1;  // Software Reset DMAC
    }                         // Wait for disabled state in case of ongoing transfers
    dmac->CTRL.bit.SWRST = 1; // Software Reset DMAC
    while (dmac->CTRL.bit.SWRST) {
    }  // Wait for software reset to complete
    } // Wait for software reset to complete

    // Configure device
    dmac->BASEADDR.reg = (uint32_t)&dmac_desc;     // Set descriptor base address
    dmac->WRBADDR.reg  = (uint32_t)&dmac_desc_wb;  // Set descriptor write back address
    dmac->CTRL.reg |= 0x0f00;                      // Handle all priorities (LVL0-3)
    dmac->BASEADDR.reg = (uint32_t)&dmac_desc;    // Set descriptor base address
    dmac->WRBADDR.reg  = (uint32_t)&dmac_desc_wb; // Set descriptor write back address
    dmac->CTRL.reg |= 0x0f00;                     // Handle all priorities (LVL0-3)

    // Disable channel
    dmac->Channel[0].CHCTRLA.bit.ENABLE = 0;  // Disable the channel
    dmac->Channel[0].CHCTRLA.bit.ENABLE = 0; // Disable the channel
    while (dmac->Channel[0].CHCTRLA.bit.ENABLE) {
    }                                        // Wait for disabled state in case of ongoing transfers
    dmac->Channel[0].CHCTRLA.bit.SWRST = 1;  // Software Reset the channel
    }                                       // Wait for disabled state in case of ongoing transfers
    dmac->Channel[0].CHCTRLA.bit.SWRST = 1; // Software Reset the channel
    while (dmac->Channel[0].CHCTRLA.bit.SWRST) {
    }  // Wait for software reset to complete
    } // Wait for software reset to complete

    // Configure channel
    dmac->Channel[0].CHCTRLA.bit.THRESHOLD = 0;                   // 1BEAT
    dmac->Channel[0].CHCTRLA.bit.BURSTLEN  = 0;                   // SINGLE
    dmac->Channel[0].CHCTRLA.bit.TRIGACT   = 2;                   // BURST
    dmac->Channel[0].CHCTRLA.bit.TRIGSRC   = SERCOM1_DMAC_ID_TX;  // Trigger source
    dmac->Channel[0].CHCTRLA.bit.RUNSTDBY  = 1;                   // Run in standby
    dmac->Channel[0].CHCTRLA.bit.THRESHOLD = 0;                  // 1BEAT
    dmac->Channel[0].CHCTRLA.bit.BURSTLEN  = 0;                  // SINGLE
    dmac->Channel[0].CHCTRLA.bit.TRIGACT   = 2;                  // BURST
    dmac->Channel[0].CHCTRLA.bit.TRIGSRC   = SERCOM1_DMAC_ID_TX; // Trigger source
    dmac->Channel[0].CHCTRLA.bit.RUNSTDBY  = 1;                  // Run in standby

    NVIC_EnableIRQ(DMAC_0_IRQn);
    dmac->Channel[0].CHINTENSET.bit.TCMPL = 1;
    dmac->Channel[0].CHINTENSET.bit.TERR  = 1;

    // Enable device
    dmac->CTRL.bit.DMAENABLE = 1;  // Enable DMAC
    dmac->CTRL.bit.DMAENABLE = 1; // Enable DMAC
    while (dmac->CTRL.bit.DMAENABLE == 0) {
    }  // Wait for enable state
    } // Wait for enable state

    DBGC(DC_I2C_DMAC_LED_INIT_COMPLETE);
}


@@ 377,14 377,14 @@ void I2C3733_Control_Set(uint8_t state) {
}

void i2c_led_desc_defaults(void) {
    dmac_desc.BTCTRL.bit.STEPSIZE = 0;  // SRCINC used in favor for auto 1 inc
    dmac_desc.BTCTRL.bit.STEPSEL  = 0;  // SRCINC used in favor for auto 1 inc
    dmac_desc.BTCTRL.bit.DSTINC   = 0;  // The Destination Address Increment is disabled
    dmac_desc.BTCTRL.bit.SRCINC   = 1;  // The Source Address Increment is enabled (Inc by 1)
    dmac_desc.BTCTRL.bit.BEATSIZE = 0;  // 8-bit bus transfer
    dmac_desc.BTCTRL.bit.BLOCKACT = 0;  // Channel will be disabled if it is the last block transfer in the transaction
    dmac_desc.BTCTRL.bit.EVOSEL   = 0;  // Event generation disabled
    dmac_desc.BTCTRL.bit.VALID    = 1;  // Set dmac valid
    dmac_desc.BTCTRL.bit.STEPSIZE = 0; // SRCINC used in favor for auto 1 inc
    dmac_desc.BTCTRL.bit.STEPSEL  = 0; // SRCINC used in favor for auto 1 inc
    dmac_desc.BTCTRL.bit.DSTINC   = 0; // The Destination Address Increment is disabled
    dmac_desc.BTCTRL.bit.SRCINC   = 1; // The Source Address Increment is enabled (Inc by 1)
    dmac_desc.BTCTRL.bit.BEATSIZE = 0; // 8-bit bus transfer
    dmac_desc.BTCTRL.bit.BLOCKACT = 0; // Channel will be disabled if it is the last block transfer in the transaction
    dmac_desc.BTCTRL.bit.EVOSEL   = 0; // Event generation disabled
    dmac_desc.BTCTRL.bit.VALID    = 1; // Set dmac valid
}

void i2c_led_prepare_send_dma(uint8_t *data, uint8_t len) {


@@ 397,9 397,9 @@ void i2c_led_prepare_send_dma(uint8_t *data, uint8_t len) {
}

void i2c_led_begin_dma(uint8_t drvid) {
    DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1;  // Enable the channel
    DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1; // Enable the channel

    SERCOM1->I2CM.ADDR.reg = (dmac_desc.BTCNT.reg << 16) | 0x2000 | issidrv[drvid].addr;  // Begin transfer
    SERCOM1->I2CM.ADDR.reg = (dmac_desc.BTCNT.reg << 16) | 0x2000 | issidrv[drvid].addr; // Begin transfer
}

void i2c_led_send_CRWL_dma(uint8_t drvid) {


@@ 429,7 429,7 @@ void i2c_led_send_GCR_dma(uint8_t drvid) {
void i2c_led_send_pwm_dma(uint8_t drvid) {
    // Note: This copies the CURRENT pwm buffer, which may be getting modified
    memcpy(dma_sendbuf, issidrv[drvid].pwm, ISSI3733_PG1_BYTES);
    *dma_sendbuf = 0;  // Force start location offset to zero
    *dma_sendbuf = 0; // Force start location offset to zero
    i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG1_BYTES);

    i2c_led_begin_dma(drvid);


@@ 438,7 438,7 @@ void i2c_led_send_pwm_dma(uint8_t drvid) {
void i2c_led_send_onoff_dma(uint8_t drvid) {
    // Note: This copies the CURRENT onoff buffer, which may be getting modified
    memcpy(dma_sendbuf, issidrv[drvid].onoff, ISSI3733_PG0_BYTES);
    *dma_sendbuf = 0;  // Force start location offset to zero
    *dma_sendbuf = 0; // Force start location offset to zero
    i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG0_BYTES);

    i2c_led_begin_dma(drvid);


@@ 452,12 452,16 @@ void i2c_led_q_init(void) {
    i2c_led_q_full    = 0;
}

uint8_t i2c_led_q_isempty(void) { return i2c_led_q_s == i2c_led_q_e; }
uint8_t i2c_led_q_isempty(void) {
    return i2c_led_q_s == i2c_led_q_e;
}

uint8_t i2c_led_q_size(void) { return (i2c_led_q_e - i2c_led_q_s) % I2C_Q_SIZE; }
uint8_t i2c_led_q_size(void) {
    return (i2c_led_q_e - i2c_led_q_s) % I2C_Q_SIZE;
}

uint8_t i2c_led_q_available(void) {
    return I2C_Q_SIZE - i2c_led_q_size() - 1;  // Never allow end to meet start
    return I2C_Q_SIZE - i2c_led_q_size() - 1; // Never allow end to meet start
}

void i2c_led_q_add(uint8_t cmd) {


@@ 466,11 470,11 @@ void i2c_led_q_add(uint8_t cmd) {
    // Assign command
    i2c_led_q[i2c_led_q_e] = cmd;

    i2c_led_q_e = (i2c_led_q_e + 1) % I2C_Q_SIZE;  // Move end up one or wrap
    i2c_led_q_e = (i2c_led_q_e + 1) % I2C_Q_SIZE; // Move end up one or wrap
}

void i2c_led_q_s_advance(void) {
    i2c_led_q_s = (i2c_led_q_s + 1) % I2C_Q_SIZE;  // Move start up one or wrap
    i2c_led_q_s = (i2c_led_q_s + 1) % I2C_Q_SIZE; // Move start up one or wrap
}

// Always request room before adding commands


@@ 480,7 484,7 @@ uint8_t i2c_led_q_request_room(uint8_t request_size) {
    if (request_size > i2c_led_q_available()) {
        i2c_led_q_full++;

        if (i2c_led_q_full >= 100)  // Give the queue a chance to clear up
        if (i2c_led_q_full >= 100) // Give the queue a chance to clear up
        {
            DBG_LED_ON;
            I2C_DMAC_LED_Init();


@@ 554,7 558,7 @@ uint8_t i2c_led_q_run(void) {
#    endif
        }

        i2c_led_q_s_advance();  // Advance last run command or if the command byte was not serviced
        i2c_led_q_s_advance(); // Advance last run command or if the command byte was not serviced

#    if I2C_LED_USE_DMA != 1
    }


@@ 583,4 587,4 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t *data, uint16_t length,
    return ret ? I2C_STATUS_SUCCESS : I2C_STATUS_ERROR;
}

#endif  // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)
#endif // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)

M tmk_core/protocol/arm_atsam/i2c_master.h => tmk_core/protocol/arm_atsam/i2c_master.h +2 -2
@@ 95,7 95,7 @@ void    i2c1_init(void);
uint8_t i2c1_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout);
void    i2c1_stop(void);

#endif  // MD_BOOTLOADER
#endif // MD_BOOTLOADER

void    i2c0_init(void);
uint8_t i2c0_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout);


@@ 110,4 110,4 @@ typedef int16_t i2c_status_t;
void         i2c_init(void);
i2c_status_t i2c_transmit(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout);

#endif  // _I2C_MASTER_H_
#endif // _I2C_MASTER_H_

M tmk_core/protocol/arm_atsam/issi3733_driver.h => tmk_core/protocol/arm_atsam/issi3733_driver.h +100 -100
@@ 20,29 20,29 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

// ISII3733 Registers

#define ISSI3733_CMDR 0xFD  // Command Register (Write Only)

#define ISSI3733_CMDRWL 0xFE                    // Command Register Write Lock (Read/Write)
#define ISSI3733_CMDRWL_WRITE_DISABLE 0x00      // Lock register
#define ISSI3733_CMDRWL_WRITE_ENABLE_ONCE 0xC5  // Enable one write to register then reset to locked

#define ISSI3733_IMR 0xF0         // Interrupt Mask Register (Write Only)
#define ISSI3733_IMR_IAC_ON 0x08  // Auto Clear Interrupt Bit - Interrupt auto clear when INTB stay low exceeds 8ms
#define ISSI3733_IMR_IAB_ON 0x04  // Auto Breath Interrupt Bit - Enable auto breath loop finish interrupt
#define ISSI3733_IMR_IS_ON 0x02   // Dot Short Interrupt Bit - Enable dot short interrupt
#define ISSI3733_IMR_IO_ON 0x01   // Dot Open Interrupt Bit - Enable dot open interrupt

#define ISSI3733_ISR 0xF1              // Interrupt Status Register (Read Only)
#define ISSI3733_ISR_ABM3_FINISH 0x10  // Auto Breath Mode 3 Finish Bit - ABM3 finished
#define ISSI3733_ISR_ABM2_FINISH 0x08  // Auto Breath Mode 2 Finish Bit - ABM2 finished
#define ISSI3733_ISR_ABM1_FINISH 0x04  // Auto Breath Mode 1 Finish Bit - ABM1 finished
#define ISSI3733_ISR_SB 0x02           // Short Bit - Shorted
#define ISSI3733_ISR_OB 0x01           // Open Bit - Opened

#define ISSI3733_PG0 0x00  // LED Control Register
#define ISSI3733_PG1 0x01  // PWM Register
#define ISSI3733_PG2 0x02  // Auto Breath Mode Register
#define ISSI3733_PG3 0x03  // Function Register
#define ISSI3733_CMDR 0xFD // Command Register (Write Only)

#define ISSI3733_CMDRWL 0xFE                   // Command Register Write Lock (Read/Write)
#define ISSI3733_CMDRWL_WRITE_DISABLE 0x00     // Lock register
#define ISSI3733_CMDRWL_WRITE_ENABLE_ONCE 0xC5 // Enable one write to register then reset to locked

#define ISSI3733_IMR 0xF0        // Interrupt Mask Register (Write Only)
#define ISSI3733_IMR_IAC_ON 0x08 // Auto Clear Interrupt Bit - Interrupt auto clear when INTB stay low exceeds 8ms
#define ISSI3733_IMR_IAB_ON 0x04 // Auto Breath Interrupt Bit - Enable auto breath loop finish interrupt
#define ISSI3733_IMR_IS_ON 0x02  // Dot Short Interrupt Bit - Enable dot short interrupt
#define ISSI3733_IMR_IO_ON 0x01  // Dot Open Interrupt Bit - Enable dot open interrupt

#define ISSI3733_ISR 0xF1             // Interrupt Status Register (Read Only)
#define ISSI3733_ISR_ABM3_FINISH 0x10 // Auto Breath Mode 3 Finish Bit - ABM3 finished
#define ISSI3733_ISR_ABM2_FINISH 0x08 // Auto Breath Mode 2 Finish Bit - ABM2 finished
#define ISSI3733_ISR_ABM1_FINISH 0x04 // Auto Breath Mode 1 Finish Bit - ABM1 finished
#define ISSI3733_ISR_SB 0x02          // Short Bit - Shorted
#define ISSI3733_ISR_OB 0x01          // Open Bit - Opened

#define ISSI3733_PG0 0x00 // LED Control Register
#define ISSI3733_PG1 0x01 // PWM Register
#define ISSI3733_PG2 0x02 // Auto Breath Mode Register
#define ISSI3733_PG3 0x03 // Function Register

#define ISSI3733_PG_ONOFF ISSI3733_PG0
#define ISSI3733_PG_OR ISSI3733_PG0


@@ 51,88 51,88 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define ISSI3733_PG_ABM ISSI3733_PG2
#define ISSI3733_PG_FN ISSI3733_PG3

#define ISSI3733_CR 0x00  // Configuration Register
#define ISSI3733_CR 0x00 // Configuration Register

// PG3: Configuration Register: Synchronize Configuration
#define ISSI3733_CR_SYNC_MASTER 0x40    // Master
#define ISSI3733_CR_SYNC_SLAVE 0x80     // Slave
#define ISSI3733_CR_SYNC_HIGH_IMP 0xC0  // High Impedance
#define ISSI3733_CR_SYNC_MASTER 0x40   // Master
#define ISSI3733_CR_SYNC_SLAVE 0x80    // Slave
#define ISSI3733_CR_SYNC_HIGH_IMP 0xC0 // High Impedance

// PG3: Configuration Register: Open/Short Detection Enable Bit
//#define ISSI3733_CR_OSD_DISABLE 0x00          //Disable open/short detection
#define ISSI3733_CR_OSD_ENABLE 0x04  // Enable open/short detection
#define ISSI3733_CR_OSD_ENABLE 0x04 // Enable open/short detection

// PG3: Configuration Register: Auto Breath Enable
//#define ISSI3733_CR_B_EN_PWM 0x00             //PWM Mode Enable
#define ISSI3733_CR_B_EN_AUTO 0x02  // Auto Breath Mode Enable
#define ISSI3733_CR_B_EN_AUTO 0x02 // Auto Breath Mode Enable

// PG3: Configuration Register: Software Shutdown Control
//#define ISSI3733_CR_SSD_SHUTDOWN 0x00         //Software shutdown
#define ISSI3733_CR_SSD_NORMAL 0x01  // Normal operation
#define ISSI3733_CR_SSD_NORMAL 0x01 // Normal operation

#define ISSI3733_GCCR 0x01  // Global Current Control Register
#define ISSI3733_GCCR 0x01 // Global Current Control Register

// 1 Byte, Iout = (GCC / 256) * (840 / Rext)
// TODO: Give user define for Rext

// PG3: Auto Breath Control Register 1
#define ISSI3733_ABCR1_ABM1 0x02  // Auto Breath Control Register 1 of ABM-1
#define ISSI3733_ABCR1_ABM2 0x06  // Auto Breath Control Register 1 of ABM-2
#define ISSI3733_ABCR1_ABM3 0x0A  // Auto Breath Control Register 1 of ABM-3
#define ISSI3733_ABCR1_ABM1 0x02 // Auto Breath Control Register 1 of ABM-1
#define ISSI3733_ABCR1_ABM2 0x06 // Auto Breath Control Register 1 of ABM-2
#define ISSI3733_ABCR1_ABM3 0x0A // Auto Breath Control Register 1 of ABM-3

// Rise time
#define ISSI3733_ABCR1_T1_0021 0x00  // 0.21s
#define ISSI3733_ABCR1_T1_0042 0x20  // 0.42s
#define ISSI3733_ABCR1_T1_0084 0x40  // 0.84s
#define ISSI3733_ABCR1_T1_0168 0x60  // 1.68s
#define ISSI3733_ABCR1_T1_0336 0x80  // 3.36s
#define ISSI3733_ABCR1_T1_0672 0xA0  // 6.72s
#define ISSI3733_ABCR1_T1_1344 0xC0  // 13.44s
#define ISSI3733_ABCR1_T1_2688 0xE0  // 26.88s
#define ISSI3733_ABCR1_T1_0021 0x00 // 0.21s
#define ISSI3733_ABCR1_T1_0042 0x20 // 0.42s
#define ISSI3733_ABCR1_T1_0084 0x40 // 0.84s
#define ISSI3733_ABCR1_T1_0168 0x60 // 1.68s
#define ISSI3733_ABCR1_T1_0336 0x80 // 3.36s
#define ISSI3733_ABCR1_T1_0672 0xA0 // 6.72s
#define ISSI3733_ABCR1_T1_1344 0xC0 // 13.44s
#define ISSI3733_ABCR1_T1_2688 0xE0 // 26.88s

// Max value time
#define ISSI3733_ABCR1_T2_0000 0x00  // 0s
#define ISSI3733_ABCR1_T2_0021 0x02  // 0.21s
#define ISSI3733_ABCR1_T2_0042 0x04  // 0.42s
#define ISSI3733_ABCR1_T2_0084 0x06  // 0.84s
#define ISSI3733_ABCR1_T2_0168 0x08  // 1.68s
#define ISSI3733_ABCR1_T2_0336 0x0A  // 3.36s
#define ISSI3733_ABCR1_T2_0672 0x0C  // 6.72s
#define ISSI3733_ABCR1_T2_1344 0x0E  // 13.44s
#define ISSI3733_ABCR1_T2_2688 0x10  // 26.88s
#define ISSI3733_ABCR1_T2_0000 0x00 // 0s
#define ISSI3733_ABCR1_T2_0021 0x02 // 0.21s
#define ISSI3733_ABCR1_T2_0042 0x04 // 0.42s
#define ISSI3733_ABCR1_T2_0084 0x06 // 0.84s
#define ISSI3733_ABCR1_T2_0168 0x08 // 1.68s
#define ISSI3733_ABCR1_T2_0336 0x0A // 3.36s
#define ISSI3733_ABCR1_T2_0672 0x0C // 6.72s
#define ISSI3733_ABCR1_T2_1344 0x0E // 13.44s
#define ISSI3733_ABCR1_T2_2688 0x10 // 26.88s

// PG3: Auto Breath Control Register 2
#define ISSI3733_ABCR2_ABM1 0x03  // Auto Breath Control Register 2 of ABM-1
#define ISSI3733_ABCR2_ABM2 0x07  // Auto Breath Control Register 2 of ABM-2
#define ISSI3733_ABCR2_ABM3 0x0B  // Auto Breath Control Register 2 of ABM-3
#define ISSI3733_ABCR2_ABM1 0x03 // Auto Breath Control Register 2 of ABM-1
#define ISSI3733_ABCR2_ABM2 0x07 // Auto Breath Control Register 2 of ABM-2
#define ISSI3733_ABCR2_ABM3 0x0B // Auto Breath Control Register 2 of ABM-3

// Fall time
#define ISSI3733_ABCR2_T3_0021 0x00  // 0.21s
#define ISSI3733_ABCR2_T3_0042 0x20  // 0.42s
#define ISSI3733_ABCR2_T3_0084 0x40  // 0.84s
#define ISSI3733_ABCR2_T3_0168 0x60  // 1.68s
#define ISSI3733_ABCR2_T3_0336 0x80  // 3.36s
#define ISSI3733_ABCR2_T3_0672 0xA0  // 6.72s
#define ISSI3733_ABCR2_T3_1344 0xC0  // 13.44s
#define ISSI3733_ABCR2_T3_2688 0xE0  // 26.88s
#define ISSI3733_ABCR2_T3_0021 0x00 // 0.21s
#define ISSI3733_ABCR2_T3_0042 0x20 // 0.42s
#define ISSI3733_ABCR2_T3_0084 0x40 // 0.84s
#define ISSI3733_ABCR2_T3_0168 0x60 // 1.68s
#define ISSI3733_ABCR2_T3_0336 0x80 // 3.36s
#define ISSI3733_ABCR2_T3_0672 0xA0 // 6.72s
#define ISSI3733_ABCR2_T3_1344 0xC0 // 13.44s
#define ISSI3733_ABCR2_T3_2688 0xE0 // 26.88s

// Min value time
#define ISSI3733_ABCR2_T4_0000 0x00   // 0s
#define ISSI3733_ABCR2_T4_0021 0x02   // 0.21s
#define ISSI3733_ABCR2_T4_0042 0x04   // 0.42s
#define ISSI3733_ABCR2_T4_0084 0x06   // 0.84s
#define ISSI3733_ABCR2_T4_0168 0x08   // 1.68s
#define ISSI3733_ABCR2_T4_0336 0x0A   // 3.36s
#define ISSI3733_ABCR2_T4_0672 0x0C   // 6.72s
#define ISSI3733_ABCR2_T4_1344 0x0E   // 13.44s
#define ISSI3733_ABCR2_T4_2688 0x10   // 26.88s
#define ISSI3733_ABCR2_T4_5376 0x12   // 53.76s
#define ISSI3733_ABCR2_T4_10752 0x14  // 107.52s
#define ISSI3733_ABCR2_T4_0000 0x00  // 0s
#define ISSI3733_ABCR2_T4_0021 0x02  // 0.21s
#define ISSI3733_ABCR2_T4_0042 0x04  // 0.42s
#define ISSI3733_ABCR2_T4_0084 0x06  // 0.84s
#define ISSI3733_ABCR2_T4_0168 0x08  // 1.68s
#define ISSI3733_ABCR2_T4_0336 0x0A  // 3.36s
#define ISSI3733_ABCR2_T4_0672 0x0C  // 6.72s
#define ISSI3733_ABCR2_T4_1344 0x0E  // 13.44s
#define ISSI3733_ABCR2_T4_2688 0x10  // 26.88s
#define ISSI3733_ABCR2_T4_5376 0x12  // 53.76s
#define ISSI3733_ABCR2_T4_10752 0x14 // 107.52s

// PG3: Auto Breath Control Register 3
#define ISSI3733_ABCR3_ABM1 0x04  // Auto Breath Control Register 3 of ABM-1
#define ISSI3733_ABCR3_ABM2 0x08  // Auto Breath Control Register 3 of ABM-2
#define ISSI3733_ABCR3_ABM3 0x0C  // Auto Breath Control Register 3 of ABM-3
#define ISSI3733_ABCR3_ABM1 0x04 // Auto Breath Control Register 3 of ABM-1
#define ISSI3733_ABCR3_ABM2 0x08 // Auto Breath Control Register 3 of ABM-2
#define ISSI3733_ABCR3_ABM3 0x0C // Auto Breath Control Register 3 of ABM-3

#define ISSI3733_ABCR3_LTA_LOOP_ENDLESS 0x00
#define ISSI3733_ABCR3_LTA_LOOP_1 0x01


@@ 158,44 158,44 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define ISSI3733_ABCR3_LB_T4 0x30

// Loop End
#define ISSI3733_ABCR3_LE_T3 0x00  // End at Off state
#define ISSI3733_ABCR3_LE_T1 0x40  // End at On State
#define ISSI3733_ABCR3_LE_T3 0x00 // End at Off state
#define ISSI3733_ABCR3_LE_T1 0x40 // End at On State

// PG3: Auto Breath Control Register 4
#define ISSI3733_ABCR4_ABM1 0x05  // Auto Breath Control Register 4 of ABM-1
#define ISSI3733_ABCR4_ABM2 0x09  // Auto Breath Control Register 4 of ABM-2
#define ISSI3733_ABCR4_ABM3 0x0D  // Auto Breath Control Register 4 of ABM-3
#define ISSI3733_ABCR4_ABM1 0x05 // Auto Breath Control Register 4 of ABM-1
#define ISSI3733_ABCR4_ABM2 0x09 // Auto Breath Control Register 4 of ABM-2
#define ISSI3733_ABCR4_ABM3 0x0D // Auto Breath Control Register 4 of ABM-3

#define ISSI3733_ABCR4_LTB_LOOP_ENDLESS 0x00
// Or 8bit loop times

// PG3: Time Update Register
#define ISSI3733_TUR 0x0E
#define ISSI3733_TUR_UPDATE 0x00  // Write to update 02h~0Dh time registers after configuring
#define ISSI3733_TUR_UPDATE 0x00 // Write to update 02h~0Dh time registers after configuring

// PG3: SWy Pull-Up Resistor Selection Register
#define ISSI3733_SWYR_PUR 0x0F
#define ISSI3733_SWYR_PUR_NONE 0x00   // No pull-up resistor
#define ISSI3733_SWYR_PUR_500 0x01    // 0.5k Ohm
#define ISSI3733_SWYR_PUR_1000 0x02   // 1.0k Ohm
#define ISSI3733_SWYR_PUR_2000 0x03   // 2.0k Ohm
#define ISSI3733_SWYR_PUR_4000 0x04   // 4.0k Ohm
#define ISSI3733_SWYR_PUR_8000 0x05   // 8.0k Ohm
#define ISSI3733_SWYR_PUR_16000 0x06  // 16k Ohm
#define ISSI3733_SWYR_PUR_32000 0x07  // 32k Ohm
#define ISSI3733_SWYR_PUR_NONE 0x00  // No pull-up resistor
#define ISSI3733_SWYR_PUR_500 0x01   // 0.5k Ohm
#define ISSI3733_SWYR_PUR_1000 0x02  // 1.0k Ohm
#define ISSI3733_SWYR_PUR_2000 0x03  // 2.0k Ohm
#define ISSI3733_SWYR_PUR_4000 0x04  // 4.0k Ohm
#define ISSI3733_SWYR_PUR_8000 0x05  // 8.0k Ohm
#define ISSI3733_SWYR_PUR_16000 0x06 // 16k Ohm
#define ISSI3733_SWYR_PUR_32000 0x07 // 32k Ohm

// PG3: CSx Pull-Down Resistor Selection Register
#define ISSI3733_CSXR_PDR 0x10
#define ISSI3733_CSXR_PDR_NONE 0x00   // No pull-down resistor
#define ISSI3733_CSXR_PDR_500 0x01    // 0.5k Ohm
#define ISSI3733_CSXR_PDR_1000 0x02   // 1.0k Ohm
#define ISSI3733_CSXR_PDR_2000 0x03   // 2.0k Ohm
#define ISSI3733_CSXR_PDR_4000 0x04   // 4.0k Ohm
#define ISSI3733_CSXR_PDR_8000 0x05   // 8.0k Ohm
#define ISSI3733_CSXR_PDR_16000 0x06  // 16k Ohm
#define ISSI3733_CSXR_PDR_32000 0x07  // 32k Ohm
#define ISSI3733_CSXR_PDR_NONE 0x00  // No pull-down resistor
#define ISSI3733_CSXR_PDR_500 0x01   // 0.5k Ohm
#define ISSI3733_CSXR_PDR_1000 0x02  // 1.0k Ohm
#define ISSI3733_CSXR_PDR_2000 0x03  // 2.0k Ohm
#define ISSI3733_CSXR_PDR_4000 0x04  // 4.0k Ohm
#define ISSI3733_CSXR_PDR_8000 0x05  // 8.0k Ohm
#define ISSI3733_CSXR_PDR_16000 0x06 // 16k Ohm
#define ISSI3733_CSXR_PDR_32000 0x07 // 32k Ohm

// PG3: Reset Register
#define ISSI3733_RR 0x11  // Read to reset all registers to default values
#define ISSI3733_RR 0x11 // Read to reset all registers to default values

#endif  //_ISSI3733_DRIVER_H_
#endif //_ISSI3733_DRIVER_H_

M tmk_core/protocol/arm_atsam/main_arm_atsam.c => tmk_core/protocol/arm_atsam/main_arm_atsam.c +58 -55
@@ 31,7 31,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
// From keyboard's directory
#include "config_led.h"

uint8_t g_usb_state = USB_FSMSTATUS_FSMSTATE_OFF_Val;  // Saved USB state from hardware value to detect changes
uint8_t g_usb_state = USB_FSMSTATUS_FSMSTATE_OFF_Val; // Saved USB state from hardware value to detect changes

void    main_subtasks(void);
uint8_t keyboard_leds(void);


@@ 42,7 42,7 @@ void    send_consumer(uint16_t data);

#ifdef DEFERRED_EXEC_ENABLE
void deferred_exec_task(void);
#endif  // DEFERRED_EXEC_ENABLE
#endif // DEFERRED_EXEC_ENABLE

host_driver_t arm_atsam_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};



@@ 53,7 53,7 @@ uint8_t keyboard_leds(void) {
    if (keymap_config.nkro)
        return udi_hid_nkro_report_set;
    else
#endif  // NKRO_ENABLE
#endif // NKRO_ENABLE
        return udi_hid_kbd_report_set;
}



@@ 62,10 62,10 @@ void send_keyboard(report_keyboard_t *report) {

#ifdef NKRO_ENABLE
    if (!keymap_config.nkro) {
#endif  // NKRO_ENABLE
#endif // NKRO_ENABLE
        while (udi_hid_kbd_b_report_trans_ongoing) {
            main_subtasks();
        }  // Run other tasks while waiting for USB to be free
        } // Run other tasks while waiting for USB to be free

        irqflags = __get_PRIMASK();
        __disable_irq();


@@ 81,7 81,7 @@ void send_keyboard(report_keyboard_t *report) {
    } else {
        while (udi_hid_nkro_b_report_trans_ongoing) {
            main_subtasks();
        }  // Run other tasks while waiting for USB to be free
        } // Run other tasks while waiting for USB to be free

        irqflags = __get_PRIMASK();
        __disable_irq();


@@ 94,7 94,7 @@ void send_keyboard(report_keyboard_t *report) {
        __DMB();
        __set_PRIMASK(irqflags);
    }
#endif  // NKRO_ENABLE
#endif // NKRO_ENABLE
}

void send_mouse(report_mouse_t *report) {


@@ 111,7 111,7 @@ void send_mouse(report_mouse_t *report) {

    __DMB();
    __set_PRIMASK(irqflags);
#endif  // MOUSEKEY_ENABLE
#endif // MOUSEKEY_ENABLE
}

#ifdef EXTRAKEY_ENABLE


@@ 130,18 130,18 @@ void send_extra(uint8_t report_id, uint16_t data) {
    __DMB();
    __set_PRIMASK(irqflags);
}
#endif  // EXTRAKEY_ENABLE
#endif // EXTRAKEY_ENABLE

void send_system(uint16_t data) {
#ifdef EXTRAKEY_ENABLE
    send_extra(REPORT_ID_SYSTEM, data);
#endif  // EXTRAKEY_ENABLE
#endif // EXTRAKEY_ENABLE
}

void send_consumer(uint16_t data) {
#ifdef EXTRAKEY_ENABLE
    send_extra(REPORT_ID_CONSUMER, data);
#endif  // EXTRAKEY_ENABLE
#endif // EXTRAKEY_ENABLE
}

#ifdef CONSOLE_ENABLE


@@ 158,81 158,81 @@ int8_t sendchar(uint8_t c) {

void main_subtask_console_flush(void) {
    while (udi_hid_con_b_report_trans_ongoing) {
    }  // Wait for any previous transfers to complete
    } // Wait for any previous transfers to complete

    uint16_t result = console_printbuf_len;
    uint32_t irqflags;
    char *   pconbuf  = console_printbuf;  // Pointer to start send from
    int      send_out = CONSOLE_EPSIZE;    // Bytes to send per transfer
    char *   pconbuf  = console_printbuf; // Pointer to start send from
    int      send_out = CONSOLE_EPSIZE;   // Bytes to send per transfer

    while (result > 0) {  // While not error and bytes remain
    while (result > 0) { // While not error and bytes remain
        while (udi_hid_con_b_report_trans_ongoing) {
        }  // Wait for any previous transfers to complete
        } // Wait for any previous transfers to complete

        irqflags = __get_PRIMASK();
        __disable_irq();
        __DMB();

        if (result < CONSOLE_EPSIZE) {                      // If remaining bytes are less than console epsize
            memset(udi_hid_con_report, 0, CONSOLE_EPSIZE);  // Clear the buffer
            send_out = result;                              // Send remaining size
        if (result < CONSOLE_EPSIZE) {                     // If remaining bytes are less than console epsize
            memset(udi_hid_con_report, 0, CONSOLE_EPSIZE); // Clear the buffer
            send_out = result;                             // Send remaining size
        }

        memcpy(udi_hid_con_report, pconbuf, send_out);  // Copy data into the send buffer
        memcpy(udi_hid_con_report, pconbuf, send_out); // Copy data into the send buffer

        udi_hid_con_b_report_valid = 1;  // Set report valid
        udi_hid_con_send_report();       // Send report
        udi_hid_con_b_report_valid = 1; // Set report valid
        udi_hid_con_send_report();      // Send report

        __DMB();
        __set_PRIMASK(irqflags);

        result -= send_out;   // Decrement result by bytes sent
        pconbuf += send_out;  // Increment buffer point by bytes sent
        result -= send_out;  // Decrement result by bytes sent
        pconbuf += send_out; // Increment buffer point by bytes sent
    }

    console_printbuf_len = 0;
}

#endif  // CONSOLE_ENABLE
#endif // CONSOLE_ENABLE

void main_subtask_usb_state(void) {
    static uint64_t fsmstate_on_delay = 0;                          // Delay timer to be sure USB is actually operating before bringing up hardware
    uint8_t         fsmstate_now      = USB->DEVICE.FSMSTATUS.reg;  // Current state from hardware register
    static uint64_t fsmstate_on_delay = 0;                         // Delay timer to be sure USB is actually operating before bringing up hardware
    uint8_t         fsmstate_now      = USB->DEVICE.FSMSTATUS.reg; // Current state from hardware register

    if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_SUSPEND_Val)  // If USB SUSPENDED
    if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_SUSPEND_Val) // If USB SUSPENDED
    {
        fsmstate_on_delay = 0;  // Clear ON delay timer
        fsmstate_on_delay = 0; // Clear ON delay timer

        if (g_usb_state != USB_FSMSTATUS_FSMSTATE_SUSPEND_Val)  // If previously not SUSPENDED
        if (g_usb_state != USB_FSMSTATUS_FSMSTATE_SUSPEND_Val) // If previously not SUSPENDED
        {
            suspend_power_down();        // Run suspend routine
            g_usb_state = fsmstate_now;  // Save current USB state
            suspend_power_down();       // Run suspend routine
            g_usb_state = fsmstate_now; // Save current USB state
        }
    } else if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_SLEEP_Val)  // Else if USB SLEEPING
    } else if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_SLEEP_Val) // Else if USB SLEEPING
    {
        fsmstate_on_delay = 0;  // Clear ON delay timer
        fsmstate_on_delay = 0; // Clear ON delay timer

        if (g_usb_state != USB_FSMSTATUS_FSMSTATE_SLEEP_Val)  // If previously not SLEEPING
        if (g_usb_state != USB_FSMSTATUS_FSMSTATE_SLEEP_Val) // If previously not SLEEPING
        {
            suspend_power_down();        // Run suspend routine
            g_usb_state = fsmstate_now;  // Save current USB state
            suspend_power_down();       // Run suspend routine
            g_usb_state = fsmstate_now; // Save current USB state
        }
    } else if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_ON_Val)  // Else if USB ON
    } else if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_ON_Val) // Else if USB ON
    {
        if (g_usb_state != USB_FSMSTATUS_FSMSTATE_ON_Val)  // If previously not ON
        if (g_usb_state != USB_FSMSTATUS_FSMSTATE_ON_Val) // If previously not ON
        {
            if (fsmstate_on_delay == 0)  // If ON delay timer is cleared
            if (fsmstate_on_delay == 0) // If ON delay timer is cleared
            {
                fsmstate_on_delay = timer_read64() + 250;   // Set ON delay timer
            } else if (timer_read64() > fsmstate_on_delay)  // Else if ON delay timer is active and timed out
                fsmstate_on_delay = timer_read64() + 250;  // Set ON delay timer
            } else if (timer_read64() > fsmstate_on_delay) // Else if ON delay timer is active and timed out
            {
                suspend_wakeup_init();       // Run wakeup routine
                g_usb_state = fsmstate_now;  // Save current USB state
                suspend_wakeup_init();      // Run wakeup routine
                g_usb_state = fsmstate_now; // Save current USB state
            }
        }
    } else  // Else if USB is in a state not being tracked
    } else // Else if USB is in a state not being tracked
    {
        fsmstate_on_delay = 0;  // Clear ON delay timer
        fsmstate_on_delay = 0; // Clear ON delay timer
    }
}



@@ 262,7 262,9 @@ void main_subtask_usb_extra_device(void) {
}

#ifdef RAW_ENABLE
void main_subtask_raw(void) { udi_hid_raw_receive_report(); }
void main_subtask_raw(void) {
    udi_hid_raw_receive_report();
}
#endif

void main_subtasks(void) {


@@ 296,7 298,7 @@ int main(void) {

#ifdef RGB_MATRIX_ENABLE
    i2c1_init();
#endif  // RGB_MATRIX_ENABLE
#endif // RGB_MATRIX_ENABLE

    matrix_init();



@@ 325,8 327,9 @@ int main(void) {

    i2c_led_q_init();

    for (uint8_t drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++) I2C_LED_Q_ONOFF(drvid);  // Queue data
#endif                                                                                       // RGB_MATRIX_ENABLE
    for (uint8_t drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++)
        I2C_LED_Q_ONOFF(drvid); // Queue data
#endif                          // RGB_MATRIX_ENABLE

    keyboard_setup();



@@ 336,18 339,18 @@ int main(void) {

#ifdef CONSOLE_ENABLE
    uint64_t next_print = 0;
#endif  // CONSOLE_ENABLE
#endif // CONSOLE_ENABLE

    v_5v_avg = adc_get(ADC_5V);

    debug_code_disable();

    while (1) {
        main_subtasks();  // Note these tasks will also be run while waiting for USB keyboard polling intervals
        main_subtasks(); // Note these tasks will also be run while waiting for USB keyboard polling intervals

        if (g_usb_state == USB_FSMSTATUS_FSMSTATE_SUSPEND_Val || g_usb_state == USB_FSMSTATUS_FSMSTATE_SLEEP_Val) {
            if (suspend_wakeup_condition()) {
                udc_remotewakeup();  // Send remote wakeup signal
                udc_remotewakeup(); // Send remote wakeup signal
                wait_ms(50);
            }



@@ 362,12 365,12 @@ int main(void) {
            // Add any debug information here that you want to see very often
            // dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n", v_5v, v_5v_avg, v_5v_avg - V5_LOW, v_5v_avg - V5_HIGH, gcr_actual, gcr_desired);
        }
#endif  // CONSOLE_ENABLE
#endif // CONSOLE_ENABLE

#ifdef DEFERRED_EXEC_ENABLE
        // Run deferred executions
        deferred_exec_task();
#endif  // DEFERRED_EXEC_ENABLE
#endif // DEFERRED_EXEC_ENABLE

        // Run housekeeping
        housekeeping_task();

M tmk_core/protocol/arm_atsam/main_arm_atsam.h => tmk_core/protocol/arm_atsam/main_arm_atsam.h +1 -1
@@ 20,4 20,4 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

uint8_t keyboard_leds(void);

#endif  //_MAIN_ARM_ATSAM_H_
#endif //_MAIN_ARM_ATSAM_H_

M tmk_core/protocol/arm_atsam/md_rgb_matrix.c => tmk_core/protocol/arm_atsam/md_rgb_matrix.c +44 -38
@@ 53,16 53,20 @@ void eeconfig_update_md_led_default(void) {
    eeconfig_flush_md_led(true);
}

void md_led_changed(void) { eeconfig_flag_md_led(true); }
void md_led_changed(void) {
    eeconfig_flag_md_led(true);
}

// todo: use real task rather than this bodge
void housekeeping_task_kb(void) { eeconfig_flush_md_led_task(FLUSH_TIMEOUT); }
void housekeeping_task_kb(void) {
    eeconfig_flush_md_led_task(FLUSH_TIMEOUT);
}

__attribute__((weak)) led_instruction_t led_instructions[] = {{.end = 1}};
static void                             md_rgb_matrix_config_override(int i);
#    else
uint8_t gcr_desired;
#    endif  // USE_MASSDROP_CONFIGURATOR
#    endif // USE_MASSDROP_CONFIGURATOR

void SERCOM1_0_Handler(void) {
    if (SERCOM1->I2CM.INTFLAG.bit.ERROR) {


@@ 125,9 129,9 @@ void gcr_compute(void) {
    if (v_5v < V5_CAT) {
        I2C3733_Control_Set(0);
        // CDC_print("USB: WARNING: 5V catastrophic level reached! Disabling LED drivers!\r\n"); //Blocking print is bad here!
        v_5v_cat_hit = 20;  //~100ms recover
        gcr_actual   = 0;   // Minimize GCR
        usb_gcr_auto = 1;   // Force auto mode enabled
        v_5v_cat_hit = 20; //~100ms recover
        gcr_actual   = 0;  // Minimize GCR
        usb_gcr_auto = 1;  // Force auto mode enabled
        return;
    } else if (v_5v_cat_hit > 1) {
        v_5v_cat_hit--;


@@ 157,24 161,24 @@ void gcr_compute(void) {
        gcr_min_counter = 0;
    } else if (action == ACT_GCR_INC) {
        if (LED_GCR_STEP_AUTO > LED_GCR_MAX - gcr_actual)
            gcr_actual = LED_GCR_MAX;  // Obey max and prevent wrapping
            gcr_actual = LED_GCR_MAX; // Obey max and prevent wrapping
        else
            gcr_actual += LED_GCR_STEP_AUTO;
        gcr_min_counter = 0;
    } else if (action == ACT_GCR_DEC) {
        if (LED_GCR_STEP_AUTO > gcr_actual)  // Prevent wrapping
        if (LED_GCR_STEP_AUTO > gcr_actual) // Prevent wrapping
        {
            gcr_actual = 0;
            // At this point, power can no longer be cut from the LED drivers, so focus on cutting out extra port if active
            if (usb_extra_state != USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG)  // If not in a wait for replug state
            if (usb_extra_state != USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) // If not in a wait for replug state
            {
                if (usb_extra_state == USB_EXTRA_STATE_ENABLED)  // If extra usb is enabled
                if (usb_extra_state == USB_EXTRA_STATE_ENABLED) // If extra usb is enabled
                {
                    gcr_min_counter++;
                    if (gcr_min_counter > 200)  // 5ms per check = 1s delay
                    if (gcr_min_counter > 200) // 5ms per check = 1s delay
                    {
                        USB_ExtraSetState(USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG);
                        usb_extra_manual = 0;  // Force disable manual mode of extra port
                        usb_extra_manual = 0; // Force disable manual mode of extra port
                        if (usb_extra_manual)
                            CDC_print("USB: Disabling extra port until replug and manual mode toggle!\r\n");
                        else


@@ 275,11 279,11 @@ static void flush(void) {
#    ifdef USE_MASSDROP_CONFIGURATOR
    if (!led_enabled) {
        return;
    }  // Prevent calculations and I2C traffic if LED drivers are not enabled
    } // Prevent calculations and I2C traffic if LED drivers are not enabled
#    else
    if (!sr_exp_data.bit.SDB_N) {
        return;
    }  // Prevent calculations and I2C traffic if LED drivers are not enabled
    } // Prevent calculations and I2C traffic if LED drivers are not enabled
#    endif

    // Wait for previous transfer to complete


@@ 319,17 323,19 @@ static void flush(void) {
    pomod = (uint32_t)pomod % 10000;
    pomod /= 100.0f;

#    endif  // USE_MASSDROP_CONFIGURATOR
#    endif // USE_MASSDROP_CONFIGURATOR

    uint8_t drvid;

    // NOTE: GCR does not need to be timed with LED processing, but there is really no harm
    if (gcr_actual != gcr_actual_last) {
        for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++) I2C_LED_Q_GCR(drvid);  // Queue data
        for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++)
            I2C_LED_Q_GCR(drvid); // Queue data
        gcr_actual_last = gcr_actual;
    }

    for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++) I2C_LED_Q_PWM(drvid);  // Queue data
    for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++)
        I2C_LED_Q_PWM(drvid); // Queue data

    i2c_led_q_run();
}


@@ 341,19 347,19 @@ void md_rgb_matrix_indicators_advanced(uint8_t led_min, uint8_t led_max) {
            if (
#    if USB_LED_NUM_LOCK_SCANCODE != 255
                (led_map[i].scan == USB_LED_NUM_LOCK_SCANCODE && (kbled & (1 << USB_LED_NUM_LOCK))) ||
#    endif  // NUM LOCK
#    endif // NUM LOCK
#    if USB_LED_CAPS_LOCK_SCANCODE != 255
                (led_map[i].scan == USB_LED_CAPS_LOCK_SCANCODE && (kbled & (1 << USB_LED_CAPS_LOCK))) ||
#    endif  // CAPS LOCK
#    endif // CAPS LOCK
#    if USB_LED_SCROLL_LOCK_SCANCODE != 255
                (led_map[i].scan == USB_LED_SCROLL_LOCK_SCANCODE && (kbled & (1 << USB_LED_SCROLL_LOCK))) ||
#    endif  // SCROLL LOCK
#    endif // SCROLL LOCK
#    if USB_LED_COMPOSE_SCANCODE != 255
                (led_map[i].scan == USB_LED_COMPOSE_SCANCODE && (kbled & (1 << USB_LED_COMPOSE))) ||
#    endif  // COMPOSE
#    endif // COMPOSE
#    if USB_LED_KANA_SCANCODE != 255
                (led_map[i].scan == USB_LED_KANA_SCANCODE && (kbled & (1 << USB_LED_KANA))) ||
#    endif  // KANA
#    endif // KANA
                (0)) {
                if (rgb_matrix_get_flags() & LED_FLAG_INDICATOR) {
                    led_buffer[i].r = 255 - led_buffer[i].r;


@@ 378,7 384,7 @@ static void led_run_pattern(led_setup_t* f, float* ro, float* go, float* bo, flo
    float po;

    while (f->end != 1) {
        po = pos;  // Reset po for new frame
        po = pos; // Reset po for new frame

        // Add in any moving effects
        if ((!led_animation_direction && f->ef & EF_SCR_R) || (led_animation_direction && (f->ef & EF_SCR_L))) {


@@ 413,17 419,17 @@ static void led_run_pattern(led_setup_t* f, float* ro, float* go, float* bo, flo

        // Add in any color effects
        if (f->ef & EF_OVER) {
            *ro = (po * (f->re - f->rs)) + f->rs;  // + 0.5;
            *go = (po * (f->ge - f->gs)) + f->gs;  // + 0.5;
            *bo = (po * (f->be - f->bs)) + f->bs;  // + 0.5;
            *ro = (po * (f->re - f->rs)) + f->rs; // + 0.5;
            *go = (po * (f->ge - f->gs)) + f->gs; // + 0.5;
            *bo = (po * (f->be - f->bs)) + f->bs; // + 0.5;
        } else if (f->ef & EF_SUBTRACT) {
            *ro -= (po * (f->re - f->rs)) + f->rs;  // + 0.5;
            *go -= (po * (f->ge - f->gs)) + f->gs;  // + 0.5;
            *bo -= (po * (f->be - f->bs)) + f->bs;  // + 0.5;
            *ro -= (po * (f->re - f->rs)) + f->rs; // + 0.5;
            *go -= (po * (f->ge - f->gs)) + f->gs; // + 0.5;
            *bo -= (po * (f->be - f->bs)) + f->bs; // + 0.5;
        } else {
            *ro += (po * (f->re - f->rs)) + f->rs;  // + 0.5;
            *go += (po * (f->ge - f->gs)) + f->gs;  // + 0.5;
            *bo += (po * (f->be - f->bs)) + f->bs;  // + 0.5;
            *ro += (po * (f->re - f->rs)) + f->rs; // + 0.5;
            *go += (po * (f->ge - f->gs)) + f->gs; // + 0.5;
            *bo += (po * (f->be - f->bs)) + f->bs; // + 0.5;
        }

        f++;


@@ 471,10 477,10 @@ static void md_rgb_matrix_config_override(int i) {

            // Check if this applies to current index
            if (led_cur_instruction->flags & LED_FLAG_MATCH_ID) {
                uint8_t   modid    = i / 32;                             // Calculate which id# contains the led bit
                uint32_t  modidbit = 1 << (i % 32);                      // Calculate the bit within the id#
                uint32_t* bitfield = &led_cur_instruction->id0 + modid;  // Add modid as offset to id0 address. *bitfield is now idX of the led id
                if (~(*bitfield) & modidbit) {                           // Check if led bit is not set in idX
                uint8_t   modid    = i / 32;                            // Calculate which id# contains the led bit
                uint32_t  modidbit = 1 << (i % 32);                     // Calculate the bit within the id#
                uint32_t* bitfield = &led_cur_instruction->id0 + modid; // Add modid as offset to id0 address. *bitfield is now idX of the led id
                if (~(*bitfield) & modidbit) {                          // Check if led bit is not set in idX
                    goto next_iter;
                }
            }


@@ 538,5 544,5 @@ static void md_rgb_matrix_config_override(int i) {
    led_buffer[i].b = (uint8_t)bo;
}

#    endif  // USE_MASSDROP_CONFIGURATOR
#endif      // RGB_MATRIX_ENABLE
#    endif // USE_MASSDROP_CONFIGURATOR
#endif     // RGB_MATRIX_ENABLE

M tmk_core/protocol/arm_atsam/md_rgb_matrix.h => tmk_core/protocol/arm_atsam/md_rgb_matrix.h +71 -71
@@ 31,10 31,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define ISSI3733_SW_COUNT 12

#define ISSI3733_LED_RGB_COUNT ISSI3733_CS_COUNT *ISSI3733_SW_COUNT
#define ISSI3733_PG0_BYTES ISSI3733_LED_RGB_COUNT / 8 + 1  //+1 for first byte being memory start offset for I2C transfer
#define ISSI3733_PG1_BYTES ISSI3733_LED_RGB_COUNT + 1      //+1 for first byte being memory start offset for I2C transfer
#define ISSI3733_PG2_BYTES ISSI3733_LED_RGB_COUNT + 1      //+1 for first byte being memory start offset for I2C transfer
#define ISSI3733_PG3_BYTES 18 + 1                          //+1 for first byte being memory start offset for I2C transfer
#define ISSI3733_PG0_BYTES ISSI3733_LED_RGB_COUNT / 8 + 1 //+1 for first byte being memory start offset for I2C transfer
#define ISSI3733_PG1_BYTES ISSI3733_LED_RGB_COUNT + 1     //+1 for first byte being memory start offset for I2C transfer
#define ISSI3733_PG2_BYTES ISSI3733_LED_RGB_COUNT + 1     //+1 for first byte being memory start offset for I2C transfer
#define ISSI3733_PG3_BYTES 18 + 1                         //+1 for first byte being memory start offset for I2C transfer

#define ISSI3733_PG_ONOFF_BYTES ISSI3733_PG0_BYTES
#define ISSI3733_PG_OR_BYTES ISSI3733_PG0_BYTES


@@ 44,38 44,38 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define ISSI3733_PG_FN_BYTES ISSI3733_PG3_BYTES

typedef struct issi3733_driver_s {
    uint8_t addr;                            // Address of the driver according to wiring "ISSI3733: Table 1 Slave Address"
    uint8_t onoff[ISSI3733_PG_ONOFF_BYTES];  // PG0 - LED Control Register - LED On/Off Register
    uint8_t open[ISSI3733_PG_OR_BYTES];      // PG0 - LED Control Register - LED Open Register
    uint8_t shrt[ISSI3733_PG_SR_BYTES];      // PG0 - LED Control Register - LED Short Register
    uint8_t pwm[ISSI3733_PG_PWM_BYTES];      // PG1 - PWM Register
    uint8_t abm[ISSI3733_PG_ABM_BYTES];      // PG2 - Auto Breath Mode Register
    uint8_t conf[ISSI3733_PG_FN_BYTES];      // PG3 - Function Register
    uint8_t addr;                           // Address of the driver according to wiring "ISSI3733: Table 1 Slave Address"
    uint8_t onoff[ISSI3733_PG_ONOFF_BYTES]; // PG0 - LED Control Register - LED On/Off Register
    uint8_t open[ISSI3733_PG_OR_BYTES];     // PG0 - LED Control Register - LED Open Register
    uint8_t shrt[ISSI3733_PG_SR_BYTES];     // PG0 - LED Control Register - LED Short Register
    uint8_t pwm[ISSI3733_PG_PWM_BYTES];     // PG1 - PWM Register
    uint8_t abm[ISSI3733_PG_ABM_BYTES];     // PG2 - Auto Breath Mode Register
    uint8_t conf[ISSI3733_PG_FN_BYTES];     // PG3 - Function Register
} issi3733_driver_t;

typedef struct issi3733_rgb_s {
    uint8_t *r;  // Direct access into PWM data
    uint8_t *g;  // Direct access into PWM data
    uint8_t *b;  // Direct access into PWM data
    uint8_t *r; // Direct access into PWM data
    uint8_t *g; // Direct access into PWM data
    uint8_t *b; // Direct access into PWM data
} issi3733_rgb_t;

typedef struct issi3733_rgb_adr_s {
    uint8_t drv;  // Driver from given list
    uint8_t cs;   // CS
    uint8_t swr;  // SW Red
    uint8_t swg;  // SW Green
    uint8_t swb;  // SW Blue
    uint8_t drv; // Driver from given list
    uint8_t cs;  // CS
    uint8_t swr; // SW Red
    uint8_t swg; // SW Green
    uint8_t swb; // SW Blue
} issi3733_rgb_adr_t;

typedef struct issi3733_led_s {
    uint8_t            id;    // According to PCB ref
    issi3733_rgb_t     rgb;   // PWM settings of R G B
    issi3733_rgb_adr_t adr;   // Hardware addresses
    float              x;     // Physical position X
    float              y;     // Physical position Y
    float              px;    // Physical position X in percent
    float              py;    // Physical position Y in percent
    uint8_t            scan;  // Key scan code from wiring (set 0xFF if no key)
    uint8_t            id;   // According to PCB ref
    issi3733_rgb_t     rgb;  // PWM settings of R G B
    issi3733_rgb_adr_t adr;  // Hardware addresses
    float              x;    // Physical position X
    float              y;    // Physical position Y
    float              px;   // Physical position X in percent
    float              py;   // Physical position Y in percent
    uint8_t            scan; // Key scan code from wiring (set 0xFF if no key)
} issi3733_led_t;

extern issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT];


@@ 92,44 92,44 @@ void md_rgb_matrix_indicators_advanced(uint8_t led_min, uint8_t led_max);

#ifdef USE_MASSDROP_CONFIGURATOR

#    define EF_NONE 0x00000000      // No effect
#    define EF_OVER 0x00000001      // Overwrite any previous color information with new
#    define EF_SCR_L 0x00000002     // Scroll left
#    define EF_SCR_R 0x00000004     // Scroll right
#    define EF_SUBTRACT 0x00000008  // Subtract color values
#    define EF_NONE 0x00000000     // No effect
#    define EF_OVER 0x00000001     // Overwrite any previous color information with new
#    define EF_SCR_L 0x00000002    // Scroll left
#    define EF_SCR_R 0x00000004    // Scroll right
#    define EF_SUBTRACT 0x00000008 // Subtract color values

typedef struct led_setup_s {
    float    hs;   // Band begin at percent
    float    he;   // Band end at percent
    uint8_t  rs;   // Red start value
    uint8_t  re;   // Red end value
    uint8_t  gs;   // Green start value
    uint8_t  ge;   // Green end value
    uint8_t  bs;   // Blue start value
    uint8_t  be;   // Blue end value
    uint32_t ef;   // Animation and color effects
    uint8_t  end;  // Set to signal end of the setup
    float    hs;  // Band begin at percent
    float    he;  // Band end at percent
    uint8_t  rs;  // Red start value
    uint8_t  re;  // Red end value
    uint8_t  gs;  // Green start value
    uint8_t  ge;  // Green end value
    uint8_t  bs;  // Blue start value
    uint8_t  be;  // Blue end value
    uint32_t ef;  // Animation and color effects
    uint8_t  end; // Set to signal end of the setup
} led_setup_t;

extern const uint8_t led_setups_count;
extern void *        led_setups[];

// LED Extra Instructions
#    define LED_FLAG_NULL 0x00                // Matching and coloring not used (default)
#    define LED_FLAG_MATCH_ID 0x01            // Match on the ID of the LED (set id#'s to desired bit pattern, first LED is id 1)
#    define LED_FLAG_MATCH_LAYER 0x02         // Match on the current active layer (set layer to desired match layer)
#    define LED_FLAG_USE_RGB 0x10             // Use a specific RGB value (set r, g, b to desired output color values)
#    define LED_FLAG_USE_PATTERN 0x20         // Use a specific pattern ID (set pattern_id to desired output pattern)
#    define LED_FLAG_USE_ROTATE_PATTERN 0x40  // Use pattern the user has cycled to manually
#    define LED_FLAG_NULL 0x00               // Matching and coloring not used (default)
#    define LED_FLAG_MATCH_ID 0x01           // Match on the ID of the LED (set id#'s to desired bit pattern, first LED is id 1)
#    define LED_FLAG_MATCH_LAYER 0x02        // Match on the current active layer (set layer to desired match layer)
#    define LED_FLAG_USE_RGB 0x10            // Use a specific RGB value (set r, g, b to desired output color values)
#    define LED_FLAG_USE_PATTERN 0x20        // Use a specific pattern ID (set pattern_id to desired output pattern)
#    define LED_FLAG_USE_ROTATE_PATTERN 0x40 // Use pattern the user has cycled to manually

typedef struct led_instruction_s {
    uint16_t flags;  // Bitfield for LED instructions
    uint32_t id0;    // Bitwise id, IDs 0-31
    uint32_t id1;    // Bitwise id, IDs 32-63
    uint32_t id2;    // Bitwise id, IDs 64-95
    uint32_t id3;    // Bitwise id, IDs 96-127
    uint32_t id4;    // Bitwise id, IDs 128-159
    uint32_t id5;    // Bitwise id, IDs 160-191
    uint16_t flags; // Bitfield for LED instructions
    uint32_t id0;   // Bitwise id, IDs 0-31
    uint32_t id1;   // Bitwise id, IDs 32-63
    uint32_t id2;   // Bitwise id, IDs 64-95
    uint32_t id3;   // Bitwise id, IDs 96-127
    uint32_t id4;   // Bitwise id, IDs 128-159
    uint32_t id5;   // Bitwise id, IDs 160-191
    uint8_t  layer;
    uint8_t  r;
    uint8_t  g;


@@ 141,7 141,7 @@ typedef struct led_instruction_s {
extern led_instruction_t led_instructions[];

typedef struct led_config_s {
    uint8_t ver;  // assumed to be zero on eeprom reset
    uint8_t ver; // assumed to be zero on eeprom reset

    uint8_t desired_gcr;
    uint8_t animation_breathing;


@@ 178,27 178,27 @@ void md_led_changed(void);
#    define led_ratio_brightness md_led_config.ratio_brightness
#    define led_edge_mode md_led_config.edge_mode

#    define LED_MODE_NORMAL 0  // Must be 0
#    define LED_MODE_NORMAL 0 // Must be 0
#    define LED_MODE_KEYS_ONLY 1
#    define LED_MODE_NON_KEYS_ONLY 2
#    define LED_MODE_INDICATORS_ONLY 3
#    define LED_MODE_MAX_INDEX LED_MODE_INDICATORS_ONLY  // Must be highest value
#    define LED_MODE_MAX_INDEX LED_MODE_INDICATORS_ONLY // Must be highest value

#    define LED_EDGE_MODE_ALL 0                        // All edge LEDs are active (Must be 0)
#    define LED_EDGE_MODE_ALTERNATE 1                  // Alternate mode of edge LEDs are active (Intention is for 'only every other edge LED' to be active)
#    define LED_EDGE_MODE_MAX LED_EDGE_MODE_ALTERNATE  // Must be the highest valued LED edge mode
#    define LED_EDGE_MODE_ALL 0                       // All edge LEDs are active (Must be 0)
#    define LED_EDGE_MODE_ALTERNATE 1                 // Alternate mode of edge LEDs are active (Intention is for 'only every other edge LED' to be active)
#    define LED_EDGE_MODE_MAX LED_EDGE_MODE_ALTERNATE // Must be the highest valued LED edge mode

#    define LED_EDGE_FULL_MODE 255  // LEDs configured with this scan code will always be on for edge lighting modes
#    define LED_EDGE_ALT_MODE 254   // LEDs configured with this scan code will turn off in edge alternating mode
#    define LED_EDGE_MIN_SCAN 254   // LEDs configured with scan code >= to this are assigned as edge LEDs
#    define LED_INDICATOR_SCAN 253  // LEDs configured as dedicated indicators
#    define LED_EDGE_FULL_MODE 255 // LEDs configured with this scan code will always be on for edge lighting modes
#    define LED_EDGE_ALT_MODE 254  // LEDs configured with this scan code will turn off in edge alternating mode
#    define LED_EDGE_MIN_SCAN 254  // LEDs configured with scan code >= to this are assigned as edge LEDs
#    define LED_INDICATOR_SCAN 253 // LEDs configured as dedicated indicators

#    define LED_IS_KEY(scan) (scan < LED_INDICATOR_SCAN)         // Return true if an LED's scan value indicates it is a key LED
#    define LED_IS_EDGE(scan) (scan >= LED_EDGE_MIN_SCAN)        // Return true if an LED's scan value indicates an edge LED
#    define LED_IS_EDGE_ALT(scan) (scan == LED_EDGE_ALT_MODE)    // Return true if an LED's scan value indicates an alternate edge mode LED
#    define LED_IS_INDICATOR(scan) (scan == LED_INDICATOR_SCAN)  // Return true if an LED's scan value indicates it is a dedicated Indicator
#    define LED_IS_KEY(scan) (scan < LED_INDICATOR_SCAN)        // Return true if an LED's scan value indicates it is a key LED
#    define LED_IS_EDGE(scan) (scan >= LED_EDGE_MIN_SCAN)       // Return true if an LED's scan value indicates an edge LED
#    define LED_IS_EDGE_ALT(scan) (scan == LED_EDGE_ALT_MODE)   // Return true if an LED's scan value indicates an alternate edge mode LED
#    define LED_IS_INDICATOR(scan) (scan == LED_INDICATOR_SCAN) // Return true if an LED's scan value indicates it is a dedicated Indicator
#else
extern uint8_t gcr_desired;
#endif  // USE_MASSDROP_CONFIGURATOR
#endif // USE_MASSDROP_CONFIGURATOR

#endif  //_LED_MATRIX_H_
#endif //_LED_MATRIX_H_

M tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c => tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c +2 -2
@@ 97,5 97,5 @@ void *led_setups[] = {leds_rainbow_s, leds_rainbow_ns, leds_teal_salmon, leds_ye

const uint8_t led_setups_count = sizeof(led_setups) / sizeof(led_setups[0]);

#    endif  // USE_MASSDROP_CONFIGURATOR
#endif      // RGB_MATRIX_ENABLE
\ No newline at end of file
#    endif // USE_MASSDROP_CONFIGURATOR
#endif     // RGB_MATRIX_ENABLE
\ No newline at end of file

M tmk_core/protocol/arm_atsam/shift_register.c => tmk_core/protocol/arm_atsam/shift_register.c +8 -4
@@ 54,7 54,9 @@ void shift_out_impl(const uint8_t *data, uint16_t length) {

#else

void shift_init_impl(void) { spi_init(); }
void shift_init_impl(void) {
    spi_init();
}

void shift_out_impl(const uint8_t *data, uint16_t length) {
    spi_start(SR_EXP_RCLK_PIN, true, 0, 0);


@@ 67,7 69,9 @@ void shift_out_impl(const uint8_t *data, uint16_t length) {

// ***************************************************************

void shift_out(const uint8_t *data, uint16_t length) { shift_out_impl(data, length); }
void shift_out(const uint8_t *data, uint16_t length) {
    shift_out_impl(data, length);
}

void shift_enable(void) {
    setPinOutput(SR_EXP_OE_PIN);


@@ 90,8 94,8 @@ sr_exp_t sr_exp_data;

void SR_EXP_WriteData(void) {
    uint8_t data[2] = {
        sr_exp_data.reg & 0xFF,         // Shift in bits 7-0
        (sr_exp_data.reg >> 8) & 0xFF,  // Shift in bits 15-8
        sr_exp_data.reg & 0xFF,        // Shift in bits 7-0
        (sr_exp_data.reg >> 8) & 0xFF, // Shift in bits 15-8
    };
    shift_out(data, 2);
}

M tmk_core/protocol/arm_atsam/spi_master.c => tmk_core/protocol/arm_atsam/spi_master.c +11 -11
@@ 45,10 45,10 @@ __attribute__((weak)) void spi_init(void) {
        CLK_set_spi_freq(CHAN_SERCOM_SPI, FREQ_SPI_DEFAULT);

        // Set up MCU SPI pins
        PORT->Group[SAMD_PORT(SPI_DATAOUT_PIN)].PMUX[SAMD_PIN(SPI_DATAOUT_PIN) / 2].bit.SPI_DATAOUT_MUX_SEL = SPI_DATAOUT_MUX;  // MUX select for sercom
        PORT->Group[SAMD_PORT(SPI_SCLK_PIN)].PMUX[SAMD_PIN(SPI_SCLK_PIN) / 2].bit.SPI_SCLK_MUX_SEL          = SPI_SCLK_MUX;     // MUX select for sercom
        PORT->Group[SAMD_PORT(SPI_DATAOUT_PIN)].PINCFG[SAMD_PIN(SPI_DATAOUT_PIN)].bit.PMUXEN                = 1;                // MUX Enable
        PORT->Group[SAMD_PORT(SPI_SCLK_PIN)].PINCFG[SAMD_PIN(SPI_SCLK_PIN)].bit.PMUXEN                      = 1;                // MUX Enable
        PORT->Group[SAMD_PORT(SPI_DATAOUT_PIN)].PMUX[SAMD_PIN(SPI_DATAOUT_PIN) / 2].bit.SPI_DATAOUT_MUX_SEL = SPI_DATAOUT_MUX; // MUX select for sercom
        PORT->Group[SAMD_PORT(SPI_SCLK_PIN)].PMUX[SAMD_PIN(SPI_SCLK_PIN) / 2].bit.SPI_SCLK_MUX_SEL          = SPI_SCLK_MUX;    // MUX select for sercom
        PORT->Group[SAMD_PORT(SPI_DATAOUT_PIN)].PINCFG[SAMD_PIN(SPI_DATAOUT_PIN)].bit.PMUXEN                = 1;               // MUX Enable
        PORT->Group[SAMD_PORT(SPI_SCLK_PIN)].PINCFG[SAMD_PIN(SPI_SCLK_PIN)].bit.PMUXEN                      = 1;               // MUX Enable

        DBGC(DC_SPI_INIT_COMPLETE);
    }


@@ 63,14 63,14 @@ bool spi_start(pin_t csPin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
    setPinOutput(currentSelectPin);
    writePinLow(currentSelectPin);

    SPI_SERCOM->SPI.CTRLA.bit.DORD = lsbFirst;  // Data Order - LSB is transferred first
    SPI_SERCOM->SPI.CTRLA.bit.CPOL = 1;         // Clock Polarity - SCK high when idle. Leading edge of cycle is falling. Trailing rising.
    SPI_SERCOM->SPI.CTRLA.bit.CPHA = 1;         // Clock Phase - Leading Edge Falling, change, Trailing Edge - Rising, sample
    SPI_SERCOM->SPI.CTRLA.bit.DIPO = 3;         // Data In Pinout - SERCOM PAD[3] is used as data input (Configure away from DOPO. Not using input.)
    SPI_SERCOM->SPI.CTRLA.bit.DOPO = 0;         // Data Output PAD[0], Serial Clock PAD[1]
    SPI_SERCOM->SPI.CTRLA.bit.MODE = 3;         // Operating Mode - Master operation
    SPI_SERCOM->SPI.CTRLA.bit.DORD = lsbFirst; // Data Order - LSB is transferred first
    SPI_SERCOM->SPI.CTRLA.bit.CPOL = 1;        // Clock Polarity - SCK high when idle. Leading edge of cycle is falling. Trailing rising.
    SPI_SERCOM->SPI.CTRLA.bit.CPHA = 1;        // Clock Phase - Leading Edge Falling, change, Trailing Edge - Rising, sample
    SPI_SERCOM->SPI.CTRLA.bit.DIPO = 3;        // Data In Pinout - SERCOM PAD[3] is used as data input (Configure away from DOPO. Not using input.)
    SPI_SERCOM->SPI.CTRLA.bit.DOPO = 0;        // Data Output PAD[0], Serial Clock PAD[1]
    SPI_SERCOM->SPI.CTRLA.bit.MODE = 3;        // Operating Mode - Master operation

    SPI_SERCOM->SPI.CTRLA.bit.ENABLE = 1;  // Enable - Peripheral is enabled or being enabled
    SPI_SERCOM->SPI.CTRLA.bit.ENABLE = 1; // Enable - Peripheral is enabled or being enabled
    while (SPI_SERCOM->SPI.SYNCBUSY.bit.ENABLE) {
        DBGC(DC_SPI_SYNC_ENABLING);
    }

M tmk_core/protocol/arm_atsam/usb/compiler.h => tmk_core/protocol/arm_atsam/usb/compiler.h +63 -61
@@ 876,66 876,66 @@ typedef struct {
// kmod #define LOW       0
// kmod #define HIGH      1

typedef int8_t   S8;   //!< 8-bit signed integer.
typedef uint8_t  U8;   //!< 8-bit unsigned integer.
typedef int16_t  S16;  //!< 16-bit signed integer.
typedef uint16_t U16;  //!< 16-bit unsigned integer.
typedef int32_t  S32;  //!< 32-bit signed integer.
typedef uint32_t U32;  //!< 32-bit unsigned integer.
typedef int64_t  S64;  //!< 64-bit signed integer.
typedef uint64_t U64;  //!< 64-bit unsigned integer.
typedef float    F32;  //!< 32-bit floating-point number.
typedef double   F64;  //!< 64-bit floating-point number.

#    define MSB(u16) (((U8 *)&(u16))[1])  //!< Most significant byte of \a u16.
#    define LSB(u16) (((U8 *)&(u16))[0])  //!< Least significant byte of \a u16.

#    define MSH(u32) (((U16 *)&(u32))[1])   //!< Most significant half-word of \a u32.
#    define LSH(u32) (((U16 *)&(u32))[0])   //!< Least significant half-word of \a u32.
#    define MSB0W(u32) (((U8 *)&(u32))[3])  //!< Most significant byte of 1st rank of \a u32.
#    define MSB1W(u32) (((U8 *)&(u32))[2])  //!< Most significant byte of 2nd rank of \a u32.
#    define MSB2W(u32) (((U8 *)&(u32))[1])  //!< Most significant byte of 3rd rank of \a u32.
#    define MSB3W(u32) (((U8 *)&(u32))[0])  //!< Most significant byte of 4th rank of \a u32.
#    define LSB3W(u32) MSB0W(u32)           //!< Least significant byte of 4th rank of \a u32.
#    define LSB2W(u32) MSB1W(u32)           //!< Least significant byte of 3rd rank of \a u32.
#    define LSB1W(u32) MSB2W(u32)           //!< Least significant byte of 2nd rank of \a u32.
#    define LSB0W(u32) MSB3W(u32)           //!< Least significant byte of 1st rank of \a u32.

#    define MSW(u64) (((U32 *)&(u64))[1])   //!< Most significant word of \a u64.
#    define LSW(u64) (((U32 *)&(u64))[0])   //!< Least significant word of \a u64.
#    define MSH0(u64) (((U16 *)&(u64))[3])  //!< Most significant half-word of 1st rank of \a u64.
#    define MSH1(u64) (((U16 *)&(u64))[2])  //!< Most significant half-word of 2nd rank of \a u64.
#    define MSH2(u64) (((U16 *)&(u64))[1])  //!< Most significant half-word of 3rd rank of \a u64.
#    define MSH3(u64) (((U16 *)&(u64))[0])  //!< Most significant half-word of 4th rank of \a u64.
#    define LSH3(u64) MSH0(u64)             //!< Least significant half-word of 4th rank of \a u64.
#    define LSH2(u64) MSH1(u64)             //!< Least significant half-word of 3rd rank of \a u64.
#    define LSH1(u64) MSH2(u64)             //!< Least significant half-word of 2nd rank of \a u64.
#    define LSH0(u64) MSH3(u64)             //!< Least significant half-word of 1st rank of \a u64.
#    define MSB0D(u64) (((U8 *)&(u64))[7])  //!< Most significant byte of 1st rank of \a u64.
#    define MSB1D(u64) (((U8 *)&(u64))[6])  //!< Most significant byte of 2nd rank of \a u64.
#    define MSB2D(u64) (((U8 *)&(u64))[5])  //!< Most significant byte of 3rd rank of \a u64.
#    define MSB3D(u64) (((U8 *)&(u64))[4])  //!< Most significant byte of 4th rank of \a u64.
#    define MSB4D(u64) (((U8 *)&(u64))[3])  //!< Most significant byte of 5th rank of \a u64.
#    define MSB5D(u64) (((U8 *)&(u64))[2])  //!< Most significant byte of 6th rank of \a u64.
#    define MSB6D(u64) (((U8 *)&(u64))[1])  //!< Most significant byte of 7th rank of \a u64.
#    define MSB7D(u64) (((U8 *)&(u64))[0])  //!< Most significant byte of 8th rank of \a u64.
#    define LSB7D(u64) MSB0D(u64)           //!< Least significant byte of 8th rank of \a u64.
#    define LSB6D(u64) MSB1D(u64)           //!< Least significant byte of 7th rank of \a u64.
#    define LSB5D(u64) MSB2D(u64)           //!< Least significant byte of 6th rank of \a u64.
#    define LSB4D(u64) MSB3D(u64)           //!< Least significant byte of 5th rank of \a u64.
#    define LSB3D(u64) MSB4D(u64)           //!< Least significant byte of 4th rank of \a u64.
#    define LSB2D(u64) MSB5D(u64)           //!< Least significant byte of 3rd rank of \a u64.
#    define LSB1D(u64) MSB6D(u64)           //!< Least significant byte of 2nd rank of \a u64.
#    define LSB0D(u64) MSB7D(u64)           //!< Least significant byte of 1st rank of \a u64.

#    define LSB0(u32) LSB0W(u32)  //!< Least significant byte of 1st rank of \a u32.
#    define LSB1(u32) LSB1W(u32)  //!< Least significant byte of 2nd rank of \a u32.
#    define LSB2(u32) LSB2W(u32)  //!< Least significant byte of 3rd rank of \a u32.
#    define LSB3(u32) LSB3W(u32)  //!< Least significant byte of 4th rank of \a u32.
#    define MSB3(u32) MSB3W(u32)  //!< Most significant byte of 4th rank of \a u32.
#    define MSB2(u32) MSB2W(u32)  //!< Most significant byte of 3rd rank of \a u32.
#    define MSB1(u32) MSB1W(u32)  //!< Most significant byte of 2nd rank of \a u32.
#    define MSB0(u32) MSB0W(u32)  //!< Most significant byte of 1st rank of \a u32.
typedef int8_t   S8;  //!< 8-bit signed integer.
typedef uint8_t  U8;  //!< 8-bit unsigned integer.
typedef int16_t  S16; //!< 16-bit signed integer.
typedef uint16_t U16; //!< 16-bit unsigned integer.
typedef int32_t  S32; //!< 32-bit signed integer.
typedef uint32_t U32; //!< 32-bit unsigned integer.
typedef int64_t  S64; //!< 64-bit signed integer.
typedef uint64_t U64; //!< 64-bit unsigned integer.
typedef float    F32; //!< 32-bit floating-point number.
typedef double   F64; //!< 64-bit floating-point number.

#    define MSB(u16) (((U8 *)&(u16))[1]) //!< Most significant byte of \a u16.
#    define LSB(u16) (((U8 *)&(u16))[0]) //!< Least significant byte of \a u16.

#    define MSH(u32) (((U16 *)&(u32))[1])  //!< Most significant half-word of \a u32.
#    define LSH(u32) (((U16 *)&(u32))[0])  //!< Least significant half-word of \a u32.
#    define MSB0W(u32) (((U8 *)&(u32))[3]) //!< Most significant byte of 1st rank of \a u32.
#    define MSB1W(u32) (((U8 *)&(u32))[2]) //!< Most significant byte of 2nd rank of \a u32.
#    define MSB2W(u32) (((U8 *)&(u32))[1]) //!< Most significant byte of 3rd rank of \a u32.
#    define MSB3W(u32) (((U8 *)&(u32))[0]) //!< Most significant byte of 4th rank of \a u32.
#    define LSB3W(u32) MSB0W(u32)          //!< Least significant byte of 4th rank of \a u32.
#    define LSB2W(u32) MSB1W(u32)          //!< Least significant byte of 3rd rank of \a u32.
#    define LSB1W(u32) MSB2W(u32)          //!< Least significant byte of 2nd rank of \a u32.
#    define LSB0W(u32) MSB3W(u32)          //!< Least significant byte of 1st rank of \a u32.

#    define MSW(u64) (((U32 *)&(u64))[1])  //!< Most significant word of \a u64.
#    define LSW(u64) (((U32 *)&(u64))[0])  //!< Least significant word of \a u64.
#    define MSH0(u64) (((U16 *)&(u64))[3]) //!< Most significant half-word of 1st rank of \a u64.
#    define MSH1(u64) (((U16 *)&(u64))[2]) //!< Most significant half-word of 2nd rank of \a u64.
#    define MSH2(u64) (((U16 *)&(u64))[1]) //!< Most significant half-word of 3rd rank of \a u64.
#    define MSH3(u64) (((U16 *)&(u64))[0]) //!< Most significant half-word of 4th rank of \a u64.
#    define LSH3(u64) MSH0(u64)            //!< Least significant half-word of 4th rank of \a u64.
#    define LSH2(u64) MSH1(u64)            //!< Least significant half-word of 3rd rank of \a u64.
#    define LSH1(u64) MSH2(u64)            //!< Least significant half-word of 2nd rank of \a u64.
#    define LSH0(u64) MSH3(u64)            //!< Least significant half-word of 1st rank of \a u64.
#    define MSB0D(u64) (((U8 *)&(u64))[7]) //!< Most significant byte of 1st rank of \a u64.
#    define MSB1D(u64) (((U8 *)&(u64))[6]) //!< Most significant byte of 2nd rank of \a u64.
#    define MSB2D(u64) (((U8 *)&(u64))[5]) //!< Most significant byte of 3rd rank of \a u64.
#    define MSB3D(u64) (((U8 *)&(u64))[4]) //!< Most significant byte of 4th rank of \a u64.
#    define MSB4D(u64) (((U8 *)&(u64))[3]) //!< Most significant byte of 5th rank of \a u64.
#    define MSB5D(u64) (((U8 *)&(u64))[2]) //!< Most significant byte of 6th rank of \a u64.
#    define MSB6D(u64) (((U8 *)&(u64))[1]) //!< Most significant byte of 7th rank of \a u64.
#    define MSB7D(u64) (((U8 *)&(u64))[0]) //!< Most significant byte of 8th rank of \a u64.
#    define LSB7D(u64) MSB0D(u64)          //!< Least significant byte of 8th rank of \a u64.
#    define LSB6D(u64) MSB1D(u64)          //!< Least significant byte of 7th rank of \a u64.
#    define LSB5D(u64) MSB2D(u64)          //!< Least significant byte of 6th rank of \a u64.
#    define LSB4D(u64) MSB3D(u64)          //!< Least significant byte of 5th rank of \a u64.
#    define LSB3D(u64) MSB4D(u64)          //!< Least significant byte of 4th rank of \a u64.
#    define LSB2D(u64) MSB5D(u64)          //!< Least significant byte of 3rd rank of \a u64.
#    define LSB1D(u64) MSB6D(u64)          //!< Least significant byte of 2nd rank of \a u64.
#    define LSB0D(u64) MSB7D(u64)          //!< Least significant byte of 1st rank of \a u64.

#    define LSB0(u32) LSB0W(u32) //!< Least significant byte of 1st rank of \a u32.
#    define LSB1(u32) LSB1W(u32) //!< Least significant byte of 2nd rank of \a u32.
#    define LSB2(u32) LSB2W(u32) //!< Least significant byte of 3rd rank of \a u32.
#    define LSB3(u32) LSB3W(u32) //!< Least significant byte of 4th rank of \a u32.
#    define MSB3(u32) MSB3W(u32) //!< Most significant byte of 4th rank of \a u32.
#    define MSB2(u32) MSB2W(u32) //!< Most significant byte of 3rd rank of \a u32.
#    define MSB1(u32) MSB1W(u32) //!< Most significant byte of 2nd rank of \a u32.
#    define MSB0(u32) MSB0W(u32) //!< Most significant byte of 1st rank of \a u32.

#    if defined(__ICCARM__)
#        define SHORTENUM __packed


@@ 1031,7 1031,9 @@ static inline void convert_16_bit_to_byte_address(uint16_t value, uint8_t *data)
 * @return 16-Bit value
 * @ingroup apiPalApi
 */
static inline uint16_t convert_byte_array_to_16_bit(uint8_t *data) { return (data[0] | ((uint16_t)data[1] << 8)); }
static inline uint16_t convert_byte_array_to_16_bit(uint8_t *data) {
    return (data[0] | ((uint16_t)data[1] << 8));
}

/* Converts a 4 Byte array into a 32-Bit value */
static inline uint32_t convert_byte_array_to_32_bit(uint8_t *data) {

M tmk_core/protocol/arm_atsam/usb/conf_usb.h => tmk_core/protocol/arm_atsam/usb/conf_usb.h +2 -2
@@ 59,7 59,7 @@
#define USB_DEVICE_VENDOR_ID VENDOR_ID
#define USB_DEVICE_PRODUCT_ID PRODUCT_ID
#define USB_DEVICE_VERSION DEVICE_VER
#define USB_DEVICE_POWER 500  // Consumption on Vbus line (mA)
#define USB_DEVICE_POWER 500 // Consumption on Vbus line (mA)
#define USB_DEVICE_ATTR (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_BUS_POWERED)
//                                      (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
//                                      (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)


@@ 161,4 161,4 @@
#include "usb_main.h"
#include "ui.h"

#endif  // _CONF_USB_H_
#endif // _CONF_USB_H_

M tmk_core/protocol/arm_atsam/usb/main_usb.c => tmk_core/protocol/arm_atsam/usb/main_usb.c +36 -12
@@ 25,15 25,25 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

uint8_t keyboard_protocol = 1;

void main_suspend_action(void) { ui_powerdown(); }
void main_suspend_action(void) {
    ui_powerdown();
}

void main_resume_action(void) { ui_wakeup(); }
void main_resume_action(void) {
    ui_wakeup();
}

void main_sof_action(void) { ui_process(udd_get_frame_number()); }
void main_sof_action(void) {
    ui_process(udd_get_frame_number());
}

void main_remotewakeup_enable(void) { ui_wakeup_enable(); }
void main_remotewakeup_enable(void) {
    ui_wakeup_enable();
}

void main_remotewakeup_disable(void) { ui_wakeup_disable(); }
void main_remotewakeup_disable(void) {
    ui_wakeup_disable();
}

volatile bool main_b_kbd_enable = false;
bool          main_kbd_enable(void) {


@@ 41,7 51,9 @@ bool          main_kbd_enable(void) {
    return true;
}

void main_kbd_disable(void) { main_b_kbd_enable = false; }
void main_kbd_disable(void) {
    main_b_kbd_enable = false;
}

#ifdef NKRO_ENABLE
volatile bool main_b_nkro_enable = false;


@@ 50,7 62,9 @@ bool          main_nkro_enable(void) {
    return true;
}

void main_nkro_disable(void) { main_b_nkro_enable = false; }
void main_nkro_disable(void) {
    main_b_nkro_enable = false;
}
#endif

#ifdef EXTRAKEY_ENABLE


@@ 60,7 74,9 @@ bool          main_exk_enable(void) {
    return true;
}

void main_exk_disable(void) { main_b_exk_enable = false; }
void main_exk_disable(void) {
    main_b_exk_enable = false;
}
#endif

#ifdef CONSOLE_ENABLE


@@ 70,7 86,9 @@ bool          main_con_enable(void) {
    return true;
}

void main_con_disable(void) { main_b_con_enable = false; }
void main_con_disable(void) {
    main_b_con_enable = false;
}
#endif

#ifdef MOUSE_ENABLE


@@ 80,7 98,9 @@ bool          main_mou_enable(void) {
    return true;
}

void main_mou_disable(void) { main_b_mou_enable = false; }
void main_mou_disable(void) {
    main_b_mou_enable = false;
}
#endif

#ifdef RAW_ENABLE


@@ 90,7 110,11 @@ bool          main_raw_enable(void) {
    return true;
}

void main_raw_disable(void) { main_b_raw_enable = false; }
void main_raw_disable(void) {
    main_b_raw_enable = false;
}

void main_raw_receive(uint8_t *buffer, uint8_t len) { raw_hid_receive(buffer, len); }
void main_raw_receive(uint8_t *buffer, uint8_t len) {
    raw_hid_receive(buffer, len);
}
#endif

M tmk_core/protocol/arm_atsam/usb/status_codes.h => tmk_core/protocol/arm_atsam/usb/status_codes.h +14 -14
@@ 124,20 124,20 @@ typedef enum status_code status_code_genare_t;
 */
enum status_code_wireless {
    // STATUS_OK               =  0, //!< Success
    ERR_IO_ERROR              = -1,   //!< I/O error
    ERR_FLUSHED               = -2,   //!< Request flushed from queue
    ERR_TIMEOUT               = -3,   //!< Operation timed out
    ERR_BAD_DATA              = -4,   //!< Data integrity check failed
    ERR_PROTOCOL              = -5,   //!< Protocol error
    ERR_UNSUPPORTED_DEV       = -6,   //!< Unsupported device
    ERR_NO_MEMORY             = -7,   //!< Insufficient memory
    ERR_INVALID_ARG           = -8,   //!< Invalid argument
    ERR_BAD_ADDRESS           = -9,   //!< Bad address
    ERR_BUSY                  = -10,  //!< Resource is busy
    ERR_BAD_FORMAT            = -11,  //!< Data format not recognized
    ERR_NO_TIMER              = -12,  //!< No timer available
    ERR_TIMER_ALREADY_RUNNING = -13,  //!< Timer already running
    ERR_TIMER_NOT_RUNNING     = -14,  //!< Timer not running
    ERR_IO_ERROR              = -1,  //!< I/O error
    ERR_FLUSHED               = -2,  //!< Request flushed from queue
    ERR_TIMEOUT               = -3,  //!< Operation timed out
    ERR_BAD_DATA              = -4,  //!< Data integrity check failed
    ERR_PROTOCOL              = -5,  //!< Protocol error
    ERR_UNSUPPORTED_DEV       = -6,  //!< Unsupported device
    ERR_NO_MEMORY             = -7,  //!< Insufficient memory
    ERR_INVALID_ARG           = -8,  //!< Invalid argument
    ERR_BAD_ADDRESS           = -9,  //!< Bad address
    ERR_BUSY                  = -10, //!< Resource is busy
    ERR_BAD_FORMAT            = -11, //!< Data format not recognized
    ERR_NO_TIMER              = -12, //!< No timer available
    ERR_TIMER_ALREADY_RUNNING = -13, //!< Timer already running
    ERR_TIMER_NOT_RUNNING     = -14, //!< Timer not running

    /**
     * \brief Operation in progress

M tmk_core/protocol/arm_atsam/usb/udc.c => tmk_core/protocol/arm_atsam/usb/udc.c +37 -29
@@ 52,7 52,7 @@
#include "udi.h"
#include "udc.h"

#define BOOTLOADER_SERIAL_MAX_SIZE 20  // DO NOT MODIFY!
#define BOOTLOADER_SERIAL_MAX_SIZE 20 // DO NOT MODIFY!

/**
 * \ingroup udc_group


@@ 132,13 132,13 @@ uint8_t     bootloader_serial_number[BOOTLOADER_SERIAL_MAX_SIZE + 1] = "";
static const uint8_t *udc_get_string_serial_name(void) {
#if defined           USB_DEVICE_SERIAL_USE_BOOTLOADER_SERIAL
    uint32_t serial_ptrloc  = (uint32_t)&_srom - 4;
    uint32_t serial_address = *(uint32_t *)serial_ptrloc;  // Address of bootloader's serial number if available
    uint32_t serial_address = *(uint32_t *)serial_ptrloc; // Address of bootloader's serial number if available

    if (serial_address != 0xFFFFFFFF && serial_address < serial_ptrloc)  // Check for factory programmed serial address
    if (serial_address != 0xFFFFFFFF && serial_address < serial_ptrloc) // Check for factory programmed serial address
    {
        if ((serial_address & 0xFF) % 4 == 0)  // Check alignment
        if ((serial_address & 0xFF) % 4 == 0) // Check alignment
        {
            uint16_t *serial_use    = (uint16_t *)(serial_address);  // Point to address of string in rom
            uint16_t *serial_use    = (uint16_t *)(serial_address); // Point to address of string in rom
            uint8_t   serial_length = 0;

            while ((*(serial_use + serial_length) > 32 && *(serial_use + serial_length) < 127) && serial_length < BOOTLOADER_SERIAL_MAX_SIZE) {


@@ 149,7 149,7 @@ static const uint8_t *udc_get_string_serial_name(void) {

            usb_device_serial_name_size = serial_length;

            return bootloader_serial_number;  // Use serial programmed into bootloader rom
            return bootloader_serial_number; // Use serial programmed into bootloader rom
        }
    }
#endif


@@ 157,9 157,9 @@ static const uint8_t *udc_get_string_serial_name(void) {
    usb_device_serial_name_size = USB_DEVICE_SERIAL_NAME_SIZE;

#if defined USB_DEVICE_SERIAL_NAME
    return (const uint8_t *)USB_DEVICE_SERIAL_NAME;  // Use serial supplied by keyboard's config.h
    return (const uint8_t *)USB_DEVICE_SERIAL_NAME; // Use serial supplied by keyboard's config.h
#else
    return 0;  // No serial supplied
    return 0; // No serial supplied
#endif
}



@@ 169,7 169,7 @@ static const uint8_t *udc_get_string_serial_name(void) {
 */
#ifndef BOOTLOADER_SERIAL_MAX_SIZE
#    define BOOTLOADER_SERIAL_MAX_SIZE 0
#endif  // BOOTLOADER_SERIAL_MAX_SIZE
#endif // BOOTLOADER_SERIAL_MAX_SIZE
struct udc_string_desc_t {
    usb_str_desc_t header;
    le16_t         string[Max(Max(Max(USB_DEVICE_MANUFACTURE_NAME_SIZE, USB_DEVICE_PRODUCT_NAME_SIZE), USB_DEVICE_SERIAL_NAME_SIZE), BOOTLOADER_SERIAL_MAX_SIZE)];


@@ 178,14 178,18 @@ COMPILER_WORD_ALIGNED
static UDC_DESC_STORAGE struct udc_string_desc_t udc_string_desc = {.header.bDescriptorType = USB_DT_STRING};
//! @}

usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void) { return udc_ptr_iface; }
usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void) {
    return udc_ptr_iface;
}

/**
 * \brief Returns a value to check the end of USB Configuration descriptor
 *
 * \return address after the last byte of USB Configuration descriptor
 */
static usb_conf_desc_t UDC_DESC_STORAGE *udc_get_eof_conf(void) { return (UDC_DESC_STORAGE usb_conf_desc_t *)((uint8_t *)udc_ptr_conf->desc + le16_to_cpu(udc_ptr_conf->desc->wTotalLength)); }
static usb_conf_desc_t UDC_DESC_STORAGE *udc_get_eof_conf(void) {
    return (UDC_DESC_STORAGE usb_conf_desc_t *)((uint8_t *)udc_ptr_conf->desc + le16_to_cpu(udc_ptr_conf->desc->wTotalLength));
}

#if (0 != USB_DEVICE_MAX_EP)
/**


@@ 209,15 213,15 @@ static usb_conf_desc_t UDC_DESC_STORAGE *udc_next_desc_in_iface(usb_conf_desc_t 
        // If new interface descriptor is found,
        // then it is the end of the current global interface descriptor
        if (USB_DT_INTERFACE == desc->bDescriptorType) {
            break;  // End of global interface descriptor
            break; // End of global interface descriptor
        }
        if (desc_id == desc->bDescriptorType) {
            return desc;  // Specific descriptor found
            return desc; // Specific descriptor found
        }
        // Go to next descriptor
        desc = (UDC_DESC_STORAGE usb_conf_desc_t *)((uint8_t *)desc + desc->bLength);
    }
    return NULL;  // No specific descriptor found
    return NULL; // No specific descriptor found
}
#endif



@@ 251,13 255,13 @@ static bool udc_update_iface_desc(uint8_t iface_num, uint8_t setting_num) {
            // A interface descriptor is found
            // Check interface and alternate setting number
            if ((iface_num == udc_ptr_iface->bInterfaceNumber) && (setting_num == udc_ptr_iface->bAlternateSetting)) {
                return true;  // Interface found
                return true; // Interface found
            }
        }
        // Go to next descriptor
        udc_ptr_iface = (UDC_DESC_STORAGE usb_iface_desc_t *)((uint8_t *)udc_ptr_iface + udc_ptr_iface->bLength);
    }
    return false;  // Interface not found
    return false; // Interface not found
}

/**


@@ 343,7 347,9 @@ static bool udc_iface_enable(uint8_t iface_num, uint8_t setting_num) {

/*! \brief Start the USB Device stack
 */
void udc_start(void) { udd_enable(); }
void udc_start(void) {
    udd_enable();
}

/*! \brief Stop the USB Device stack
 */


@@ 510,7 516,7 @@ static bool udc_req_std_dev_set_feature(void) {
                    udd_g_ctrlreq.callback = udd_test_mode_packet;
                    return true;

                case USB_DEV_TEST_MODE_FORCE_ENABLE:  // Only for downstream facing hub ports
                case USB_DEV_TEST_MODE_FORCE_ENABLE: // Only for downstream facing hub ports
                default:
                    break;
            }


@@ 544,7 550,9 @@ static bool udc_req_std_ep_set_feature(void) {
 * \brief Change the address of device
 * Callback called at the end of request set address
 */
static void udc_valid_address(void) { udd_set_address(udd_g_ctrlreq.req.wValue & 0x7F); }
static void udc_valid_address(void) {
    udd_set_address(udd_g_ctrlreq.req.wValue & 0x7F);
}

/**
 * \brief Standard device request to set device address


@@ 763,7 771,7 @@ static bool udc_req_std_dev_set_configuration(void) {
    // Enable new configuration
    udc_num_configuration = udd_g_ctrlreq.req.wValue & 0xFF;
    if (udc_num_configuration == 0) {
        return true;  // Default empty configuration requested
        return true; // Default empty configuration requested
    }
    // Update pointer of the configuration descriptor
#ifdef USB_DEVICE_HS_SUPPORT


@@ 796,10 804,10 @@ static bool udc_req_std_iface_get_setting(void) {
    udi_api_t UDC_DESC_STORAGE *udi_api;

    if (udd_g_ctrlreq.req.wLength != 1) {
        return false;  // Error in request
        return false; // Error in request
    }
    if (!udc_num_configuration) {
        return false;  // The device is not is configured state yet
        return false; // The device is not is configured state yet
    }

    // Check the interface number included in the request


@@ 832,10 840,10 @@ static bool udc_req_std_iface_set_setting(void) {
    uint8_t iface_num, setting_num;

    if (udd_g_ctrlreq.req.wLength) {
        return false;  // Error in request
        return false; // Error in request
    }
    if (!udc_num_configuration) {
        return false;  // The device is not is configured state yet
        return false; // The device is not is configured state yet
    }

    iface_num   = udd_g_ctrlreq.req.wIndex & 0xFF;


@@ 859,7 867,7 @@ static bool udc_reqstd(void) {
    if (Udd_setup_is_in()) {
        // GET Standard Requests
        if (udd_g_ctrlreq.req.wLength == 0) {
            return false;  // Error for USB host
            return false; // Error for USB host
        }

        if (USB_REQ_RECIP_DEVICE == Udd_setup_recipient()) {


@@ 953,7 961,7 @@ static bool udc_req_iface(void) {
    udi_api_t UDC_DESC_STORAGE *udi_api;

    if (0 == udc_num_configuration) {
        return false;  // The device is not is configured state yet
        return false; // The device is not is configured state yet
    }
    // Check interface number
    iface_num = udd_g_ctrlreq.req.wIndex & 0xFF;


@@ 987,7 995,7 @@ static bool udc_req_ep(void) {
    udi_api_t UDC_DESC_STORAGE *udi_api;

    if (0 == udc_num_configuration) {
        return false;  // The device is not is configured state yet
        return false; // The device is not is configured state yet
    }
    // Send this request on all enabled interfaces
    iface_num = udd_g_ctrlreq.req.wIndex & 0xFF;


@@ 1027,7 1035,7 @@ bool udc_process_setup(void) {

    if (Udd_setup_is_in()) {
        if (udd_g_ctrlreq.req.wLength == 0) {
            return false;  // Error from USB host
            return false; // Error from USB host
        }
    }



@@ 1055,7 1063,7 @@ bool udc_process_setup(void) {
    // Here SETUP request unknown by UDC and UDIs
#ifdef USB_DEVICE_SPECIFIC_REQUEST
    // Try to decode it in specific callback
    return USB_DEVICE_SPECIFIC_REQUEST();  // Ex: Vendor request,...
    return USB_DEVICE_SPECIFIC_REQUEST(); // Ex: Vendor request,...
#else
    return false;
#endif

M tmk_core/protocol/arm_atsam/usb/udc.h => tmk_core/protocol/arm_atsam/usb/udc.h +13 -5
@@ 172,7 172,9 @@ extern "C" {
    }
\endcode
 */
static inline bool udc_include_vbus_monitoring(void) { return udd_include_vbus_monitoring(); }
static inline bool udc_include_vbus_monitoring(void) {
    return udd_include_vbus_monitoring();
}

/*! \brief Start the USB Device stack
 */


@@ 189,19 191,25 @@ void udc_stop(void);
 * then it will attach device when an acceptable Vbus
 * level from the host is detected.
 */
static inline void udc_attach(void) { udd_attach(); }
static inline void udc_attach(void) {
    udd_attach();
}

/**
 * \brief Detaches the device from the bus
 *
 * The driver must remove pull-up on USB line D- or D+.
 */
static inline void udc_detach(void) { udd_detach(); }
static inline void udc_detach(void) {
    udd_detach();
}

/*! \brief The USB driver sends a resume signal called \e "Upstream Resume"
 * This is authorized only when the remote wakeup feature is enabled by host.
 */
inline void udc_remotewakeup(void) { udd_send_remotewakeup(); }
inline void udc_remotewakeup(void) {
    udd_send_remotewakeup();
}

/**
 * \brief Returns a pointer on the current interface descriptor


@@ 245,4 253,4 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void);
}
#endif

#endif  // _UDC_H_
#endif // _UDC_H_

M tmk_core/protocol/arm_atsam/usb/udc_desc.h => tmk_core/protocol/arm_atsam/usb/udc_desc.h +1 -1
@@ 129,4 129,4 @@ extern UDC_DESC_STORAGE udc_config_t udc_config;
#ifdef __cplusplus
}
#endif
#endif  // _UDC_DESC_H_
#endif // _UDC_DESC_H_

M tmk_core/protocol/arm_atsam/usb/udd.h => tmk_core/protocol/arm_atsam/usb/udd.h +1 -1
@@ 381,4 381,4 @@ extern void udc_sof_notify(void);
#ifdef __cplusplus
}
#endif
#endif  // _UDD_H_
#endif // _UDD_H_

M tmk_core/protocol/arm_atsam/usb/udi.h => tmk_core/protocol/arm_atsam/usb/udi.h +1 -1
@@ 130,4 130,4 @@ typedef struct {
#ifdef __cplusplus
}
#endif
#endif  // _UDI_H_
#endif // _UDI_H_

M tmk_core/protocol/arm_atsam/usb/udi_cdc.c => tmk_core/protocol/arm_atsam/usb/udi_cdc.c +105 -53
@@ 386,7 386,7 @@ bool udi_cdc_comm_setup(void) {
            switch (udd_g_ctrlreq.req.bRequest) {
                case USB_REQ_CDC_GET_LINE_CODING:
                    // Get configuration of CDC line
                    if (sizeof(usb_cdc_line_coding_t) != udd_g_ctrlreq.req.wLength) return false;  // Error for USB host
                    if (sizeof(usb_cdc_line_coding_t) != udd_g_ctrlreq.req.wLength) return false; // Error for USB host
                    udd_g_ctrlreq.payload      = (uint8_t *)&udi_cdc_line_coding[port];
                    udd_g_ctrlreq.payload_size = sizeof(usb_cdc_line_coding_t);
                    return true;


@@ 400,7 400,7 @@ bool udi_cdc_comm_setup(void) {
            switch (udd_g_ctrlreq.req.bRequest) {
                case USB_REQ_CDC_SET_LINE_CODING:
                    // Change configuration of CDC line
                    if (sizeof(usb_cdc_line_coding_t) != udd_g_ctrlreq.req.wLength) return false;  // Error for USB host
                    if (sizeof(usb_cdc_line_coding_t) != udd_g_ctrlreq.req.wLength) return false; // Error for USB host
                    udd_g_ctrlreq.callback     = udi_cdc_line_coding_received;
                    udd_g_ctrlreq.payload      = (uint8_t *)&udi_cdc_line_coding[port];
                    udd_g_ctrlreq.payload_size = sizeof(usb_cdc_line_coding_t);


@@ 417,15 417,15 @@ bool udi_cdc_comm_setup(void) {
            }
        }
    }
    return false;  // request Not supported
    return false; // request Not supported
}

bool udi_cdc_data_setup(void) {
    return false;  // request Not supported
    return false; // request Not supported
}

uint8_t udi_cdc_getsetting(void) {
    return 0;  // CDC don't have multiple alternate setting
    return 0; // CDC don't have multiple alternate setting
}

void udi_cdc_data_sof_notify(void) {


@@ 476,7 476,7 @@ static void udi_cdc_line_coding_received(void) {

static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask) {
    udd_ep_id_t ep_comm;
    uint32_t    irqflags;  // irqflags_t
    uint32_t    irqflags; // irqflags_t

    //#if UDI_CDC_PORT_NB == 1 // To optimize code
    port = 0;


@@ 514,7 514,7 @@ static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask)
}

static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep) {
#    if UDI_CDC_PORT_NB == 1  // To optimize code
#    if UDI_CDC_PORT_NB == 1 // To optimize code
    port = 0;
#    endif



@@ 562,7 562,7 @@ static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n,
//------- Internal routines to process data transfer

static bool udi_cdc_rx_start(uint8_t port) {
    uint32_t    irqflags;  // irqflags_t
    uint32_t    irqflags; // irqflags_t
    uint8_t     buf_sel_trans;
    udd_ep_id_t ep;



@@ 685,7 685,7 @@ static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t
}

static void udi_cdc_tx_send(uint8_t port) {
    uint32_t        irqflags;  // irqflags_t
    uint32_t        irqflags; // irqflags_t
    uint8_t         buf_sel_trans;
    bool            b_short_packet;
    udd_ep_id_t     ep;


@@ 696,15 696,15 @@ static void udi_cdc_tx_send(uint8_t port) {
    //#endif

    if (udi_cdc_tx_trans_ongoing[port]) {
        return;  // Already on going or wait next SOF to send next data
        return; // Already on going or wait next SOF to send next data
    }
    if (udd_is_high_speed()) {
        if (udi_cdc_tx_sof_num[port] == udd_get_micro_frame_number()) {
            return;  // Wait next SOF to send next data
            return; // Wait next SOF to send next data
        }
    } else {
        if (udi_cdc_tx_sof_num[port] == udd_get_frame_number()) {
            return;  // Wait next SOF to send next data
            return; // Wait next SOF to send next data
        }
    }



@@ 743,7 743,7 @@ static void udi_cdc_tx_send(uint8_t port) {
            udi_cdc_tx_sof_num[port] = udd_get_frame_number();
        }
    } else {
        udi_cdc_tx_sof_num[port] = 0;  // Force next transfer without wait SOF
        udi_cdc_tx_sof_num[port] = 0; // Force next transfer without wait SOF
    }

    /*


@@ 768,28 768,48 @@ static void udi_cdc_tx_send(uint8_t port) {
//---------------------------------------------
//------- Application interface

void udi_cdc_ctrl_signal_dcd(bool b_set) { udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD); }
void udi_cdc_ctrl_signal_dcd(bool b_set) {
    udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD);
}

void udi_cdc_ctrl_signal_dsr(bool b_set) { udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR); }
void udi_cdc_ctrl_signal_dsr(bool b_set) {
    udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR);
}

void udi_cdc_signal_framing_error(void) { udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING); }
void udi_cdc_signal_framing_error(void) {
    udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING);
}

void udi_cdc_signal_parity_error(void) { udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY); }
void udi_cdc_signal_parity_error(void) {
    udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY);
}

void udi_cdc_signal_overrun(void) { udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN); }
void udi_cdc_signal_overrun(void) {
    udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN);
}

void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set) { udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD); }
void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set) {
    udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD);
}

void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set) { udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR); }
void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set) {
    udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR);
}

void udi_cdc_multi_signal_framing_error(uint8_t port) { udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING); }
void udi_cdc_multi_signal_framing_error(uint8_t port) {
    udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING);
}

void udi_cdc_multi_signal_parity_error(uint8_t port) { udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY); }
void udi_cdc_multi_signal_parity_error(uint8_t port) {
    udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY);
}

void udi_cdc_multi_signal_overrun(uint8_t port) { udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN); }
void udi_cdc_multi_signal_overrun(uint8_t port) {
    udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN);
}

iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port) {
    uint32_t    irqflags;  // irqflags_t
    uint32_t    irqflags; // irqflags_t
    uint16_t    pos;
    iram_size_t nb_received;



@@ 807,14 827,20 @@ iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port) {
    return nb_received;
}

iram_size_t udi_cdc_get_nb_received_data(void) { return udi_cdc_multi_get_nb_received_data(0); }
iram_size_t udi_cdc_get_nb_received_data(void) {
    return udi_cdc_multi_get_nb_received_data(0);
}

bool udi_cdc_multi_is_rx_ready(uint8_t port) { return (udi_cdc_multi_get_nb_received_data(port) > 0); }
bool udi_cdc_multi_is_rx_ready(uint8_t port) {
    return (udi_cdc_multi_get_nb_received_data(port) > 0);
}

bool udi_cdc_is_rx_ready(void) { return udi_cdc_multi_is_rx_ready(0); }
bool udi_cdc_is_rx_ready(void) {
    return udi_cdc_multi_is_rx_ready(0);
}

int udi_cdc_multi_getc(uint8_t port) {
    uint32_t irqflags;  // irqflags_t
    uint32_t irqflags; // irqflags_t
    int      rx_data = 0;
    bool     b_databit_9;
    uint16_t pos;


@@ 859,10 885,12 @@ udi_cdc_getc_process_one_byte:
    return rx_data;
}

int udi_cdc_getc(void) { return udi_cdc_multi_getc(0); }
int udi_cdc_getc(void) {
    return udi_cdc_multi_getc(0);
}

iram_size_t udi_cdc_multi_read_buf(uint8_t port, void *buf, iram_size_t size) {
    uint32_t    irqflags;  // irqflags_t
    uint32_t    irqflags; // irqflags_t
    uint8_t *   ptr_buf = (uint8_t *)buf;
    iram_size_t copy_nb;
    uint16_t    pos;


@@ 912,7 940,7 @@ static iram_size_t udi_cdc_multi_read_no_polling(uint8_t port, void *buf, iram_s
    iram_size_t nb_avail_data;
    uint16_t    pos;
    uint8_t     buf_sel;
    uint32_t    irqflags;  // irqflags_t
    uint32_t    irqflags; // irqflags_t

    //#if UDI_CDC_PORT_NB == 1 // To optimize code
    port = 0;


@@ 952,12 980,16 @@ static iram_size_t udi_cdc_multi_read_no_polling(uint8_t port, void *buf, iram_s
    return (nb_avail_data);
}

iram_size_t udi_cdc_read_no_polling(void *buf, iram_size_t size) { return udi_cdc_multi_read_no_polling(0, buf, size); }
iram_size_t udi_cdc_read_no_polling(void *buf, iram_size_t size) {
    return udi_cdc_multi_read_no_polling(0, buf, size);
}

iram_size_t udi_cdc_read_buf(void *buf, iram_size_t size) { return udi_cdc_multi_read_buf(0, buf, size); }
iram_size_t udi_cdc_read_buf(void *buf, iram_size_t size) {
    return udi_cdc_multi_read_buf(0, buf, size);
}

iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port) {
    uint32_t    irqflags;  // irqflags_t
    uint32_t    irqflags; // irqflags_t
    iram_size_t buf_sel_nb, retval;
    uint8_t     buf_sel;



@@ 986,14 1018,20 @@ iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port) {
    return retval;
}

iram_size_t udi_cdc_get_free_tx_buffer(void) { return udi_cdc_multi_get_free_tx_buffer(0); }
iram_size_t udi_cdc_get_free_tx_buffer(void) {
    return udi_cdc_multi_get_free_tx_buffer(0);
}

bool udi_cdc_multi_is_tx_ready(uint8_t port) { return (udi_cdc_multi_get_free_tx_buffer(port) != 0); }
bool udi_cdc_multi_is_tx_ready(uint8_t port) {
    return (udi_cdc_multi_get_free_tx_buffer(port) != 0);
}

bool udi_cdc_is_tx_ready(void) { return udi_cdc_multi_is_tx_ready(0); }
bool udi_cdc_is_tx_ready(void) {
    return udi_cdc_multi_is_tx_ready(0);
}

int udi_cdc_multi_putc(uint8_t port, int value) {
    uint32_t irqflags;  // irqflags_t
    uint32_t irqflags; // irqflags_t
    bool     b_databit_9;
    uint8_t  buf_sel;



@@ 1030,10 1068,12 @@ udi_cdc_putc_process_one_byte:
    return true;
}

int udi_cdc_putc(int value) { return udi_cdc_multi_putc(0, value); }
int udi_cdc_putc(int value) {
    return udi_cdc_multi_putc(0, value);
}

iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void *buf, iram_size_t size) {
    uint32_t    irqflags;  // irqflags_t
    uint32_t    irqflags; // irqflags_t
    uint8_t     buf_sel;
    uint16_t    buf_nb;
    iram_size_t copy_nb;


@@ 1083,7 1123,9 @@ udi_cdc_write_buf_loop_wait:
    return 0;
}

iram_size_t udi_cdc_write_buf(const void *buf, iram_size_t size) { return udi_cdc_multi_write_buf(0, buf, size); }
iram_size_t udi_cdc_write_buf(const void *buf, iram_size_t size) {
    return udi_cdc_multi_write_buf(0, buf, size);
}

#    define MAX_PRINT 256
#    define CDC_SEND_INTERVAL 2


@@ 1121,10 1163,10 @@ uint32_t CDC_print(char *printbuf) {
char printbuf[CDC_PRINTBUF_SIZE];

int CDC_printf(const char *_Format, ...) {
    va_list va;  // Variable argument list variable
    va_list va; // Variable argument list variable
    int     result;

    va_start(va, _Format);  // Initialize the variable argument list
    va_start(va, _Format); // Initialize the variable argument list
    result = vsnprintf(printbuf, CDC_PRINTBUF_SIZE, _Format, va);
    va_end(va);



@@ 1146,18 1188,18 @@ uint32_t CDC_input_buf(inbuf_t inbuf, uint32_t inbuf_size) {

    if (RXChar) {
        switch (RXChar) {
            case '\t':  // tab - repeat last
            case '\t': // tab - repeat last
                inbuf.count                = inbuf.lastcount;
                inbuf.buf[inbuf.count + 1] = 0;
                CDC_print(inbuf.buf);
                break;
            case '\r':  // enter
            case '\r': // enter
                inbuf.buf[inbuf.count] = 0;
                inbuf.lastcount        = inbuf.count;
                inbuf.count            = 0;
                entered                = 1;
                break;
            case '\b':  // backspace
            case '\b': // backspace
                if (inbuf.count > 0) {
                    inbuf.count -= 1;
                    CDC_print("\b \b\0");


@@ 1181,7 1223,9 @@ uint32_t CDC_input_buf(inbuf_t inbuf, uint32_t inbuf_size) {
    return entered;
}

uint32_t CDC_input() { return CDC_input_buf(inbuf, CDC_INBUF_SIZE); }
uint32_t CDC_input() {
    return CDC_input_buf(inbuf, CDC_INBUF_SIZE);
}

void CDC_init(void) {
    inbuf.count           = 0;


@@ 1190,19 1234,27 @@ void CDC_init(void) {
    cdc_tx_send_time_next = timer_read64() + CDC_SEND_INTERVAL;
}

#else  // CDC line 62
#else // CDC line 62

char printbuf[CDC_PRINTBUF_SIZE];

void CDC_send(void) { return; }
void CDC_send(void) {
    return;
}

uint32_t CDC_print(char *printbuf) { return 0; }
uint32_t CDC_print(char *printbuf) {
    return 0;
}

int CDC_printf(const char *_Format, ...) { return 0; }
int CDC_printf(const char *_Format, ...) {
    return 0;
}

inbuf_t inbuf;

uint32_t CDC_input(void) { return 0; }
uint32_t CDC_input(void) {
    return 0;
}

void CDC_init(void) {
    inbuf.count     = 0;


@@ 1210,6 1262,6 @@ void CDC_init(void) {
    printbuf[0]     = 0;
}

#endif  // CDC line 62
#endif // CDC line 62

//@}

M tmk_core/protocol/arm_atsam/usb/udi_cdc.h => tmk_core/protocol/arm_atsam/usb/udi_cdc.h +3 -3
@@ 346,7 346,7 @@ typedef struct {
    char     buf[CDC_INBUF_SIZE];
} inbuf_t;

#else  // VIRTSER_ENABLE
#else // VIRTSER_ENABLE

// keep these to accommodate calls if remaining
#    define CDC_PRINTBUF_SIZE 1


@@ 362,7 362,7 @@ typedef struct {

extern inbuf_t inbuf;

#endif  // VIRTSER_ENABLE
#endif // VIRTSER_ENABLE

uint32_t CDC_print(char* printbuf);
int      CDC_printf(const char* _Format, ...);


@@ 373,4 373,4 @@ void     CDC_init(void);
}
#endif

#endif  // _UDI_CDC_H_
#endif // _UDI_CDC_H_

M tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h => tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h +4 -4
@@ 59,9 59,9 @@
extern "C" {
#endif

#define UDI_CDC_DATA_EP_IN_0 ((CDC_TX_ENDPOINT) | (USB_EP_DIR_IN))    // TX
#define UDI_CDC_DATA_EP_OUT_0 ((CDC_RX_ENDPOINT) | (USB_EP_DIR_OUT))  // RX
#define UDI_CDC_COMM_EP_0 ((CDC_ACM_ENDPOINT) | (USB_EP_DIR_IN))      // Notify endpoint
#define UDI_CDC_DATA_EP_IN_0 ((CDC_TX_ENDPOINT) | (USB_EP_DIR_IN))   // TX
#define UDI_CDC_DATA_EP_OUT_0 ((CDC_RX_ENDPOINT) | (USB_EP_DIR_OUT)) // RX
#define UDI_CDC_COMM_EP_0 ((CDC_ACM_ENDPOINT) | (USB_EP_DIR_IN))     // Notify endpoint

#define UDI_CDC_COMM_IFACE_NUMBER_0 (CDC_STATUS_INTERFACE)
#define UDI_CDC_DATA_IFACE_NUMBER_0 (CDC_DATA_INTERFACE)


@@ 69,4 69,4 @@ extern "C" {
#ifdef __cplusplus
}
#endif
#endif  // _UDI_CDC_CONF_H_
#endif // _UDI_CDC_CONF_H_

M tmk_core/protocol/arm_atsam/usb/udi_device_conf.h => tmk_core/protocol/arm_atsam/usb/udi_device_conf.h +10 -10
@@ 220,7 220,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#    define NEXT_OUT_EPNUM_4 (CDC_OUT_EPNUM + 1)

#    define CDC_ACM_SIZE CDC_NOTIFICATION_EPSIZE
#    define CDC_RX_SIZE CDC_EPSIZE  // KFSMOD was 64
#    define CDC_RX_SIZE CDC_EPSIZE // KFSMOD was 64
#    define CDC_TX_SIZE CDC_RX_SIZE
#    define CDC_ACM_POLLING_INTERVAL 255
#    define CDC_EP_INTERVAL_STATUS CDC_ACM_POLLING_INTERVAL


@@ 370,7 370,7 @@ extern udi_hid_exk_report_t udi_hid_exk_report;

COMPILER_PACK_RESET()

#endif  // EXTRAKEY_ENABLE
#endif // EXTRAKEY_ENABLE

// **********************************************************************
// NKRO Descriptor structure and content


@@ 433,7 433,7 @@ extern uint8_t udi_hid_nkro_report[UDI_HID_NKRO_REPORT_SIZE];

COMPILER_PACK_RESET()

#endif  // NKRO_ENABLE
#endif // NKRO_ENABLE

// **********************************************************************
// MOU Descriptor structure and content


@@ 449,7 449,7 @@ typedef struct {
} udi_hid_mou_desc_t;

typedef struct {
    uint8_t array[77];  // MOU PDS
    uint8_t array[77]; // MOU PDS
} udi_hid_mou_report_desc_t;

// clang-format off


@@ 488,12 488,12 @@ typedef struct {
// clang-format on

// report buffer
#    define UDI_HID_MOU_REPORT_SIZE 5  // MOU PDS
#    define UDI_HID_MOU_REPORT_SIZE 5 // MOU PDS
extern uint8_t udi_hid_mou_report[UDI_HID_MOU_REPORT_SIZE];

COMPILER_PACK_RESET()

#endif  // MOUSE_ENABLE
#endif // MOUSE_ENABLE

// **********************************************************************
// RAW Descriptor structure and content


@@ 565,7 565,7 @@ extern uint8_t udi_hid_raw_report[UDI_HID_RAW_REPORT_SIZE];

COMPILER_PACK_RESET()

#endif  // RAW_ENABLE
#endif // RAW_ENABLE

// **********************************************************************
// CON Descriptor structure and content


@@ 637,7 637,7 @@ extern uint8_t udi_hid_con_report[UDI_HID_CON_REPORT_SIZE];

COMPILER_PACK_RESET()

#endif  // CONSOLE_ENABLE
#endif // CONSOLE_ENABLE

// **********************************************************************
// CDC Descriptor structure and content


@@ 780,7 780,7 @@ typedef struct {

COMPILER_PACK_RESET()

#endif  // VIRTSER_ENABLE
#endif // VIRTSER_ENABLE

// **********************************************************************
// CONFIGURATION Descriptor structure and content


@@ 815,4 815,4 @@ typedef struct {

COMPILER_PACK_RESET()

#endif  //_UDI_DEVICE_CONF_H_
#endif //_UDI_DEVICE_CONF_H_

M tmk_core/protocol/arm_atsam/usb/udi_device_epsize.h => tmk_core/protocol/arm_atsam/usb/udi_device_epsize.h +1 -1
@@ 28,4 28,4 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define CDC_NOTIFICATION_EPSIZE 8
#define CDC_EPSIZE 16

#endif  //_UDI_DEVICE_EPSIZE_H_
#endif //_UDI_DEVICE_EPSIZE_H_

M tmk_core/protocol/arm_atsam/usb/udi_hid.c => tmk_core/protocol/arm_atsam/usb/udi_hid.c +1 -1
@@ 110,7 110,7 @@ bool udi_hid_setup(uint8_t *rate, uint8_t *protocol, uint8_t *report_desc, bool 
            }
        }
    }
    return false;  // Request not supported
    return false; // Request not supported
}

//---------------------------------------------

M tmk_core/protocol/arm_atsam/usb/udi_hid.h => tmk_core/protocol/arm_atsam/usb/udi_hid.h +1 -1
@@ 82,4 82,4 @@ bool udi_hid_setup(uint8_t *rate, uint8_t *protocol, uint8_t *report_desc, bool 
#ifdef __cplusplus
}
#endif
#endif  // _UDI_HID_H_
#endif // _UDI_HID_H_

M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c => tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c +79 -67
@@ 94,42 94,42 @@ static uint8_t udi_hid_kbd_report_trans[UDI_HID_KBD_REPORT_SIZE];

COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_kbd_report_desc_t udi_hid_kbd_report_desc = {{
    0x05, 0x01,  // Usage Page (Generic Desktop)
    0x09, 0x06,  // Usage (Keyboard)
    0xA1, 0x01,  // Collection (Application)
    0x05, 0x01, // Usage Page (Generic Desktop)
    0x09, 0x06, // Usage (Keyboard)
    0xA1, 0x01, // Collection (Application)
    // Modifiers (8 bits)
    0x05, 0x07,  //   Usage Page (Keyboard)
    0x19, 0xE0,  //   Usage Minimum (Keyboard Left Control)
    0x29, 0xE7,  //   Usage Maximum (Keyboard Right GUI)
    0x15, 0x00,  //   Logical Minimum (0)
    0x25, 0x01,  //   Logical Maximum (1)
    0x95, 0x08,  //   Report Count (8)
    0x75, 0x01,  //   Report Size (1)
    0x81, 0x02,  //   Input (Data, Variable, Absolute)
    0x05, 0x07, //   Usage Page (Keyboard)
    0x19, 0xE0, //   Usage Minimum (Keyboard Left Control)
    0x29, 0xE7, //   Usage Maximum (Keyboard Right GUI)
    0x15, 0x00, //   Logical Minimum (0)
    0x25, 0x01, //   Logical Maximum (1)
    0x95, 0x08, //   Report Count (8)
    0x75, 0x01, //   Report Size (1)
    0x81, 0x02, //   Input (Data, Variable, Absolute)
    // Reserved (1 byte)
    0x81, 0x01,  //   Input (Constant)
    0x81, 0x01, //   Input (Constant)
    // Keycodes (6 bytes)
    0x19, 0x00,  //   Usage Minimum (0)
    0x29, 0xFF,  //   Usage Maximum (255)
    0x15, 0x00,  //   Logical Minimum (0)
    0x25, 0xFF,  //   Logical Maximum (255)
    0x95, 0x06,  //   Report Count (6)
    0x75, 0x08,  //   Report Size (8)
    0x81, 0x00,  //   Input (Data, Array, Absolute)
    0x19, 0x00, //   Usage Minimum (0)
    0x29, 0xFF, //   Usage Maximum (255)
    0x15, 0x00, //   Logical Minimum (0)
    0x25, 0xFF, //   Logical Maximum (255)
    0x95, 0x06, //   Report Count (6)
    0x75, 0x08, //   Report Size (8)
    0x81, 0x00, //   Input (Data, Array, Absolute)

    // Status LEDs (5 bits)
    0x05, 0x08,  //   Usage Page (LED)
    0x19, 0x01,  //   Usage Minimum (Num Lock)
    0x29, 0x05,  //   Usage Maximum (Kana)
    0x15, 0x00,  //   Logical Minimum (0)
    0x25, 0x01,  //   Logical Maximum (1)
    0x95, 0x05,  //   Report Count (5)
    0x75, 0x01,  //   Report Size (1)
    0x91, 0x02,  //   Output (Data, Variable, Absolute)
    0x05, 0x08, //   Usage Page (LED)
    0x19, 0x01, //   Usage Minimum (Num Lock)
    0x29, 0x05, //   Usage Maximum (Kana)
    0x15, 0x00, //   Logical Minimum (0)
    0x25, 0x01, //   Logical Maximum (1)
    0x95, 0x05, //   Report Count (5)
    0x75, 0x01, //   Report Size (1)
    0x91, 0x02, //   Output (Data, Variable, Absolute)
    // LED padding (3 bits)
    0x95, 0x03,  //   Report Count (3)
    0x91, 0x01,  //   Output (Constant)
    0xC0         // End Collection
    0x95, 0x03, //   Report Count (3)
    0x91, 0x01, //   Output (Constant)
    0xC0        // End Collection
}};

static bool udi_hid_kbd_setreport(void);


@@ 148,11 148,17 @@ bool udi_hid_kbd_enable(void) {
    return UDI_HID_KBD_ENABLE_EXT();
}

void udi_hid_kbd_disable(void) { UDI_HID_KBD_DISABLE_EXT(); }
void udi_hid_kbd_disable(void) {
    UDI_HID_KBD_DISABLE_EXT();
}

bool udi_hid_kbd_setup(void) { return udi_hid_setup(&udi_hid_kbd_rate, &udi_hid_kbd_protocol, (uint8_t *)&udi_hid_kbd_report_desc, udi_hid_kbd_setreport); }
bool udi_hid_kbd_setup(void) {
    return udi_hid_setup(&udi_hid_kbd_rate, &udi_hid_kbd_protocol, (uint8_t *)&udi_hid_kbd_report_desc, udi_hid_kbd_setreport);
}

uint8_t udi_hid_kbd_getsetting(void) { return 0; }
uint8_t udi_hid_kbd_getsetting(void) {
    return 0;
}

static bool udi_hid_kbd_setreport(void) {
    if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8)) && (0 == (0xFF & udd_g_ctrlreq.req.wValue)) && (1 == udd_g_ctrlreq.req.wLength)) {


@@ 234,41 240,41 @@ static uint8_t udi_hid_nkro_report_trans[UDI_HID_NKRO_REPORT_SIZE];

COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_nkro_report_desc_t udi_hid_nkro_report_desc = {{
    0x05, 0x01,  // Usage Page (Generic Desktop)
    0x09, 0x06,  // Usage (Keyboard)
    0xA1, 0x01,  // Collection (Application)
    0x05, 0x01, // Usage Page (Generic Desktop)
    0x09, 0x06, // Usage (Keyboard)
    0xA1, 0x01, // Collection (Application)

    // Modifiers (8 bits)
    0x05, 0x07,  //   Usage Page (Keyboard/Keypad)
    0x19, 0xE0,  //   Usage Minimum (Keyboard Left Control)
    0x29, 0xE7,  //   Usage Maximum (Keyboard Right GUI)
    0x15, 0x00,  //   Logical Minimum (0)
    0x25, 0x01,  //   Logical Maximum (1)
    0x95, 0x08,  //   Report Count (8)
    0x75, 0x01,  //   Report Size (1)
    0x81, 0x02,  //   Input (Data, Variable, Absolute)
    0x05, 0x07, //   Usage Page (Keyboard/Keypad)
    0x19, 0xE0, //   Usage Minimum (Keyboard Left Control)
    0x29, 0xE7, //   Usage Maximum (Keyboard Right GUI)
    0x15, 0x00, //   Logical Minimum (0)
    0x25, 0x01, //   Logical Maximum (1)
    0x95, 0x08, //   Report Count (8)
    0x75, 0x01, //   Report Size (1)
    0x81, 0x02, //   Input (Data, Variable, Absolute)
    // Keycodes
    0x05, 0x07,  //   Usage Page (Keyboard/Keypad)
    0x19, 0x00,  //   Usage Minimum (0)
    0x29, 0xF7,  //   Usage Maximum (247)
    0x15, 0x00,  //   Logical Minimum (0)
    0x25, 0x01,  //   Logical Maximum (1)
    0x95, 0xF8,  //   Report Count (248)
    0x75, 0x01,  //   Report Size (1)
    0x81, 0x02,  //   Input (Data, Variable, Absolute, Bitfield)
    0x05, 0x07, //   Usage Page (Keyboard/Keypad)
    0x19, 0x00, //   Usage Minimum (0)
    0x29, 0xF7, //   Usage Maximum (247)
    0x15, 0x00, //   Logical Minimum (0)
    0x25, 0x01, //   Logical Maximum (1)
    0x95, 0xF8, //   Report Count (248)
    0x75, 0x01, //   Report Size (1)
    0x81, 0x02, //   Input (Data, Variable, Absolute, Bitfield)

    // Status LEDs (5 bits)
    0x05, 0x08,  //   Usage Page (LED)
    0x19, 0x01,  //   Usage Minimum (Num Lock)
    0x29, 0x05,  //   Usage Maximum (Kana)
    0x95, 0x05,  //   Report Count (5)
    0x75, 0x01,  //   Report Size (1)
    0x91, 0x02,  //   Output (Data, Variable, Absolute)
    0x05, 0x08, //   Usage Page (LED)
    0x19, 0x01, //   Usage Minimum (Num Lock)
    0x29, 0x05, //   Usage Maximum (Kana)
    0x95, 0x05, //   Report Count (5)
    0x75, 0x01, //   Report Size (1)
    0x91, 0x02, //   Output (Data, Variable, Absolute)
    // LED padding (3 bits)
    0x95, 0x01,  //   Report Count (1)
    0x75, 0x03,  //   Report Size (3)
    0x91, 0x03,  //   Output (Constant)
    0xC0         // End Collection
    0x95, 0x01, //   Report Count (1)
    0x75, 0x03, //   Report Size (3)
    0x91, 0x03, //   Output (Constant)
    0xC0        // End Collection
}};

static bool udi_hid_nkro_setreport(void);


@@ 285,18 291,24 @@ bool udi_hid_nkro_enable(void) {
    return UDI_HID_NKRO_ENABLE_EXT();
}

void udi_hid_nkro_disable(void) { UDI_HID_NKRO_DISABLE_EXT(); }
void udi_hid_nkro_disable(void) {
    UDI_HID_NKRO_DISABLE_EXT();
}

bool udi_hid_nkro_setup(void) { return udi_hid_setup(&udi_hid_nkro_rate, &udi_hid_nkro_protocol, (uint8_t *)&udi_hid_nkro_report_desc, udi_hid_nkro_setreport); }
bool udi_hid_nkro_setup(void) {
    return udi_hid_setup(&udi_hid_nkro_rate, &udi_hid_nkro_protocol, (uint8_t *)&udi_hid_nkro_report_desc, udi_hid_nkro_setreport);
}

uint8_t udi_hid_nkro_getsetting(void) { return 0; }
uint8_t udi_hid_nkro_getsetting(void) {
    return 0;
}

// keyboard receives LED report here
static bool udi_hid_nkro_setreport(void) {
    if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8)) && (0 == (0xFF & udd_g_ctrlreq.req.wValue)) && (1 == udd_g_ctrlreq.req.wLength)) {
        // Report OUT type on report ID 0 from USB Host
        udd_g_ctrlreq.payload      = &udi_hid_nkro_report_set;
        udd_g_ctrlreq.callback     = udi_hid_nkro_setreport_valid;  // must call routine to transform setreport to LED state
        udd_g_ctrlreq.callback     = udi_hid_nkro_setreport_valid; // must call routine to transform setreport to LED state
        udd_g_ctrlreq.payload_size = 1;
        return true;
    }


@@ 333,7 345,7 @@ static void udi_hid_nkro_setreport_valid(void) {
    // UDI_HID_NKRO_CHANGE_LED(udi_hid_nkro_report_set);
}

#endif  // NKRO_ENABLE
#endif // NKRO_ENABLE

//********************************************************************************************
// EXK (extra-keys) SYS-CTRL  Keyboard

M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h => tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h +6 -6
@@ 71,7 71,7 @@ extern UDC_DESC_STORAGE udi_api_t udi_api_hid_nkro;
extern bool                       udi_hid_nkro_b_report_valid;
extern volatile bool              udi_hid_nkro_b_report_trans_ongoing;
bool                              udi_hid_nkro_send_report(void);
#endif  // NKRO_ENABLE
#endif // NKRO_ENABLE

//********************************************************************************************
// SYS-CTRL interface


@@ 81,7 81,7 @@ extern UDC_DESC_STORAGE udi_api_t udi_api_hid_exk;
extern bool                       udi_hid_exk_b_report_valid;
extern uint8_t                    udi_hid_exk_report_set;
bool                              udi_hid_exk_send_report(void);
#endif  // EXTRAKEY_ENABLE
#endif // EXTRAKEY_ENABLE

//********************************************************************************************
// CON Console


@@ 92,7 92,7 @@ extern bool                       udi_hid_con_b_report_valid;
extern uint8_t                    udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE];
extern volatile bool              udi_hid_con_b_report_trans_ongoing;
bool                              udi_hid_con_send_report(void);
#endif  // CONSOLE_ENABLE
#endif // CONSOLE_ENABLE

//********************************************************************************************
// MOU Mouse


@@ 101,7 101,7 @@ bool                              udi_hid_con_send_report(void);
extern UDC_DESC_STORAGE udi_api_t udi_api_hid_mou;
extern bool                       udi_hid_mou_b_report_valid;
bool                              udi_hid_mou_send_report(void);
#endif  // MOUSE_ENABLE
#endif // MOUSE_ENABLE

//********************************************************************************************
// RAW Raw


@@ 110,7 110,7 @@ bool                              udi_hid_mou_send_report(void);
extern UDC_DESC_STORAGE udi_api_t udi_api_hid_raw;
bool                              udi_hid_raw_send_report(void);
bool                              udi_hid_raw_receive_report(void);
#endif  // RAW_ENABLE
#endif // RAW_ENABLE

//@}



@@ 118,4 118,4 @@ bool                              udi_hid_raw_receive_report(void);
}
#endif

#endif  // _UDC_HID_KBD_H_
#endif // _UDC_HID_KBD_H_

M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h => tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h +1 -1
@@ 57,4 57,4 @@

#include "udi_hid_kbd.h"

#endif  // _UDI_HID_KBD_CONF_H_
#endif // _UDI_HID_KBD_CONF_H_

M tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c => tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c +3 -3
@@ 78,17 78,17 @@ UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = {.bLength         = sizeof(usb
#ifdef USB_DEVICE_MANUFACTURE_NAME
                                                   .iManufacturer = 1,
#else
                                                   .iManufacturer = 0,  // No manufacture string
                                                   .iManufacturer = 0, // No manufacture string
#endif
#ifdef USB_DEVICE_PRODUCT_NAME
                                                   .iProduct = 2,
#else
                                                   .iProduct      = 0,  // No product string
                                                   .iProduct      = 0, // No product string
#endif
#if (defined USB_DEVICE_SERIAL_NAME || defined USB_DEVICE_GET_SERIAL_NAME_POINTER)
                                                   .iSerialNumber = 3,
#else
                                                   .iSerialNumber = 0,  // No serial string
                                                   .iSerialNumber = 0, // No serial string
#endif
                                                   .bNumConfigurations = 1};


M tmk_core/protocol/arm_atsam/usb/ui.c => tmk_core/protocol/arm_atsam/usb/ui.c +1 -1
@@ 48,7 48,7 @@
#    define ARM_MATH_CM4
#endif

#undef LITTLE_ENDIAN  // redefined in samd51j18a.h
#undef LITTLE_ENDIAN // redefined in samd51j18a.h
#include "samd51j18a.h"
#include "ui.h"


M tmk_core/protocol/arm_atsam/usb/ui.h => tmk_core/protocol/arm_atsam/usb/ui.h +1 -1
@@ 73,4 73,4 @@ void ui_process(uint16_t framenumber);
 */
void ui_kbd_led(uint8_t value);

#endif  // _UI_H_
#endif // _UI_H_

M tmk_core/protocol/arm_atsam/usb/usb.c => tmk_core/protocol/arm_atsam/usb/usb.c +17 -11
@@ 52,7 52,7 @@
#endif

#include "compiler.h"
#undef LITTLE_ENDIAN  // redefined in samd51j18a.h
#undef LITTLE_ENDIAN // redefined in samd51j18a.h
#include "samd51j18a.h"
#include <stdbool.h>
#include <string.h>


@@ 319,7 319,7 @@ enum status_code usb_device_endpoint_enable_callback(struct usb_module *module_i
    module_inst->device_endpoint_enabled_callback_mask[ep_num] |= _usb_endpoint_irq_bits[callback_type];

    if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRCPT) {
        if (ep_num == 0) {  // control endpoint
        if (ep_num == 0) { // control endpoint
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1;
        } else if (ep & USB_EP_DIR_IN) {
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT1;


@@ 329,7 329,7 @@ enum status_code usb_device_endpoint_enable_callback(struct usb_module *module_i
    }

    if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL) {
        if (ep_num == 0) {  // control endpoint
        if (ep_num == 0) { // control endpoint
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRFAIL0 | USB_DEVICE_EPINTENSET_TRFAIL1;
        } else if (ep & USB_EP_DIR_IN) {
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRFAIL1;


@@ 377,7 377,7 @@ enum status_code usb_device_endpoint_disable_callback(struct usb_module *module_
    module_inst->device_endpoint_enabled_callback_mask[ep_num] &= ~_usb_endpoint_irq_bits[callback_type];

    if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRCPT) {
        if (ep_num == 0) {  // control endpoint
        if (ep_num == 0) { // control endpoint
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRCPT0 | USB_DEVICE_EPINTENCLR_TRCPT1;
        } else if (ep & USB_EP_DIR_IN) {
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRCPT1;


@@ 387,7 387,7 @@ enum status_code usb_device_endpoint_disable_callback(struct usb_module *module_
    }

    if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL) {
        if (ep_num == 0) {  // control endpoint
        if (ep_num == 0) { // control endpoint
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRFAIL0 | USB_DEVICE_EPINTENCLR_TRFAIL1;
        } else if (ep & USB_EP_DIR_IN) {
            module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRFAIL1;


@@ 903,11 903,17 @@ void USB_0_Handler(void) {
    }
}

void USB_1_Handler(void) { _usb_device_interrupt_handler(); }
void USB_1_Handler(void) {
    _usb_device_interrupt_handler();
}

void USB_2_Handler(void) { _usb_device_interrupt_handler(); }
void USB_2_Handler(void) {
    _usb_device_interrupt_handler();
}

void USB_3_Handler(void) { _usb_device_interrupt_handler(); }
void USB_3_Handler(void) {
    _usb_device_interrupt_handler();
}

/**
 * \brief Get the default USB module settings


@@ 974,10 980,10 @@ enum status_code usb_init(struct usb_module *module_inst, Usb *const hw, struct 
    pmclk->APBBMASK.bit.USB_ = 1;

    /* Set up the USB DP/DN pins */
    pport->Group[0].PMUX[12].reg          = 0x77;  // PA24, PA25, function column H for USB D-, D+
    pport->Group[0].PMUX[12].reg          = 0x77; // PA24, PA25, function column H for USB D-, D+
    pport->Group[0].PINCFG[24].bit.PMUXEN = 1;
    pport->Group[0].PINCFG[25].bit.PMUXEN = 1;
    pport->Group[1].PMUX[11].bit.PMUXE    = 7;  // PB22, function column H for USB SOF_1KHz output
    pport->Group[1].PMUX[11].bit.PMUXE    = 7; // PB22, function column H for USB SOF_1KHz output
    pport->Group[1].PINCFG[22].bit.PMUXEN = 1;

    // configure and enable DFLL for USB clock recovery mode at 48MHz


@@ 996,7 1002,7 @@ enum status_code usb_init(struct usb_module *module_inst, Usb *const hw, struct 
    while (posc->DFLLSYNC.bit.DFLLCTRLB)
        ;
    posc->DFLLCTRLB.bit.CCDIS = 1;
    posc->DFLLMUL.bit.MUL     = 0xbb80;  // 4800 x 1KHz
    posc->DFLLMUL.bit.MUL     = 0xbb80; // 4800 x 1KHz
    while (posc->DFLLSYNC.bit.DFLLMUL)
        ;
    posc->DFLLCTRLA.bit.ENABLE = 1;

M tmk_core/protocol/arm_atsam/usb/usb.h => tmk_core/protocol/arm_atsam/usb/usb.h +24 -8
@@ 319,14 319,18 @@ enum status_code usb_init(struct usb_module *module_inst, Usb *const hw, struct 
 *
 * \param module_inst Pointer to USB device module instance
 */
static inline void usb_device_attach(struct usb_module *module_inst) { module_inst->hw->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH; }
static inline void usb_device_attach(struct usb_module *module_inst) {
    module_inst->hw->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH;
}

/**
 * \brief Detach USB device from the bus
 *
 * \param module_inst Pointer to USB device module instance
 */
static inline void usb_device_detach(struct usb_module *module_inst) { module_inst->hw->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_DETACH; }
static inline void usb_device_detach(struct usb_module *module_inst) {
    module_inst->hw->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_DETACH;
}

/**
 * \brief Get the speed mode of USB device


@@ 348,7 352,9 @@ static inline enum usb_speed usb_device_get_speed(struct usb_module *module_inst
 * \param module_inst Pointer to USB device module instance
 * \return USB device address value.
 */
static inline uint8_t usb_device_get_address(struct usb_module *module_inst) { return ((uint8_t)(module_inst->hw->DEVICE.DADD.bit.DADD)); }
static inline uint8_t usb_device_get_address(struct usb_module *module_inst) {
    return ((uint8_t)(module_inst->hw->DEVICE.DADD.bit.DADD));
}

/**
 * \brief Set the speed mode of USB device


@@ 356,7 362,9 @@ static inline uint8_t usb_device_get_address(struct usb_module *module_inst) { r
 * \param module_inst Pointer to USB device module instance
 * \param address     USB device address value
 */
static inline void usb_device_set_address(struct usb_module *module_inst, uint8_t address) { module_inst->hw->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | address; }
static inline void usb_device_set_address(struct usb_module *module_inst, uint8_t address) {
    module_inst->hw->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | address;
}

/**
 * \brief Get the frame number of USB device


@@ 364,7 372,9 @@ static inline void usb_device_set_address(struct usb_module *module_inst, uint8_
 * \param module_inst Pointer to USB device module instance
 * \return USB device frame number value.
 */
static inline uint16_t usb_device_get_frame_number(struct usb_module *module_inst) { return ((uint16_t)(module_inst->hw->DEVICE.FNUM.bit.FNUM)); }
static inline uint16_t usb_device_get_frame_number(struct usb_module *module_inst) {
    return ((uint16_t)(module_inst->hw->DEVICE.FNUM.bit.FNUM));
}

/**
 * \brief Get the micro-frame number of USB device


@@ 372,14 382,18 @@ static inline uint16_t usb_device_get_frame_number(struct usb_module *module_ins
 * \param module_inst Pointer to USB device module instance
 * \return USB device micro-frame number value.
 */
static inline uint16_t usb_device_get_micro_frame_number(struct usb_module *module_inst) { return ((uint16_t)(module_inst->hw->DEVICE.FNUM.reg)); }
static inline uint16_t usb_device_get_micro_frame_number(struct usb_module *module_inst) {
    return ((uint16_t)(module_inst->hw->DEVICE.FNUM.reg));
}

/**
 * \brief USB device send the resume wakeup
 *
 * \param module_inst Pointer to USB device module instance
 */
static inline void usb_device_send_remote_wake_up(struct usb_module *module_inst) { module_inst->hw->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_UPRSM; }
static inline void usb_device_send_remote_wake_up(struct usb_module *module_inst) {
    module_inst->hw->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_UPRSM;
}

/**
 * \brief USB device set the LPM mode


@@ 387,7 401,9 @@ static inline void usb_device_send_remote_wake_up(struct usb_module *module_inst
 * \param module_inst Pointer to USB device module instance
 * \param lpm_mode    LPM mode
 */
static inline void usb_device_set_lpm_mode(struct usb_module *module_inst, enum usb_device_lpm_mode lpm_mode) { module_inst->hw->DEVICE.CTRLB.bit.LPMHDSK = lpm_mode; }
static inline void usb_device_set_lpm_mode(struct usb_module *module_inst, enum usb_device_lpm_mode lpm_mode) {
    module_inst->hw->DEVICE.CTRLB.bit.LPMHDSK = lpm_mode;
}

/**
 * \name USB Device Callback Management

M tmk_core/protocol/arm_atsam/usb/usb_atmel.h => tmk_core/protocol/arm_atsam/usb/usb_atmel.h +2 -2
@@ 109,7 109,7 @@
#define USB_PID_ATMEL_UC3_EVK1101_CTRLPANEL_HID_MS 0x2306
#define USB_PID_ATMEL_UC3_CDC 0x2307
#define USB_PID_ATMEL_UC3_AUDIO_MICRO 0x2308
#define USB_PID_ATMEL_UC3_CDC_DEBUG 0x2310  // Virtual Com (debug interface) on EVK11xx
#define USB_PID_ATMEL_UC3_CDC_DEBUG 0x2310 // Virtual Com (debug interface) on EVK11xx
#define USB_PID_ATMEL_UC3_AUDIO_SPEAKER_MICRO 0x2311
#define USB_PID_ATMEL_UC3_CDC_MSC 0x2312
//! @}


@@ 186,4 186,4 @@

//! @}

#endif  // _USB_ATMEL_H_
#endif // _USB_ATMEL_H_

M tmk_core/protocol/arm_atsam/usb/usb_device_udd.c => tmk_core/protocol/arm_atsam/usb/usb_device_udd.c +25 -13
@@ 127,12 127,12 @@ uint8_t udd_ctrl_buffer[USB_DEVICE_EP_CTRL_SIZE];

/** Bit definitions about endpoint control state machine for udd_ep_control_state */
typedef enum {
    UDD_EPCTRL_SETUP                  = 0,  //!< Wait a SETUP packet
    UDD_EPCTRL_DATA_OUT               = 1,  //!< Wait a OUT data packet
    UDD_EPCTRL_DATA_IN                = 2,  //!< Wait a IN data packet
    UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP  = 3,  //!< Wait a IN ZLP packet
    UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP = 4,  //!< Wait a OUT ZLP packet
    UDD_EPCTRL_STALL_REQ              = 5,  //!< STALL enabled on IN & OUT packet
    UDD_EPCTRL_SETUP                  = 0, //!< Wait a SETUP packet
    UDD_EPCTRL_DATA_OUT               = 1, //!< Wait a OUT data packet
    UDD_EPCTRL_DATA_IN                = 2, //!< Wait a IN data packet
    UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP  = 3, //!< Wait a IN ZLP packet
    UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP = 4, //!< Wait a OUT ZLP packet
    UDD_EPCTRL_STALL_REQ              = 5, //!< STALL enabled on IN & OUT packet
} udd_ctrl_ep_state_t;

/** Global variable to give and record information of the set up request management */


@@ 363,11 363,17 @@ void udd_ep_abort(udd_ep_id_t ep) {
    }
}

bool udd_is_high_speed(void) { return false; }
bool udd_is_high_speed(void) {
    return false;
}

uint16_t udd_get_frame_number(void) { return usb_device_get_frame_number(&usb_device); }
uint16_t udd_get_frame_number(void) {
    return usb_device_get_frame_number(&usb_device);
}

uint16_t udd_get_micro_frame_number(void) { return usb_device_get_micro_frame_number(&usb_device); }
uint16_t udd_get_micro_frame_number(void) {
    return usb_device_get_micro_frame_number(&usb_device);
}

void udd_ep_free(udd_ep_id_t ep) {
    struct usb_device_endpoint_config config_ep;


@@ 436,7 442,9 @@ bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize
    return true;
}

bool udd_ep_is_halted(udd_ep_id_t ep) { return usb_device_endpoint_is_halted(&usb_device, ep); }
bool udd_ep_is_halted(udd_ep_id_t ep) {
    return usb_device_endpoint_is_halted(&usb_device, ep);
}

bool udd_ep_set_halt(udd_ep_id_t ep) {
    uint8_t ep_num = ep & USB_EP_ADDR_MASK;


@@ 591,9 599,13 @@ bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t *buf, iram_size_t bu
    }
}

void udd_set_address(uint8_t address) { usb_device_set_address(&usb_device, address); }
void udd_set_address(uint8_t address) {
    usb_device_set_address(&usb_device, address);
}

uint8_t udd_getaddress(void) { return usb_device_get_address(&usb_device); }
uint8_t udd_getaddress(void) {
    return usb_device_get_address(&usb_device);
}

void udd_send_remotewakeup(void) {
    uint32_t try


@@ 913,7 925,7 @@ static void _usb_device_lpm_suspend(struct usb_module *module_inst, void *pointe
    usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP);

    //#warning Here the sleep mode must be choose to have a DFLL startup time < bmAttribut.HIRD
    udd_sleep_mode(UDD_STATE_SUSPEND_LPM);  // Enter in LPM SUSPEND mode
    udd_sleep_mode(UDD_STATE_SUSPEND_LPM); // Enter in LPM SUSPEND mode
    if ((*lpm_wakeup_enable)) {
        UDC_REMOTEWAKEUP_LPM_ENABLE();
    }

M tmk_core/protocol/arm_atsam/usb/usb_hub.c => tmk_core/protocol/arm_atsam/usb/usb_hub.c +39 -37
@@ 27,7 27,7 @@ uint8_t usb_extra_state;
uint8_t usb_extra_manual;
uint8_t usb_gcr_auto;

#endif  // MD_BOOTLOADER
#endif // MD_BOOTLOADER

uint16_t adc_extra;



@@ 51,10 51,10 @@ void USB_Hub_init(void) {
    pmclk->APBBMASK.bit.USB_    = 1;

    // setup port pins for D-, D+, and SOF_1KHZ
    pport->Group[0].PMUX[12].reg          = 0x77;  // PA24, PA25, function column H for USB D-, D+
    pport->Group[0].PMUX[12].reg          = 0x77; // PA24, PA25, function column H for USB D-, D+
    pport->Group[0].PINCFG[24].bit.PMUXEN = 1;
    pport->Group[0].PINCFG[25].bit.PMUXEN = 1;
    pport->Group[1].PMUX[11].bit.PMUXE    = 7;  // PB22, function column H for USB SOF_1KHz output
    pport->Group[1].PMUX[11].bit.PMUXE    = 7; // PB22, function column H for USB SOF_1KHz output
    pport->Group[1].PINCFG[22].bit.PMUXEN = 1;

    // configure and enable DFLL for USB clock recovery mode at 48MHz


@@ 78,7 78,7 @@ void USB_Hub_init(void) {
        DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_4);
    }
    posc->DFLLCTRLB.bit.CCDIS = 1;
    posc->DFLLMUL.bit.MUL     = 0xBB80;  // 4800 x 1KHz
    posc->DFLLMUL.bit.MUL     = 0xBB80; // 4800 x 1KHz
    while (posc->DFLLSYNC.bit.DFLLMUL) {
        DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLMUL);
    }


@@ 99,7 99,7 @@ void USB_Hub_init(void) {
    pusb->DEVICE.PADCAL.bit.TRANSP = (USB_FUSES_TRANSP_ADDR >> USB_FUSES_TRANSP_Pos) & USB_FUSES_TRANSP_Msk;
    pusb->DEVICE.PADCAL.bit.TRIM   = (USB_FUSES_TRIM_ADDR >> USB_FUSES_TRIM_Pos) & USB_FUSES_TRIM_Msk;
    // device mode, enabled
    pusb->DEVICE.CTRLB.bit.SPDCONF = 0;  // full speed
    pusb->DEVICE.CTRLB.bit.SPDCONF = 0; // full speed
    pusb->DEVICE.CTRLA.bit.MODE    = 0;
    pusb->DEVICE.CTRLA.bit.ENABLE  = 1;
    while (pusb->DEVICE.SYNCBUSY.bit.ENABLE) {


@@ 111,8 111,8 @@ void USB_Hub_init(void) {

    USB2422_init();

    sr_exp_data.bit.HUB_CONNECT = 1;  // connect signal
    sr_exp_data.bit.HUB_RESET_N = 1;  // reset high
    sr_exp_data.bit.HUB_CONNECT = 1; // connect signal
    sr_exp_data.bit.HUB_RESET_N = 1; // reset high
    SR_EXP_WriteData();

    wait_us(100);


@@ 122,7 122,7 @@ void USB_Hub_init(void) {
    usb_extra_manual = 0;
    usb_gcr_auto     = 1;

#endif  // MD_BOOTLOADER
#endif // MD_BOOTLOADER

    DBGC(DC_USB2422_INIT_COMPLETE);
}


@@ 131,10 131,10 @@ void USB_reset(void) {
    DBGC(DC_USB_RESET_BEGIN);

    // pulse reset for at least 1 usec
    sr_exp_data.bit.HUB_RESET_N = 0;  // reset low
    sr_exp_data.bit.HUB_RESET_N = 0; // reset low
    SR_EXP_WriteData();
    wait_us(2);
    sr_exp_data.bit.HUB_RESET_N = 1;  // reset high to run
    sr_exp_data.bit.HUB_RESET_N = 1; // reset high to run
    SR_EXP_WriteData();

    DBGC(DC_USB_RESET_COMPLETE);


@@ 150,7 150,9 @@ void USB_configure(void) {
    DBGC(DC_USB_CONFIGURE_COMPLETE);
}

uint16_t USB_active(void) { return USB2422_active(); }
uint16_t USB_active(void) {
    return USB2422_active();
}

void USB_set_host_by_voltage(void) {
    // UP is upstream device (HOST)


@@ 162,13 164,13 @@ void USB_set_host_by_voltage(void) {
    usb_host_port = USB_HOST_PORT_UNKNOWN;
#ifndef MD_BOOTLOADER
    usb_extra_state = USB_EXTRA_STATE_UNKNOWN;
#endif                             // MD_BOOTLOADER
    sr_exp_data.bit.SRC_1    = 1;  // USBC-1 available for test
    sr_exp_data.bit.SRC_2    = 1;  // USBC-2 available for test
    sr_exp_data.bit.E_UP_N   = 1;  // HOST disable
    sr_exp_data.bit.E_DN1_N  = 1;  // EXTRA disable
    sr_exp_data.bit.E_VBUS_1 = 0;  // USBC-1 disable full power I/O
    sr_exp_data.bit.E_VBUS_2 = 0;  // USBC-2 disable full power I/O
#endif                            // MD_BOOTLOADER
    sr_exp_data.bit.SRC_1    = 1; // USBC-1 available for test
    sr_exp_data.bit.SRC_2    = 1; // USBC-2 available for test
    sr_exp_data.bit.E_UP_N   = 1; // HOST disable
    sr_exp_data.bit.E_DN1_N  = 1; // EXTRA disable
    sr_exp_data.bit.E_VBUS_1 = 0; // USBC-1 disable full power I/O
    sr_exp_data.bit.E_VBUS_2 = 0; // USBC-2 disable full power I/O

    SR_EXP_WriteData();



@@ 185,33 187,33 @@ void USB_set_host_by_voltage(void) {
    v_con_2_boot = v_con_2;

    if (v_con_1 > v_con_2) {
        sr_exp_data.bit.S_UP  = 0;  // HOST to USBC-1
        sr_exp_data.bit.S_DN1 = 1;  // EXTRA to USBC-2
        sr_exp_data.bit.SRC_1 = 1;  // HOST on USBC-1
        sr_exp_data.bit.SRC_2 = 0;  // EXTRA available on USBC-2
        sr_exp_data.bit.S_UP  = 0; // HOST to USBC-1
        sr_exp_data.bit.S_DN1 = 1; // EXTRA to USBC-2
        sr_exp_data.bit.SRC_1 = 1; // HOST on USBC-1
        sr_exp_data.bit.SRC_2 = 0; // EXTRA available on USBC-2

        sr_exp_data.bit.E_VBUS_1 = 1;  // USBC-1 enable full power I/O
        sr_exp_data.bit.E_VBUS_2 = 0;  // USBC-2 disable full power I/O
        sr_exp_data.bit.E_VBUS_1 = 1; // USBC-1 enable full power I/O
        sr_exp_data.bit.E_VBUS_2 = 0; // USBC-2 disable full power I/O

        SR_EXP_WriteData();

        sr_exp_data.bit.E_UP_N = 0;  // HOST enable
        sr_exp_data.bit.E_UP_N = 0; // HOST enable

        SR_EXP_WriteData();

        usb_host_port = USB_HOST_PORT_1;
    } else {
        sr_exp_data.bit.S_UP  = 1;  // EXTRA to USBC-1
        sr_exp_data.bit.S_DN1 = 0;  // HOST to USBC-2
        sr_exp_data.bit.SRC_1 = 0;  // EXTRA available on USBC-1
        sr_exp_data.bit.SRC_2 = 1;  // HOST on USBC-2
        sr_exp_data.bit.S_UP  = 1; // EXTRA to USBC-1
        sr_exp_data.bit.S_DN1 = 0; // HOST to USBC-2
        sr_exp_data.bit.SRC_1 = 0; // EXTRA available on USBC-1
        sr_exp_data.bit.SRC_2 = 1; // HOST on USBC-2

        sr_exp_data.bit.E_VBUS_1 = 0;  // USBC-1 disable full power I/O
        sr_exp_data.bit.E_VBUS_2 = 1;  // USBC-2 enable full power I/O
        sr_exp_data.bit.E_VBUS_1 = 0; // USBC-1 disable full power I/O
        sr_exp_data.bit.E_VBUS_2 = 1; // USBC-2 enable full power I/O

        SR_EXP_WriteData();

        sr_exp_data.bit.E_UP_N = 0;  // HOST enable
        sr_exp_data.bit.E_UP_N = 0; // HOST enable

        SR_EXP_WriteData();



@@ 220,7 222,7 @@ void USB_set_host_by_voltage(void) {

#ifndef MD_BOOTLOADER
    usb_extra_state = USB_EXTRA_STATE_DISABLED;
#endif  // MD_BOOTLOADER
#endif // MD_BOOTLOADER

    USB_reset();
    USB_configure();


@@ 241,7 243,7 @@ uint8_t USB_Hub_Port_Detect_Init(void) {
    while (!USB_active()) {
        tmod = timer_read64() % PORT_DETECT_RETRY_INTERVAL;

        if (v_con_1 > v_con_2)  // Values updated from USB_set_host_by_voltage();
        if (v_con_1 > v_con_2) // Values updated from USB_set_host_by_voltage();
        {
            // 1 flash for port 1 detected
            if (tmod > 500 && tmod < 600) {


@@ 249,7 251,7 @@ uint8_t USB_Hub_Port_Detect_Init(void) {
            } else {
                DBG_LED_OFF;
            }
        } else if (v_con_2 > v_con_1)  // Values updated from USB_set_host_by_voltage();
        } else if (v_con_2 > v_con_1) // Values updated from USB_set_host_by_voltage();
        {
            // 2 flash for port 2 detected
            if (tmod > 500 && tmod < 600) {


@@ 321,7 323,7 @@ void USB_HandleExtraDevice(void) {
        // Detect unplug and reset state to disabled
        if (adc_extra > USB_EXTRA_ADC_THRESHOLD) usb_extra_state = USB_EXTRA_STATE_DISABLED;

        return;  // Return even if unplug detected
        return; // Return even if unplug detected
    }

    if (usb_extra_manual) {


@@ 337,4 339,4 @@ void USB_HandleExtraDevice(void) {
        USB_ExtraSetState(USB_EXTRA_STATE_DISABLED);
}

#endif  // MD_BOOTLOADER
#endif // MD_BOOTLOADER

M tmk_core/protocol/arm_atsam/usb/usb_hub.h => tmk_core/protocol/arm_atsam/usb/usb_hub.h +1 -1
@@ 48,4 48,4 @@ uint16_t adc_get(uint8_t muxpos);
void     USB_HandleExtraDevice(void);
void     USB_ExtraSetState(uint8_t state);

#endif  //_USB2422_H_
#endif //_USB2422_H_

M tmk_core/protocol/arm_atsam/usb/usb_main.h => tmk_core/protocol/arm_atsam/usb/usb_main.h +6 -6
@@ 71,31 71,31 @@ void                 main_kbd_disable(void);
extern volatile bool main_b_nkro_enable;
bool                 main_nkro_enable(void);
void                 main_nkro_disable(void);
#endif  // NKRO_ENABLE
#endif // NKRO_ENABLE

#ifdef EXTRAKEY_ENABLE
extern volatile bool main_b_exk_enable;
bool                 main_exk_enable(void);
void                 main_exk_disable(void);
#endif  // EXTRAKEY_ENABLE
#endif // EXTRAKEY_ENABLE

#ifdef CONSOLE_ENABLE
extern volatile bool main_b_con_enable;
bool                 main_con_enable(void);
void                 main_con_disable(void);
#endif  // CONSOLE_ENABLE
#endif // CONSOLE_ENABLE

#ifdef MOUSE_ENABLE
extern volatile bool main_b_mou_enable;
bool                 main_mou_enable(void);
void                 main_mou_disable(void);
#endif  // MOUSE_ENABLE
#endif // MOUSE_ENABLE

#ifdef RAW_ENABLE
extern volatile bool main_b_raw_enable;
bool                 main_raw_enable(void);
void                 main_raw_disable(void);
void                 main_raw_receive(uint8_t *buffer, uint8_t len);
#endif  // RAW_ENABLE
#endif // RAW_ENABLE

#endif  // _MAIN_H_
#endif // _MAIN_H_

M tmk_core/protocol/arm_atsam/usb/usb_protocol.h => tmk_core/protocol/arm_atsam/usb/usb_protocol.h +38 -38
@@ 63,8 63,8 @@
 */

//! Value for field bcdUSB
#define USB_V2_0 0x0200  //!< USB Specification version 2.00
#define USB_V2_1 0x0201  //!< USB Specification version 2.01
#define USB_V2_0 0x0200 //!< USB Specification version 2.00
#define USB_V2_1 0x0201 //!< USB Specification version 2.01

/*! \name Generic definitions (Class, subclass and protocol)
 */


@@ 85,26 85,26 @@
/**
 * \brief USB request data transfer direction (bmRequestType)
 */
#define USB_REQ_DIR_OUT (0 << 7)   //!< Host to device
#define USB_REQ_DIR_IN (1 << 7)    //!< Device to host
#define USB_REQ_DIR_MASK (1 << 7)  //!< Mask
#define USB_REQ_DIR_OUT (0 << 7)  //!< Host to device
#define USB_REQ_DIR_IN (1 << 7)   //!< Device to host
#define USB_REQ_DIR_MASK (1 << 7) //!< Mask

/**
 * \brief USB request types (bmRequestType)
 */
#define USB_REQ_TYPE_STANDARD (0 << 5)  //!< Standard request
#define USB_REQ_TYPE_CLASS (1 << 5)     //!< Class-specific request
#define USB_REQ_TYPE_VENDOR (2 << 5)    //!< Vendor-specific request
#define USB_REQ_TYPE_MASK (3 << 5)      //!< Mask
#define USB_REQ_TYPE_STANDARD (0 << 5) //!< Standard request
#define USB_REQ_TYPE_CLASS (1 << 5)    //!< Class-specific request
#define USB_REQ_TYPE_VENDOR (2 << 5)   //!< Vendor-specific request
#define USB_REQ_TYPE_MASK (3 << 5)     //!< Mask

/**
 * \brief USB recipient codes (bmRequestType)
 */
#define USB_REQ_RECIP_DEVICE (0 << 0)     //!< Recipient device
#define USB_REQ_RECIP_INTERFACE (1 << 0)  //!< Recipient interface
#define USB_REQ_RECIP_ENDPOINT (2 << 0)   //!< Recipient endpoint
#define USB_REQ_RECIP_OTHER (3 << 0)      //!< Recipient other
#define USB_REQ_RECIP_MASK (0x1F)         //!< Mask
#define USB_REQ_RECIP_DEVICE (0 << 0)    //!< Recipient device
#define USB_REQ_RECIP_INTERFACE (1 << 0) //!< Recipient interface
#define USB_REQ_RECIP_ENDPOINT (2 << 0)  //!< Recipient endpoint
#define USB_REQ_RECIP_OTHER (3 << 0)     //!< Recipient other
#define USB_REQ_RECIP_MASK (0x1F)        //!< Mask

/**
 * \brief Standard USB requests (bRequest)


@@ 149,8 149,8 @@ enum usb_endpoint_status {
 * \note valid for SetFeature request.
 */
enum usb_device_feature {
    USB_DEV_FEATURE_REMOTE_WAKEUP         = 1,  //!< Remote wakeup enabled
    USB_DEV_FEATURE_TEST_MODE             = 2,  //!< USB test mode
    USB_DEV_FEATURE_REMOTE_WAKEUP         = 1, //!< Remote wakeup enabled
    USB_DEV_FEATURE_TEST_MODE             = 2, //!< USB test mode
    USB_DEV_FEATURE_OTG_B_HNP_ENABLE      = 3,
    USB_DEV_FEATURE_OTG_A_HNP_SUPPORT     = 4,
    USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5


@@ 261,7 261,7 @@ enum usb_ep_type {
 * \brief Standard USB language IDs for string descriptors
 */
enum usb_langid {
    USB_LANGID_EN_US = 0x0409,  //!< English (United States)
    USB_LANGID_EN_US = 0x0409, //!< English (United States)
};

/**


@@ 396,14 396,14 @@ typedef struct {
 * \brief Standard USB Interface Association Descriptor structure
 */
typedef struct {
    uint8_t bLength;            //!< size of this descriptor in bytes
    uint8_t bDescriptorType;    //!< INTERFACE descriptor type
    uint8_t bFirstInterface;    //!< Number of interface
    uint8_t bInterfaceCount;    //!< value to select alternate setting
    uint8_t bFunctionClass;     //!< Class code assigned by the USB
    uint8_t bFunctionSubClass;  //!< Sub-class code assigned by the USB
    uint8_t bFunctionProtocol;  //!< Protocol code assigned by the USB
    uint8_t iFunction;          //!< Index of string descriptor
    uint8_t bLength;           //!< size of this descriptor in bytes
    uint8_t bDescriptorType;   //!< INTERFACE descriptor type
    uint8_t bFirstInterface;   //!< Number of interface
    uint8_t bInterfaceCount;   //!< value to select alternate setting
    uint8_t bFunctionClass;    //!< Class code assigned by the USB
    uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB
    uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB
    uint8_t iFunction;         //!< Index of string descriptor
} usb_association_desc_t;

/**


@@ 420,25 420,25 @@ typedef struct {
    uint8_t bMaxPower;
} usb_conf_desc_t;

#define USB_CONFIG_ATTR_MUST_SET (1 << 7)       //!< Must always be set
#define USB_CONFIG_ATTR_BUS_POWERED (0 << 6)    //!< Bus-powered
#define USB_CONFIG_ATTR_SELF_POWERED (1 << 6)   //!< Self-powered
#define USB_CONFIG_ATTR_REMOTE_WAKEUP (1 << 5)  //!< remote wakeup supported
#define USB_CONFIG_ATTR_MUST_SET (1 << 7)      //!< Must always be set
#define USB_CONFIG_ATTR_BUS_POWERED (0 << 6)   //!< Bus-powered
#define USB_CONFIG_ATTR_SELF_POWERED (1 << 6)  //!< Self-powered
#define USB_CONFIG_ATTR_REMOTE_WAKEUP (1 << 5) //!< remote wakeup supported

#define USB_CONFIG_MAX_POWER(ma) (((ma) + 1) / 2)  //!< Max power in mA
#define USB_CONFIG_MAX_POWER(ma) (((ma) + 1) / 2) //!< Max power in mA

/**
 * \brief Standard USB association descriptor structure
 */
typedef struct {
    uint8_t bLength;            //!< Size of this descriptor in bytes
    uint8_t bDescriptorType;    //!< Interface descriptor type
    uint8_t bFirstInterface;    //!< Number of interface
    uint8_t bInterfaceCount;    //!< value to select alternate setting
    uint8_t bFunctionClass;     //!< Class code assigned by the USB
    uint8_t bFunctionSubClass;  //!< Sub-class code assigned by the USB
    uint8_t bFunctionProtocol;  //!< Protocol code assigned by the USB
    uint8_t iFunction;          //!< Index of string descriptor
    uint8_t bLength;           //!< Size of this descriptor in bytes
    uint8_t bDescriptorType;   //!< Interface descriptor type
    uint8_t bFirstInterface;   //!< Number of interface
    uint8_t bInterfaceCount;   //!< value to select alternate setting
    uint8_t bFunctionClass;    //!< Class code assigned by the USB
    uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB
    uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB
    uint8_t iFunction;         //!< Index of string descriptor
} usb_iad_desc_t;

/**

M tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h => tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h +40 -40
@@ 50,41 50,41 @@

#ifdef VIRTSER_ENABLE

#    define CDC_CLASS_DEVICE 0x02  //!< USB Communication Device Class
#    define CDC_CLASS_COMM 0x02    //!< CDC Communication Class Interface
#    define CDC_CLASS_DATA 0x0A    //!< CDC Data Class Interface

#    define CDC_SUBCLASS_DLCM 0x01  //!< Direct Line Control Model
#    define CDC_SUBCLASS_ACM 0x02   //!< Abstract Control Model
#    define CDC_SUBCLASS_TCM 0x03   //!< Telephone Control Model
#    define CDC_SUBCLASS_MCCM 0x04  //!< Multi-Channel Control Model
#    define CDC_SUBCLASS_CCM 0x05   //!< CAPI Control Model
#    define CDC_SUBCLASS_ETH 0x06   //!< Ethernet Networking Control Model
#    define CDC_SUBCLASS_ATM 0x07   //!< ATM Networking Control Model

#    define CDC_PROTOCOL_V25TER 0x01  //!< Common AT commands

#    define CDC_PROTOCOL_I430 0x30    //!< ISDN BRI
#    define CDC_PROTOCOL_HDLC 0x31    //!< HDLC
#    define CDC_PROTOCOL_TRANS 0x32   //!< Transparent
#    define CDC_PROTOCOL_Q921M 0x50   //!< Q.921 management protocol
#    define CDC_PROTOCOL_Q921 0x51    //!< Q.931 [sic] Data link protocol
#    define CDC_PROTOCOL_Q921TM 0x52  //!< Q.921 TEI-multiplexor
#    define CDC_PROTOCOL_V42BIS 0x90  //!< Data compression procedures
#    define CDC_PROTOCOL_Q931 0x91    //!< Euro-ISDN protocol control
#    define CDC_PROTOCOL_V120 0x92    //!< V.24 rate adaption to ISDN
#    define CDC_PROTOCOL_CAPI20 0x93  //!< CAPI Commands
#    define CDC_PROTOCOL_HOST 0xFD    //!< Host based driver
#    define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class
#    define CDC_CLASS_COMM 0x02   //!< CDC Communication Class Interface
#    define CDC_CLASS_DATA 0x0A   //!< CDC Data Class Interface

#    define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model
#    define CDC_SUBCLASS_ACM 0x02  //!< Abstract Control Model
#    define CDC_SUBCLASS_TCM 0x03  //!< Telephone Control Model
#    define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model
#    define CDC_SUBCLASS_CCM 0x05  //!< CAPI Control Model
#    define CDC_SUBCLASS_ETH 0x06  //!< Ethernet Networking Control Model
#    define CDC_SUBCLASS_ATM 0x07  //!< ATM Networking Control Model

#    define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands

#    define CDC_PROTOCOL_I430 0x30   //!< ISDN BRI
#    define CDC_PROTOCOL_HDLC 0x31   //!< HDLC
#    define CDC_PROTOCOL_TRANS 0x32  //!< Transparent
#    define CDC_PROTOCOL_Q921M 0x50  //!< Q.921 management protocol
#    define CDC_PROTOCOL_Q921 0x51   //!< Q.931 [sic] Data link protocol
#    define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor
#    define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures
#    define CDC_PROTOCOL_Q931 0x91   //!< Euro-ISDN protocol control
#    define CDC_PROTOCOL_V120 0x92   //!< V.24 rate adaption to ISDN
#    define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands
#    define CDC_PROTOCOL_HOST 0xFD   //!< Host based driver

#    define CDC_PROTOCOL_PUFD 0xFE

#    define CDC_CS_INTERFACE 0x24  //!< Interface Functional Descriptor
#    define CDC_CS_ENDPOINT 0x25   //!< Endpoint Functional Descriptor
#    define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor
#    define CDC_CS_ENDPOINT 0x25  //!< Endpoint Functional Descriptor

#    define CDC_SCS_HEADER 0x00     //!< Header Functional Descriptor
#    define CDC_SCS_CALL_MGMT 0x01  //!< Call Management
#    define CDC_SCS_ACM 0x02        //!< Abstract Control Management
#    define CDC_SCS_UNION 0x06      //!< Union Functional Descriptor
#    define CDC_SCS_HEADER 0x00    //!< Header Functional Descriptor
#    define CDC_SCS_CALL_MGMT 0x01 //!< Call Management
#    define CDC_SCS_ACM 0x02       //!< Abstract Control Management
#    define CDC_SCS_UNION 0x06     //!< Union Functional Descriptor

#    define USB_REQ_CDC_SEND_ENCAPSULATED_COMMAND 0x00
#    define USB_REQ_CDC_GET_ENCAPSULATED_RESPONSE 0x01


@@ 144,17 144,17 @@ typedef struct {
#    pragma pack(pop)

enum cdc_char_format {
    CDC_STOP_BITS_1   = 0,  //!< 1 stop bit
    CDC_STOP_BITS_1_5 = 1,  //!< 1.5 stop bits
    CDC_STOP_BITS_2   = 2,  //!< 2 stop bits
    CDC_STOP_BITS_1   = 0, //!< 1 stop bit
    CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits
    CDC_STOP_BITS_2   = 2, //!< 2 stop bits
};

enum cdc_parity {
    CDC_PAR_NONE  = 0,  //!< No parity
    CDC_PAR_ODD   = 1,  //!< Odd parity
    CDC_PAR_EVEN  = 2,  //!< Even parity
    CDC_PAR_MARK  = 3,  //!< Parity forced to 0 (space)
    CDC_PAR_SPACE = 4,  //!< Parity forced to 1 (mark)
    CDC_PAR_NONE  = 0, //!< No parity
    CDC_PAR_ODD   = 1, //!< Odd parity
    CDC_PAR_EVEN  = 2, //!< Even parity
    CDC_PAR_MARK  = 3, //!< Parity forced to 0 (space)
    CDC_PAR_SPACE = 4, //!< Parity forced to 1 (mark)
};

typedef struct {


@@ 187,4 187,4 @@ typedef struct {

#endif

#endif  // _USB_PROTOCOL_CDC_H_
#endif // _USB_PROTOCOL_CDC_H_

M tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h => tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h +51 -51
@@ 121,13 121,13 @@ COMPILER_PACK_SET(1)

//! \brief HID Descriptor
typedef struct {
    uint8_t bLength;            //!< Size of this descriptor in bytes
    uint8_t bDescriptorType;    //!< HID descriptor type
    le16_t  bcdHID;             //!< Binary Coded Decimal Spec. release
    uint8_t bCountryCode;       //!< Hardware target country
    uint8_t bNumDescriptors;    //!< Number of HID class descriptors to follow
    uint8_t bRDescriptorType;   //!< Report descriptor type
    le16_t  wDescriptorLength;  //!< Total length of Report descriptor
    uint8_t bLength;           //!< Size of this descriptor in bytes
    uint8_t bDescriptorType;   //!< HID descriptor type
    le16_t  bcdHID;            //!< Binary Coded Decimal Spec. release
    uint8_t bCountryCode;      //!< Hardware target country
    uint8_t bNumDescriptors;   //!< Number of HID class descriptors to follow
    uint8_t bRDescriptorType;  //!< Report descriptor type
    le16_t  wDescriptorLength; //!< Total length of Report descriptor
} usb_hid_descriptor_t;

COMPILER_PACK_RESET()


@@ 151,45 151,45 @@ COMPILER_PACK_RESET()

//! \name Country code
//! @{
#define USB_HID_NO_COUNTRY_CODE 0             // Not Supported
#define USB_HID_COUNTRY_ARABIC 1              // Arabic
#define USB_HID_COUNTRY_BELGIAN 2             // Belgian
#define USB_HID_COUNTRY_CANADIAN_BILINGUAL 3  // Canadian-Bilingual
#define USB_HID_COUNTRY_CANADIAN_FRENCH 4     // Canadian-French
#define USB_HID_COUNTRY_CZECH_REPUBLIC 5      // Czech Republic
#define USB_HID_COUNTRY_DANISH 6              // Danish
#define USB_HID_COUNTRY_FINNISH 7             // Finnish
#define USB_HID_COUNTRY_FRENCH 8              // French
#define USB_HID_COUNTRY_GERMAN 9              // German
#define USB_HID_COUNTRY_GREEK 10              // Greek
#define USB_HID_COUNTRY_HEBREW 11             // Hebrew
#define USB_HID_COUNTRY_HUNGARY 12            // Hungary
#define USB_HID_COUNTRY_INTERNATIONAL_ISO 13  // International (ISO)
#define USB_HID_COUNTRY_ITALIAN 14            // Italian
#define USB_HID_COUNTRY_JAPAN_KATAKANA 15     // Japan (Katakana)
#define USB_HID_COUNTRY_KOREAN 16             // Korean
#define USB_HID_COUNTRY_LATIN_AMERICAN 17     // Latin American
#define USB_HID_COUNTRY_NETHERLANDS_DUTCH 18  // Netherlands/Dutch
#define USB_HID_COUNTRY_NORWEGIAN 19          // Norwegian
#define USB_HID_COUNTRY_PERSIAN_FARSI 20      // Persian (Farsi)
#define USB_HID_COUNTRY_POLAND 21             // Poland
#define USB_HID_COUNTRY_PORTUGUESE 22         // Portuguese
#define USB_HID_COUNTRY_RUSSIA 23             // Russia
#define USB_HID_COUNTRY_SLOVAKIA 24           // Slovakia
#define USB_HID_COUNTRY_SPANISH 25            // Spanish
#define USB_HID_COUNTRY_SWEDISH 26            // Swedish
#define USB_HID_COUNTRY_SWISS_FRENCH 27       // Swiss/French
#define USB_HID_COUNTRY_SWISS_GERMAN 28       // Swiss/German
#define USB_HID_COUNTRY_SWITZERLAND 29        // Switzerland
#define USB_HID_COUNTRY_TAIWAN 30             // Taiwan
#define USB_HID_COUNTRY_TURKISH_Q 31          // Turkish-Q
#define USB_HID_COUNTRY_UK 32                 // UK
#define USB_HID_COUNTRY_US 33                 // US
#define USB_HID_COUNTRY_YUGOSLAVIA 34         // Yugoslavia
#define USB_HID_NO_COUNTRY_CODE 0            // Not Supported
#define USB_HID_COUNTRY_ARABIC 1             // Arabic
#define USB_HID_COUNTRY_BELGIAN 2            // Belgian
#define USB_HID_COUNTRY_CANADIAN_BILINGUAL 3 // Canadian-Bilingual
#define USB_HID_COUNTRY_CANADIAN_FRENCH 4    // Canadian-French
#define USB_HID_COUNTRY_CZECH_REPUBLIC 5     // Czech Republic
#define USB_HID_COUNTRY_DANISH 6             // Danish
#define USB_HID_COUNTRY_FINNISH 7            // Finnish
#define USB_HID_COUNTRY_FRENCH 8             // French
#define USB_HID_COUNTRY_GERMAN 9             // German
#define USB_HID_COUNTRY_GREEK 10             // Greek
#define USB_HID_COUNTRY_HEBREW 11            // Hebrew
#define USB_HID_COUNTRY_HUNGARY 12           // Hungary
#define USB_HID_COUNTRY_INTERNATIONAL_ISO 13 // International (ISO)
#define USB_HID_COUNTRY_ITALIAN 14           // Italian
#define USB_HID_COUNTRY_JAPAN_KATAKANA 15    // Japan (Katakana)
#define USB_HID_COUNTRY_KOREAN 16            // Korean
#define USB_HID_COUNTRY_LATIN_AMERICAN 17    // Latin American
#define USB_HID_COUNTRY_NETHERLANDS_DUTCH 18 // Netherlands/Dutch
#define USB_HID_COUNTRY_NORWEGIAN 19         // Norwegian
#define USB_HID_COUNTRY_PERSIAN_FARSI 20     // Persian (Farsi)
#define USB_HID_COUNTRY_POLAND 21            // Poland
#define USB_HID_COUNTRY_PORTUGUESE 22        // Portuguese
#define USB_HID_COUNTRY_RUSSIA 23            // Russia
#define USB_HID_COUNTRY_SLOVAKIA 24          // Slovakia
#define USB_HID_COUNTRY_SPANISH 25           // Spanish
#define USB_HID_COUNTRY_SWEDISH 26           // Swedish
#define USB_HID_COUNTRY_SWISS_FRENCH 27      // Swiss/French
#define USB_HID_COUNTRY_SWISS_GERMAN 28      // Swiss/German
#define USB_HID_COUNTRY_SWITZERLAND 29       // Switzerland
#define USB_HID_COUNTRY_TAIWAN 30            // Taiwan
#define USB_HID_COUNTRY_TURKISH_Q 31         // Turkish-Q
#define USB_HID_COUNTRY_UK 32                // UK
#define USB_HID_COUNTRY_US 33                // US
#define USB_HID_COUNTRY_YUGOSLAVIA 34        // Yugoslavia
#define USB_HID_COUNTRY_TURKISH_F \
    35  // Turkish-F
        //! @}
        //! @}
    35 // Turkish-F
       //! @}
       //! @}
//! @}

//! \name HID KEYS values


@@ 237,12 237,12 @@ COMPILER_PACK_RESET()
#define HID_SPACEBAR 44
#define HID_UNDERSCORE 45
#define HID_PLUS 46
#define HID_OPEN_BRACKET 47   // {
#define HID_CLOSE_BRACKET 48  // }
#define HID_OPEN_BRACKET 47  // {
#define HID_CLOSE_BRACKET 48 // }
#define HID_BACKSLASH 49
#define HID_ASH 50    // # ~
#define HID_COLON 51  // ; :
#define HID_QUOTE 52  // ' "
#define HID_ASH 50   // # ~
#define HID_COLON 51 // ; :
#define HID_QUOTE 52 // ' "
#define HID_TILDE 53
#define HID_COMMA 54
#define HID_DOT 55


@@ 314,4 314,4 @@ COMPILER_PACK_RESET()
#define HID_LED_KANA (1 << 4)
//! @}

#endif  // _USB_PROTOCOL_HID_H_
#endif // _USB_PROTOCOL_HID_H_

M tmk_core/protocol/arm_atsam/usb/usb_util.c => tmk_core/protocol/arm_atsam/usb/usb_util.c +14 -8
@@ 11,17 11,17 @@ char digit(int d, int radix) {
}

int UTIL_ltoa_radix(int64_t value, char *dest, int radix) {
    int64_t original = value;  // save original value
    int64_t original = value; // save original value
    char    buf[25]  = "";
    int     c        = sizeof(buf) - 1;
    int     last     = c;
    int     d;
    int     size;

    if (value < 0)  // if it's negative, take the absolute value
    if (value < 0) // if it's negative, take the absolute value
        value = -value;

    do  // write least significant digit of value that's left
    do // write least significant digit of value that's left
    {
        d        = (value % radix);
        buf[--c] = digit(d, radix);


@@ 30,14 30,20 @@ int UTIL_ltoa_radix(int64_t value, char *dest, int radix) {

    if (original < 0) buf[--c] = '-';

    size = last - c + 1;  // includes null at end
    size = last - c + 1; // includes null at end
    memcpy(dest, &buf[c], last - c + 1);

    return (size - 1);  // without null termination
    return (size - 1); // without null termination
}

int UTIL_ltoa(int64_t value, char *dest) { return UTIL_ltoa_radix(value, dest, 10); }
int UTIL_ltoa(int64_t value, char *dest) {
    return UTIL_ltoa_radix(value, dest, 10);
}

int UTIL_itoa(int value, char *dest) { return UTIL_ltoa_radix((int64_t)value, dest, 10); }
int UTIL_itoa(int value, char *dest) {
    return UTIL_ltoa_radix((int64_t)value, dest, 10);
}

int UTIL_utoa(uint32_t value, char *dest) { return UTIL_ltoa_radix((int64_t)value, dest, 10); }
int UTIL_utoa(uint32_t value, char *dest) {
    return UTIL_ltoa_radix((int64_t)value, dest, 10);
}

M tmk_core/protocol/arm_atsam/usb/usb_util.h => tmk_core/protocol/arm_atsam/usb/usb_util.h +1 -1
@@ 6,4 6,4 @@ int UTIL_ltoa(int64_t value, char *dest);
int UTIL_itoa(int value, char *dest);
int UTIL_utoa(uint32_t value, char *dest);

#endif  //_USB_UTIL_H_
#endif //_USB_UTIL_H_

M tmk_core/protocol/chibios/chibios.c => tmk_core/protocol/chibios/chibios.c +5 -3
@@ 107,7 107,7 @@ __attribute__((weak)) void early_hardware_init_pre(void) {
#if EARLY_INIT_PERFORM_BOOTLOADER_JUMP
    void enter_bootloader_mode_if_requested(void);
    enter_bootloader_mode_if_requested();
#endif  // EARLY_INIT_PERFORM_BOOTLOADER_JUMP
#endif // EARLY_INIT_PERFORM_BOOTLOADER_JUMP
}

__attribute__((weak)) void early_hardware_init_post(void) {}


@@ 176,7 176,9 @@ void protocol_pre_init(void) {
    print("USB configured.\n");
}

void protocol_post_init(void) { host_set_driver(driver); }
void protocol_post_init(void) {
    host_set_driver(driver);
}

void protocol_pre_task(void) {
    usb_event_queue_task();


@@ 186,7 188,7 @@ void protocol_pre_task(void) {
        print("[s]");
        while (USB_DRIVER.state == USB_SUSPENDED) {
            /* Do this in the suspended state */
            suspend_power_down();  // on AVR this deep sleeps for 15ms
            suspend_power_down(); // on AVR this deep sleeps for 15ms
            /* Remote wakeup */
            if (suspend_wakeup_condition()) {
                usbWakeupHost(&USB_DRIVER);

M tmk_core/protocol/chibios/usb_driver.c => tmk_core/protocol/chibios/usb_driver.c +24 -8
@@ 80,21 80,37 @@ static bool qmkusb_start_receive(QMKUSBDriver *qmkusbp) {
 * Interface implementation.
 */

static size_t _write(void *ip, const uint8_t *bp, size_t n) { return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, TIME_INFINITE); }
static size_t _write(void *ip, const uint8_t *bp, size_t n) {
    return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, TIME_INFINITE);
}

static size_t _read(void *ip, uint8_t *bp, size_t n) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE); }
static size_t _read(void *ip, uint8_t *bp, size_t n) {
    return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE);
}

static msg_t _put(void *ip, uint8_t b) { return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, TIME_INFINITE); }
static msg_t _put(void *ip, uint8_t b) {
    return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, TIME_INFINITE);
}

static msg_t _get(void *ip) { return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, TIME_INFINITE); }
static msg_t _get(void *ip) {
    return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, TIME_INFINITE);
}

static msg_t _putt(void *ip, uint8_t b, sysinterval_t timeout) { return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, timeout); }
static msg_t _putt(void *ip, uint8_t b, sysinterval_t timeout) {
    return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, timeout);
}

static msg_t _gett(void *ip, sysinterval_t timeout) { return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, timeout); }
static msg_t _gett(void *ip, sysinterval_t timeout) {
    return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, timeout);
}

static size_t _writet(void *ip, const uint8_t *bp, size_t n, sysinterval_t timeout) { return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, timeout); }
static size_t _writet(void *ip, const uint8_t *bp, size_t n, sysinterval_t timeout) {
    return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, timeout);
}

static size_t _readt(void *ip, uint8_t *bp, size_t n, sysinterval_t timeout) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, timeout); }
static size_t _readt(void *ip, uint8_t *bp, size_t n, sysinterval_t timeout) {
    return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, timeout);
}

static const struct QMKUSBDriverVMT vmt = {0, _write, _read, _put, _get, _putt, _gett, _writet, _readt};


M tmk_core/protocol/chibios/usb_main.c => tmk_core/protocol/chibios/usb_main.c +17 -7
@@ 775,7 775,9 @@ void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
/* start-of-frame handler
 * TODO: i guess it would be better to re-implement using timers,
 *  so that this is not going to have to be checked every 1ms */
void kbd_sof_cb(USBDriver *usbp) { (void)usbp; }
void kbd_sof_cb(USBDriver *usbp) {
    (void)usbp;
}

/* Idle requests timer code
 * callback (called from ISR, unlocked state) */


@@ 815,7 817,9 @@ static void keyboard_idle_timer_cb(void *arg) {
}

/* LED status */
uint8_t keyboard_leds(void) { return keyboard_led_state; }
uint8_t keyboard_leds(void) {
    return keyboard_led_state;
}

/* prepare and start sending a report IN
 * not callable from ISR or locked state */


@@ 915,7 919,9 @@ void send_mouse(report_mouse_t *report) {
}

#else  /* MOUSE_ENABLE */
void send_mouse(report_mouse_t *report) { (void)report; }
void send_mouse(report_mouse_t *report) {
    (void)report;
}
#endif /* MOUSE_ENABLE */

/* ---------------------------------------------------------


@@ 1107,7 1113,9 @@ void raw_hid_task(void) {

#ifdef MIDI_ENABLE

void send_midi_packet(MIDI_EventPacket_t *event) { chnWrite(&drivers.midi_driver.driver, (uint8_t *)event, sizeof(MIDI_EventPacket_t)); }
void send_midi_packet(MIDI_EventPacket_t *event) {
    chnWrite(&drivers.midi_driver.driver, (uint8_t *)event, sizeof(MIDI_EventPacket_t));
}

bool recv_midi_packet(MIDI_EventPacket_t *const event) {
    size_t size = chnReadTimeout(&drivers.midi_driver.driver, (uint8_t *)event, sizeof(MIDI_EventPacket_t), TIME_IMMEDIATE);


@@ 1130,7 1138,9 @@ void midi_ep_task(void) {

void virtser_init(void) {}

void virtser_send(const uint8_t byte) { chnWrite(&drivers.serial_driver.driver, &byte, 1); }
void virtser_send(const uint8_t byte) {
    chnWrite(&drivers.serial_driver.driver, &byte, 1);
}

__attribute__((weak)) void virtser_recv(uint8_t c) {
    // Ignore by default


@@ 1174,7 1184,7 @@ void send_joystick_packet(joystick_t *joystick) {
          joystick->axes[5],
#        endif
        },
#    endif  // JOYSTICK_AXES_COUNT>0
#    endif // JOYSTICK_AXES_COUNT>0

#    if JOYSTICK_BUTTON_COUNT > 0
        .buttons = {


@@ 1190,7 1200,7 @@ void send_joystick_packet(joystick_t *joystick) {
            joystick->buttons[3],
#        endif
        }
#    endif  // JOYSTICK_BUTTON_COUNT>0
#    endif // JOYSTICK_BUTTON_COUNT>0
    };

    // chnWrite(&drivers.joystick_driver.driver, (uint8_t *)&rep, sizeof(rep));

M tmk_core/protocol/chibios/usb_util.c => tmk_core/protocol/chibios/usb_util.c +6 -2
@@ 16,6 16,10 @@
#include <hal.h>
#include "usb_util.h"

void usb_disconnect(void) { usbStop(&USBD1); }
void usb_disconnect(void) {
    usbStop(&USBD1);
}

bool usb_connected_state(void) { return usbGetDriverStateI(&USBD1) == USB_ACTIVE; }
bool usb_connected_state(void) {
    return usbGetDriverStateI(&USBD1) == USB_ACTIVE;
}

M tmk_core/protocol/host.c => tmk_core/protocol/host.c +21 -7
@@ 34,13 34,19 @@ static uint16_t       last_system_report              = 0;
static uint16_t       last_consumer_report            = 0;
static uint32_t       last_programmable_button_report = 0;

void host_set_driver(host_driver_t *d) { driver = d; }
void host_set_driver(host_driver_t *d) {
    driver = d;
}

host_driver_t *host_get_driver(void) { return driver; }
host_driver_t *host_get_driver(void) {
    return driver;
}

#ifdef SPLIT_KEYBOARD
uint8_t split_led_state = 0;
void    set_split_host_keyboard_leds(uint8_t led_state) { split_led_state = led_state; }
void    set_split_host_keyboard_leds(uint8_t led_state) {
    split_led_state = led_state;
}
#endif

uint8_t host_keyboard_leds(void) {


@@ 51,7 57,9 @@ uint8_t host_keyboard_leds(void) {
    return (*driver->keyboard_leds)();
}

led_t host_keyboard_led_state(void) { return (led_t)host_keyboard_leds(); }
led_t host_keyboard_led_state(void) {
    return (led_t)host_keyboard_leds();
}

/* send report */
void host_keyboard_send(report_keyboard_t *report) {


@@ 131,8 139,14 @@ void host_programmable_button_send(uint32_t report) {
    (*driver->send_programmable_button)(report);
}

uint16_t host_last_system_report(void) { return last_system_report; }
uint16_t host_last_system_report(void) {
    return last_system_report;
}

uint16_t host_last_consumer_report(void) { return last_consumer_report; }
uint16_t host_last_consumer_report(void) {
    return last_consumer_report;
}

uint32_t host_last_programmable_button_report(void) { return last_programmable_button_report; }
uint32_t host_last_programmable_button_report(void) {
    return last_programmable_button_report;
}

M tmk_core/protocol/lufa/lufa.c => tmk_core/protocol/lufa/lufa.c +36 -17
@@ 256,7 256,8 @@ static void Console_Task(void) {
    }

    // fill empty bank
    while (Endpoint_IsReadWriteAllowed()) Endpoint_Write_8(0);
    while (Endpoint_IsReadWriteAllowed())
        Endpoint_Write_8(0);

    // flush sendchar packet
    if (Endpoint_IsINReady()) {


@@ 296,7 297,7 @@ void send_joystick_packet(joystick_t *joystick) {
          joystick->axes[5],
#        endif
        },
#    endif  // JOYSTICK_AXES_COUNT>0
#    endif // JOYSTICK_AXES_COUNT>0

#    if JOYSTICK_BUTTON_COUNT > 0
        .buttons = {


@@ 312,14 313,15 @@ void send_joystick_packet(joystick_t *joystick) {
            joystick->buttons[3],
#        endif
        }
#    endif  // JOYSTICK_BUTTON_COUNT>0
#    endif // JOYSTICK_BUTTON_COUNT>0
    };

    /* Select the Joystick Report Endpoint */
    Endpoint_SelectEndpoint(JOYSTICK_IN_EPNUM);

    /* Check if write ready for a polling interval around 10ms */
    while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
    while (timeout-- && !Endpoint_IsReadWriteAllowed())
        _delay_us(40);
    if (!Endpoint_IsReadWriteAllowed()) return;

    /* Write Joystick Report Data */


@@ 414,9 416,11 @@ void EVENT_USB_Device_WakeUp() {

#ifdef CONSOLE_ENABLE
static bool console_flush = false;
#    define CONSOLE_FLUSH_SET(b)                                     \
        do {                                                         \
            ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { console_flush = b; } \
#    define CONSOLE_FLUSH_SET(b)                \
        do {                                    \
            ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { \
                console_flush = b;              \
            }                                   \
        } while (0)

/** \brief Event USB Device Start Of Frame


@@ 634,7 638,9 @@ void EVENT_USB_Device_ControlRequest(void) {
 *
 * FIXME: Needs doc
 */
static uint8_t keyboard_leds(void) { return keyboard_led_state; }
static uint8_t keyboard_leds(void) {
    return keyboard_led_state;
}

/** \brief Send Keyboard
 *


@@ 665,7 671,8 @@ static void send_keyboard(report_keyboard_t *report) {
#endif
    Endpoint_SelectEndpoint(ep);
    /* Check if write ready for a polling interval around 10ms */
    while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
    while (timeout-- && !Endpoint_IsReadWriteAllowed())
        _delay_us(40);
    if (!Endpoint_IsReadWriteAllowed()) return;

    /* If we're in Boot Protocol, don't send any report ID or other funky fields */


@@ 705,7 712,8 @@ static void send_mouse(report_mouse_t *report) {
    Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);

    /* Check if write ready for a polling interval around 10ms */
    while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
    while (timeout-- && !Endpoint_IsReadWriteAllowed())
        _delay_us(40);
    if (!Endpoint_IsReadWriteAllowed()) return;

    /* Write Mouse Report Data */


@@ 725,7 733,8 @@ static void send_report(void *report, size_t size) {
    Endpoint_SelectEndpoint(SHARED_IN_EPNUM);

    /* Check if write ready for a polling interval around 10ms */
    while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
    while (timeout-- && !Endpoint_IsReadWriteAllowed())
        _delay_us(40);
    if (!Endpoint_IsReadWriteAllowed()) return;

    Endpoint_Write_Stream_LE(report, size, NULL);


@@ 876,9 885,13 @@ USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface = {

// clang-format on

void send_midi_packet(MIDI_EventPacket_t *event) { MIDI_Device_SendEventPacket(&USB_MIDI_Interface, event); }
void send_midi_packet(MIDI_EventPacket_t *event) {
    MIDI_Device_SendEventPacket(&USB_MIDI_Interface, event);
}

bool recv_midi_packet(MIDI_EventPacket_t *const event) { return MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, event); }
bool recv_midi_packet(MIDI_EventPacket_t *const event) {
    return MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, event);
}

#endif



@@ 934,7 947,8 @@ void virtser_send(const uint8_t byte) {
            return;
        }

        while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
        while (timeout-- && !Endpoint_IsReadWriteAllowed())
            _delay_us(40);

        Endpoint_Write_8(byte);
        CDC_Device_Flush(&cdc_device);


@@ 957,7 971,8 @@ void send_digitizer(report_digitizer_t *report) {
    Endpoint_SelectEndpoint(DIGITIZER_IN_EPNUM);

    /* Check if write ready for a polling interval around 10ms */
    while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
    while (timeout-- && !Endpoint_IsReadWriteAllowed())
        _delay_us(40);
    if (!Endpoint_IsReadWriteAllowed()) return;

    Endpoint_Write_Stream_LE(report, sizeof(report_digitizer_t), NULL);


@@ 1033,7 1048,9 @@ void protocol_pre_init(void) {
#endif
}

void protocol_post_init(void) { host_set_driver(&lufa_driver); }
void protocol_post_init(void) {
    host_set_driver(&lufa_driver);
}

void protocol_pre_task(void) {
#if !defined(NO_USB_STARTUP_CHECK)


@@ 1084,4 1101,6 @@ void protocol_post_task(void) {
#endif
}

uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint16_t wIndex, const void **const DescriptorAddress) { return get_usb_descriptor(wValue, wIndex, DescriptorAddress); }
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint16_t wIndex, const void **const DescriptorAddress) {
    return get_usb_descriptor(wValue, wIndex, DescriptorAddress);
}

M tmk_core/protocol/lufa/usb_util.c => tmk_core/protocol/lufa/usb_util.c +5 -3
@@ 22,13 22,15 @@ void usb_disconnect(void) {
    USB_DeviceState = DEVICE_STATE_Unattached;
}

bool usb_connected_state(void) { return USB_Device_IsAddressSet(); }
bool usb_connected_state(void) {
    return USB_Device_IsAddressSet();
}

#if defined(OTGPADE)
bool usb_vbus_state(void) {
    USB_OTGPAD_On();  // enables VBUS pad
    USB_OTGPAD_On(); // enables VBUS pad
    wait_us(5);

    return USB_VBUS_GetStatus();  // checks state of VBUS
    return USB_VBUS_GetStatus(); // checks state of VBUS
}
#endif

M tmk_core/protocol/midi/bytequeue/bytequeue.c => tmk_core/protocol/midi/bytequeue/bytequeue.c +3 -1
@@ 52,7 52,9 @@ byteQueueIndex_t bytequeue_length(byteQueue_t* queue) {
}

// we don't need to avoid interrupts if there is only one reader
uint8_t bytequeue_get(byteQueue_t* queue, byteQueueIndex_t index) { return queue->data[(queue->start + index) % queue->length]; }
uint8_t bytequeue_get(byteQueue_t* queue, byteQueueIndex_t index) {
    return queue->data[(queue->start + index) % queue->length];
}

// we just update the start index to remove elements
void bytequeue_remove(byteQueue_t* queue, byteQueueIndex_t numToRemove) {

M tmk_core/protocol/midi/bytequeue/interrupt_setting.c => tmk_core/protocol/midi/bytequeue/interrupt_setting.c +6 -2
@@ 30,7 30,9 @@ interrupt_setting_t store_and_clear_interrupt(void) {
    return sreg;
}

void restore_interrupt_setting(interrupt_setting_t setting) { SREG = setting; }
void restore_interrupt_setting(interrupt_setting_t setting) {
    SREG = setting;
}
#elif defined(__arm__)
#    include <ch.h>



@@ 39,5 41,7 @@ interrupt_setting_t store_and_clear_interrupt(void) {
    return 0;
}

void restore_interrupt_setting(interrupt_setting_t setting) { chSysUnlock(); }
void restore_interrupt_setting(interrupt_setting_t setting) {
    chSysUnlock();
}
#endif

M tmk_core/protocol/midi/midi.c => tmk_core/protocol/midi/midi.c +97 -33
@@ 17,7 17,7 @@
// along with avr-midi.  If not, see <http://www.gnu.org/licenses/>.

#include "midi.h"
#include <string.h>  //for memcpy
#include <string.h> //for memcpy

#define MIN(x, y) (((x) < (y)) ? (x) : (y))



@@ 25,9 25,13 @@
#    define NULL 0
#endif

bool midi_is_statusbyte(uint8_t theByte) { return (bool)(theByte & MIDI_STATUSMASK); }
bool midi_is_statusbyte(uint8_t theByte) {
    return (bool)(theByte & MIDI_STATUSMASK);
}

bool midi_is_realtime(uint8_t theByte) { return (theByte >= MIDI_CLOCK); }
bool midi_is_realtime(uint8_t theByte) {
    return (theByte >= MIDI_CLOCK);
}

midi_packet_length_t midi_packet_length(uint8_t status) {
    switch (status & 0xF0) {


@@ 83,7 87,9 @@ void midi_send_noteoff(MidiDevice* device, uint8_t chan, uint8_t num, uint8_t ve
    device->send_func(device, 3, MIDI_NOTEOFF | (chan & MIDI_CHANMASK), num & 0x7F, vel & 0x7F);
}

void midi_send_aftertouch(MidiDevice* device, uint8_t chan, uint8_t note_num, uint8_t amt) { device->send_func(device, 3, MIDI_AFTERTOUCH | (chan & MIDI_CHANMASK), note_num & 0x7F, amt & 0x7F); }
void midi_send_aftertouch(MidiDevice* device, uint8_t chan, uint8_t note_num, uint8_t amt) {
    device->send_func(device, 3, MIDI_AFTERTOUCH | (chan & MIDI_CHANMASK), note_num & 0x7F, amt & 0x7F);
}

// XXX does this work right?
// amt in range -0x2000, 0x1fff


@@ 102,34 108,62 @@ void midi_send_pitchbend(MidiDevice* device, uint8_t chan, int16_t amt) {
    device->send_func(device, 3, MIDI_PITCHBEND | (chan & MIDI_CHANMASK), uAmt & 0x7F, (uAmt >> 7) & 0x7F);
}

void midi_send_programchange(MidiDevice* device, uint8_t chan, uint8_t num) { device->send_func(device, 2, MIDI_PROGCHANGE | (chan & MIDI_CHANMASK), num & 0x7F, 0); }
void midi_send_programchange(MidiDevice* device, uint8_t chan, uint8_t num) {
    device->send_func(device, 2, MIDI_PROGCHANGE | (chan & MIDI_CHANMASK), num & 0x7F, 0);
}

void midi_send_channelpressure(MidiDevice* device, uint8_t chan, uint8_t amt) { device->send_func(device, 2, MIDI_CHANPRESSURE | (chan & MIDI_CHANMASK), amt & 0x7F, 0); }
void midi_send_channelpressure(MidiDevice* device, uint8_t chan, uint8_t amt) {
    device->send_func(device, 2, MIDI_CHANPRESSURE | (chan & MIDI_CHANMASK), amt & 0x7F, 0);
}

void midi_send_clock(MidiDevice* device) { device->send_func(device, 1, MIDI_CLOCK, 0, 0); }
void midi_send_clock(MidiDevice* device) {
    device->send_func(device, 1, MIDI_CLOCK, 0, 0);
}

void midi_send_tick(MidiDevice* device) { device->send_func(device, 1, MIDI_TICK, 0, 0); }
void midi_send_tick(MidiDevice* device) {
    device->send_func(device, 1, MIDI_TICK, 0, 0);
}

void midi_send_start(MidiDevice* device) { device->send_func(device, 1, MIDI_START, 0, 0); }
void midi_send_start(MidiDevice* device) {
    device->send_func(device, 1, MIDI_START, 0, 0);
}

void midi_send_continue(MidiDevice* device) { device->send_func(device, 1, MIDI_CONTINUE, 0, 0); }
void midi_send_continue(MidiDevice* device) {
    device->send_func(device, 1, MIDI_CONTINUE, 0, 0);
}

void midi_send_stop(MidiDevice* device) { device->send_func(device, 1, MIDI_STOP, 0, 0); }
void midi_send_stop(MidiDevice* device) {
    device->send_func(device, 1, MIDI_STOP, 0, 0);
}

void midi_send_activesense(MidiDevice* device) { device->send_func(device, 1, MIDI_ACTIVESENSE, 0, 0); }
void midi_send_activesense(MidiDevice* device) {
    device->send_func(device, 1, MIDI_ACTIVESENSE, 0, 0);
}

void midi_send_reset(MidiDevice* device) { device->send_func(device, 1, MIDI_RESET, 0, 0); }
void midi_send_reset(MidiDevice* device) {
    device->send_func(device, 1, MIDI_RESET, 0, 0);
}

void midi_send_tcquarterframe(MidiDevice* device, uint8_t time) { device->send_func(device, 2, MIDI_TC_QUARTERFRAME, time & 0x7F, 0); }
void midi_send_tcquarterframe(MidiDevice* device, uint8_t time) {
    device->send_func(device, 2, MIDI_TC_QUARTERFRAME, time & 0x7F, 0);
}

// XXX is this right?
void midi_send_songposition(MidiDevice* device, uint16_t pos) { device->send_func(device, 3, MIDI_SONGPOSITION, pos & 0x7F, (pos >> 7) & 0x7F); }
void midi_send_songposition(MidiDevice* device, uint16_t pos) {
    device->send_func(device, 3, MIDI_SONGPOSITION, pos & 0x7F, (pos >> 7) & 0x7F);
}

void midi_send_songselect(MidiDevice* device, uint8_t song) { device->send_func(device, 2, MIDI_SONGSELECT, song & 0x7F, 0); }
void midi_send_songselect(MidiDevice* device, uint8_t song) {
    device->send_func(device, 2, MIDI_SONGSELECT, song & 0x7F, 0);
}

void midi_send_tunerequest(MidiDevice* device) { device->send_func(device, 1, MIDI_TUNEREQUEST, 0, 0); }
void midi_send_tunerequest(MidiDevice* device) {
    device->send_func(device, 1, MIDI_TUNEREQUEST, 0, 0);
}

void midi_send_byte(MidiDevice* device, uint8_t b) { device->send_func(device, 1, b, 0, 0); }
void midi_send_byte(MidiDevice* device, uint8_t b) {
    device->send_func(device, 1, b, 0, 0);
}

void midi_send_data(MidiDevice* device, uint16_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2) {
    // ensure that the count passed along is always 3 or lower


@@ 150,32 184,62 @@ void midi_send_array(MidiDevice* device, uint16_t count, uint8_t* array) {
    }
}

void midi_register_cc_callback(MidiDevice* device, midi_three_byte_func_t func) { device->input_cc_callback = func; }
void midi_register_cc_callback(MidiDevice* device, midi_three_byte_func_t func) {
    device->input_cc_callback = func;
}

void midi_register_noteon_callback(MidiDevice* device, midi_three_byte_func_t func) { device->input_noteon_callback = func; }
void midi_register_noteon_callback(MidiDevice* device, midi_three_byte_func_t func) {
    device->input_noteon_callback = func;
}

void midi_register_noteoff_callback(MidiDevice* device, midi_three_byte_func_t func) { device->input_noteoff_callback = func; }
void midi_register_noteoff_callback(MidiDevice* device, midi_three_byte_func_t func) {
    device->input_noteoff_callback = func;
}

void midi_register_aftertouch_callback(MidiDevice* device, midi_three_byte_func_t func) { device->input_aftertouch_callback = func; }
void midi_register_aftertouch_callback(MidiDevice* device, midi_three_byte_func_t func) {
    device->input_aftertouch_callback = func;
}

void midi_register_pitchbend_callback(MidiDevice* device, midi_three_byte_func_t func) { device->input_pitchbend_callback = func; }
void midi_register_pitchbend_callback(MidiDevice* device, midi_three_byte_func_t func) {
    device->input_pitchbend_callback = func;
}

void midi_register_songposition_callback(MidiDevice* device, midi_three_byte_func_t func) { device->input_songposition_callback = func; }
void midi_register_songposition_callback(MidiDevice* device, midi_three_byte_func_t func) {
    device->input_songposition_callback = func;
}

void midi_register_progchange_callback(MidiDevice* device, midi_two_byte_func_t func) { device->input_progchange_callback = func; }
void midi_register_progchange_callback(MidiDevice* device, midi_two_byte_func_t func) {
    device->input_progchange_callback = func;
}

void midi_register_chanpressure_callback(MidiDevice* device, midi_two_byte_func_t func) { device->input_chanpressure_callback = func; }
void midi_register_chanpressure_callback(MidiDevice* device, midi_two_byte_func_t func) {
    device->input_chanpressure_callback = func;
}

void midi_register_songselect_callback(MidiDevice* device, midi_two_byte_func_t func) { device->input_songselect_callback = func; }
void midi_register_songselect_callback(MidiDevice* device, midi_two_byte_func_t func) {
    device->input_songselect_callback = func;
}

void midi_register_tc_quarterframe_callback(MidiDevice* device, midi_two_byte_func_t func) { device->input_tc_quarterframe_callback = func; }
void midi_register_tc_quarterframe_callback(MidiDevice* device, midi_two_byte_func_t func) {
    device->input_tc_quarterframe_callback = func;
}

void midi_register_realtime_callback(MidiDevice* device, midi_one_byte_func_t func) { device->input_realtime_callback = func; }
void midi_register_realtime_callback(MidiDevice* device, midi_one_byte_func_t func) {
    device->input_realtime_callback = func;
}

void midi_register_tunerequest_callback(MidiDevice* device, midi_one_byte_func_t func) { device->input_tunerequest_callback = func; }
void midi_register_tunerequest_callback(MidiDevice* device, midi_one_byte_func_t func) {
    device->input_tunerequest_callback = func;
}

void midi_register_sysex_callback(MidiDevice* device, midi_sysex_func_t func) { device->input_sysex_callback = func; }
void midi_register_sysex_callback(MidiDevice* device, midi_sysex_func_t func) {
    device->input_sysex_callback = func;
}

void midi_register_fallthrough_callback(MidiDevice* device, midi_var_byte_func_t func) { device->input_fallthrough_callback = func; }
void midi_register_fallthrough_callback(MidiDevice* device, midi_var_byte_func_t func) {
    device->input_fallthrough_callback = func;
}

void midi_register_catchall_callback(MidiDevice* device, midi_var_byte_func_t func) { device->input_catchall_callback = func; }
void midi_register_catchall_callback(MidiDevice* device, midi_var_byte_func_t func) {
    device->input_catchall_callback = func;
}

M tmk_core/protocol/midi/midi.h => tmk_core/protocol/midi/midi.h +3 -3
@@ 48,7 48,7 @@ extern "C" {
 *
 * @param device the device to initialize
 */
void midi_device_init(MidiDevice* device);  // [implementation in midi_device.c]
void midi_device_init(MidiDevice* device); // [implementation in midi_device.c]

/**
 * @brief Process input data


@@ 58,7 58,7 @@ void midi_device_init(MidiDevice* device);  // [implementation in midi_device.c]
 *
 * @param device the device to process
 */
void midi_device_process(MidiDevice* device);  // [implementation in midi_device.c]
void midi_device_process(MidiDevice* device); // [implementation in midi_device.c]

/**@}*/



@@ 115,7 115,7 @@ void midi_send_aftertouch(MidiDevice* device, uint8_t chan, uint8_t note_num, ui
 * @param chan the channel to send on, 0-15
 * @param amt the bend amount range: -8192..8191, 0 means no bend
 */
void midi_send_pitchbend(MidiDevice* device, uint8_t chan, int16_t amt);  // range -8192, 8191
void midi_send_pitchbend(MidiDevice* device, uint8_t chan, int16_t amt); // range -8192, 8191

/**
 * @brief Send a program change message via the given device.

M tmk_core/protocol/midi/midi_device.c => tmk_core/protocol/midi/midi_device.c +8 -3
@@ 60,12 60,17 @@ void midi_device_init(MidiDevice* device) {

void midi_device_input(MidiDevice* device, uint8_t cnt, uint8_t* input) {
    uint8_t i;
    for (i = 0; i < cnt; i++) bytequeue_enqueue(&device->input_queue, input[i]);
    for (i = 0; i < cnt; i++)
        bytequeue_enqueue(&device->input_queue, input[i]);
}

void midi_device_set_send_func(MidiDevice* device, midi_var_byte_func_t send_func) { device->send_func = send_func; }
void midi_device_set_send_func(MidiDevice* device, midi_var_byte_func_t send_func) {
    device->send_func = send_func;
}

void midi_device_set_pre_input_process_func(MidiDevice* device, midi_no_byte_func_t pre_process_func) { device->pre_input_process_callback = pre_process_func; }
void midi_device_set_pre_input_process_func(MidiDevice* device, midi_no_byte_func_t pre_process_func) {
    device->pre_input_process_callback = pre_process_func;
}

void midi_device_process(MidiDevice* device) {
    // call the pre_input_process_callback if there is one

M tmk_core/protocol/midi/qmk_midi.c => tmk_core/protocol/midi/qmk_midi.c +1 -1
@@ 50,7 50,7 @@ static void usb_send_func(MidiDevice* device, uint16_t cnt, uint8_t byte0, uint8
                    event.Event = MIDI_EVENT(cable, SYSEX_START_OR_CONT);
                break;
            default:
                return;  // invalid cnt
                return; // invalid cnt
        }
    } else {
        // deal with 'system common' messages

M tmk_core/protocol/midi/sysex_tools.c => tmk_core/protocol/midi/sysex_tools.c +1 -1
@@ 35,7 35,7 @@ uint16_t sysex_decoded_length(uint16_t encoded_length) {
}

uint16_t sysex_encode(uint8_t *encoded, const uint8_t *source, const uint16_t length) {
    uint16_t encoded_full = length / 7;  // number of full 8 byte sections from 7 bytes of input
    uint16_t encoded_full = length / 7; // number of full 8 byte sections from 7 bytes of input
    uint16_t i, j;

    // fill out the fully encoded sections

M tmk_core/protocol/usb_descriptor.h => tmk_core/protocol/usb_descriptor.h +1 -1
@@ 200,7 200,7 @@ enum usb_interfaces {
 * Endpoint numbers
 */
enum usb_endpoints {
    __unused_epnum__ = NEXT_EPNUM,  // Endpoint numbering starts at 1
    __unused_epnum__ = NEXT_EPNUM, // Endpoint numbering starts at 1

#ifndef KEYBOARD_SHARED_EP
    KEYBOARD_IN_EPNUM = NEXT_EPNUM,

M tmk_core/protocol/usb_device_state.c => tmk_core/protocol/usb_device_state.c +3 -1
@@ 22,7 22,9 @@

enum usb_device_state usb_device_state = USB_DEVICE_STATE_NO_INIT;

__attribute__((weak)) void notify_usb_device_state_change_kb(enum usb_device_state usb_device_state) { notify_usb_device_state_change_user(usb_device_state); }
__attribute__((weak)) void notify_usb_device_state_change_kb(enum usb_device_state usb_device_state) {
    notify_usb_device_state_change_user(usb_device_state);
}

__attribute__((weak)) void notify_usb_device_state_change_user(enum usb_device_state usb_device_state) {}


M tmk_core/protocol/usb_device_state.h => tmk_core/protocol/usb_device_state.h +4 -4
@@ 27,10 27,10 @@ void usb_device_state_set_reset(void);
void usb_device_state_init(void);

enum usb_device_state {
    USB_DEVICE_STATE_NO_INIT    = 0,  // We're in this state before calling usb_device_state_init()
    USB_DEVICE_STATE_INIT       = 1,  // Can consume up to 100mA
    USB_DEVICE_STATE_CONFIGURED = 2,  // Can consume up to what is specified in configuration descriptor, typically 500mA
    USB_DEVICE_STATE_SUSPEND    = 3   // Can consume only suspend current
    USB_DEVICE_STATE_NO_INIT    = 0, // We're in this state before calling usb_device_state_init()
    USB_DEVICE_STATE_INIT       = 1, // Can consume up to 100mA
    USB_DEVICE_STATE_CONFIGURED = 2, // Can consume up to what is specified in configuration descriptor, typically 500mA
    USB_DEVICE_STATE_SUSPEND    = 3  // Can consume only suspend current
};

extern enum usb_device_state usb_device_state;

M tmk_core/protocol/usb_util.c => tmk_core/protocol/usb_util.c +3 -1
@@ 17,7 17,9 @@
#include "usb_util.h"

__attribute__((weak)) void usb_disconnect(void) {}
__attribute__((weak)) bool usb_connected_state(void) { return true; }
__attribute__((weak)) bool usb_connected_state(void) {
    return true;
}
__attribute__((weak)) bool usb_vbus_state(void) {
#ifdef USB_VBUS_PIN
    setPinInput(USB_VBUS_PIN);

M tmk_core/protocol/vusb/protocol.c => tmk_core/protocol/vusb/protocol.c +3 -1
@@ 97,7 97,9 @@ static void vusb_wakeup(void) {
 *
 * FIXME: Needs doc
 */
static void setup_usb(void) { initForUsbConnectivity(); }
static void setup_usb(void) {
    initForUsbConnectivity();
}

uint16_t sof_timer = 0;


M tmk_core/protocol/vusb/usb_util.c => tmk_core/protocol/vusb/usb_util.c +3 -1
@@ 16,7 16,9 @@
#include <usbdrv/usbdrv.h>
#include "usb_util.h"

void usb_disconnect(void) { usbDeviceDisconnect(); }
void usb_disconnect(void) {
    usbDeviceDisconnect();
}

bool usb_connected_state(void) {
    usbPoll();

M tmk_core/protocol/vusb/vusb.c => tmk_core/protocol/vusb/vusb.c +181 -177
@@ 230,9 230,13 @@ static void    send_programmable_button(uint32_t data);

static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};

host_driver_t *vusb_driver(void) { return &driver; }
host_driver_t *vusb_driver(void) {
    return &driver;
}

static uint8_t keyboard_leds(void) { return keyboard_led_state; }
static uint8_t keyboard_leds(void) {
    return keyboard_led_state;
}

static void send_keyboard(report_keyboard_t *report) {
    uint8_t next = (kbuf_head + 1) % KBUF_SIZE;


@@ 348,7 352,7 @@ usbMsgLen_t usbFunctionSetup(uchar data[8]) {
                last_req.kind = SET_LED;
                last_req.len  = rq->wLength.word;
            }
            return USB_NO_MSG;  // to get data in usbFunctionWrite
            return USB_NO_MSG; // to get data in usbFunctionWrite
        } else {
            dprint("UNKNOWN:");
        }


@@ 410,47 414,47 @@ const PROGMEM uchar shared_hid_report[] = {
#else
const PROGMEM uchar keyboard_hid_report[] = {
#endif
    0x05, 0x01,  // Usage Page (Generic Desktop)
    0x09, 0x06,  // Usage (Keyboard)
    0xA1, 0x01,  // Collection (Application)
    0x05, 0x01, // Usage Page (Generic Desktop)
    0x09, 0x06, // Usage (Keyboard)
    0xA1, 0x01, // Collection (Application)
#ifdef KEYBOARD_SHARED_EP
    0x85, REPORT_ID_KEYBOARD,  // Report ID
    0x85, REPORT_ID_KEYBOARD, // Report ID
#endif
    // Modifiers (8 bits)
    0x05, 0x07,  //   Usage Page (Keyboard/Keypad)
    0x19, 0xE0,  //   Usage Minimum (Keyboard Left Control)
    0x29, 0xE7,  //   Usage Maximum (Keyboard Right GUI)
    0x15, 0x00,  //   Logical Minimum (0)
    0x25, 0x01,  //   Logical Maximum (1)
    0x95, 0x08,  //   Report Count (8)
    0x75, 0x01,  //   Report Size (1)
    0x81, 0x02,  //   Input (Data, Variable, Absolute)
    0x05, 0x07, //   Usage Page (Keyboard/Keypad)
    0x19, 0xE0, //   Usage Minimum (Keyboard Left Control)
    0x29, 0xE7, //   Usage Maximum (Keyboard Right GUI)
    0x15, 0x00, //   Logical Minimum (0)
    0x25, 0x01, //   Logical Maximum (1)
    0x95, 0x08, //   Report Count (8)
    0x75, 0x01, //   Report Size (1)
    0x81, 0x02, //   Input (Data, Variable, Absolute)
    // Reserved (1 byte)
    0x95, 0x01,  //   Report Count (1)
    0x75, 0x08,  //   Report Size (8)
    0x81, 0x03,  //   Input (Constant)
    0x95, 0x01, //   Report Count (1)
    0x75, 0x08, //   Report Size (8)
    0x81, 0x03, //   Input (Constant)
    // Keycodes (6 bytes)
    0x05, 0x07,        //   Usage Page (Keyboard/Keypad)
    0x19, 0x00,        //   Usage Minimum (0)
    0x29, 0xFF,        //   Usage Maximum (255)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x95, 0x06,        //   Report Count (6)
    0x75, 0x08,        //   Report Size (8)
    0x81, 0x00,        //   Input (Data, Array, Absolute)
    0x05, 0x07,       //   Usage Page (Keyboard/Keypad)
    0x19, 0x00,       //   Usage Minimum (0)
    0x29, 0xFF,       //   Usage Maximum (255)
    0x15, 0x00,       //   Logical Minimum (0)
    0x26, 0xFF, 0x00, //   Logical Maximum (255)
    0x95, 0x06,       //   Report Count (6)
    0x75, 0x08,       //   Report Size (8)
    0x81, 0x00,       //   Input (Data, Array, Absolute)

    // Status LEDs (5 bits)
    0x05, 0x08,  //   Usage Page (LED)
    0x19, 0x01,  //   Usage Minimum (Num Lock)
    0x29, 0x05,  //   Usage Maximum (Kana)
    0x95, 0x05,  //   Report Count (5)
    0x75, 0x01,  //   Report Size (1)
    0x91, 0x02,  //   Output (Data, Variable, Absolute)
    0x05, 0x08, //   Usage Page (LED)
    0x19, 0x01, //   Usage Minimum (Num Lock)
    0x29, 0x05, //   Usage Maximum (Kana)
    0x95, 0x05, //   Report Count (5)
    0x75, 0x01, //   Report Size (1)
    0x91, 0x02, //   Output (Data, Variable, Absolute)
    // LED padding (3 bits)
    0x95, 0x01,  //   Report Count (1)
    0x75, 0x03,  //   Report Size (3)
    0x91, 0x03,  //   Output (Constant)
    0xC0,        // End Collection
    0x95, 0x01, //   Report Count (1)
    0x75, 0x03, //   Report Size (3)
    0x91, 0x03, //   Output (Constant)
    0xC0,       // End Collection
#ifndef KEYBOARD_SHARED_EP
};
#endif


@@ 462,135 466,135 @@ const PROGMEM uchar shared_hid_report[] = {

#ifdef MOUSE_ENABLE
    // Mouse report descriptor
    0x05, 0x01,             // Usage Page (Generic Desktop)
    0x09, 0x02,             // Usage (Mouse)
    0xA1, 0x01,             // Collection (Application)
    0x85, REPORT_ID_MOUSE,  //   Report ID
    0x09, 0x01,             //   Usage (Pointer)
    0xA1, 0x00,             //   Collection (Physical)
    0x05, 0x01,            // Usage Page (Generic Desktop)
    0x09, 0x02,            // Usage (Mouse)
    0xA1, 0x01,            // Collection (Application)
    0x85, REPORT_ID_MOUSE, //   Report ID
    0x09, 0x01,            //   Usage (Pointer)
    0xA1, 0x00,            //   Collection (Physical)
    // Buttons (8 bits)
    0x05, 0x09,  //     Usage Page (Button)
    0x19, 0x01,  //     Usage Minimum (Button 1)
    0x29, 0x08,  //     Usage Maximum (Button 8)
    0x15, 0x00,  //     Logical Minimum (0)
    0x25, 0x01,  //     Logical Maximum (1)
    0x95, 0x08,  //     Report Count (8)
    0x75, 0x01,  //     Report Size (1)
    0x81, 0x02,  //     Input (Data, Variable, Absolute)
    0x05, 0x09, //     Usage Page (Button)
    0x19, 0x01, //     Usage Minimum (Button 1)
    0x29, 0x08, //     Usage Maximum (Button 8)
    0x15, 0x00, //     Logical Minimum (0)
    0x25, 0x01, //     Logical Maximum (1)
    0x95, 0x08, //     Report Count (8)
    0x75, 0x01, //     Report Size (1)
    0x81, 0x02, //     Input (Data, Variable, Absolute)

    // X/Y position (2 bytes)
    0x05, 0x01,  //     Usage Page (Generic Desktop)
    0x09, 0x30,  //     Usage (X)
    0x09, 0x31,  //     Usage (Y)
    0x15, 0x81,  //     Logical Minimum (-127)
    0x25, 0x7F,  //     Logical Maximum (127)
    0x95, 0x02,  //     Report Count (2)
    0x75, 0x08,  //     Report Size (8)
    0x81, 0x06,  //     Input (Data, Variable, Relative)
    0x05, 0x01, //     Usage Page (Generic Desktop)
    0x09, 0x30, //     Usage (X)
    0x09, 0x31, //     Usage (Y)
    0x15, 0x81, //     Logical Minimum (-127)
    0x25, 0x7F, //     Logical Maximum (127)
    0x95, 0x02, //     Report Count (2)
    0x75, 0x08, //     Report Size (8)
    0x81, 0x06, //     Input (Data, Variable, Relative)

    // Vertical wheel (1 byte)
    0x09, 0x38,  //     Usage (Wheel)
    0x15, 0x81,  //     Logical Minimum (-127)
    0x25, 0x7F,  //     Logical Maximum (127)
    0x95, 0x01,  //     Report Count (1)
    0x75, 0x08,  //     Report Size (8)
    0x81, 0x06,  //     Input (Data, Variable, Relative)
    0x09, 0x38, //     Usage (Wheel)
    0x15, 0x81, //     Logical Minimum (-127)
    0x25, 0x7F, //     Logical Maximum (127)
    0x95, 0x01, //     Report Count (1)
    0x75, 0x08, //     Report Size (8)
    0x81, 0x06, //     Input (Data, Variable, Relative)
    // Horizontal wheel (1 byte)
    0x05, 0x0C,        //     Usage Page (Consumer)
    0x0A, 0x38, 0x02,  //     Usage (AC Pan)
    0x15, 0x81,        //     Logical Minimum (-127)
    0x25, 0x7F,        //     Logical Maximum (127)
    0x95, 0x01,        //     Report Count (1)
    0x75, 0x08,        //     Report Size (8)
    0x81, 0x06,        //     Input (Data, Variable, Relative)
    0xC0,              //   End Collection
    0xC0,              // End Collection
    0x05, 0x0C,       //     Usage Page (Consumer)
    0x0A, 0x38, 0x02, //     Usage (AC Pan)
    0x15, 0x81,       //     Logical Minimum (-127)
    0x25, 0x7F,       //     Logical Maximum (127)
    0x95, 0x01,       //     Report Count (1)
    0x75, 0x08,       //     Report Size (8)
    0x81, 0x06,       //     Input (Data, Variable, Relative)
    0xC0,             //   End Collection
    0xC0,             // End Collection
#endif

#ifdef EXTRAKEY_ENABLE
    // Extrakeys report descriptor
    0x05, 0x01,              // Usage Page (Generic Desktop)
    0x09, 0x80,              // Usage (System Control)
    0xA1, 0x01,              // Collection (Application)
    0x85, REPORT_ID_SYSTEM,  //   Report ID
    0x19, 0x01,              //   Usage Minimum (Pointer)
    0x2A, 0xB7, 0x00,        //   Usage Maximum (System Display LCD Autoscale)
    0x15, 0x01,              //   Logical Minimum
    0x26, 0xB7, 0x00,        //   Logical Maximum
    0x95, 0x01,              //   Report Count (1)
    0x75, 0x10,              //   Report Size (16)
    0x81, 0x00,              //   Input (Data, Array, Absolute)
    0xC0,                    // End Collection

    0x05, 0x0C,                // Usage Page (Consumer)
    0x09, 0x01,                // Usage (Consumer Control)
    0xA1, 0x01,                // Collection (Application)
    0x85, REPORT_ID_CONSUMER,  //   Report ID
    0x19, 0x01,                //   Usage Minimum (Consumer Control)
    0x2A, 0xA0, 0x02,          //   Usage Maximum (AC Desktop Show All Applications)
    0x15, 0x01,                //   Logical Minimum
    0x26, 0xA0, 0x02,          //   Logical Maximum
    0x95, 0x01,                //   Report Count (1)
    0x75, 0x10,                //   Report Size (16)
    0x81, 0x00,                //   Input (Data, Array, Absolute)
    0xC0,                      // End Collection
    0x05, 0x01,             // Usage Page (Generic Desktop)
    0x09, 0x80,             // Usage (System Control)
    0xA1, 0x01,             // Collection (Application)
    0x85, REPORT_ID_SYSTEM, //   Report ID
    0x19, 0x01,             //   Usage Minimum (Pointer)
    0x2A, 0xB7, 0x00,       //   Usage Maximum (System Display LCD Autoscale)
    0x15, 0x01,             //   Logical Minimum
    0x26, 0xB7, 0x00,       //   Logical Maximum
    0x95, 0x01,             //   Report Count (1)
    0x75, 0x10,             //   Report Size (16)
    0x81, 0x00,             //   Input (Data, Array, Absolute)
    0xC0,                   // End Collection

    0x05, 0x0C,               // Usage Page (Consumer)
    0x09, 0x01,               // Usage (Consumer Control)
    0xA1, 0x01,               // Collection (Application)
    0x85, REPORT_ID_CONSUMER, //   Report ID
    0x19, 0x01,               //   Usage Minimum (Consumer Control)
    0x2A, 0xA0, 0x02,         //   Usage Maximum (AC Desktop Show All Applications)
    0x15, 0x01,               //   Logical Minimum
    0x26, 0xA0, 0x02,         //   Logical Maximum
    0x95, 0x01,               //   Report Count (1)
    0x75, 0x10,               //   Report Size (16)
    0x81, 0x00,               //   Input (Data, Array, Absolute)
    0xC0,                     // End Collection
#endif

#ifdef DIGITIZER_ENABLE
    // Digitizer report descriptor
    0x05, 0x0D,                 // Usage Page (Digitizers)
    0x09, 0x01,                 // Usage (Digitizer)
    0xA1, 0x01,                 // Collection (Application)
    0x85, REPORT_ID_DIGITIZER,  //   Report ID
    0x09, 0x22,                 //   Usage (Finger)
    0xA1, 0x00,                 //   Collection (Physical)
    0x05, 0x0D,                // Usage Page (Digitizers)
    0x09, 0x01,                // Usage (Digitizer)
    0xA1, 0x01,                // Collection (Application)
    0x85, REPORT_ID_DIGITIZER, //   Report ID
    0x09, 0x22,                //   Usage (Finger)
    0xA1, 0x00,                //   Collection (Physical)
    // Tip Switch (1 bit)
    0x09, 0x42,  //     Usage (Tip Switch)
    0x15, 0x00,  //     Logical Minimum
    0x25, 0x01,  //     Logical Maximum
    0x95, 0x01,  //     Report Count (1)
    0x75, 0x01,  //     Report Size (16)
    0x81, 0x02,  //     Input (Data, Variable, Absolute)
    0x09, 0x42, //     Usage (Tip Switch)
    0x15, 0x00, //     Logical Minimum
    0x25, 0x01, //     Logical Maximum
    0x95, 0x01, //     Report Count (1)
    0x75, 0x01, //     Report Size (16)
    0x81, 0x02, //     Input (Data, Variable, Absolute)
    // In Range (1 bit)
    0x09, 0x32,  //     Usage (In Range)
    0x81, 0x02,  //     Input (Data, Variable, Absolute)
    0x09, 0x32, //     Usage (In Range)
    0x81, 0x02, //     Input (Data, Variable, Absolute)
    // Padding (6 bits)
    0x95, 0x06,  //     Report Count (6)
    0x81, 0x03,  //     Input (Constant)
    0x95, 0x06, //     Report Count (6)
    0x81, 0x03, //     Input (Constant)

    // X/Y Position (4 bytes)
    0x05, 0x01,        //     Usage Page (Generic Desktop)
    0x26, 0xFF, 0x7F,  //     Logical Maximum (32767)
    0x95, 0x01,        //     Report Count (1)
    0x75, 0x10,        //     Report Size (16)
    0x65, 0x33,        //     Unit (Inch, English Linear)
    0x55, 0x0E,        //     Unit Exponent (-2)
    0x09, 0x30,        //     Usage (X)
    0x81, 0x02,        //     Input (Data, Variable, Absolute)
    0x09, 0x31,        //     Usage (Y)
    0x81, 0x02,        //     Input (Data, Variable, Absolute)
    0xC0,              //   End Collection
    0xC0,              // End Collection
    0x05, 0x01,       //     Usage Page (Generic Desktop)
    0x26, 0xFF, 0x7F, //     Logical Maximum (32767)
    0x95, 0x01,       //     Report Count (1)
    0x75, 0x10,       //     Report Size (16)
    0x65, 0x33,       //     Unit (Inch, English Linear)
    0x55, 0x0E,       //     Unit Exponent (-2)
    0x09, 0x30,       //     Usage (X)
    0x81, 0x02,       //     Input (Data, Variable, Absolute)
    0x09, 0x31,       //     Usage (Y)
    0x81, 0x02,       //     Input (Data, Variable, Absolute)
    0xC0,             //   End Collection
    0xC0,             // End Collection
#endif

#ifdef PROGRAMMABLE_BUTTON_ENABLE
    // Programmable buttons report descriptor
    0x05, 0x0C,                           // Usage Page (Consumer)
    0x09, 0x01,                           // Usage (Consumer Control)
    0xA1, 0x01,                           // Collection (Application)
    0x85, REPORT_ID_PROGRAMMABLE_BUTTON,  //   Report ID
    0x09, 0x03,                           //   Usage (Programmable Buttons)
    0xA1, 0x04,                           //   Collection (Named Array)
    0x05, 0x09,                           //     Usage Page (Button)
    0x19, 0x01,                           //     Usage Minimum (Button 1)
    0x29, 0x20,                           //     Usage Maximum (Button 32)
    0x15, 0x00,                           //     Logical Minimum (0)
    0x25, 0x01,                           //     Logical Maximum (1)
    0x95, 0x20,                           //     Report Count (32)
    0x75, 0x01,                           //     Report Size (1)
    0x81, 0x02,                           //     Input (Data, Variable, Absolute)
    0xC0,                                 //   End Collection
    0xC0,                                 // End Collection
    0x05, 0x0C,                          // Usage Page (Consumer)
    0x09, 0x01,                          // Usage (Consumer Control)
    0xA1, 0x01,                          // Collection (Application)
    0x85, REPORT_ID_PROGRAMMABLE_BUTTON, //   Report ID
    0x09, 0x03,                          //   Usage (Programmable Buttons)
    0xA1, 0x04,                          //   Collection (Named Array)
    0x05, 0x09,                          //     Usage Page (Button)
    0x19, 0x01,                          //     Usage Minimum (Button 1)
    0x29, 0x20,                          //     Usage Maximum (Button 32)
    0x15, 0x00,                          //     Logical Minimum (0)
    0x25, 0x01,                          //     Logical Maximum (1)
    0x95, 0x20,                          //     Report Count (32)
    0x75, 0x01,                          //     Report Size (1)
    0x81, 0x02,                          //     Input (Data, Variable, Absolute)
    0xC0,                                //   End Collection
    0xC0,                                // End Collection
#endif

#ifdef SHARED_EP_ENABLE


@@ 599,47 603,47 @@ const PROGMEM uchar shared_hid_report[] = {

#ifdef RAW_ENABLE
const PROGMEM uchar raw_hid_report[] = {
    0x06, RAW_USAGE_PAGE_LO, RAW_USAGE_PAGE_HI,  // Usage Page (Vendor Defined)
    0x09, RAW_USAGE_ID,                          // Usage (Vendor Defined)
    0xA1, 0x01,                                  // Collection (Application)
    0x06, RAW_USAGE_PAGE_LO, RAW_USAGE_PAGE_HI, // Usage Page (Vendor Defined)
    0x09, RAW_USAGE_ID,                         // Usage (Vendor Defined)
    0xA1, 0x01,                                 // Collection (Application)
    // Data to host
    0x09, 0x62,             //   Usage (Vendor Defined)
    0x15, 0x00,             //   Logical Minimum (0)
    0x26, 0xFF, 0x00,       //   Logical Maximum (255)
    0x95, RAW_BUFFER_SIZE,  //   Report Count
    0x75, 0x08,             //   Report Size (8)
    0x81, 0x02,             //   Input (Data, Variable, Absolute)
    0x09, 0x62,            //   Usage (Vendor Defined)
    0x15, 0x00,            //   Logical Minimum (0)
    0x26, 0xFF, 0x00,      //   Logical Maximum (255)
    0x95, RAW_BUFFER_SIZE, //   Report Count
    0x75, 0x08,            //   Report Size (8)
    0x81, 0x02,            //   Input (Data, Variable, Absolute)
    // Data from host
    0x09, 0x63,             //   Usage (Vendor Defined)
    0x15, 0x00,             //   Logical Minimum (0)
    0x26, 0xFF, 0x00,       //   Logical Maximum (255)
    0x95, RAW_BUFFER_SIZE,  //   Report Count
    0x75, 0x08,             //   Report Size (8)
    0x91, 0x02,             //   Output (Data, Variable, Absolute)
    0xC0                    // End Collection
    0x09, 0x63,            //   Usage (Vendor Defined)
    0x15, 0x00,            //   Logical Minimum (0)
    0x26, 0xFF, 0x00,      //   Logical Maximum (255)
    0x95, RAW_BUFFER_SIZE, //   Report Count
    0x75, 0x08,            //   Report Size (8)
    0x91, 0x02,            //   Output (Data, Variable, Absolute)
    0xC0                   // End Collection
};
#endif

#if defined(CONSOLE_ENABLE)
const PROGMEM uchar console_hid_report[] = {
    0x06, 0x31, 0xFF,  // Usage Page (Vendor Defined - PJRC Teensy compatible)
    0x09, 0x74,        // Usage (Vendor Defined - PJRC Teensy compatible)
    0xA1, 0x01,        // Collection (Application)
    0x06, 0x31, 0xFF, // Usage Page (Vendor Defined - PJRC Teensy compatible)
    0x09, 0x74,       // Usage (Vendor Defined - PJRC Teensy compatible)
    0xA1, 0x01,       // Collection (Application)
    // Data to host
    0x09, 0x75,                 //   Usage (Vendor Defined)
    0x15, 0x00,                 //   Logical Minimum (0x00)
    0x26, 0xFF, 0x00,           //   Logical Maximum (0x00FF)
    0x95, CONSOLE_BUFFER_SIZE,  //   Report Count
    0x75, 0x08,                 //   Report Size (8)
    0x81, 0x02,                 //   Input (Data, Variable, Absolute)
    0x09, 0x75,                //   Usage (Vendor Defined)
    0x15, 0x00,                //   Logical Minimum (0x00)
    0x26, 0xFF, 0x00,          //   Logical Maximum (0x00FF)
    0x95, CONSOLE_BUFFER_SIZE, //   Report Count
    0x75, 0x08,                //   Report Size (8)
    0x81, 0x02,                //   Input (Data, Variable, Absolute)
    // Data from host
    0x09, 0x76,                 //   Usage (Vendor Defined)
    0x15, 0x00,                 //   Logical Minimum (0x00)
    0x26, 0xFF, 0x00,           //   Logical Maximum (0x00FF)
    0x95, CONSOLE_BUFFER_SIZE,  //   Report Count
    0x75, 0x08,                 //   Report Size (8)
    0x91, 0x02,                 //   Output (Data)
    0xC0                        // End Collection
    0x09, 0x76,                //   Usage (Vendor Defined)
    0x15, 0x00,                //   Logical Minimum (0x00)
    0x26, 0xFF, 0x00,          //   Logical Maximum (0x00FF)
    0x95, CONSOLE_BUFFER_SIZE, //   Report Count
    0x75, 0x08,                //   Report Size (8)
    0x91, 0x02,                //   Output (Data)
    0xC0                       // End Collection
};
#endif



@@ 939,16 943,16 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
                    usbMsgPtr = (usbMsgPtr_t)&usbStringDescriptorZero;
                    len       = usbStringDescriptorZero.header.bLength;
                    break;
                case 1:  // iManufacturer
                case 1: // iManufacturer
                    usbMsgPtr = (usbMsgPtr_t)&usbStringDescriptorManufacturer;
                    len       = usbStringDescriptorManufacturer.header.bLength;
                    break;
                case 2:  // iProduct
                case 2: // iProduct
                    usbMsgPtr = (usbMsgPtr_t)&usbStringDescriptorProduct;
                    len       = usbStringDescriptorProduct.header.bLength;
                    break;
#if defined(SERIAL_NUMBER)
                case 3:  // iSerialNumber
                case 3: // iSerialNumber
                    usbMsgPtr = (usbMsgPtr_t)&usbStringDescriptorSerial;
                    len       = usbStringDescriptorSerial.header.bLength;
                    break;