[Core] Speed up pimoroni trackball driver (#13823)
This commit is contained in:
		
							parent
							
								
									e988f58374
								
							
						
					
					
						commit
						7f1c90b7a8
					
				
					 2 changed files with 160 additions and 97 deletions
				
			
		|  | @ -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 | ||||
|  | @ -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; | ||||
| 
 | ||||
| static uint16_t i2c_timeout_timer; | ||||
| 
 | ||||
| #ifndef PIMORONI_I2C_TIMEOUT | ||||
| #    define PIMORONI_I2C_TIMEOUT 100 | ||||
| #ifndef PIMORONI_TRACKBALL_ADDRESS | ||||
| #    define PIMORONI_TRACKBALL_ADDRESS 0x0A | ||||
| #endif | ||||
| #ifndef I2C_WAITCHECK | ||||
| #    define I2C_WAITCHECK 1000 | ||||
| #ifndef PIMORONI_TRACKBALL_INTERVAL_MS | ||||
| #    define PIMORONI_TRACKBALL_INTERVAL_MS 8 | ||||
| #endif | ||||
| #ifndef MOUSE_DEBOUNCE | ||||
| #    define MOUSE_DEBOUNCE 5 | ||||
| #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 | ||||
| 
 | ||||
| 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); | ||||
| #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 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 | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 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 update_member(int8_t* member, int16_t* offset) { | ||||
| __attribute__((weak)) void pointing_device_init(void) { | ||||
|     i2c_init(); | ||||
|     trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); | ||||
| } | ||||
| 
 | ||||
| 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 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 { | ||||
| #ifdef PIMORONI_TRACKBALL_INVERT_X | ||||
|                             x_offset -= trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_MOUSE_SCALE); | ||||
| #else | ||||
|                             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 -= trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_MOUSE_SCALE); | ||||
| #else | ||||
|                             y_offset += trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_MOUSE_SCALE); | ||||
| #endif | ||||
|                         } | ||||
|                         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 { | ||||
| #ifdef PIMORONI_TRACKBALL_INVERT_X | ||||
|                     x_offset -= mouse_offset(state[2], state[3], 5); | ||||
| #else | ||||
|                     x_offset += mouse_offset(state[2], state[3], 5); | ||||
| #endif | ||||
| #ifdef PIMORONI_TRACKBALL_INVERT_Y | ||||
|                     y_offset -= mouse_offset(state[1], state[0], 5); | ||||
| #else | ||||
|                     y_offset += mouse_offset(state[1], state[0], 5); | ||||
| #endif | ||||
|                 } | ||||
|             } else { | ||||
|                 if (state[4]) { | ||||
|                     debounce       = true; | ||||
|                     debounce_timer = timer_read(); | ||||
|                     trackball_click(true, &mouse_report); | ||||
|                     debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             i2c_timeout_timer = timer_read(); | ||||
|             error_count++; | ||||
|         } | ||||
| 
 | ||||
|         pointing_device_set_report(mouse_report); | ||||
|         pointing_device_send(); | ||||
| 
 | ||||
|         throttle = timer_read_fast(); | ||||
|     } | ||||
| 
 | ||||
|     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 | ||||
| 
 | ||||
| #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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -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) | ||||
| 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); | ||||
| void trackball_register_button(bool pressed, enum mouse_buttons button); | ||||
| 
 | ||||
| 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); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dasky
						Dasky