Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[develop] Speed up pimoroni driver. #13823

Merged
merged 6 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 137 additions & 76 deletions drivers/sensors/pimoroni_trackball.c
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
Expand All @@ -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(&current_pimoroni_data);

if (status == I2C_STATUS_SUCCESS) {
error_count = 0;

if (pointing_device_task_user(&current_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();
}
}
30 changes: 16 additions & 14 deletions drivers/sensors/pimoroni_trackball.h
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
Expand All @@ -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);