trackball.ino 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * clockworkpi devterm trackball
  3. */
  4. #include "keys_io_map.h"
  5. #include <stdint.h>
  6. #include <stdbool.h>
  7. #include <string.h>
  8. #include <USBComposite.h>
  9. #include "trackball.h"
  10. #include "ratemeter.h"
  11. #include "glider.h"
  12. #include "math.h"
  13. enum Axis: uint8_t {
  14. AXIS_X,
  15. AXIS_Y,
  16. AXIS_NUM,
  17. };
  18. static TrackballMode lastMode;
  19. static int8_t distances[AXIS_NUM];
  20. static RateMeter rateMeter[AXIS_NUM];
  21. static Glider glider[AXIS_NUM];
  22. static const int8_t WHEEL_DENOM = 2;
  23. static int8_t wheelBuffer;
  24. static float rateToVelocityCurve(float input) {
  25. //return std::pow(std::abs(input) / 50, 1.4);
  26. return std::abs(input) / 30;
  27. }
  28. template<Axis AXIS, int8_t Direction >
  29. static void interrupt( ) {
  30. distances[AXIS] += Direction;
  31. rateMeter[AXIS].onInterrupt();
  32. glider[AXIS].setDirection(Direction);
  33. const auto rx = rateMeter[AXIS_X].rate();
  34. const auto ry = rateMeter[AXIS_Y].rate();
  35. const auto rate = std::sqrt(rx * rx + ry * ry);
  36. const auto ratio = rateToVelocityCurve(rate) / rate;
  37. const auto vx = rx * ratio;
  38. const auto vy = ry * ratio;
  39. if (AXIS == AXIS_X) {
  40. glider[AXIS_X].update(vx, std::sqrt(rateMeter[AXIS_X].delta()));
  41. glider[AXIS_Y].updateSpeed(vy);
  42. } else {
  43. glider[AXIS_X].updateSpeed(vx);
  44. glider[AXIS_Y].update(vy, std::sqrt(rateMeter[AXIS_Y].delta()));
  45. }
  46. }
  47. void trackball_task(DEVTERM*dv) {
  48. int8_t x = 0, y = 0, w = 0;
  49. noInterrupts();
  50. const auto mode = dv->state->moveTrackball();
  51. if (lastMode != mode) {
  52. rateMeter[AXIS_X].expire();
  53. rateMeter[AXIS_Y].expire();
  54. wheelBuffer = 0;
  55. }
  56. else {
  57. rateMeter[AXIS_X].tick(dv->delta);
  58. rateMeter[AXIS_Y].tick(dv->delta);
  59. }
  60. lastMode = mode;
  61. switch(mode){
  62. case TrackballMode::Mouse: {
  63. const auto rX = glider[AXIS_X].glide(dv->delta);
  64. const auto rY = glider[AXIS_Y].glide(dv->delta);
  65. x = rX.value;
  66. y = rY.value;
  67. if (rX.stopped) {
  68. glider[AXIS_Y].stop();
  69. }
  70. if (rY.stopped) {
  71. glider[AXIS_Y].stop();
  72. }
  73. break;
  74. }
  75. case TrackballMode::Wheel: {
  76. wheelBuffer += distances[AXIS_Y];
  77. w = wheelBuffer / WHEEL_DENOM;
  78. wheelBuffer -= w * WHEEL_DENOM;
  79. if(w != 0){
  80. dv->state->setScrolled();
  81. }
  82. break;
  83. }
  84. }
  85. distances[AXIS_X] = 0;
  86. distances[AXIS_Y] = 0;
  87. interrupts();
  88. if(x !=0 || y != 0 || -w!=0) {
  89. dv->Mouse->move(x, y, -w);
  90. }
  91. }
  92. void trackball_init(DEVTERM*dv){
  93. pinMode(LEFT_PIN, INPUT);
  94. pinMode(UP_PIN, INPUT);
  95. pinMode(RIGHT_PIN, INPUT);
  96. pinMode(DOWN_PIN, INPUT);
  97. attachInterrupt(LEFT_PIN, &interrupt<AXIS_X,-1> , ExtIntTriggerMode::CHANGE);
  98. attachInterrupt(RIGHT_PIN, &interrupt<AXIS_X, 1>, ExtIntTriggerMode::CHANGE);
  99. attachInterrupt(UP_PIN, &interrupt<AXIS_Y, -1>, ExtIntTriggerMode::CHANGE);
  100. attachInterrupt(DOWN_PIN, &interrupt<AXIS_Y, 1>, ExtIntTriggerMode::CHANGE);
  101. }