logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

pimoroni_trackball.c (5837B)


  1. /* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
  2. * Copyright 2021 Dasky (@daskygit)
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "pointing_device_internal.h"
  18. #include "pimoroni_trackball.h"
  19. #include "i2c_master.h"
  20. #include "timer.h"
  21. // clang-format off
  22. #define PIMORONI_TRACKBALL_REG_LED_RED 0x00
  23. #define PIMORONI_TRACKBALL_REG_LED_GRN 0x01
  24. #define PIMORONI_TRACKBALL_REG_LED_BLU 0x02
  25. #define PIMORONI_TRACKBALL_REG_LED_WHT 0x03
  26. #define PIMORONI_TRACKBALL_REG_LEFT 0x04
  27. #define PIMORONI_TRACKBALL_REG_RIGHT 0x05
  28. #define PIMORONI_TRACKBALL_REG_UP 0x06
  29. #define PIMORONI_TRACKBALL_REG_DOWN 0x07
  30. // clang-format on
  31. static uint16_t precision = 128;
  32. const pointing_device_driver_t pimoroni_trackball_pointing_device_driver = {
  33. .init = pimoroni_trackball_device_init,
  34. .get_report = pimoroni_trackball_get_report,
  35. .set_cpi = pimoroni_trackball_set_cpi,
  36. .get_cpi = pimoroni_trackball_get_cpi,
  37. };
  38. uint16_t pimoroni_trackball_get_cpi(void) {
  39. return (precision * 125);
  40. }
  41. /**
  42. * @brief Sets the scaling value for pimoroni trackball
  43. *
  44. * Sets a scaling value for pimoroni trackball to allow runtime adjustment. This isn't used by the sensor and is an
  45. * approximation so the functions are consistent across drivers.
  46. *
  47. * NOTE: This rounds down to the nearest number divisable by 125 that's a positive integer, values below 125 are clamped to 125.
  48. *
  49. * @param cpi uint16_t
  50. */
  51. void pimoroni_trackball_set_cpi(uint16_t cpi) {
  52. if (cpi < 249) {
  53. precision = 1;
  54. } else {
  55. precision = (cpi - (cpi % 125)) / 125;
  56. }
  57. }
  58. void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
  59. uint8_t data[4] = {r, g, b, w};
  60. __attribute__((unused)) i2c_status_t status = i2c_write_register(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LED_RED, data, sizeof(data), PIMORONI_TRACKBALL_TIMEOUT);
  61. pd_dprintf("Trackball RGBW i2c_status_t: %d\n", status);
  62. }
  63. i2c_status_t read_pimoroni_trackball(pimoroni_data_t *data) {
  64. i2c_status_t status = i2c_read_register(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LEFT, (uint8_t *)data, sizeof(*data), PIMORONI_TRACKBALL_TIMEOUT);
  65. #ifdef POINTING_DEVICE_DEBUG
  66. static uint16_t d_timer;
  67. if (timer_elapsed(d_timer) > PIMORONI_TRACKBALL_DEBUG_INTERVAL) {
  68. pd_dprintf("Trackball READ i2c_status_t: %d L: %d R: %d Up: %d D: %d SW: %d\n", status, data->left, data->right, data->up, data->down, data->click);
  69. d_timer = timer_read();
  70. }
  71. #endif
  72. return status;
  73. }
  74. __attribute__((weak)) void pimoroni_trackball_device_init(void) {
  75. i2c_init();
  76. pimoroni_trackball_set_rgbw(0x00, 0x00, 0x00, 0x00);
  77. }
  78. int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale) {
  79. uint8_t offset = 0;
  80. bool isnegative = false;
  81. if (negative_dir > positive_dir) {
  82. offset = negative_dir - positive_dir;
  83. isnegative = true;
  84. } else {
  85. offset = positive_dir - negative_dir;
  86. }
  87. uint16_t magnitude = (scale * offset * offset * precision) >> 7;
  88. return isnegative ? -(int16_t)(magnitude) : (int16_t)(magnitude);
  89. }
  90. mouse_xy_report_t pimoroni_trackball_adapt_values(xy_clamp_range_t *offset) {
  91. if (*offset > MOUSE_REPORT_XY_MAX) {
  92. *offset -= MOUSE_REPORT_XY_MAX;
  93. return (mouse_xy_report_t)MOUSE_REPORT_XY_MAX;
  94. } else if (*offset < MOUSE_REPORT_XY_MIN) {
  95. *offset += MOUSE_REPORT_XY_MAX;
  96. return (mouse_xy_report_t)MOUSE_REPORT_XY_MIN;
  97. } else {
  98. mouse_xy_report_t temp_return = *offset;
  99. *offset = 0;
  100. return temp_return;
  101. }
  102. }
  103. report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) {
  104. static uint16_t debounce = 0;
  105. static uint8_t error_count = 0;
  106. pimoroni_data_t pimoroni_data = {0};
  107. static xy_clamp_range_t x_offset = 0, y_offset = 0;
  108. if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) {
  109. i2c_status_t status = read_pimoroni_trackball(&pimoroni_data);
  110. if (status == I2C_STATUS_SUCCESS) {
  111. error_count = 0;
  112. if (!(pimoroni_data.click & 128)) {
  113. mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
  114. if (!debounce) {
  115. x_offset += pimoroni_trackball_get_offsets(pimoroni_data.right, pimoroni_data.left, PIMORONI_TRACKBALL_SCALE);
  116. y_offset += pimoroni_trackball_get_offsets(pimoroni_data.down, pimoroni_data.up, PIMORONI_TRACKBALL_SCALE);
  117. mouse_report.x = pimoroni_trackball_adapt_values(&x_offset);
  118. mouse_report.y = pimoroni_trackball_adapt_values(&y_offset);
  119. } else {
  120. debounce--;
  121. }
  122. } else {
  123. mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1);
  124. debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES;
  125. }
  126. } else {
  127. error_count++;
  128. }
  129. }
  130. return mouse_report;
  131. }