From 17269a8c72a8aad61b31f410abe85a9279f7159a Mon Sep 17 00:00:00 2001 From: cuu Date: Wed, 14 Jun 2023 13:46:28 +1200 Subject: [PATCH] add keyboard source code --- Code/uconsole_keyboard/README.md | 13 + Code/uconsole_keyboard/debouncer.h | 53 ++ Code/uconsole_keyboard/debouncer.ino | 23 + Code/uconsole_keyboard/devterm.h | 60 ++ Code/uconsole_keyboard/glider.h | 29 + Code/uconsole_keyboard/glider.ino | 60 ++ Code/uconsole_keyboard/helper.h | 19 + Code/uconsole_keyboard/helper.ino | 10 + Code/uconsole_keyboard/keyboard.h | 83 +++ Code/uconsole_keyboard/keyboard.ino | 204 +++++++ Code/uconsole_keyboard/keymaps.ino | 542 +++++++++++++++++++ Code/uconsole_keyboard/keys.h | 27 + Code/uconsole_keyboard/keys.ino | 106 ++++ Code/uconsole_keyboard/keys_io_map.h | 49 ++ Code/uconsole_keyboard/math.h | 56 ++ Code/uconsole_keyboard/math.ino | 23 + Code/uconsole_keyboard/ratemeter.h | 38 ++ Code/uconsole_keyboard/ratemeter.ino | 47 ++ Code/uconsole_keyboard/state.h | 37 ++ Code/uconsole_keyboard/state.ino | 47 ++ Code/uconsole_keyboard/tickwaiter.h | 30 + Code/uconsole_keyboard/trackball.h | 25 + Code/uconsole_keyboard/trackball.ino | 130 +++++ Code/uconsole_keyboard/uconsole_keyboard.ino | 139 +++++ 24 files changed, 1850 insertions(+) create mode 100644 Code/uconsole_keyboard/README.md create mode 100644 Code/uconsole_keyboard/debouncer.h create mode 100644 Code/uconsole_keyboard/debouncer.ino create mode 100644 Code/uconsole_keyboard/devterm.h create mode 100644 Code/uconsole_keyboard/glider.h create mode 100644 Code/uconsole_keyboard/glider.ino create mode 100644 Code/uconsole_keyboard/helper.h create mode 100644 Code/uconsole_keyboard/helper.ino create mode 100644 Code/uconsole_keyboard/keyboard.h create mode 100644 Code/uconsole_keyboard/keyboard.ino create mode 100644 Code/uconsole_keyboard/keymaps.ino create mode 100644 Code/uconsole_keyboard/keys.h create mode 100644 Code/uconsole_keyboard/keys.ino create mode 100644 Code/uconsole_keyboard/keys_io_map.h create mode 100644 Code/uconsole_keyboard/math.h create mode 100644 Code/uconsole_keyboard/math.ino create mode 100644 Code/uconsole_keyboard/ratemeter.h create mode 100644 Code/uconsole_keyboard/ratemeter.ino create mode 100644 Code/uconsole_keyboard/state.h create mode 100644 Code/uconsole_keyboard/state.ino create mode 100644 Code/uconsole_keyboard/tickwaiter.h create mode 100644 Code/uconsole_keyboard/trackball.h create mode 100644 Code/uconsole_keyboard/trackball.ino create mode 100644 Code/uconsole_keyboard/uconsole_keyboard.ino diff --git a/Code/uconsole_keyboard/README.md b/Code/uconsole_keyboard/README.md new file mode 100644 index 0000000..4b896fa --- /dev/null +++ b/Code/uconsole_keyboard/README.md @@ -0,0 +1,13 @@ +Arduino 1.8.13 + +http://dan.drown.org/stm32duino/package_STM32duino_index.json + +STM32F1xx/GD32F1xx boards +by stm32duino version 2021.2.22 + + GENERIC STM32F103R series + + gd32f1_generic_boot20_pc13.bin + generic_boot20_pc13.bin + + \ No newline at end of file diff --git a/Code/uconsole_keyboard/debouncer.h b/Code/uconsole_keyboard/debouncer.h new file mode 100644 index 0000000..dc36f17 --- /dev/null +++ b/Code/uconsole_keyboard/debouncer.h @@ -0,0 +1,53 @@ +#ifndef DEBOUNCER_H +#define DEBOUNCER_H + +#include + +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 +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 diff --git a/Code/uconsole_keyboard/debouncer.ino b/Code/uconsole_keyboard/debouncer.ino new file mode 100644 index 0000000..93cd13d --- /dev/null +++ b/Code/uconsole_keyboard/debouncer.ino @@ -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; +} diff --git a/Code/uconsole_keyboard/devterm.h b/Code/uconsole_keyboard/devterm.h new file mode 100644 index 0000000..ac6029f --- /dev/null +++ b/Code/uconsole_keyboard/devterm.h @@ -0,0 +1,60 @@ +#ifndef DEVTERM_H +#define DEVTERM_H + +#define KEY_LATENCY 1400 +#include "state.h" + +#include +typedef struct key_debouncing{ + + bool deing;//debouncing + uint16_t de_time; + +}KEY_DEB; + +typedef struct keyboard_lock{ + + uint16_t lock;// + uint16_t time;// + uint16_t begin;// + +}KEYBOARD_LOCK; + +typedef struct keyboard_state{ + + uint8_t layer; + uint8_t prev_layer; + uint8_t fn_on; + uint8_t sf_on;//shift on + + uint8_t backlight;//0 1 2 3 + uint8_t lock;//0 1 + + + KEYBOARD_LOCK ctrl; + KEYBOARD_LOCK shift; + KEYBOARD_LOCK alt; + KEYBOARD_LOCK fn; + +}KEYBOARD_STATE; + +class DEVTERM { + public: + HIDKeyboard *Keyboard; + HIDMouse *Mouse; + HIDJoystick *Joystick; + HIDConsumer *Consumer; + KEYBOARD_STATE Keyboard_state; + USBCompositeSerial *_Serial; + //if not to use USBCompositeSerial,then use default Serial + //**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 0 // 1 for PULLUP, 0 FOR PULLDOWN +#define KEYBOARD_LED_PWM_PERIOD 200 + +#endif diff --git a/Code/uconsole_keyboard/glider.h b/Code/uconsole_keyboard/glider.h new file mode 100644 index 0000000..f4f9785 --- /dev/null +++ b/Code/uconsole_keyboard/glider.h @@ -0,0 +1,29 @@ +#ifndef GLIDER_H +#define GLIDER_H + +#include + + +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 diff --git a/Code/uconsole_keyboard/glider.ino b/Code/uconsole_keyboard/glider.ino new file mode 100644 index 0000000..8ecb221 --- /dev/null +++ b/Code/uconsole_keyboard/glider.ino @@ -0,0 +1,60 @@ +#include + +#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(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 }; +} diff --git a/Code/uconsole_keyboard/helper.h b/Code/uconsole_keyboard/helper.h new file mode 100644 index 0000000..6079d10 --- /dev/null +++ b/Code/uconsole_keyboard/helper.h @@ -0,0 +1,19 @@ +/* + * + + + + */ +#ifndef HELPER_H +#define HELPER_H + +#include +#include +#include + + +uint8_t read_io(uint8_t io); + + + +#endif diff --git a/Code/uconsole_keyboard/helper.ino b/Code/uconsole_keyboard/helper.ino new file mode 100644 index 0000000..24645e2 --- /dev/null +++ b/Code/uconsole_keyboard/helper.ino @@ -0,0 +1,10 @@ +#include "helper.h" + + +uint8_t read_io(uint8_t io) { + if(digitalRead(io) == LOW ){ + return 0; + }else { + return 1; + } +} diff --git a/Code/uconsole_keyboard/keyboard.h b/Code/uconsole_keyboard/keyboard.h new file mode 100644 index 0000000..ae3bee2 --- /dev/null +++ b/Code/uconsole_keyboard/keyboard.h @@ -0,0 +1,83 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +/* + * clockworkpi devterm keyboard test2 + * able to correct scan the 8x8 keypads re-action + */ + +#include "devterm.h" + +#include "keys_io_map.h" + +#include +#include +#include + +#define MATRIX_ROWS 8 +#define MATRIX_COLS 8 + +#define MATRIX_KEYS 64 // 8*8 + +#ifndef DEBOUNCE +# define DEBOUNCE 20 +#endif + +enum SKEYS { + _SELECT_KEY =0xe8, //Joystick.button(n) + _START_KEY, //Joystick.button(n) + _JOYSTICK_UP, //B1 //Joystick.Y() + _JOYSTICK_DOWN, //Joystick.Y() + _JOYSTICK_LEFT, //Joystick.X() + _JOYSTICK_RIGHT, //Joystick.X() + _JOYSTICK_A, //Joystick.button(1) + _JOYSTICK_B, //Joystick.button(2) + _JOYSTICK_X, //Joystick.button(3) + _JOYSTICK_Y, //Joystick.button(4) + _JOYSTICK_L, + _JOYSTICK_R, + _FN_KEY, + _MOUSE_LEFT, // Mouse.press(1) + _MOUSE_MID, // Mouse.press(2) + _MOUSE_RIGHT, // Mouse.press(3) + + _FN_BRIGHTNESS_UP, //USB Consumer brightness up https://github.com/torvalds/linux/blob/7fe10096c1508c7f033d34d0741809f8eecc1ed4/drivers/hid/hid-input.c#L903 + _FN_BRIGHTNESS_DOWN, //USB Consumer brightness down + + _VOLUME_M, + _VOLUME_P, + _VOLUME_MUTE, //https://github.com/torvalds/linux/blob/7fe10096c1508c7f033d34d0741809f8eecc1ed4/drivers/hid/hid-input.c#L956 + _TRACKBALL_BTN, + _FN_LOCK_KEYBOARD, + _FN_LIGHT_KEYBOARD, +}; + +void init_rows(); +void init_cols(); +uint8_t read_io(uint8_t io); + +void matrix_init(); +uint8_t matrix_scan(void); + +bool matrix_is_on(uint8_t row, uint8_t col); +uint8_t matrix_get_row(uint8_t row) ; + + +//void matrix_print(void); + + + +void keyboard_task(DEVTERM*); +void keyboard_init(DEVTERM*); + + +#define KEY_PRESSED 1 +#define KEY_RELEASED 0 + +#define KEY_PRNT_SCRN 0xCE //Print screen - 0x88 == usb hut1_12v2.pdf keyboard code +#define KEY_PAUSE 0xd0 // - 0x88 == usb hut1_12v2.pdf keyboard code + +#define KEY_VOLUME_UP 0x108 // - 0x88 == usb hut1_12v2.pdf keyboard code +#define KEY_VOLUME_DOWN 0x109 // - 0x88 == usb hut1_12v2.pdf keyboard code + +#endif diff --git a/Code/uconsole_keyboard/keyboard.ino b/Code/uconsole_keyboard/keyboard.ino new file mode 100644 index 0000000..e2a040a --- /dev/null +++ b/Code/uconsole_keyboard/keyboard.ino @@ -0,0 +1,204 @@ +#include "keyboard.h" +#include "helper.h" + +KEY_DEB keyboard_debouncing; + +uint8_t matrix_rows[ MATRIX_ROWS ]= {ROW1,ROW2,ROW3,ROW4,ROW5,ROW6,ROW7,ROW8}; +uint8_t matrix_cols[ MATRIX_COLS ] = {COL1,COL2,COL3,COL4,COL5,COL6,COL7,COL8}; + +/* matrix state(1:on, 0:off) */ +static uint8_t matrix[MATRIX_ROWS]; +static uint8_t matrix_debouncing[MATRIX_COLS]; +static uint8_t matrix_prev[MATRIX_ROWS]; + +uint8_t read_kbd_io(uint8_t io) { + +#if defined KEYBOARD_PULL && KEYBOARD_PULL == 0 + if(digitalRead(io) == LOW ){ + return 0; + }else { + return 1; + } +#elif defined KEYBOARD_PULL && KEYBOARD_PULL == 1 + if(digitalRead(io) == LOW ){ + return 1; + }else { + return 0; + } +#endif + +} + +void init_rows(){ + int i; + for(i=0;i<8;i++) { + +#if defined KEYBOARD_PULL && KEYBOARD_PULL == 0 + pinMode(matrix_rows[i],OUTPUT); + digitalWrite(matrix_rows[i],LOW); + pinMode(matrix_rows[i],INPUT_PULLDOWN); + +#elif defined KEYBOARD_PULL && KEYBOARD_PULL == 1 + pinMode(matrix_rows[i],INPUT_PULLUP); +#endif + + } +} + +void init_cols() { + + int i; + for(i=0;i<8;i++){ + pinMode(matrix_cols[i],OUTPUT); + digitalWrite(matrix_cols[i],LOW); + } +} + + + +void matrix_init() { + init_cols(); + init_rows(); + + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; + matrix_prev[i] = 0; + } + + + delay(500); +} + +uint8_t matrix_scan(void) { + + uint8_t data; + for(int col = 0; col < MATRIX_COLS;col++){ + data = 0; + +#if defined KEYBOARD_PULL && KEYBOARD_PULL == 1 + + digitalWrite(matrix_cols[col],LOW); +#elif defined KEYBOARD_PULL && KEYBOARD_PULL == 0 + digitalWrite(matrix_cols[col],HIGH); + +#endif + delayMicroseconds(700); + + data =( + ( read_kbd_io(matrix_rows[0]) << 0 ) | + ( read_kbd_io(matrix_rows[1]) << 1 ) | + ( read_kbd_io(matrix_rows[2]) << 2 ) | + ( read_kbd_io(matrix_rows[3]) << 3 ) | + ( read_kbd_io(matrix_rows[4]) << 4 ) | + ( read_kbd_io(matrix_rows[5]) << 5 ) | + ( read_kbd_io(matrix_rows[6]) << 6 ) | + ( read_kbd_io(matrix_rows[7]) << 7 ) + ); + +#if defined KEYBOARD_PULL && KEYBOARD_PULL == 1 + digitalWrite(matrix_cols[col],HIGH); +#elif defined KEYBOARD_PULL && KEYBOARD_PULL == 0 + digitalWrite(matrix_cols[col],LOW); +#endif + + if (matrix_debouncing[col] != data) { + matrix_debouncing[col] = data; + keyboard_debouncing.deing = true; + keyboard_debouncing.de_time = millis(); + } + } + + if (keyboard_debouncing.deing == true && ( (millis() - keyboard_debouncing.de_time) > DEBOUNCE )) { + for (int row = 0; row < MATRIX_ROWS; row++) { + + matrix[row] = 0; + for (int col = 0; col < MATRIX_COLS; col++) { + matrix[row] |= ((matrix_debouncing[col] & (1 << row) ? 1 : 0) << col); + } + } + keyboard_debouncing.deing = false; + + }else{ + delay(1); + } + + return 1; +} + + +bool matrix_is_on(uint8_t row, uint8_t col) { + return (matrix[row] & (1<_Serial->print(buff); + keyboard_action(dv,row,col,KEY_PRESSED); + } + +} + +void matrix_release(DEVTERM*dv,uint8_t row,uint8_t col) { + char buff[128]; + + + if(matrix_is_on(row,col) == false ){ + sprintf(buff,"%d %d M%d released\n",row,col,(row+1)*10+col+1); + //dv->_Serial->print(buff); + keyboard_action(dv,row,col,KEY_RELEASED); + + } + +} + +void keyboard_task(DEVTERM*dv) +{ + char buff[128]; + uint8_t matrix_row = 0; + uint8_t matrix_change = 0; + uint8_t pressed = 0; + + matrix_scan(); + + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { + matrix_row = matrix_get_row(r); + matrix_change = matrix_row ^ matrix_prev[r]; + if (matrix_change) { + //sprintf(buff,"matrix_row: %d %d\n",matrix_row,matrix_prev[r]); + //dv->_Serial->print(buff); + uint8_t col_mask = 1; + for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) { + if (matrix_change & col_mask) { + pressed = (matrix_row & col_mask); + if(pressed != 0) { + matrix_press(dv,r,c); + }else { + matrix_release(dv,r,c); + } + matrix_prev[r] ^= col_mask; + + } + } + } + } + + +} + +void keyboard_init(DEVTERM*){ + matrix_init(); + keyboard_debouncing.deing=false; + keyboard_debouncing.de_time = 0; + +} diff --git a/Code/uconsole_keyboard/keymaps.ino b/Code/uconsole_keyboard/keymaps.ino new file mode 100644 index 0000000..f816690 --- /dev/null +++ b/Code/uconsole_keyboard/keymaps.ino @@ -0,0 +1,542 @@ +#include "devterm.h" +#include "keyboard.h" +#include "keys.h" + +#define EMP 0XFFFF + +/* +B1 joystick up +B2 joystick down +B3 joystick left +B4 joystick right + +B5 joystick A +B6 joystick B +B7 joystick X +B8 joystick Y + +B9 left shift +B10 Fn +B11 left Ctrl +B12 Cmd +B13 left Alt +B14 mouse left +B15 mouse mid +B16 mouse right +*/ +#define _PRINT_KEY KEY_PRNT_SCRN +#define _PAUSE_KEY KEY_PAUSE + +#define _LEFT_SHIFT_KEY KEY_LEFT_SHIFT +#define _LEFT_CTRL_KEY KEY_LEFT_CTRL +#define _CMD_KEY KEY_RIGHT_GUI +#define _LEFT_ALT KEY_LEFT_ALT + +#define _FN_KEY_UP_ARROW KEY_PAGE_UP +#define _FN_KEY_DOWN_ARROW KEY_PAGE_DOWN +#define _FN_KEY_LEFT_ARROW KEY_HOME +#define _FN_KEY_RIGHT_ARROW KEY_END + + +#define DEF_LAYER 0x00 +#define FN_LAYER 0x01 + + +/* + * keyboard_maps + * M11 - M18 + * M21 - M28 + * M31 - M38 + * M41 - M48 + * M51 - M58 + * M61 - M68 + * M71 - M78 + * M81 - M88 + */ +const uint16_t keyboard_maps[][MATRIX_KEYS] = { + + [DEF_LAYER] = { _SELECT_KEY,_START_KEY,_VOLUME_M,'`','[',']','-','=', \ + '1','2','3','4','5','6','7','8',\ + '9','0',KEY_ESC,KEY_TAB,EMP,EMP,EMP,EMP, \ + 'q','w','e','r','t','y','u','i', \ + 'o','p','a','s','d','f','g','h',\ + 'j','k','l','z','x','c','v','b', \ + 'n','m',',','.','/','\\',';','\'', \ + KEY_BACKSPACE,KEY_RETURN,_FN_KEY,_FN_KEY,' ',EMP,EMP,EMP}, + + [FN_LAYER] = { _PRINT_KEY,_PAUSE_KEY,_VOLUME_MUTE,'`','[',']',KEY_F11,KEY_F12, \ + KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,\ + KEY_F9,KEY_F10,_FN_LOCK_KEYBOARD,KEY_CAPS_LOCK,EMP,EMP,EMP,EMP, \ + 'q','w','e','r','t','y',KEY_PAGE_UP,KEY_INSERT, \ + 'o','p','a','s','d','f','g',KEY_HOME,\ + KEY_END,KEY_PAGE_DOWN,'l','z','x','c','v','b', \ + 'n','m',_FN_BRIGHTNESS_DOWN,_FN_BRIGHTNESS_UP,'/','\\',';','\'', \ + KEY_DELETE,KEY_RETURN,_FN_KEY,_FN_KEY,_FN_LIGHT_KEYBOARD,EMP,EMP,EMP} + +}; + + +static uint8_t fn_actions[MATRIX_KEYS]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +const uint16_t keys_maps[][KEYS_NUM] = { + + [DEF_LAYER] = {KEY_UP_ARROW,KEY_DOWN_ARROW, KEY_LEFT_ARROW,KEY_RIGHT_ARROW, \ + _JOYSTICK_A,_JOYSTICK_B, _JOYSTICK_X,_JOYSTICK_Y, \ + _LEFT_SHIFT_KEY,KEY_RIGHT_SHIFT,_LEFT_CTRL_KEY, KEY_RIGHT_CTRL, \ + _LEFT_ALT, _MOUSE_LEFT, KEY_RIGHT_ALT,_MOUSE_RIGHT, \ + _TRACKBALL_BTN }, + + [FN_LAYER] = {_FN_KEY_UP_ARROW,_FN_KEY_DOWN_ARROW, _FN_KEY_LEFT_ARROW, _FN_KEY_RIGHT_ARROW, \ + _JOYSTICK_A,_JOYSTICK_B, _JOYSTICK_X,_JOYSTICK_Y, \ + _LEFT_SHIFT_KEY,KEY_RIGHT_SHIFT,_LEFT_CTRL_KEY, KEY_RIGHT_CTRL, \ + _CMD_KEY, _MOUSE_LEFT, KEY_RIGHT_ALT,_MOUSE_RIGHT, \ + _TRACKBALL_BTN }, + + }; + + + +const uint16_t backlight_vals[3] = {0,500,2000}; + +uint8_t check_pd2(){ // if swtich 2 in back is set to on(HIGH) + + return digitalRead(PD2); +} + +void dt_kbd_set_layer(DEVTERM*dv,uint8_t new_layer) { + + if( dv->Keyboard_state.layer != new_layer) { + + dv->Keyboard_state.prev_layer = dv->Keyboard_state.layer; + dv->Keyboard_state.layer = new_layer; + } +} + +void dt_kbd_restore_layer(DEVTERM*dv) { + + dv->Keyboard_state.layer = dv->Keyboard_state.prev_layer; + +} + +void press_any_key_to_release_lock(DEVTERM*dv, KEYBOARD_LOCK*lock, uint16_t k,uint8_t mode) { + + + if( lock->lock > 0 ) { + if(mode == KEY_RELEASED + && k != _LEFT_CTRL_KEY && k!= KEY_RIGHT_CTRL + && k != _LEFT_ALT && k!= KEY_RIGHT_ALT + && k != _LEFT_SHIFT_KEY && k!= KEY_RIGHT_SHIFT + && k != _FN_KEY) { + lock->lock = 0; + + if(lock->begin!= _FN_KEY) { + dv->Keyboard->release(lock->begin); + } + lock->begin = 0; + lock->time = 0; + //dv->_Serial->println("ctrl lock released"); + } + } +} + +void keyboard_action(DEVTERM*dv,uint8_t row,uint8_t col,uint8_t mode) { + + uint16_t k; + uint8_t addr; + addr = row*MATRIX_COLS+col; + if(dv->Keyboard_state.fn_on > 0){ + k = keyboard_maps[dv->Keyboard_state.fn_on][addr]; + fn_actions[addr] = 1; + }else { + k = keyboard_maps[dv->Keyboard_state.layer][addr]; + } + + if(k == EMP){ + return; + } + + if(k != _FN_KEY && k != _FN_LOCK_KEYBOARD && dv->Keyboard_state.lock == 1) { + return; + } + + switch(k) { + case KEY_CAPS_LOCK: + if(mode == KEY_PRESSED) { + + dv->Keyboard->press(k); + dv->Keyboard->setAdjustForHostCapsLock(true); + }else if(mode == KEY_RELEASED) { + + dv->Keyboard->setAdjustForHostCapsLock(false); + dv->Keyboard->release(k); + } + + break; + + case _SELECT_KEY: + if(check_pd2() == HIGH) { + k = ' '; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + dv->Joystick->button(9,mode); + } + break; + case _START_KEY: + if(check_pd2() == HIGH) { + k = KEY_RETURN; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + dv->Joystick->button(10,mode); + } + break; + + case _FN_BRIGHTNESS_UP: + if(mode == KEY_PRESSED) { + dv->Consumer->press(HIDConsumer::BRIGHTNESS_UP); + }else { + dv->Consumer->release(); + } + break; + case _FN_BRIGHTNESS_DOWN: + if(mode == KEY_PRESSED) { + dv->Consumer->press(HIDConsumer::BRIGHTNESS_DOWN); + }else { + dv->Consumer->release(); + } + break; + + case _VOLUME_P:{ + if(mode == KEY_PRESSED) { + dv->Consumer->press(HIDConsumer::VOLUME_UP); + }else { + dv->Consumer->release(); + } + }break; + case _VOLUME_M:{ + if(mode == KEY_PRESSED) { + if(dv->Keyboard_state.sf_on == 1){ + dv->Consumer->press(HIDConsumer::VOLUME_UP); + }else{ + dv->Consumer->press(HIDConsumer::VOLUME_DOWN); + } + }else { + dv->Consumer->release(); + } + }break; + case _VOLUME_MUTE:{ + if(mode == KEY_PRESSED) { + dv->Consumer->press(HIDConsumer::MUTE); + }else { + dv->Consumer->release(); + } + }break; + case _FN_LOCK_KEYBOARD:{ + if(mode == KEY_PRESSED) { + dv->Keyboard_state.lock = dv->Keyboard_state.lock ^ 1; + } + }break; + case _FN_LIGHT_KEYBOARD: { + //dv->_Serial->println("light keyboard"); + + if(mode == KEY_PRESSED) { + dv->Keyboard_state.backlight ++; + if(dv->Keyboard_state.backlight >= 3) { + dv->Keyboard_state.backlight = 0; + } + timer.resume(); + pwmWrite(PA8,backlight_vals[ dv->Keyboard_state.backlight ] ); + } + }break; + case _FN_KEY: + if(mode == KEY_PRESSED){ + if(dv->Keyboard_state.fn.lock == 0){ + dv->Keyboard_state.fn_on = FN_LAYER; + dv->Keyboard_state.fn.begin = k; + } + }else if(mode == KEY_RELEASED ) { + if(dv->Keyboard_state.fn.lock == 0){ + for(int i=0;i<64;i++) { + if(fn_actions[i] !=0) { + k = keyboard_maps[dv->Keyboard_state.fn_on][i]; + dv->Keyboard->release(k); + fn_actions[i] = 0; + } + } + dv->Keyboard_state.fn_on = 0; + } + + dv->Keyboard_state.fn.begin = 0; + dv->Keyboard_state.fn.time = 0; + } + break; + + default: + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + + if(dv->Keyboard_state.fn_on > 0){ + fn_actions[addr] = 0; + } + } + break; + } + /* + press_any_key_to_release_lock(dv,&dv->Keyboard_state.ctrl,k,mode); + press_any_key_to_release_lock(dv,&dv->Keyboard_state.alt,k,mode); + press_any_key_to_release_lock(dv,&dv->Keyboard_state.shift,k,mode); + press_any_key_to_release_lock(dv,&dv->Keyboard_state.fn,k,mode); + */ +} + + +void keypad_action(DEVTERM*dv,uint8_t col,uint8_t mode) { + + uint16_t k; + + if(dv->Keyboard_state.fn_on > 0){ + k = keys_maps[dv->Keyboard_state.fn_on][col]; + }else { + k = keys_maps[dv->Keyboard_state.layer][col]; + } + + if(k == EMP){ + return; + } + + if(dv->Keyboard_state.lock == 1) { + return; + } + + switch(k) { + case _LEFT_SHIFT_KEY: + case KEY_RIGHT_SHIFT: + if(mode == KEY_PRESSED) { + dv->Keyboard_state.sf_on = 1; + if(dv->Keyboard_state.shift.lock == 0){ + dv->Keyboard->press(k); + dv->Keyboard_state.shift.begin=k; + } + }else if(mode == KEY_RELEASED) { + dv->Keyboard_state.sf_on = 0; + if(dv->Keyboard_state.shift.lock == 0){ + dv->Keyboard->release(k); + dv->Keyboard_state.shift.begin = 0; + dv->Keyboard_state.shift.time = 0; + } + } + break; + + case _JOYSTICK_UP: + if(check_pd2() == HIGH) { + k = KEY_UP_ARROW; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + if(mode == KEY_RELEASED){ + dv->Joystick->Y(511); + }else { + dv->Joystick->Y(0); + } + } + break; + case _JOYSTICK_DOWN: + if(check_pd2() == HIGH) { + k = KEY_DOWN_ARROW; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + if(mode == KEY_RELEASED){ + dv->Joystick->Y(511); + }else { + dv->Joystick->Y(1023); + } + } + break; + case _JOYSTICK_LEFT: + if(check_pd2() == HIGH) { + k = KEY_LEFT_ARROW; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + if(mode == KEY_RELEASED){ + dv->Joystick->X(511); + }else { + dv->Joystick->X(0); + } + } + break; + case _JOYSTICK_RIGHT: + if(check_pd2() == HIGH) { + k = KEY_RIGHT_ARROW; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + if(mode == KEY_RELEASED){ + dv->Joystick->X(511); + }else { + dv->Joystick->X(1023); + } + } + break; + case _JOYSTICK_A: + if(check_pd2() == HIGH) { + k = 'j'; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + dv->Joystick->button(2,mode); + } + break; + case _JOYSTICK_B: + if(check_pd2() == HIGH) { + k = 'k'; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + dv->Joystick->button(3,mode); + } + break; + case _JOYSTICK_X: + if(check_pd2() == HIGH) { + k = 'u'; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + dv->Joystick->button(1,mode); + } + break; + case _JOYSTICK_Y: + if(check_pd2() == HIGH) { + k = 'i'; + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + }else { + dv->Joystick->button(4,mode); + } + break; + case _MOUSE_LEFT: + if(mode == KEY_PRESSED){ + dv->Mouse->press(1); + }else if(mode == KEY_RELEASED){ + dv->Mouse->release(1); + } + break; + case _MOUSE_MID: + if(mode == KEY_PRESSED) { + dv->state->pressMiddleClick(); + }else { + if(dv->state->getScrolled() == false){ + //if no scrolling happend ,do as a normal mid mouse key click + dv->Mouse->click(MOUSE_MIDDLE); + } + dv->state->releaseMiddleClick(); + + } + break; + + case _MOUSE_RIGHT: + if(mode == KEY_PRESSED){ + dv->Mouse->press(2); + }else if(mode == KEY_RELEASED){ + dv->Mouse->release(2); + } + break; + + //_LEFT_CTRL_KEY,_CMD_KEY , _LEFT_ALT + case _LEFT_CTRL_KEY: + case KEY_RIGHT_CTRL: + if(mode == KEY_PRESSED){ + if(dv->Keyboard_state.ctrl.lock == 0){ + dv->Keyboard->press(k); + dv->Keyboard_state.ctrl.begin = k; + } + }else { + if(dv->Keyboard_state.ctrl.lock == 0){ + dv->Keyboard->release(k); + dv->Keyboard_state.ctrl.begin = 0; + dv->Keyboard_state.ctrl.time = 0; + } + } + break; + + case _LEFT_ALT: + case KEY_RIGHT_ALT: + if(mode == KEY_PRESSED){ + if(dv->Keyboard_state.alt.lock == 0){ + dv->Keyboard->press(k); + dv->Keyboard_state.alt.begin=k; + } + }else { + if(dv->Keyboard_state.alt.lock == 0){ + dv->Keyboard->release(k); + dv->Keyboard_state.alt.begin = 0; + dv->Keyboard_state.alt.time = 0; + } + } + break; + + case _CMD_KEY: + if(mode == KEY_PRESSED){ + dv->Keyboard->press(k); + }else { + dv->Keyboard->release(k); + } + break; + + case _TRACKBALL_BTN: + if(mode == KEY_PRESSED){ + dv->Mouse->press(MOUSE_MIDDLE); + }else if(mode == KEY_RELEASED){ + dv->Mouse->release(MOUSE_MIDDLE); + } + break; + default: + if(mode == KEY_PRESSED) { + dv->Keyboard->press(k); + }else if(mode == KEY_RELEASED) { + dv->Keyboard->release(k); + } + break; + + } + /* + press_any_key_to_release_lock(dv,&dv->Keyboard_state.ctrl,k,mode); + press_any_key_to_release_lock(dv,&dv->Keyboard_state.alt,k,mode); + press_any_key_to_release_lock(dv,&dv->Keyboard_state.shift,k,mode); + press_any_key_to_release_lock(dv,&dv->Keyboard_state.fn,k,mode); + */ +} diff --git a/Code/uconsole_keyboard/keys.h b/Code/uconsole_keyboard/keys.h new file mode 100644 index 0000000..93b537b --- /dev/null +++ b/Code/uconsole_keyboard/keys.h @@ -0,0 +1,27 @@ +#ifndef KEYS_H +#define KEYS_H +/* + * keys include the joystick and mouse left/mid/right keys + */ + +#include "devterm.h" +#include "keys_io_map.h" + +#include +#include +#include + + +#ifndef KEY_DEBOUNCE +# define KEY_DEBOUNCE 5 +#endif + +#define KEYS_NUM 17 + + +void keys_task(DEVTERM*); +void keys_init(DEVTERM*); + + + +#endif diff --git a/Code/uconsole_keyboard/keys.ino b/Code/uconsole_keyboard/keys.ino new file mode 100644 index 0000000..a1a80f9 --- /dev/null +++ b/Code/uconsole_keyboard/keys.ino @@ -0,0 +1,106 @@ +#include "keys.h" + +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,KEY0}; + +/* keys state(1:on, 0:off) */ +static uint32_t keys; +static uint32_t keys_debouncing; +static uint32_t keys_prev; + +void init_keys(){ + int i; + for(i=0;i KEY_DEBOUNCE )) { + keys = keys_debouncing; + keypad_debouncing.deing = false; + }else { + delay(1); + } + + return 1; +} + + +void print_keys(DEVTERM*dv) { + char buff[128]; + + for (int i = 0; i < KEYS_NUM; i++) { + if( keys & (1<< i) ){ + sprintf(buff,"B%d pressed\n",i+1); + dv->_Serial->print(buff); + } + } + + +} + +void keys_task(DEVTERM*dv){ + + scan_keys(); + + uint32_t _mask =1; + uint32_t _change = 0; + uint32_t _pressed = 0; + + _change = keys ^ keys_prev; + + if(_change) { + + for(uint8_t c=0;c < KEYS_NUM;c++,_mask <<=1) { + if (_change & _mask) { + _pressed = keys & _mask; + if(_pressed) { + keypad_action(dv,c,KEY_PRESSED); + }else { + keypad_action(dv,c,KEY_RELEASED); + } + + keys_prev ^= _mask; + } + + } + } + +} +void keys_init(DEVTERM*dv){ + + init_keys(); + //center the position + dv->Joystick->X(511); + dv->Joystick->Y(511); + + keypad_debouncing.deing = false; + keypad_debouncing.de_time = 0; + +} diff --git a/Code/uconsole_keyboard/keys_io_map.h b/Code/uconsole_keyboard/keys_io_map.h new file mode 100644 index 0000000..a579326 --- /dev/null +++ b/Code/uconsole_keyboard/keys_io_map.h @@ -0,0 +1,49 @@ +#ifndef KEYS_IO_MAP_H +#define KEYS_IO_MAP_H + +#define ROW1 PA0 +#define ROW2 PA1 +#define ROW3 PA2 +#define ROW4 PA3 +#define ROW5 PA4 +#define ROW6 PA5 +#define ROW7 PA6 +#define ROW8 PA7 + +#define COL1 PC0 +#define COL2 PC1 +#define COL3 PC2 +#define COL4 PC3 +#define COL5 PC4 +#define COL6 PC5 +#define COL7 PC6 +#define COL8 PC7 + +#define KEY1 PB0 // +#define KEY2 PB1 +#define KEY3 PB2 +#define KEY4 PB3 +#define KEY5 PB4 +#define KEY6 PB5 +#define KEY7 PB6 +#define KEY8 PB7 +#define KEY9 PB8 +#define KEY10 PB9 +#define KEY11 PB10 +#define KEY12 PB11 +#define KEY13 PB12 +#define KEY14 PB13 +#define KEY15 PB14 +#define KEY16 PB15 // + +//ball +#define HO1 PC8 +#define HO2 PC9 +#define HO3 PC10 +#define HO4 PC11 +#define KEY0 PC12 + + + + +#endif diff --git a/Code/uconsole_keyboard/math.h b/Code/uconsole_keyboard/math.h new file mode 100644 index 0000000..8e6ccdf --- /dev/null +++ b/Code/uconsole_keyboard/math.h @@ -0,0 +1,56 @@ +#ifndef MATH_H +#define MATH_H + +#include +#include +#include + +uint32_t getDelta(uint32_t prev, uint32_t now); +uint32_t getDelta(uint32_t prev, uint32_t now, uint32_t max); + +template +T sign(T value) { + if (value > 0) { + return 1; + } + if (value < 0) { + return -1; + } + return 0; +} + +template +T clamp(U value) { + if (value >= std::numeric_limits().max()) { + return std::numeric_limits().max(); + } + + if (value <= std::numeric_limits().min()) { + return std::numeric_limits().min(); + } + + return value; +} + +template +T min(T x, T y) { + if (x < y) { + return x; + } + return y; +} + +template +T max(T x, T y) { + if (x > y) { + return x; + } + return y; +} + +template +T hypot(T x, T y) { + return std::sqrt(x * x + y * y); +} + +#endif diff --git a/Code/uconsole_keyboard/math.ino b/Code/uconsole_keyboard/math.ino new file mode 100644 index 0000000..fe6f058 --- /dev/null +++ b/Code/uconsole_keyboard/math.ino @@ -0,0 +1,23 @@ +#include + +#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().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; +} diff --git a/Code/uconsole_keyboard/ratemeter.h b/Code/uconsole_keyboard/ratemeter.h new file mode 100644 index 0000000..451b189 --- /dev/null +++ b/Code/uconsole_keyboard/ratemeter.h @@ -0,0 +1,38 @@ +#ifndef RATEMETER_H +#define RATEMETER_H + +#include + +#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 cutoff; +}; + +#endif diff --git a/Code/uconsole_keyboard/ratemeter.ino b/Code/uconsole_keyboard/ratemeter.ino new file mode 100644 index 0000000..bcc3528 --- /dev/null +++ b/Code/uconsole_keyboard/ratemeter.ino @@ -0,0 +1,47 @@ +#include +#include + +#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); + if (!cutoff.get()) { + averageDelta += delta; + } +} + +void RateMeter::expire() { + cutoff.expire(); +} + +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; + } +} diff --git a/Code/uconsole_keyboard/state.h b/Code/uconsole_keyboard/state.h new file mode 100644 index 0000000..8d65173 --- /dev/null +++ b/Code/uconsole_keyboard/state.h @@ -0,0 +1,37 @@ +#ifndef STATE_H +#define STATE_H + +#include +#include +#include + +#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(); + bool getScrolled(); + void setScrolled(); + TrackballMode moveTrackball(); + private: + bool middleClick; + bool scrolled; + Timeout middleClickTimeout; +}; + +#endif diff --git a/Code/uconsole_keyboard/state.ino b/Code/uconsole_keyboard/state.ino new file mode 100644 index 0000000..b0fc330 --- /dev/null +++ b/Code/uconsole_keyboard/state.ino @@ -0,0 +1,47 @@ +#include +#include +#include + +#include "state.h" + +State::State() + : fn(false), + middleClick(false), + scrolled(false) +{ +} + +void State::tick(millis_t delta) +{ + middleClickTimeout.updateTime(delta); +} +void State::setScrolled() { + if(middleClick==true){ + scrolled = true; + } +} + +bool State::getScrolled() { + return scrolled; +} + +void State::pressMiddleClick() { + middleClick = true; + middleClickTimeout.reset(); +} + +bool State::releaseMiddleClick() { + middleClick = false; + scrolled = false; + const auto timeout = middleClickTimeout.get(); + return !timeout; +} + +TrackballMode State::moveTrackball() { + middleClickTimeout.expire(); + if (middleClick) { + return TrackballMode::Wheel; + } else { + return TrackballMode::Mouse; + } +} diff --git a/Code/uconsole_keyboard/tickwaiter.h b/Code/uconsole_keyboard/tickwaiter.h new file mode 100644 index 0000000..9698024 --- /dev/null +++ b/Code/uconsole_keyboard/tickwaiter.h @@ -0,0 +1,30 @@ +#ifndef TICKWAITER_H +#define TICKWAITER_H + +#include +#include "math.h" + +template +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 diff --git a/Code/uconsole_keyboard/trackball.h b/Code/uconsole_keyboard/trackball.h new file mode 100644 index 0000000..277f85b --- /dev/null +++ b/Code/uconsole_keyboard/trackball.h @@ -0,0 +1,25 @@ +#ifndef TRACKBALL_H +#define TRACKBALL_H + +#include "devterm.h" + +#include "keys_io_map.h" + +/* +#define BOUNCE_INTERVAL 30 +#define BASE_MOVE_PIXELS 5 +#define EXPONENTIAL_BOUND 15 +#define EXPONENTIAL_BASE 1.2 +*/ + +#define RIGHT_PIN HO2 +#define LEFT_PIN HO4 +#define DOWN_PIN HO3 +#define UP_PIN HO1 + + +void trackball_init(DEVTERM*); +void trackball_task(DEVTERM*); + + +#endif diff --git a/Code/uconsole_keyboard/trackball.ino b/Code/uconsole_keyboard/trackball.ino new file mode 100644 index 0000000..2b0f797 --- /dev/null +++ b/Code/uconsole_keyboard/trackball.ino @@ -0,0 +1,130 @@ +/* + * clockworkpi devterm trackball + */ +#include "keys_io_map.h" + +#include +#include +#include + +#include + + +#include "trackball.h" + +#include "ratemeter.h" +#include "glider.h" +#include "math.h" + + + +enum Axis: uint8_t { + AXIS_X, + AXIS_Y, + AXIS_NUM, +}; +static TrackballMode lastMode; +static int8_t distances[AXIS_NUM]; +static RateMeter rateMeter[AXIS_NUM]; +static Glider glider[AXIS_NUM]; + +static const int8_t WHEEL_DENOM = 2; +static int8_t wheelBuffer; + +static float rateToVelocityCurve(float input) { + //return std::pow(std::abs(input) / 50, 1.4); + return std::abs(input) / 30; +} + +template +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, std::sqrt(rateMeter[AXIS_X].delta())); + glider[AXIS_Y].updateSpeed(vy); + + } else { + glider[AXIS_X].updateSpeed(vx); + glider[AXIS_Y].update(vy, std::sqrt(rateMeter[AXIS_Y].delta())); + + } + + +} + +void trackball_task(DEVTERM*dv) { + int8_t x = 0, y = 0, w = 0; + noInterrupts(); + const auto mode = dv->state->moveTrackball(); + if (lastMode != mode) { + rateMeter[AXIS_X].expire(); + rateMeter[AXIS_Y].expire(); + wheelBuffer = 0; + } + else { + rateMeter[AXIS_X].tick(dv->delta); + rateMeter[AXIS_Y].tick(dv->delta); + } + lastMode = mode; + + 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; + if(w != 0){ + dv->state->setScrolled(); + } + break; + } + } + distances[AXIS_X] = 0; + distances[AXIS_Y] = 0; + interrupts(); + + if(x !=0 || y != 0 || -w!=0) { + dv->Mouse->move(x, y, -w); + } + +} + + +void trackball_init(DEVTERM*dv){ + + pinMode(LEFT_PIN, INPUT); + pinMode(UP_PIN, INPUT); + pinMode(RIGHT_PIN, INPUT); + pinMode(DOWN_PIN, INPUT); + + attachInterrupt(LEFT_PIN, &interrupt , ExtIntTriggerMode::CHANGE); + attachInterrupt(RIGHT_PIN, &interrupt, ExtIntTriggerMode::CHANGE); + attachInterrupt(UP_PIN, &interrupt, ExtIntTriggerMode::CHANGE); + attachInterrupt(DOWN_PIN, &interrupt, ExtIntTriggerMode::CHANGE); + +} diff --git a/Code/uconsole_keyboard/uconsole_keyboard.ino b/Code/uconsole_keyboard/uconsole_keyboard.ino new file mode 100644 index 0000000..374bf4f --- /dev/null +++ b/Code/uconsole_keyboard/uconsole_keyboard.ino @@ -0,0 +1,139 @@ +#include "keyboard.h" +#include "keys.h" +#include "trackball.h" +#include "devterm.h" +#include "tickwaiter.h" + +#include + +#define SER_NUM_STR "20230307" + +USBHID HID; +DEVTERM dev_term; + +const uint8_t reportDescription[] = { + HID_CONSUMER_REPORT_DESCRIPTOR(), + HID_KEYBOARD_REPORT_DESCRIPTOR(), + HID_JOYSTICK_REPORT_DESCRIPTOR(), + HID_MOUSE_REPORT_DESCRIPTOR() +}; + +static const uint32_t LOOP_INTERVAL_MS = 0; +static TickWaiter waiter; + +HardwareTimer timer(1); +//HardwareTimer ctrl_timer(4); + +void setup() { + USBComposite.setManufacturerString("ClockworkPI"); + USBComposite.setProductString("uConsole"); + USBComposite.setSerialString(SER_NUM_STR); + + dev_term.Keyboard = new HIDKeyboard(HID); + dev_term.Joystick = new HIDJoystick(HID); + dev_term.Mouse = new HIDMouse(HID); + 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; + dev_term.Keyboard_state.fn_on = 0; + dev_term.Keyboard_state.sf_on = 0; + + //dev_term.Keyboard_state.shift = 0; + dev_term.Keyboard_state.backlight = 0; + dev_term.Keyboard_state.lock = 0; + + dev_term.Keyboard_state.ctrl.lock = 0; + dev_term.Keyboard_state.ctrl.time = 0; + dev_term.Keyboard_state.ctrl.begin = 0; + + dev_term.Keyboard_state.shift.lock = 0; + dev_term.Keyboard_state.shift.time = 0; + dev_term.Keyboard_state.shift.begin = 0; + + dev_term.Keyboard_state.alt.lock = 0; + dev_term.Keyboard_state.alt.time = 0; + dev_term.Keyboard_state.alt.begin = 0; + + dev_term.Keyboard_state.fn.lock = 0; + dev_term.Keyboard_state.fn.time = 0; + dev_term.Keyboard_state.fn.begin = 0; + + dev_term._Serial = new USBCompositeSerial; + + HID.begin(*dev_term._Serial,reportDescription, sizeof(reportDescription)); + + while(!USBComposite);//wait until usb port been plugged in to PC + + + keyboard_init(&dev_term); + keys_init(&dev_term); + trackball_init(&dev_term); + + //dev_term._Serial->println("setup done"); + + pinMode(PD2,INPUT);// switch 2 in back + + timer.setPeriod(KEYBOARD_LED_PWM_PERIOD); + timer.resume(); + + /* + ctrl_timer.setPeriod(20*1000); + ctrl_timer.attachInterrupt(1,ctrl_timer_handler); + ctrl_timer.refresh(); + ctrl_timer.resume(); + */ + pinMode(PA8,PWM); + pwmWrite(PA8,0); + + + delay(1000); +} + +#define LOCK_TIME 50 + +//DO NOT USE dev_term._Serial->println(""); in timer interrupt function,will block +void check_keyboard_lock(KEYBOARD_LOCK*lock){ + if( lock->begin >0) { + lock->time++; + + if( lock->time>=LOCK_TIME && lock->time<200){ + lock->lock = 1; + } + + if( lock->time > 200){ + if(lock->begin != _FN_KEY) { + dev_term.Keyboard->release(lock->begin); + } + lock->time = 0; + lock->lock = 0; + lock->begin = 0; + } + } +} + +#define LOCK_TIME 50 +void ctrl_timer_handler(void) { + + check_keyboard_lock(&dev_term.Keyboard_state.ctrl); + check_keyboard_lock(&dev_term.Keyboard_state.shift); + check_keyboard_lock(&dev_term.Keyboard_state.alt); + check_keyboard_lock(&dev_term.Keyboard_state.fn); + +} + +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); + + +}