mirror of
https://github.com/clockworkpi/DevTerm.git
synced 2025-12-12 18:28:50 +01:00
borrwoed a lot code from https://github.com/foriequal0/devterm_keyboard in order to optimize the trackball
This commit is contained in:
parent
1a1be01dbb
commit
b1370d2124
53
Code/devterm_keyboard/debouncer.h
Normal file
53
Code/devterm_keyboard/debouncer.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef DEBOUNCER_H
|
||||
#define DEBOUNCER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef uint8_t millis_t;
|
||||
|
||||
const millis_t DEBOUNCE_MS = 5;
|
||||
|
||||
/**
|
||||
@brief Asymmetric debouncer
|
||||
*/
|
||||
class Debouncer {
|
||||
public:
|
||||
Debouncer();
|
||||
void updateTime(millis_t delta);
|
||||
bool sample(bool value);
|
||||
private:
|
||||
millis_t timeout;
|
||||
};
|
||||
|
||||
template<typename T, T millis>
|
||||
class Timeout {
|
||||
public:
|
||||
Timeout() {
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
void updateTime(millis_t delta) {
|
||||
if (timeout > delta) {
|
||||
timeout -= delta;
|
||||
} else {
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void expire() {
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
bool get() const {
|
||||
return timeout == 0;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
timeout = millis;
|
||||
}
|
||||
private:
|
||||
uint16_t timeout;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
23
Code/devterm_keyboard/debouncer.ino
Normal file
23
Code/devterm_keyboard/debouncer.ino
Normal file
@ -0,0 +1,23 @@
|
||||
#include "debouncer.h"
|
||||
|
||||
Debouncer::Debouncer()
|
||||
: timeout(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Debouncer::updateTime(millis_t delta) {
|
||||
if (timeout > delta) {
|
||||
timeout -= delta;
|
||||
} else {
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Debouncer::sample(bool value) {
|
||||
if (value || timeout == 0) {
|
||||
timeout = DEBOUNCE_MS;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
#define DEVTERM_H
|
||||
|
||||
#define KEY_LATENCY 1400
|
||||
#include "state.h"
|
||||
|
||||
#include <USBComposite.h>
|
||||
typedef struct key_debouncing{
|
||||
@ -32,6 +33,8 @@ class DEVTERM {
|
||||
//**Serial and USBCompositeSerial can not use together, otherwise the keyboard firmware uploading will be dead**
|
||||
//and you will need to find a way out to flash the stm32duino bootloader once again
|
||||
//USBSerial *_Serial;//_Serial = &Serial;
|
||||
State *state;
|
||||
uint32_t delta;
|
||||
};
|
||||
|
||||
#define KEYBOARD_PULL 1 // 1 for PULLUP, 0 FOR PULLDOWN
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "keys.h"
|
||||
#include "trackball.h"
|
||||
#include "devterm.h"
|
||||
#include "tickwaiter.h"
|
||||
|
||||
#include <USBComposite.h>
|
||||
|
||||
@ -17,6 +18,8 @@ const uint8_t reportDescription[] = {
|
||||
HID_MOUSE_REPORT_DESCRIPTOR()
|
||||
};
|
||||
|
||||
static const uint32_t LOOP_INTERVAL_MS = 0;
|
||||
static TickWaiter<LOOP_INTERVAL_MS> waiter;
|
||||
|
||||
void setup() {
|
||||
USBComposite.setManufacturerString("ClockworkPI");
|
||||
@ -29,7 +32,8 @@ void setup() {
|
||||
dev_term.Consumer = new HIDConsumer(HID);
|
||||
|
||||
dev_term.Keyboard->setAdjustForHostCapsLock(false);
|
||||
|
||||
|
||||
dev_term.state = new State();
|
||||
|
||||
dev_term.Keyboard_state.layer = 0;
|
||||
dev_term.Keyboard_state.prev_layer = 0;
|
||||
@ -55,8 +59,11 @@ void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
dev_term.delta = waiter.waitForNextTick();
|
||||
dev_term.state->tick(dev_term.delta);
|
||||
|
||||
trackball_task(&dev_term);
|
||||
|
||||
keys_task(&dev_term); //keys above keyboard
|
||||
keyboard_task(&dev_term);
|
||||
|
||||
|
||||
29
Code/devterm_keyboard/glider.h
Normal file
29
Code/devterm_keyboard/glider.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef GLIDER_H
|
||||
#define GLIDER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
class Glider {
|
||||
public:
|
||||
Glider();
|
||||
void setDirection(int8_t);
|
||||
void update(float velocity, uint16_t sustain);
|
||||
void updateSpeed(float velocity);
|
||||
void stop();
|
||||
|
||||
struct GlideResult {
|
||||
int8_t value;
|
||||
bool stopped;
|
||||
};
|
||||
GlideResult glide(uint8_t delta);
|
||||
|
||||
public:
|
||||
int8_t direction;
|
||||
float speed;
|
||||
uint16_t sustain;
|
||||
uint16_t release;
|
||||
float error;
|
||||
};
|
||||
|
||||
#endif
|
||||
60
Code/devterm_keyboard/glider.ino
Normal file
60
Code/devterm_keyboard/glider.ino
Normal file
@ -0,0 +1,60 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "glider.h"
|
||||
#include "math.h"
|
||||
|
||||
Glider::Glider()
|
||||
: speed(0),
|
||||
sustain(0),
|
||||
release(0),
|
||||
error(0)
|
||||
{}
|
||||
|
||||
void Glider::setDirection(int8_t direction) {
|
||||
if (this->direction != direction) {
|
||||
stop();
|
||||
}
|
||||
this->direction = direction;
|
||||
}
|
||||
|
||||
void Glider::update(float speed, uint16_t sustain) {
|
||||
this->speed = speed;
|
||||
this->sustain = sustain;
|
||||
this->release = sustain;
|
||||
}
|
||||
|
||||
void Glider::updateSpeed(float speed) {
|
||||
this->speed = speed;
|
||||
}
|
||||
|
||||
void Glider::stop() {
|
||||
this->speed = 0;
|
||||
this->sustain = 0;
|
||||
this->release = 0;
|
||||
this->error = 0;
|
||||
}
|
||||
|
||||
Glider::GlideResult Glider::glide(millis_t delta) {
|
||||
const auto alreadyStopped = speed == 0;
|
||||
|
||||
error += speed * delta;
|
||||
int8_t distance = 0;
|
||||
if (error > 0) {
|
||||
distance = clamp<int8_t>(std::ceil(error));
|
||||
}
|
||||
error -= distance;
|
||||
|
||||
if (sustain > 0) {
|
||||
const auto sustained = min(sustain, (uint16_t)delta);
|
||||
sustain -= sustained;
|
||||
} else if (release > 0) {
|
||||
const auto released = min(release, (uint16_t)delta);
|
||||
speed = speed * (release - released) / release;
|
||||
release -= released;
|
||||
} else {
|
||||
speed = 0;
|
||||
}
|
||||
|
||||
const int8_t result = direction * distance;
|
||||
return GlideResult { result, !alreadyStopped && speed == 0 };
|
||||
}
|
||||
@ -58,7 +58,7 @@ enum SKEYS {
|
||||
|
||||
_VOLUME_M,
|
||||
_VOLUME_P,
|
||||
|
||||
_TRACKBALL_BTN,
|
||||
};
|
||||
|
||||
#define DEF_LAYER 0x00
|
||||
@ -105,7 +105,7 @@ const uint16_t keys_maps[KEYS_NUM] = {_JOYSTICK_UP,_JOYSTICK_DOWN, _JOYSTICK_LEF
|
||||
_JOYSTICK_RIGHT,_JOYSTICK_A,_JOYSTICK_B, \
|
||||
_JOYSTICK_X,_JOYSTICK_Y,_LEFT_SHIFT_KEY,_FN_KEY,\
|
||||
_LEFT_CTRL_KEY,_CMD_KEY , _LEFT_ALT, \
|
||||
_MOUSE_LEFT,_MOUSE_MID,_MOUSE_RIGHT};
|
||||
_MOUSE_LEFT,_MOUSE_MID,_MOUSE_RIGHT,_TRACKBALL_BTN};
|
||||
|
||||
|
||||
uint8_t check_pd2(){ // if swtich 2 in back is set to on(HIGH)
|
||||
@ -241,13 +241,14 @@ void keyboard_action(DEVTERM*dv,uint8_t row,uint8_t col,uint8_t mode) {
|
||||
void keypad_action(DEVTERM*dv,uint8_t col,uint8_t mode) {
|
||||
|
||||
uint16_t k;
|
||||
|
||||
k = keys_maps[col];
|
||||
|
||||
k = keys_maps[col];
|
||||
|
||||
if(k == EMP){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch(k) {
|
||||
case _LEFT_SHIFT_KEY:
|
||||
if(mode == KEY_PRESSED) {
|
||||
@ -419,7 +420,15 @@ void keypad_action(DEVTERM*dv,uint8_t col,uint8_t mode) {
|
||||
dv->Keyboard->release(k);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case _TRACKBALL_BTN:
|
||||
if(mode == KEY_PRESSED) {
|
||||
dv->state->pressMiddleClick();
|
||||
}else {
|
||||
dv->state->releaseMiddleClick();
|
||||
dv->Mouse->click(MOUSE_MIDDLE);
|
||||
}
|
||||
break;
|
||||
default:break;
|
||||
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
# define KEY_DEBOUNCE 5
|
||||
#endif
|
||||
|
||||
#define KEYS_NUM 16
|
||||
#define KEYS_NUM 17
|
||||
|
||||
|
||||
void keys_task(DEVTERM*);
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
|
||||
KEY_DEB keypad_debouncing;
|
||||
|
||||
uint8_t keys_io[ KEYS_NUM ]= {KEY1,KEY2,KEY3,KEY4,KEY5,KEY6,KEY7,KEY8,KEY9,KEY10,KEY11,KEY12,KEY13,KEY14,KEY15,KEY16};
|
||||
uint8_t keys_io[ KEYS_NUM ]= {KEY1,KEY2,KEY3,KEY4,KEY5,KEY6,KEY7,KEY8,KEY9,KEY10,KEY11,KEY12,KEY13,KEY14,KEY15,KEY16,KEY0};
|
||||
|
||||
/* keys state(1:on, 0:off) */
|
||||
static uint16_t keys;
|
||||
static uint16_t keys_debouncing;
|
||||
static uint16_t keys_prev;
|
||||
static uint32_t keys;
|
||||
static uint32_t keys_debouncing;
|
||||
static uint32_t keys_prev;
|
||||
|
||||
void init_keys(){
|
||||
int i;
|
||||
@ -19,7 +19,7 @@ void init_keys(){
|
||||
}
|
||||
|
||||
uint8_t scan_keys(){
|
||||
uint16_t data;
|
||||
uint32_t data;
|
||||
uint8_t s;
|
||||
|
||||
data = 0;
|
||||
@ -69,9 +69,9 @@ void keys_task(DEVTERM*dv){
|
||||
|
||||
scan_keys();
|
||||
|
||||
uint16_t _mask =1;
|
||||
uint16_t _change = 0;
|
||||
uint16_t _pressed = 0;
|
||||
uint32_t _mask =1;
|
||||
uint32_t _change = 0;
|
||||
uint32_t _pressed = 0;
|
||||
|
||||
_change = keys ^ keys_prev;
|
||||
|
||||
|
||||
56
Code/devterm_keyboard/math.h
Normal file
56
Code/devterm_keyboard/math.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef MATH_H
|
||||
#define MATH_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
uint32_t getDelta(uint32_t prev, uint32_t now);
|
||||
uint32_t getDelta(uint32_t prev, uint32_t now, uint32_t max);
|
||||
|
||||
template<typename T>
|
||||
T sign(T value) {
|
||||
if (value > 0) {
|
||||
return 1;
|
||||
}
|
||||
if (value < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
T clamp(U value) {
|
||||
if (value >= std::numeric_limits<T>().max()) {
|
||||
return std::numeric_limits<T>().max();
|
||||
}
|
||||
|
||||
if (value <= std::numeric_limits<T>().min()) {
|
||||
return std::numeric_limits<T>().min();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T min(T x, T y) {
|
||||
if (x < y) {
|
||||
return x;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T max(T x, T y) {
|
||||
if (x > y) {
|
||||
return x;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T hypot(T x, T y) {
|
||||
return std::sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
#endif
|
||||
23
Code/devterm_keyboard/math.ino
Normal file
23
Code/devterm_keyboard/math.ino
Normal file
@ -0,0 +1,23 @@
|
||||
#include <limits>
|
||||
|
||||
#include "math.h"
|
||||
|
||||
uint32_t getDelta(uint32_t prev, uint32_t now) {
|
||||
uint32_t delta;
|
||||
if (now >= prev) {
|
||||
delta = now - prev;
|
||||
} else {
|
||||
delta = std::numeric_limits<uint32_t>().max() - prev - now + 1;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
uint32_t getDelta(uint32_t prev, uint32_t now, uint32_t max) {
|
||||
const auto delta = getDelta(prev, now);
|
||||
|
||||
if (delta < max) {
|
||||
return delta;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
38
Code/devterm_keyboard/ratemeter.h
Normal file
38
Code/devterm_keyboard/ratemeter.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef RATEMETER_H
|
||||
#define RATEMETER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "debouncer.h"
|
||||
|
||||
class RateMeter {
|
||||
public:
|
||||
RateMeter();
|
||||
void onInterrupt();
|
||||
void tick(millis_t delta);
|
||||
void expire();
|
||||
|
||||
uint16_t delta() const;
|
||||
// Hall sensor edges per seconds.
|
||||
// stopped: 0
|
||||
// really slow => ~3
|
||||
// medium => ~30
|
||||
// fast => < 300
|
||||
// max => 1000
|
||||
float rate() const;
|
||||
|
||||
private:
|
||||
uint32_t lastTime;
|
||||
|
||||
// really Range, emperically:
|
||||
// fast => < 5_000 us,
|
||||
// medium => 20_000 - 40_000 us
|
||||
// really slow => 250_000 us
|
||||
uint32_t averageDelta;
|
||||
|
||||
static const uint16_t CUTOFF_MS = 1000;
|
||||
// Cut off after some seconds to prevent multiple timestamp overflow (~70 mins)
|
||||
Timeout<uint16_t, CUTOFF_MS> cutoff;
|
||||
};
|
||||
|
||||
#endif
|
||||
40
Code/devterm_keyboard/ratemeter.ino
Normal file
40
Code/devterm_keyboard/ratemeter.ino
Normal file
@ -0,0 +1,40 @@
|
||||
#include <Arduino.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "ratemeter.h"
|
||||
#include "math.h"
|
||||
|
||||
RateMeter::RateMeter()
|
||||
: lastTime(0)
|
||||
{}
|
||||
|
||||
void RateMeter::onInterrupt() {
|
||||
const auto now = millis();
|
||||
if (cutoff.get()) {
|
||||
averageDelta = CUTOFF_MS;
|
||||
} else {
|
||||
const auto delta = getDelta(lastTime, now, CUTOFF_MS);
|
||||
averageDelta = (averageDelta + delta) / 2;
|
||||
}
|
||||
lastTime = now;
|
||||
cutoff.reset();
|
||||
}
|
||||
|
||||
void RateMeter::tick(millis_t delta) {
|
||||
cutoff.updateTime(delta);
|
||||
}
|
||||
|
||||
uint16_t RateMeter::delta() const {
|
||||
return averageDelta;
|
||||
}
|
||||
|
||||
float RateMeter::rate() const {
|
||||
if (cutoff.get()) {
|
||||
return 0.0f;
|
||||
} else if (averageDelta == 0) {
|
||||
// to ensure range 0 ~ 1000.0
|
||||
return 1000.0f;
|
||||
} else {
|
||||
return 1000.0f / (float)averageDelta;
|
||||
}
|
||||
}
|
||||
34
Code/devterm_keyboard/state.h
Normal file
34
Code/devterm_keyboard/state.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef STATE_H
|
||||
#define STATE_H
|
||||
|
||||
#include <bitset>
|
||||
#include <array>
|
||||
#include <USBComposite.h>
|
||||
|
||||
#include "debouncer.h"
|
||||
|
||||
enum class TrackballMode : uint8_t {
|
||||
Wheel,
|
||||
Mouse,
|
||||
};
|
||||
|
||||
class State
|
||||
{
|
||||
public:
|
||||
static const uint16_t MIDDLE_CLICK_TIMEOUT_MS = 0;
|
||||
|
||||
State();
|
||||
|
||||
void tick(uint8_t delta);
|
||||
|
||||
bool fn;
|
||||
|
||||
void pressMiddleClick();
|
||||
bool releaseMiddleClick();
|
||||
TrackballMode moveTrackball();
|
||||
private:
|
||||
bool middleClick;
|
||||
Timeout<uint16_t, MIDDLE_CLICK_TIMEOUT_MS> middleClickTimeout;
|
||||
};
|
||||
|
||||
#endif
|
||||
36
Code/devterm_keyboard/state.ino
Normal file
36
Code/devterm_keyboard/state.ino
Normal file
@ -0,0 +1,36 @@
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "state.h"
|
||||
|
||||
State::State()
|
||||
: fn(false),
|
||||
middleClick(false)
|
||||
{
|
||||
}
|
||||
|
||||
void State::tick(millis_t delta)
|
||||
{
|
||||
middleClickTimeout.updateTime(delta);
|
||||
}
|
||||
|
||||
void State::pressMiddleClick() {
|
||||
middleClick = true;
|
||||
middleClickTimeout.reset();
|
||||
}
|
||||
|
||||
bool State::releaseMiddleClick() {
|
||||
middleClick = false;
|
||||
const auto timeout = middleClickTimeout.get();
|
||||
return !timeout;
|
||||
}
|
||||
|
||||
TrackballMode State::moveTrackball() {
|
||||
middleClickTimeout.expire();
|
||||
if (middleClick) {
|
||||
return TrackballMode::Wheel;
|
||||
} else {
|
||||
return TrackballMode::Mouse;
|
||||
}
|
||||
}
|
||||
30
Code/devterm_keyboard/tickwaiter.h
Normal file
30
Code/devterm_keyboard/tickwaiter.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef TICKWAITER_H
|
||||
#define TICKWAITER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "math.h"
|
||||
|
||||
template<uint32_t TargetInterval>
|
||||
class TickWaiter {
|
||||
public:
|
||||
uint8_t waitForNextTick() {
|
||||
const auto last = this->last;
|
||||
const auto now = millis();
|
||||
this->last = now;
|
||||
|
||||
const auto delta = getDelta(last, now, 255);
|
||||
|
||||
if (delta >= TargetInterval) {
|
||||
return delta;
|
||||
}
|
||||
|
||||
delay(TargetInterval - delta);
|
||||
|
||||
const auto now2 = millis();
|
||||
return getDelta(last, now2, 255);
|
||||
}
|
||||
private:
|
||||
uint32_t last = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -12,64 +12,11 @@
|
||||
#define EXPONENTIAL_BASE 1.2
|
||||
*/
|
||||
|
||||
#define BTN_PIN KEY0
|
||||
#define RIGHT_PIN HO3
|
||||
#define LEFT_PIN HO1
|
||||
#define DOWN_PIN HO4
|
||||
#define UP_PIN HO2
|
||||
|
||||
typedef struct _track_speed {
|
||||
uint8_t bounce_interval;
|
||||
uint8_t base_move_pixels;
|
||||
uint8_t exponential_bound;
|
||||
double exponential_base;
|
||||
|
||||
}TrackSpeed;
|
||||
|
||||
class Direction {
|
||||
public:
|
||||
Direction(int pin1, int pin2) {
|
||||
this->pins[0] = pin1;
|
||||
this->pins[1] = pin2;
|
||||
pinMode(this->pins[0], INPUT);
|
||||
pinMode(this->pins[1], INPUT);
|
||||
};
|
||||
|
||||
int read_action() {
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
this->current_actions[i] = digitalRead(this->pins[i]);
|
||||
this->current_action_times[i] = millis();
|
||||
if(this->current_actions[i] != this->last_actions[i]) {
|
||||
this->last_actions[i] = this->current_actions[i];
|
||||
exponential = ( ts->exponential_bound - (this->current_action_times[i] - this->last_action_times[i]));
|
||||
exponential = (exponential > 0) ? exponential : 1;
|
||||
move_multiply = ts->exponential_base;
|
||||
for(int i = 0; i < exponential; ++i) {
|
||||
move_multiply *= ts->exponential_base;
|
||||
}
|
||||
this->last_action_times[i] = this->current_action_times[i];
|
||||
if(i == 0) {
|
||||
return (-1) * ts->base_move_pixels * move_multiply;
|
||||
} else {
|
||||
return ts->base_move_pixels * move_multiply;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
TrackSpeed *ts;
|
||||
|
||||
private:
|
||||
int pins[2];
|
||||
int current_actions[2];
|
||||
int last_actions[2];
|
||||
int exponential;
|
||||
double move_multiply;
|
||||
unsigned long current_action_times[2];
|
||||
unsigned long last_action_times[2];
|
||||
|
||||
};
|
||||
|
||||
void trackball_init(DEVTERM*);
|
||||
void trackball_task(DEVTERM*);
|
||||
|
||||
@ -9,71 +9,103 @@
|
||||
|
||||
#include <USBComposite.h>
|
||||
|
||||
|
||||
#include "trackball.h"
|
||||
|
||||
#include "ratemeter.h"
|
||||
#include "glider.h"
|
||||
#include "math.h"
|
||||
|
||||
int btn_state;
|
||||
int btn_read_state;
|
||||
unsigned long btn_current_action_time;
|
||||
unsigned long btn_last_action_time;
|
||||
|
||||
// mouse move
|
||||
int x_move, y_move;
|
||||
Direction x_direction(LEFT_PIN, RIGHT_PIN);
|
||||
Direction y_direction(UP_PIN, DOWN_PIN);
|
||||
|
||||
enum Axis: uint8_t {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_NUM,
|
||||
};
|
||||
|
||||
TrackSpeed Normal_ts;
|
||||
TrackSpeed Detail_ts;
|
||||
TrackSpeed *ts_ptr;
|
||||
static int8_t distances[AXIS_NUM];
|
||||
static RateMeter rateMeter[AXIS_NUM];
|
||||
static Glider glider[AXIS_NUM];
|
||||
|
||||
void trackball_task(DEVTERM*dv) {
|
||||
|
||||
if(dv-> Keyboard_state.fn_on > 0) {
|
||||
ts_ptr = &Detail_ts;
|
||||
}else {
|
||||
ts_ptr = &Normal_ts;
|
||||
static const int8_t WHEEL_DENOM = 2;
|
||||
static int8_t wheelBuffer;
|
||||
|
||||
static float rateToVelocityCurve(float input) {
|
||||
return std::pow(std::abs(input) / 50, 1.5);
|
||||
}
|
||||
|
||||
template<Axis AXIS, int8_t Direction>
|
||||
static void interrupt() {
|
||||
distances[AXIS] += Direction;
|
||||
rateMeter[AXIS].onInterrupt();
|
||||
glider[AXIS].setDirection(Direction);
|
||||
|
||||
const auto rx = rateMeter[AXIS_X].rate();
|
||||
const auto ry = rateMeter[AXIS_Y].rate();
|
||||
|
||||
const auto rate = std::sqrt(rx * rx + ry * ry);
|
||||
const auto ratio = rateToVelocityCurve(rate) / rate;
|
||||
|
||||
const auto vx = rx * ratio;
|
||||
const auto vy = ry * ratio;
|
||||
|
||||
if (AXIS == AXIS_X) {
|
||||
glider[AXIS_X].update(vx, rateMeter[AXIS_X].delta());
|
||||
glider[AXIS_Y].updateSpeed(vy);
|
||||
} else {
|
||||
glider[AXIS_X].updateSpeed(vx);
|
||||
glider[AXIS_Y].update(vy, rateMeter[AXIS_Y].delta());
|
||||
}
|
||||
|
||||
x_direction.ts = ts_ptr;
|
||||
y_direction.ts = ts_ptr;
|
||||
|
||||
btn_read_state = digitalRead(BTN_PIN);
|
||||
|
||||
if(btn_read_state != btn_state) {
|
||||
btn_current_action_time = millis();
|
||||
if(btn_current_action_time - btn_last_action_time > ts_ptr->bounce_interval ) {
|
||||
btn_state = btn_read_state;
|
||||
btn_last_action_time = btn_current_action_time;
|
||||
|
||||
if(btn_state == HIGH) {
|
||||
dv->Mouse->release();
|
||||
} else {
|
||||
dv->Mouse->press();
|
||||
}
|
||||
|
||||
void trackball_task(DEVTERM*dv) {
|
||||
int8_t x = 0, y = 0, w = 0;
|
||||
noInterrupts();
|
||||
rateMeter[AXIS_X].tick(dv->delta);
|
||||
rateMeter[AXIS_Y].tick(dv->delta);
|
||||
const auto mode = dv->state->moveTrackball();
|
||||
switch(mode){
|
||||
case TrackballMode::Mouse: {
|
||||
const auto rX = glider[AXIS_X].glide(dv->delta);
|
||||
const auto rY = glider[AXIS_Y].glide(dv->delta);
|
||||
x = rX.value;
|
||||
y = rY.value;
|
||||
if (rX.stopped) {
|
||||
glider[AXIS_Y].stop();
|
||||
}
|
||||
if (rY.stopped) {
|
||||
glider[AXIS_Y].stop();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TrackballMode::Wheel: {
|
||||
wheelBuffer += distances[AXIS_Y];
|
||||
w = wheelBuffer / WHEEL_DENOM;
|
||||
wheelBuffer -= w * WHEEL_DENOM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
distances[AXIS_X] = 0;
|
||||
distances[AXIS_Y] = 0;
|
||||
interrupts();
|
||||
|
||||
x_move = x_direction.read_action();
|
||||
y_move = y_direction.read_action();
|
||||
if(x_move != 0 || y_move != 0) {
|
||||
dv->Mouse->move(x_move, y_move, 0);
|
||||
}
|
||||
|
||||
dv->Mouse->move(x, y, -w);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void trackball_init(DEVTERM*){
|
||||
pinMode(BTN_PIN,INPUT);
|
||||
|
||||
Normal_ts.bounce_interval = 30;
|
||||
Normal_ts.base_move_pixels = 5;
|
||||
Normal_ts.exponential_bound = 14;
|
||||
Normal_ts.exponential_base = 1.2;
|
||||
|
||||
Detail_ts.bounce_interval = 100;
|
||||
Detail_ts.base_move_pixels = 3;
|
||||
Detail_ts.exponential_bound = 10;
|
||||
Detail_ts.exponential_base = 1.2;
|
||||
pinMode(LEFT_PIN, INPUT);
|
||||
pinMode(UP_PIN, INPUT);
|
||||
pinMode(RIGHT_PIN, INPUT);
|
||||
pinMode(DOWN_PIN, INPUT);
|
||||
|
||||
attachInterrupt(LEFT_PIN, &interrupt<AXIS_X, -1>, ExtIntTriggerMode::CHANGE);
|
||||
attachInterrupt(RIGHT_PIN, &interrupt<AXIS_X, 1>, ExtIntTriggerMode::CHANGE);
|
||||
attachInterrupt(UP_PIN, &interrupt<AXIS_Y, -1>, ExtIntTriggerMode::CHANGE);
|
||||
attachInterrupt(DOWN_PIN, &interrupt<AXIS_Y, 1>, ExtIntTriggerMode::CHANGE);
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user