diff options
author | Drashna Jaelre <drashna@live.com> | 2020-12-19 10:43:00 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-19 19:43:00 +0100 |
commit | 5619b1d3db335750bed394b0d27980d67f4f50c5 (patch) | |
tree | 854f8fa7cb055193aa481e1e601ae58403e9ee9f /keyboards/handwired/dactyl_manuform/5x6_right_trackball/pointer_transport.c | |
parent | bded5f473c887fb36a2ca9d473635c1b84d0a04b (diff) |
[Keyboard] Add drashna's dactyl manuform 5x6 with trackball (#11062)
Co-authored-by: James Young <18669334+noroadsleft@users.noreply.github.com>
Co-authored-by: Erovia <Erovia@users.noreply.github.com>
Diffstat (limited to 'keyboards/handwired/dactyl_manuform/5x6_right_trackball/pointer_transport.c')
-rw-r--r-- | keyboards/handwired/dactyl_manuform/5x6_right_trackball/pointer_transport.c | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/keyboards/handwired/dactyl_manuform/5x6_right_trackball/pointer_transport.c b/keyboards/handwired/dactyl_manuform/5x6_right_trackball/pointer_transport.c new file mode 100644 index 0000000000..003468c828 --- /dev/null +++ b/keyboards/handwired/dactyl_manuform/5x6_right_trackball/pointer_transport.c @@ -0,0 +1,375 @@ +/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stddef.h> + +#include "matrix.h" +#include QMK_KEYBOARD_H + +#define ROWS_PER_HAND (MATRIX_ROWS / 2) + +#ifdef RGBLIGHT_ENABLE +# include "rgblight.h" +#endif + +#ifdef BACKLIGHT_ENABLE +# include "backlight.h" +#endif + +#ifdef ENCODER_ENABLE +# include "encoder.h" +static pin_t encoders_pad[] = ENCODERS_PAD_A; +# define NUMBER_OF_ENCODERS (sizeof(encoders_pad) / sizeof(pin_t)) +#endif + +#ifdef POINTING_DEVICE_ENABLE +static uint16_t device_cpi = 0; +static int8_t split_mouse_x = 0, split_mouse_y = 0; +#endif + +#if defined(USE_I2C) + +# include "i2c_master.h" +# include "i2c_slave.h" + +typedef struct _I2C_slave_buffer_t { + matrix_row_t smatrix[ROWS_PER_HAND]; + uint8_t backlight_level; +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + rgblight_syncinfo_t rgblight_sync; +# endif +# ifdef ENCODER_ENABLE + uint8_t encoder_state[NUMBER_OF_ENCODERS]; +# endif +# ifdef WPM_ENABLE + uint8_t current_wpm; +# endif + int8_t mouse_x; + int8_t mouse_y; + uint16_t device_cpi; +} I2C_slave_buffer_t; + +static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg; + +# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level) +# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync) +# define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, mmatrix) +# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state) +# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm) +# define I2C_MOUSE_X_START offsetof(I2C_slave_buffer_t, mouse_x) +# define I2C_MOUSE_Y_START offsetof(I2C_slave_buffer_t, mouse_y) +# define I2C_MOUSE_DPI_START offsetof(I2C_slave_buffer_t, device_cpi) +# define TIMEOUT 100 + +# ifndef SLAVE_I2C_ADDRESS +# define SLAVE_I2C_ADDRESS 0x32 +# endif + +// Get rows from other half over i2c +bool transport_master(matrix_row_t matrix[]) { + i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_START, (void *)matrix, sizeof(i2c_buffer->smatrix), TIMEOUT); + + // write backlight info +# ifdef BACKLIGHT_ENABLE + uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0; + if (level != i2c_buffer->backlight_level) { + if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_BACKLIGHT_START, (void *)&level, sizeof(level), TIMEOUT) >= 0) { + i2c_buffer->backlight_level = level; + } + } +# endif + +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + if (rgblight_get_change_flags()) { + rgblight_syncinfo_t rgblight_sync; + rgblight_get_syncinfo(&rgblight_sync); + if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_START, (void *)&rgblight_sync, sizeof(rgblight_sync), TIMEOUT) >= 0) { + rgblight_clear_change_flags(); + } + } +# endif + +# ifdef ENCODER_ENABLE + i2c_readReg(SLAVE_I2C_ADDRESS, I2C_ENCODER_START, (void *)i2c_buffer->encoder_state, sizeof(i2c_buffer->encoder_state), TIMEOUT); + encoder_update_raw(i2c_buffer->encoder_state); +# endif + +# ifdef WPM_ENABLE + uint8_t current_wpm = get_current_wpm(); + if (current_wpm != i2c_buffer->current_wpm) { + if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WPM_START, (void *)¤t_wpm, sizeof(current_wpm), TIMEOUT) >= 0) { + i2c_buffer->current_wpm = current_wpm; + } + } +# endif + +# ifdef POINTING_DEVICE_ENABLE + if (is_keyboard_left()) { + report_mouse_t temp_report = pointing_device_get_report(); + i2c_readReg(SLAVE_I2C_ADDRESS, I2C_MOUSE_X_START, (void *)&i2c_buffer->mouse_x, sizeof(i2c_buffer->mouse_x), TIMEOUT); + temp_report.x = i2c_buffer->mouse_x; + i2c_readReg(SLAVE_I2C_ADDRESS, I2C_MOUSE_Y_START, (void *)&i2c_buffer->mouse_y, sizeof(i2c_buffer->mouse_y), TIMEOUT); + temp_report.y = i2c_buffer->mouse_y; + pointing_device_set_report(temp_report); + + if (device_cpi != i2c_buffer->device_cpi) { + if(i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_MOUSE_DPI_START, (void *)&device_cpi, sizeof(device_cpi), TIMEOUT) >= 0) { + i2c_buffer->device_cpi = device_cpi + } + } + } +# endif + + return true; +} + +void transport_slave(matrix_row_t matrix[]) { + // Copy matrix to I2C buffer + memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix)); + +// Read Backlight Info +# ifdef BACKLIGHT_ENABLE + backlight_set(i2c_buffer->backlight_level); +# endif + +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + // Update the RGB with the new data + if (i2c_buffer->rgblight_sync.status.change_flags != 0) { + rgblight_update_sync(&i2c_buffer->rgblight_sync, false); + i2c_buffer->rgblight_sync.status.change_flags = 0; + } +# endif + +# ifdef ENCODER_ENABLE + encoder_state_raw(i2c_buffer->encoder_state); +# endif + +# ifdef WPM_ENABLE + set_current_wpm(i2c_buffer->current_wpm); +# endif + +# ifdef POINTING_DEVICE_ENABLE + if (!is_keyboard_left()) { + static uint16_t cpi; + if (cpi != i2c_buffer->device_cpi) { + cpi = i2c_buffer->device_cpi; + pmw_set_cpi(cpi); + } + i2c_buffer->mouse_x = split_mouse_x; + i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_MOUSE_X_START, (void *)&i2c_buffer->mouse_x, sizeof(i2c_buffer->mouse_x), TIMEOUT); + i2c_buffer->mouse_y = split_mouse_y; + i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_MOUSE_Y_START, (void *)&i2c_buffer->mouse_y, sizeof(i2c_buffer->mouse_y), TIMEOUT); + } + +# endif +} + +void transport_master_init(void) { i2c_init(); } + +void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); } + +#else // USE_SERIAL + +# include "serial.h" + +typedef struct _Serial_s2m_buffer_t { + // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack + matrix_row_t smatrix[ROWS_PER_HAND]; +# ifdef ENCODER_ENABLE + uint8_t encoder_state[NUMBER_OF_ENCODERS]; +# endif + int8_t mouse_x; + int8_t mouse_y; +} Serial_s2m_buffer_t; + +typedef struct _Serial_m2s_buffer_t { +# ifdef BACKLIGHT_ENABLE + uint8_t backlight_level; +# endif +# ifdef WPM_ENABLE + uint8_t current_wpm; +# endif + uint16_t device_cpi; +} Serial_m2s_buffer_t; + +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) +// When MCUs on both sides drive their respective RGB LED chains, +// it is necessary to synchronize, so it is necessary to communicate RGB +// information. In that case, define RGBLIGHT_SPLIT with info on the number +// of LEDs on each half. +// +// Otherwise, if the master side MCU drives both sides RGB LED chains, +// there is no need to communicate. + +typedef struct _Serial_rgblight_t { + rgblight_syncinfo_t rgblight_sync; +} Serial_rgblight_t; + +volatile Serial_rgblight_t serial_rgblight = {}; +uint8_t volatile status_rgblight = 0; +# endif + +volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; +volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; +uint8_t volatile status0 = 0; + +enum serial_transaction_id { + GET_SLAVE_MATRIX = 0, +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + PUT_RGBLIGHT, +# endif +}; + +SSTD_t transactions[] = { + [GET_SLAVE_MATRIX] = + { + (uint8_t *)&status0, + sizeof(serial_m2s_buffer), + (uint8_t *)&serial_m2s_buffer, + sizeof(serial_s2m_buffer), + (uint8_t *)&serial_s2m_buffer, + }, +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + [PUT_RGBLIGHT] = + { + (uint8_t *)&status_rgblight, sizeof(serial_rgblight), (uint8_t *)&serial_rgblight, 0, NULL // no slave to master transfer + }, +# endif +}; + +void transport_master_init(void) { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } + +void transport_slave_init(void) { soft_serial_target_init(transactions, TID_LIMIT(transactions)); } + +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + +// rgblight synchronization information communication. + +void transport_rgblight_master(void) { + if (rgblight_get_change_flags()) { + rgblight_get_syncinfo((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync); + if (soft_serial_transaction(PUT_RGBLIGHT) == TRANSACTION_END) { + rgblight_clear_change_flags(); + } + } +} + +void transport_rgblight_slave(void) { + if (status_rgblight == TRANSACTION_ACCEPTED) { + rgblight_update_sync((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync, false); + status_rgblight = TRANSACTION_END; + } +} + +# else +# define transport_rgblight_master() +# define transport_rgblight_slave() +# endif + +bool transport_master(matrix_row_t matrix[]) { +# ifndef SERIAL_USE_MULTI_TRANSACTION + if (soft_serial_transaction() != TRANSACTION_END) { + return false; + } +# else + transport_rgblight_master(); + if (soft_serial_transaction(GET_SLAVE_MATRIX) != TRANSACTION_END) { + return false; + } +# endif + + // TODO: if MATRIX_COLS > 8 change to unpack() + for (int i = 0; i < ROWS_PER_HAND; ++i) { + matrix[i] = serial_s2m_buffer.smatrix[i]; + } + +# ifdef BACKLIGHT_ENABLE + // Write backlight level for slave to read + serial_m2s_buffer.backlight_level = is_backlight_enabled() ? get_backlight_level() : 0; +# endif + +# ifdef ENCODER_ENABLE + encoder_update_raw((uint8_t *)serial_s2m_buffer.encoder_state); +# endif + +# ifdef WPM_ENABLE + // Write wpm to slave + serial_m2s_buffer.current_wpm = get_current_wpm(); +# endif + +# ifdef POINTING_DEVICE_ENABLE + if (is_keyboard_left()) { + report_mouse_t temp_report = pointing_device_get_report(); + temp_report.x = serial_s2m_buffer.mouse_x; + temp_report.y = serial_s2m_buffer.mouse_y; + pointing_device_set_report(temp_report); + serial_m2s_buffer.device_cpi = device_cpi; + } +# endif + + return true; +} + +void transport_slave(matrix_row_t matrix[]) { + transport_rgblight_slave(); + + // TODO: if MATRIX_COLS > 8 change to pack() + for (int i = 0; i < ROWS_PER_HAND; ++i) { + serial_s2m_buffer.smatrix[i] = matrix[i]; + } + +# ifdef BACKLIGHT_ENABLE + backlight_set(serial_m2s_buffer.backlight_level); +# endif + +# ifdef ENCODER_ENABLE + encoder_state_raw((uint8_t *)serial_s2m_buffer.encoder_state); +# endif + +# ifdef WPM_ENABLE + set_current_wpm(serial_m2s_buffer.current_wpm); +# endif + +# ifdef POINTING_DEVICE_ENABLE + if (!is_keyboard_left()) { + static uint16_t cpi; + if (cpi != serial_m2s_buffer.device_cpi) { + cpi = serial_m2s_buffer.device_cpi; + pmw_set_cpi(cpi); + } + serial_s2m_buffer.mouse_x = split_mouse_x; + serial_s2m_buffer.mouse_y = split_mouse_y; + } + +# endif +} + +#endif + +#ifdef POINTING_DEVICE_ENABLE +void master_mouse_send(int8_t x, int8_t y) { + split_mouse_x = x; + split_mouse_y = y; +} +void trackball_set_cpi(uint16_t cpi) { + if (!is_keyboard_left()) { + pmw_set_cpi(cpi); + } else { + device_cpi = cpi * 1.5; + } +} +#endif |