add keyboard source code

This commit is contained in:
cuu 2023-06-14 13:46:28 +12:00
parent 5b69e9c831
commit 17269a8c72
24 changed files with 1850 additions and 0 deletions

View File

@ -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

View 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

View 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;
}

View File

@ -0,0 +1,60 @@
#ifndef DEVTERM_H
#define DEVTERM_H
#define KEY_LATENCY 1400
#include "state.h"
#include <USBComposite.h>
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

View 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

View 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 };
}

View File

@ -0,0 +1,19 @@
/*
*
*/
#ifndef HELPER_H
#define HELPER_H
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
uint8_t read_io(uint8_t io);
#endif

View File

@ -0,0 +1,10 @@
#include "helper.h"
uint8_t read_io(uint8_t io) {
if(digitalRead(io) == LOW ){
return 0;
}else {
return 1;
}
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#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

View File

@ -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<<col));
}
uint8_t matrix_get_row(uint8_t row) {
return matrix[row];
}
void matrix_press(DEVTERM*dv,uint8_t row,uint8_t col) {
char buff[128];
if(matrix_is_on(row,col) == true ){
sprintf(buff,"%d %d M%d pressed\n",row,col,(row+1)*10+col+1);
//dv->_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;
}

View File

@ -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);
*/
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#ifndef KEY_DEBOUNCE
# define KEY_DEBOUNCE 5
#endif
#define KEYS_NUM 17
void keys_task(DEVTERM*);
void keys_init(DEVTERM*);
#endif

View File

@ -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<KEYS_NUM;i++) {
pinMode( keys_io[i],INPUT_PULLUP);
}
}
uint8_t scan_keys(){
uint32_t data;
uint8_t s;
data = 0;
delayMicroseconds(30);
for(int i = 0;i < KEYS_NUM;i++) {
s = read_io(keys_io[i]);
s ^= 1;
data |= s << i;
}
if ( keys_debouncing != data ) {
keys_debouncing = data;
keypad_debouncing.deing = true;
keypad_debouncing.de_time = millis();
}
if (keypad_debouncing.deing == true && ( (millis() - keypad_debouncing.de_time) > 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;
}

View File

@ -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

View 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

View 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;
}

View 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

View File

@ -0,0 +1,47 @@
#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);
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;
}
}

View File

@ -0,0 +1,37 @@
#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();
bool getScrolled();
void setScrolled();
TrackballMode moveTrackball();
private:
bool middleClick;
bool scrolled;
Timeout<uint16_t, MIDDLE_CLICK_TIMEOUT_MS> middleClickTimeout;
};
#endif

View File

@ -0,0 +1,47 @@
#include <cassert>
#include <algorithm>
#include <limits>
#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;
}
}

View 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

View File

@ -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

View File

@ -0,0 +1,130 @@
/*
* clockworkpi devterm trackball
*/
#include "keys_io_map.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <USBComposite.h>
#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<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, 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<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);
}

View File

@ -0,0 +1,139 @@
#include "keyboard.h"
#include "keys.h"
#include "trackball.h"
#include "devterm.h"
#include "tickwaiter.h"
#include <USBComposite.h>
#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<LOOP_INTERVAL_MS> 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);
}