[Split] Sync Timer feature (#10997)
A timer that is kept in sync between the halves of a split keyboard
This commit is contained in:
parent
9c03a89596
commit
a8d0ec0749
8 changed files with 154 additions and 15 deletions
|
@ -53,6 +53,7 @@
|
||||||
#include "eeconfig.h"
|
#include "eeconfig.h"
|
||||||
#include "bootloader.h"
|
#include "bootloader.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "sync_timer.h"
|
||||||
#include "config_common.h"
|
#include "config_common.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "action_util.h"
|
#include "action_util.h"
|
||||||
|
|
|
@ -266,9 +266,9 @@ static bool rgb_matrix_none(effect_params_t *params) {
|
||||||
|
|
||||||
static void rgb_task_timers(void) {
|
static void rgb_task_timers(void) {
|
||||||
#if defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
|
#if defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
|
||||||
uint32_t deltaTime = timer_elapsed32(rgb_timer_buffer);
|
uint32_t deltaTime = sync_timer_elapsed32(rgb_timer_buffer);
|
||||||
#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
|
#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
|
||||||
rgb_timer_buffer = timer_read32();
|
rgb_timer_buffer = sync_timer_read32();
|
||||||
|
|
||||||
// Update double buffer timers
|
// Update double buffer timers
|
||||||
#if RGB_DISABLE_TIMEOUT > 0
|
#if RGB_DISABLE_TIMEOUT > 0
|
||||||
|
@ -296,7 +296,7 @@ static void rgb_task_timers(void) {
|
||||||
|
|
||||||
static void rgb_task_sync(void) {
|
static void rgb_task_sync(void) {
|
||||||
// next task
|
// next task
|
||||||
if (timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
|
if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rgb_task_start(void) {
|
static void rgb_task_start(void) {
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "wait.h"
|
#include "wait.h"
|
||||||
#include "progmem.h"
|
#include "progmem.h"
|
||||||
#include "timer.h"
|
#include "sync_timer.h"
|
||||||
#include "rgblight.h"
|
#include "rgblight.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
@ -684,18 +684,16 @@ static void rgblight_layers_write(void) {
|
||||||
|
|
||||||
# ifdef RGBLIGHT_LAYER_BLINK
|
# ifdef RGBLIGHT_LAYER_BLINK
|
||||||
rgblight_layer_mask_t _blinked_layer_mask = 0;
|
rgblight_layer_mask_t _blinked_layer_mask = 0;
|
||||||
uint16_t _blink_duration = 0;
|
|
||||||
static uint16_t _blink_timer;
|
static uint16_t _blink_timer;
|
||||||
|
|
||||||
void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
|
void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
|
||||||
rgblight_set_layer_state(layer, true);
|
rgblight_set_layer_state(layer, true);
|
||||||
_blinked_layer_mask |= 1 << layer;
|
_blinked_layer_mask |= 1 << layer;
|
||||||
_blink_timer = timer_read();
|
_blink_timer = sync_timer_read() + duration_ms;
|
||||||
_blink_duration = duration_ms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rgblight_unblink_layers(void) {
|
void rgblight_unblink_layers(void) {
|
||||||
if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) {
|
if (_blinked_layer_mask != 0 && timer_expired(sync_timer_read(), _blink_timer)) {
|
||||||
for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
|
for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
|
||||||
if ((_blinked_layer_mask & 1 << layer) != 0) {
|
if ((_blinked_layer_mask & 1 << layer) != 0) {
|
||||||
rgblight_set_layer_state(layer, false);
|
rgblight_set_layer_state(layer, false);
|
||||||
|
@ -799,7 +797,7 @@ void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
|
||||||
animation_status.restart = true;
|
animation_status.restart = true;
|
||||||
}
|
}
|
||||||
# endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
|
# endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
|
||||||
# endif /* RGBLIGHT_USE_TIMER */
|
# endif /* RGBLIGHT_USE_TIMER */
|
||||||
}
|
}
|
||||||
#endif /* RGBLIGHT_SPLIT */
|
#endif /* RGBLIGHT_SPLIT */
|
||||||
|
|
||||||
|
@ -832,7 +830,7 @@ void rgblight_timer_enable(void) {
|
||||||
if (!is_static_effect(rgblight_config.mode)) {
|
if (!is_static_effect(rgblight_config.mode)) {
|
||||||
rgblight_status.timer_enabled = true;
|
rgblight_status.timer_enabled = true;
|
||||||
}
|
}
|
||||||
animation_status.last_timer = timer_read();
|
animation_status.last_timer = sync_timer_read();
|
||||||
RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
|
RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
|
||||||
dprintf("rgblight timer enabled.\n");
|
dprintf("rgblight timer enabled.\n");
|
||||||
}
|
}
|
||||||
|
@ -941,18 +939,19 @@ void rgblight_task(void) {
|
||||||
# endif
|
# endif
|
||||||
if (animation_status.restart) {
|
if (animation_status.restart) {
|
||||||
animation_status.restart = false;
|
animation_status.restart = false;
|
||||||
animation_status.last_timer = timer_read() - interval_time - 1;
|
animation_status.last_timer = sync_timer_read();
|
||||||
animation_status.pos16 = 0; // restart signal to local each effect
|
animation_status.pos16 = 0; // restart signal to local each effect
|
||||||
}
|
}
|
||||||
if (timer_elapsed(animation_status.last_timer) >= interval_time) {
|
uint16_t now = sync_timer_read();
|
||||||
|
if (timer_expired(now, animation_status.last_timer)) {
|
||||||
# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
|
# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
|
||||||
static uint16_t report_last_timer = 0;
|
static uint16_t report_last_timer = 0;
|
||||||
static bool tick_flag = false;
|
static bool tick_flag = false;
|
||||||
uint16_t oldpos16;
|
uint16_t oldpos16;
|
||||||
if (tick_flag) {
|
if (tick_flag) {
|
||||||
tick_flag = false;
|
tick_flag = false;
|
||||||
if (timer_elapsed(report_last_timer) >= 30000) {
|
if (timer_expired(now, report_last_timer)) {
|
||||||
report_last_timer = timer_read();
|
report_last_timer += 30000;
|
||||||
dprintf("rgblight animation tick report to slave\n");
|
dprintf("rgblight animation tick report to slave\n");
|
||||||
RGBLIGHT_SPLIT_ANIMATION_TICK;
|
RGBLIGHT_SPLIT_ANIMATION_TICK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "quantum.h"
|
#include "quantum.h"
|
||||||
|
|
||||||
#define ROWS_PER_HAND (MATRIX_ROWS / 2)
|
#define ROWS_PER_HAND (MATRIX_ROWS / 2)
|
||||||
|
#define SYNC_TIMER_OFFSET 2
|
||||||
|
|
||||||
#ifdef RGBLIGHT_ENABLE
|
#ifdef RGBLIGHT_ENABLE
|
||||||
# include "rgblight.h"
|
# include "rgblight.h"
|
||||||
|
@ -27,6 +28,9 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
|
||||||
# include "i2c_slave.h"
|
# include "i2c_slave.h"
|
||||||
|
|
||||||
typedef struct _I2C_slave_buffer_t {
|
typedef struct _I2C_slave_buffer_t {
|
||||||
|
# ifndef DISABLE_SYNC_TIMER
|
||||||
|
uint32_t sync_timer;
|
||||||
|
# endif
|
||||||
matrix_row_t smatrix[ROWS_PER_HAND];
|
matrix_row_t smatrix[ROWS_PER_HAND];
|
||||||
uint8_t backlight_level;
|
uint8_t backlight_level;
|
||||||
# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
||||||
|
@ -44,6 +48,7 @@ static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_re
|
||||||
|
|
||||||
# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
|
# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
|
||||||
# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
|
# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
|
||||||
|
# define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer)
|
||||||
# define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
|
# define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
|
||||||
# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
|
# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
|
||||||
# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)
|
# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)
|
||||||
|
@ -91,10 +96,18 @@ bool transport_master(matrix_row_t matrix[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# ifndef DISABLE_SYNC_TIMER
|
||||||
|
i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
|
||||||
|
i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT);
|
||||||
|
# endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void transport_slave(matrix_row_t matrix[]) {
|
void transport_slave(matrix_row_t matrix[]) {
|
||||||
|
# ifndef DISABLE_SYNC_TIMER
|
||||||
|
sync_timer_update(i2c_buffer->sync_timer);
|
||||||
|
# endif
|
||||||
// Copy matrix to I2C buffer
|
// Copy matrix to I2C buffer
|
||||||
memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
|
memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
|
||||||
|
|
||||||
|
@ -133,12 +146,15 @@ typedef struct _Serial_s2m_buffer_t {
|
||||||
matrix_row_t smatrix[ROWS_PER_HAND];
|
matrix_row_t smatrix[ROWS_PER_HAND];
|
||||||
|
|
||||||
# ifdef ENCODER_ENABLE
|
# ifdef ENCODER_ENABLE
|
||||||
uint8_t encoder_state[NUMBER_OF_ENCODERS];
|
uint8_t encoder_state[NUMBER_OF_ENCODERS];
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
} Serial_s2m_buffer_t;
|
} Serial_s2m_buffer_t;
|
||||||
|
|
||||||
typedef struct _Serial_m2s_buffer_t {
|
typedef struct _Serial_m2s_buffer_t {
|
||||||
|
# ifndef DISABLE_SYNC_TIMER
|
||||||
|
uint32_t sync_timer;
|
||||||
|
# endif
|
||||||
# ifdef BACKLIGHT_ENABLE
|
# ifdef BACKLIGHT_ENABLE
|
||||||
uint8_t backlight_level;
|
uint8_t backlight_level;
|
||||||
# endif
|
# endif
|
||||||
|
@ -251,11 +267,19 @@ bool transport_master(matrix_row_t matrix[]) {
|
||||||
// Write wpm to slave
|
// Write wpm to slave
|
||||||
serial_m2s_buffer.current_wpm = get_current_wpm();
|
serial_m2s_buffer.current_wpm = get_current_wpm();
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# ifndef DISABLE_SYNC_TIMER
|
||||||
|
serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
|
||||||
|
# endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void transport_slave(matrix_row_t matrix[]) {
|
void transport_slave(matrix_row_t matrix[]) {
|
||||||
transport_rgblight_slave();
|
transport_rgblight_slave();
|
||||||
|
# ifndef DISABLE_SYNC_TIMER
|
||||||
|
sync_timer_update(serial_m2s_buffer.sync_timer);
|
||||||
|
# endif
|
||||||
|
|
||||||
// TODO: if MATRIX_COLS > 8 change to pack()
|
// TODO: if MATRIX_COLS > 8 change to pack()
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
||||||
serial_s2m_buffer.smatrix[i] = matrix[i];
|
serial_s2m_buffer.smatrix[i] = matrix[i];
|
||||||
|
|
|
@ -18,6 +18,7 @@ TMK_COMMON_SRC += $(COMMON_DIR)/host.c \
|
||||||
$(COMMON_DIR)/report.c \
|
$(COMMON_DIR)/report.c \
|
||||||
$(PLATFORM_COMMON_DIR)/suspend.c \
|
$(PLATFORM_COMMON_DIR)/suspend.c \
|
||||||
$(PLATFORM_COMMON_DIR)/timer.c \
|
$(PLATFORM_COMMON_DIR)/timer.c \
|
||||||
|
$(COMMON_DIR)/sync_timer.c \
|
||||||
$(PLATFORM_COMMON_DIR)/bootloader.c \
|
$(PLATFORM_COMMON_DIR)/bootloader.c \
|
||||||
|
|
||||||
ifeq ($(PLATFORM),AVR)
|
ifeq ($(PLATFORM),AVR)
|
||||||
|
|
|
@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "keycode.h"
|
#include "keycode.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "sync_timer.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
@ -255,6 +256,7 @@ __attribute__((weak)) void housekeeping_task_user(void) {}
|
||||||
*/
|
*/
|
||||||
void keyboard_init(void) {
|
void keyboard_init(void) {
|
||||||
timer_init();
|
timer_init();
|
||||||
|
sync_timer_init();
|
||||||
matrix_init();
|
matrix_init();
|
||||||
#ifdef VIA_ENABLE
|
#ifdef VIA_ENABLE
|
||||||
via_init();
|
via_init();
|
||||||
|
|
58
tmk_core/common/sync_timer.c
Normal file
58
tmk_core/common/sync_timer.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
If you happen to meet one of the copyright holders in a bar you are obligated
|
||||||
|
to buy them one pint of beer.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sync_timer.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
|
||||||
|
#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_update(uint32_t time) {
|
||||||
|
if (is_keyboard_master()) return;
|
||||||
|
sync_timer_ms = time - timer_read32();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sync_timer_read(void) {
|
||||||
|
if (is_keyboard_master()) return timer_read();
|
||||||
|
return sync_timer_read32();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sync_timer_read32(void) {
|
||||||
|
if (is_keyboard_master()) return timer_read32();
|
||||||
|
return sync_timer_ms + timer_read32();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sync_timer_elapsed(uint16_t last) {
|
||||||
|
if (is_keyboard_master()) return timer_elapsed(last);
|
||||||
|
return TIMER_DIFF_16(sync_timer_read(), last);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sync_timer_elapsed32(uint32_t last) {
|
||||||
|
if (is_keyboard_master()) return timer_elapsed32(last);
|
||||||
|
return TIMER_DIFF_32(sync_timer_read32(), last);
|
||||||
|
}
|
||||||
|
#endif
|
54
tmk_core/common/sync_timer.h
Normal file
54
tmk_core/common/sync_timer.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
If you happen to meet one of the copyright holders in a bar you are obligated
|
||||||
|
to buy them one pint of beer.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
|
||||||
|
void sync_timer_init(void);
|
||||||
|
void sync_timer_update(uint32_t time);
|
||||||
|
uint16_t sync_timer_read(void);
|
||||||
|
uint32_t sync_timer_read32(void);
|
||||||
|
uint16_t sync_timer_elapsed(uint16_t last);
|
||||||
|
uint32_t sync_timer_elapsed32(uint32_t last);
|
||||||
|
#else
|
||||||
|
# define sync_timer_init()
|
||||||
|
# define sync_timer_clear()
|
||||||
|
# define sync_timer_update(t)
|
||||||
|
# define sync_timer_read() timer_read()
|
||||||
|
# define sync_timer_read32() timer_read32()
|
||||||
|
# define sync_timer_elapsed(t) timer_elapsed(t)
|
||||||
|
# define sync_timer_elapsed32(t) timer_elapsed32(t)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in a new issue