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 2 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
169 changes: 100 additions & 69 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) <drashna@live.com>
* 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,41 +14,66 @@
* 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;
#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

static uint16_t i2c_timeout_timer;
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;

#ifndef PIMORONI_I2C_TIMEOUT
# define PIMORONI_I2C_TIMEOUT 100
#endif
#ifndef I2C_WAITCHECK
# define I2C_WAITCHECK 1000
#endif
#ifndef MOUSE_DEBOUNCE
# define MOUSE_DEBOUNCE 5
float trackball_get_precision(void) { return (float)(precision >> 7); }
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(TRACKBALL_ADDRESS << 1, TRACKBALL_REG_LED_RED, data, sizeof(data), TRACKBALL_TIMEOUT);
dprintf("Trackball RGBW i2c_status_t: %d\n", status);
}

void read_pimoroni_trackball(pimoroni_data* data) {
__attribute__((unused)) i2c_status_t status = i2c_readReg(TRACKBALL_ADDRESS << 1, TRACKBALL_REG_LEFT, (uint8_t*)data, sizeof(*data), TRACKBALL_TIMEOUT);
#ifdef TRACKBALL_DEBUG_READ
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
}

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 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 update_values(int8_t* member, int16_t* offset) {
if (*offset > 127) {
*member = 127;
*offset -= 127;
Expand All @@ -68,73 +94,78 @@ __attribute__((weak)) void trackball_check_click(bool pressed, report_mouse_t* m
}
}

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; }
void pointing_device_task() {
static fast_timer_t throttle = 0;
static uint8_t debounce = 0;

if (timer_elapsed_fast(throttle) > TRACKBALL_INTERVAL_MS) {
static pimoroni_data last_read_data = {0};
mouse_report = pointing_device_get_report();
read_pimoroni_trackball(&current_pimoroni_data);

__attribute__((weak)) void pointing_device_init(void) { i2c_init(); trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); }
if (!debounce) {
if (memcmp(&last_read_data, &current_pimoroni_data, sizeof(current_pimoroni_data))) {
memcpy(&last_read_data, &current_pimoroni_data, sizeof(current_pimoroni_data));

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) {
#ifdef PIMORONI_TRACKBALL_CLICK
if (current_pimoroni_data.click & 128) {
trackball_check_click(true, &mouse_report);
debounce = TRACKBALL_DEBOUNCE_ONCLICK;
} else {
trackball_check_click(false, &mouse_report);
}
#endif
if (scrolling) {
#ifdef PIMORONI_TRACKBALL_INVERT_X
h_offset += mouse_offset(state[2], state[3], 1);
h_offset += get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, 5);
#else
h_offset -= mouse_offset(state[2], state[3], 1);
h_offset -= get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, 5);
#endif
#ifdef PIMORONI_TRACKBALL_INVERT_Y
v_offset += mouse_offset(state[1], state[0], 1);
v_offset += get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, 5);
#else
v_offset -= mouse_offset(state[1], state[0], 1);
v_offset -= get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, 5);
#endif
} else {
#ifdef PIMORONI_TRACKBALL_INVERT_X
x_offset -= mouse_offset(state[2], state[3], 5);
x_offset -= get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, 5);
#else
x_offset += mouse_offset(state[2], state[3], 5);
x_offset += get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, 5);
#endif
#ifdef PIMORONI_TRACKBALL_INVERT_Y
y_offset -= mouse_offset(state[1], state[0], 5);
y_offset -= get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, 5);
#else
y_offset += mouse_offset(state[1], state[0], 5);
y_offset += get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, 5);
#endif
}
} else {
if (state[4]) {
debounce = true;
debounce_timer = timer_read();
}
}
} else {
i2c_timeout_timer = timer_read();
debounce--;
}
}

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);
if (scrolling) {
#ifndef PIMORONI_TRACKBALL_ROTATE
update_values(&mouse_report.h, &h_offset);
update_values(&mouse_report.v, &v_offset);
#else
update_values(&mouse_report.h, &v_offset);
update_values(&mouse_report.v, &h_offset);
#endif

mouse_report.x = 0;
mouse_report.y = 0;
} else {
#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);
update_values(&mouse_report.x, &x_offset);
update_values(&mouse_report.y, &y_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);
update_values(&mouse_report.x, &y_offset);
update_values(&mouse_report.y, &x_offset);
#endif
pointing_device_set_report(mouse);
pointing_device_send();
mouse_report.h = 0;
mouse_report.v = 0;
}
pointing_device_set_report(mouse_report);
pointing_device_send();

throttle = timer_read_fast();
}
}
19 changes: 16 additions & 3 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) <drashna@live.com>
* 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,7 +14,6 @@
* 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"
Expand All @@ -22,8 +22,21 @@
#ifndef TRACKBALL_ADDRESS
# define TRACKBALL_ADDRESS 0x0A
#endif
#define TRACKBALL_WRITE ((TRACKBALL_ADDRESS << 1) | I2C_WRITE)
#define TRACKBALL_READ (TRACKBALL_ADDRESS << 1)

#ifndef TRACKBALL_INTERVAL_MS
# define TRACKBALL_INTERVAL_MS 8
#endif

#ifndef TRACKBALL_DEBOUNCE_ONCLICK
# define TRACKBALL_DEBOUNCE_ONCLICK 5
#endif
typedef struct pimoroni_data {
uint8_t left;
uint8_t right;
uint8_t up;
uint8_t down;
uint8_t click;
} pimoroni_data;

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);
Expand Down