forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Core] Speed up pimoroni trackball driver (qmk#13823)
- Loading branch information
Showing
2 changed files
with
153 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <[email protected]> | ||
* Copyright 2021 Dasky (@daskygit) | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
|
@@ -13,128 +14,188 @@ | |
* 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 "pimoroni_trackball.h" | ||
#include "i2c_master.h" | ||
#include "print.h" | ||
|
||
static uint8_t scrolling = 0; | ||
static int16_t x_offset = 0; | ||
static int16_t y_offset = 0; | ||
static int16_t h_offset = 0; | ||
static int16_t v_offset = 0; | ||
static float precisionSpeed = 1; | ||
#ifndef PIMORONI_TRACKBALL_ADDRESS | ||
# define PIMORONI_TRACKBALL_ADDRESS 0x0A | ||
#endif | ||
#ifndef PIMORONI_TRACKBALL_INTERVAL_MS | ||
# define PIMORONI_TRACKBALL_INTERVAL_MS 8 | ||
#endif | ||
#ifndef PIMORONI_TRACKBALL_MOUSE_SCALE | ||
# define PIMORONI_TRACKBALL_MOUSE_SCALE 5 | ||
#endif | ||
#ifndef PIMORONI_TRACKBALL_SCROLL_SCALE | ||
# define PIMORONI_TRACKBALL_SCROLL_SCALE 1 | ||
#endif | ||
#ifndef PIMORONI_TRACKBALL_DEBOUNCE_CYCLES | ||
# define PIMORONI_TRACKBALL_DEBOUNCE_CYCLES 20 | ||
#endif | ||
#ifndef PIMORONI_TRACKBALL_ERROR_COUNT | ||
# define PIMORONI_TRACKBALL_ERROR_COUNT 10 | ||
#endif | ||
|
||
static uint16_t i2c_timeout_timer; | ||
#define TRACKBALL_TIMEOUT 100 | ||
#define TRACKBALL_REG_LED_RED 0x00 | ||
#define TRACKBALL_REG_LED_GRN 0x01 | ||
#define TRACKBALL_REG_LED_BLU 0x02 | ||
#define TRACKBALL_REG_LED_WHT 0x03 | ||
#define TRACKBALL_REG_LEFT 0x04 | ||
#define TRACKBALL_REG_RIGHT 0x05 | ||
#define TRACKBALL_REG_UP 0x06 | ||
#define TRACKBALL_REG_DOWN 0x07 | ||
|
||
#ifndef PIMORONI_I2C_TIMEOUT | ||
# define PIMORONI_I2C_TIMEOUT 100 | ||
#endif | ||
#ifndef I2C_WAITCHECK | ||
# define I2C_WAITCHECK 1000 | ||
static pimoroni_data current_pimoroni_data; | ||
static report_mouse_t mouse_report; | ||
static bool scrolling = false; | ||
static int16_t x_offset = 0; | ||
static int16_t y_offset = 0; | ||
static int16_t h_offset = 0; | ||
static int16_t v_offset = 0; | ||
static uint16_t precision = 128; | ||
static uint8_t error_count = 0; | ||
|
||
float trackball_get_precision(void) { return ((float)precision / 128); } | ||
void trackball_set_precision(float floatprecision) { precision = (floatprecision * 128); } | ||
bool trackball_is_scrolling(void) { return scrolling; } | ||
void trackball_set_scrolling(bool scroll) { scrolling = scroll; } | ||
|
||
void trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { | ||
uint8_t data[4] = {r, g, b, w}; | ||
__attribute__((unused)) i2c_status_t status = i2c_writeReg(PIMORONI_TRACKBALL_ADDRESS << 1, TRACKBALL_REG_LED_RED, data, sizeof(data), TRACKBALL_TIMEOUT); | ||
#ifdef TRACKBALL_DEBUG | ||
dprintf("Trackball RGBW i2c_status_t: %d\n", status); | ||
#endif | ||
#ifndef MOUSE_DEBOUNCE | ||
# define MOUSE_DEBOUNCE 5 | ||
} | ||
|
||
i2c_status_t read_pimoroni_trackball(pimoroni_data* data) { | ||
i2c_status_t status = i2c_readReg(PIMORONI_TRACKBALL_ADDRESS << 1, TRACKBALL_REG_LEFT, (uint8_t*)data, sizeof(*data), TRACKBALL_TIMEOUT); | ||
#ifdef TRACKBALL_DEBUG | ||
dprintf("Trackball READ i2c_status_t: %d\nLeft: %d\nRight: %d\nUp: %d\nDown: %d\nSwtich: %d\n", status, data->left, data->right, data->up, data->down, data->click); | ||
#endif | ||
return status; | ||
} | ||
|
||
void trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) { | ||
uint8_t data[] = {0x00, red, green, blue, white}; | ||
i2c_transmit(TRACKBALL_WRITE, data, sizeof(data), PIMORONI_I2C_TIMEOUT); | ||
__attribute__((weak)) void pointing_device_init(void) { | ||
i2c_init(); | ||
trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); | ||
} | ||
|
||
int16_t mouse_offset(uint8_t positive, uint8_t negative, int16_t scale) { | ||
int16_t offset = (int16_t)positive - (int16_t)negative; | ||
int16_t magnitude = (int16_t)(scale * offset * offset * precisionSpeed); | ||
return offset < 0 ? -magnitude : magnitude; | ||
int16_t trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale) { | ||
uint8_t offset = 0; | ||
bool isnegative = false; | ||
if (negative_dir > positive_dir) { | ||
offset = negative_dir - positive_dir; | ||
isnegative = true; | ||
} else { | ||
offset = positive_dir - negative_dir; | ||
} | ||
uint16_t magnitude = (scale * offset * offset * precision) >> 7; | ||
return isnegative ? -(int16_t)(magnitude) : (int16_t)(magnitude); | ||
} | ||
|
||
void update_member(int8_t* member, int16_t* offset) { | ||
void trackball_adapt_values(int8_t* mouse, int16_t* offset) { | ||
if (*offset > 127) { | ||
*member = 127; | ||
*mouse = 127; | ||
*offset -= 127; | ||
} else if (*offset < -127) { | ||
*member = -127; | ||
*mouse = -127; | ||
*offset += 127; | ||
} else { | ||
*member = *offset; | ||
*mouse = *offset; | ||
*offset = 0; | ||
} | ||
} | ||
|
||
__attribute__((weak)) void trackball_check_click(bool pressed, report_mouse_t* mouse) { | ||
__attribute__((weak)) void trackball_click(bool pressed, report_mouse_t* mouse) { | ||
#ifdef PIMORONI_TRACKBALL_CLICK | ||
if (pressed) { | ||
mouse->buttons |= MOUSE_BTN1; | ||
} else { | ||
mouse->buttons &= ~MOUSE_BTN1; | ||
} | ||
#endif | ||
} | ||
|
||
float trackball_get_precision(void) { return precisionSpeed; } | ||
void trackball_set_precision(float precision) { precisionSpeed = precision; } | ||
bool trackball_is_scrolling(void) { return scrolling; } | ||
void trackball_set_scrolling(bool scroll) { scrolling = scroll; } | ||
__attribute__((weak)) bool pointing_device_task_user(pimoroni_data* trackball_data) { return true; }; | ||
|
||
__attribute__((weak)) void pointing_device_init(void) { i2c_init(); trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); } | ||
__attribute__((weak)) void pointing_device_task() { | ||
static fast_timer_t throttle = 0; | ||
static uint16_t debounce = 0; | ||
|
||
void pointing_device_task(void) { | ||
static bool debounce; | ||
static uint16_t debounce_timer; | ||
uint8_t state[5] = {}; | ||
if (timer_elapsed(i2c_timeout_timer) > I2C_WAITCHECK) { | ||
if (i2c_readReg(TRACKBALL_READ, 0x04, state, 5, PIMORONI_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) { | ||
if (!state[4] && !debounce) { | ||
if (scrolling) { | ||
if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT && timer_elapsed_fast(throttle) >= PIMORONI_TRACKBALL_INTERVAL_MS) { | ||
i2c_status_t status = read_pimoroni_trackball(¤t_pimoroni_data); | ||
|
||
if (status == I2C_STATUS_SUCCESS) { | ||
error_count = 0; | ||
|
||
if (pointing_device_task_user(¤t_pimoroni_data)) { | ||
mouse_report = pointing_device_get_report(); | ||
|
||
if (!(current_pimoroni_data.click & 128)) { | ||
trackball_click(false, &mouse_report); | ||
if (!debounce) { | ||
if (scrolling) { | ||
#ifdef PIMORONI_TRACKBALL_INVERT_X | ||
h_offset += mouse_offset(state[2], state[3], 1); | ||
h_offset += trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_SCROLL_SCALE); | ||
#else | ||
h_offset -= mouse_offset(state[2], state[3], 1); | ||
h_offset -= trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_SCROLL_SCALE); | ||
#endif | ||
#ifdef PIMORONI_TRACKBALL_INVERT_Y | ||
v_offset += mouse_offset(state[1], state[0], 1); | ||
v_offset += trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_SCROLL_SCALE); | ||
#else | ||
v_offset -= mouse_offset(state[1], state[0], 1); | ||
v_offset -= trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_SCROLL_SCALE); | ||
#endif | ||
} else { | ||
} else { | ||
#ifdef PIMORONI_TRACKBALL_INVERT_X | ||
x_offset -= mouse_offset(state[2], state[3], 5); | ||
x_offset -= trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_MOUSE_SCALE); | ||
#else | ||
x_offset += mouse_offset(state[2], state[3], 5); | ||
x_offset += trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_MOUSE_SCALE); | ||
#endif | ||
#ifdef PIMORONI_TRACKBALL_INVERT_Y | ||
y_offset -= mouse_offset(state[1], state[0], 5); | ||
y_offset -= trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_MOUSE_SCALE); | ||
#else | ||
y_offset += mouse_offset(state[1], state[0], 5); | ||
y_offset += trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_MOUSE_SCALE); | ||
#endif | ||
} | ||
} else { | ||
if (state[4]) { | ||
debounce = true; | ||
debounce_timer = timer_read(); | ||
} | ||
if (scrolling) { | ||
#ifndef PIMORONI_TRACKBALL_ROTATE | ||
trackball_adapt_values(&mouse_report.h, &h_offset); | ||
trackball_adapt_values(&mouse_report.v, &v_offset); | ||
#else | ||
trackball_adapt_values(&mouse_report.h, &v_offset); | ||
trackball_adapt_values(&mouse_report.v, &h_offset); | ||
#endif | ||
mouse_report.x = 0; | ||
mouse_report.y = 0; | ||
} else { | ||
#ifndef PIMORONI_TRACKBALL_ROTATE | ||
trackball_adapt_values(&mouse_report.x, &x_offset); | ||
trackball_adapt_values(&mouse_report.y, &y_offset); | ||
#else | ||
trackball_adapt_values(&mouse_report.x, &y_offset); | ||
trackball_adapt_values(&mouse_report.y, &x_offset); | ||
#endif | ||
mouse_report.h = 0; | ||
mouse_report.v = 0; | ||
} | ||
} else { | ||
debounce--; | ||
} | ||
} else { | ||
trackball_click(true, &mouse_report); | ||
debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES; | ||
} | ||
} | ||
} else { | ||
i2c_timeout_timer = timer_read(); | ||
error_count++; | ||
} | ||
} | ||
|
||
if (timer_elapsed(debounce_timer) > MOUSE_DEBOUNCE) debounce = false; | ||
|
||
report_mouse_t mouse = pointing_device_get_report(); | ||
|
||
#ifdef PIMORONI_TRACKBALL_CLICK | ||
trackball_check_click(state[4] & (1 << 7), &mouse); | ||
#endif | ||
pointing_device_set_report(mouse_report); | ||
pointing_device_send(); | ||
|
||
#ifndef PIMORONI_TRACKBALL_ROTATE | ||
update_member(&mouse.x, &x_offset); | ||
update_member(&mouse.y, &y_offset); | ||
update_member(&mouse.h, &h_offset); | ||
update_member(&mouse.v, &v_offset); | ||
#else | ||
update_member(&mouse.x, &y_offset); | ||
update_member(&mouse.y, &x_offset); | ||
update_member(&mouse.h, &v_offset); | ||
update_member(&mouse.v, &h_offset); | ||
#endif | ||
pointing_device_set_report(mouse); | ||
pointing_device_send(); | ||
throttle = timer_read_fast(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <[email protected]> | ||
* Copyright 2021 Dasky (@daskygit) | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
|
@@ -13,23 +14,24 @@ | |
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "quantum.h" | ||
#include "pointing_device.h" | ||
|
||
#ifndef TRACKBALL_ADDRESS | ||
# define TRACKBALL_ADDRESS 0x0A | ||
#endif | ||
#define TRACKBALL_WRITE ((TRACKBALL_ADDRESS << 1) | I2C_WRITE) | ||
#define TRACKBALL_READ (TRACKBALL_ADDRESS << 1) | ||
|
||
void trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white); | ||
void trackball_check_click(bool pressed, report_mouse_t *mouse); | ||
void trackball_register_button(bool pressed, enum mouse_buttons button); | ||
typedef struct pimoroni_data { | ||
uint8_t left; | ||
uint8_t right; | ||
uint8_t up; | ||
uint8_t down; | ||
uint8_t click; | ||
} pimoroni_data; | ||
|
||
float trackball_get_precision(void); | ||
void trackball_set_precision(float precision); | ||
bool trackball_is_scrolling(void); | ||
void trackball_set_scrolling(bool scroll); | ||
void trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white); | ||
void trackball_click(bool pressed, report_mouse_t* mouse); | ||
int16_t trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale); | ||
void trackball_adapt_values(int8_t* mouse, int16_t* offset); | ||
float trackball_get_precision(void); | ||
void trackball_set_precision(float precision); | ||
bool trackball_is_scrolling(void); | ||
void trackball_set_scrolling(bool scroll); |