mirror of
https://github.com/grymoire/i2c_puppet-Linux.git
synced 2024-12-27 05:48:21 +01:00
Improvements commited 2 months later (I really should leave notes for myself)
This commit is contained in:
parent
c9791af550
commit
04604f3a1c
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
static void key_cb(char key, enum key_state state)
|
static void key_cb(char key, enum key_state state)
|
||||||
{
|
{
|
||||||
printf("key: 0x%02X/%d/%c, state: %d, bkl: %d\r\n", key, key, key, state, reg_get_value(REG_ID_BKL));
|
printf("key: 0x%02X/%d/%c, state: %d\r\n", key, key, key, state);
|
||||||
}
|
}
|
||||||
static struct key_callback key_callback =
|
static struct key_callback key_callback =
|
||||||
{
|
{
|
||||||
@ -37,7 +37,7 @@ static struct key_lock_callback key_lock_callback =
|
|||||||
|
|
||||||
static void touch_cb(int8_t x, int8_t y)
|
static void touch_cb(int8_t x, int8_t y)
|
||||||
{
|
{
|
||||||
printf("%s: x: %d, y: %d !\r\n", __func__, x, y);
|
// printf("%s: x: %d, y: %d !\r\n", __func__, x, y);
|
||||||
}
|
}
|
||||||
static struct touch_callback touch_callback =
|
static struct touch_callback touch_callback =
|
||||||
{
|
{
|
||||||
@ -105,7 +105,7 @@ void debug_init(void)
|
|||||||
{
|
{
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
stdio_set_driver_enabled(&stdio_usb, true);
|
// stdio_set_driver_enabled(&stdio_usb, true);
|
||||||
|
|
||||||
printf("I2C Puppet SW v%d.%d\r\n", VERSION_MAJOR, VERSION_MINOR);
|
printf("I2C Puppet SW v%d.%d\r\n", VERSION_MAJOR, VERSION_MINOR);
|
||||||
|
|
||||||
|
203
app/keyboard.c
203
app/keyboard.c
@ -7,22 +7,11 @@
|
|||||||
|
|
||||||
#define LIST_SIZE 10 // size of the list keeping track of all the pressed keys
|
#define LIST_SIZE 10 // size of the list keeping track of all the pressed keys
|
||||||
|
|
||||||
enum mod
|
|
||||||
{
|
|
||||||
MOD_NONE = 0,
|
|
||||||
MOD_SYM,
|
|
||||||
MOD_ALT,
|
|
||||||
MOD_SHL,
|
|
||||||
MOD_SHR,
|
|
||||||
|
|
||||||
MOD_LAST,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct entry
|
struct entry
|
||||||
{
|
{
|
||||||
char chr;
|
char chr;
|
||||||
char symb;
|
char alt;
|
||||||
enum mod mod;
|
enum key_mod mod;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct list_item
|
struct list_item
|
||||||
@ -30,7 +19,8 @@ struct list_item
|
|||||||
const struct entry *p_entry;
|
const struct entry *p_entry;
|
||||||
uint32_t hold_start_time;
|
uint32_t hold_start_time;
|
||||||
enum key_state state;
|
enum key_state state;
|
||||||
bool mods[MOD_LAST];
|
bool mods[KEY_MOD_ID_LAST];
|
||||||
|
char effective_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t row_pins[NUM_OF_ROWS] =
|
static const uint8_t row_pins[NUM_OF_ROWS] =
|
||||||
@ -48,13 +38,13 @@ static const uint8_t col_pins[NUM_OF_COLS] =
|
|||||||
|
|
||||||
static const struct entry kbd_entries[][NUM_OF_COLS] =
|
static const struct entry kbd_entries[][NUM_OF_COLS] =
|
||||||
{
|
{
|
||||||
{ { KEY_JOY_CENTER }, { 'W', '1' }, { 'G', '/' }, { 'S', '4' }, { 'L', '"' }, { 'H' , ':' } },
|
{ { KEY_JOY_CENTER }, { 'W', '1' }, { 'G', '/' }, { 'S', '4' }, { 'L', '"' }, { 'H' , ':' } },
|
||||||
{ { }, { 'Q', '#' }, { 'R', '3' }, { 'E', '2' }, { 'O', '+' }, { 'U', '_' } },
|
{ { }, { 'Q', '#' }, { 'R', '3' }, { 'E', '2' }, { 'O', '+' }, { 'U', '_' } },
|
||||||
{ { KEY_BTN_LEFT1 }, { '~', '0' }, { 'F', '6' }, { .mod = MOD_SHL }, { 'K', '\'' }, { 'J', ';' } },
|
{ { KEY_BTN_LEFT1 }, { '~', '0' }, { 'F', '6' }, { .mod = KEY_MOD_ID_SHL }, { 'K', '\'' }, { 'J', ';' } },
|
||||||
{ { }, { ' ', '\t' }, { 'C', '9' }, { 'Z', '7' }, { 'M', '.' }, { 'N', ',' } },
|
{ { }, { ' ', '\t' }, { 'C', '9' }, { 'Z', '7' }, { 'M', '.' }, { 'N', ',' } },
|
||||||
{ { KEY_BTN_LEFT2 }, { .mod = MOD_SYM }, { 'T', '(' }, { 'D', '5' }, { 'I', '-' }, { 'Y', ')' } },
|
{ { KEY_BTN_LEFT2 }, { .mod = KEY_MOD_ID_SYM }, { 'T', '(' }, { 'D', '5' }, { 'I', '-' }, { 'Y', ')' } },
|
||||||
{ { KEY_BTN_RIGHT1 }, { .mod = MOD_ALT }, { 'V', '?' }, { 'X', '8' }, { '$', '`' }, { 'B', '!' } },
|
{ { KEY_BTN_RIGHT1 }, { .mod = KEY_MOD_ID_ALT }, { 'V', '?' }, { 'X', '8' }, { '$', '`' }, { 'B', '!' } },
|
||||||
{ { }, { 'A', '*' }, { .mod = MOD_SHR }, { 'P', '@' }, { '\b' }, { '\n', '|' } },
|
{ { }, { 'A', '*' }, { .mod = KEY_MOD_ID_SHR }, { 'P', '@' }, { '\b' }, { '\n', '|' } },
|
||||||
};
|
};
|
||||||
|
|
||||||
#if NUM_OF_BTNS > 0
|
#if NUM_OF_BTNS > 0
|
||||||
@ -78,9 +68,7 @@ static struct
|
|||||||
|
|
||||||
struct list_item list[LIST_SIZE];
|
struct list_item list[LIST_SIZE];
|
||||||
|
|
||||||
uint32_t last_process_time;
|
bool mods[KEY_MOD_ID_LAST];
|
||||||
|
|
||||||
bool mods[MOD_LAST];
|
|
||||||
|
|
||||||
bool capslock_changed;
|
bool capslock_changed;
|
||||||
bool capslock;
|
bool capslock;
|
||||||
@ -95,66 +83,56 @@ static void transition_to(struct list_item * const p_item, const enum key_state
|
|||||||
|
|
||||||
p_item->state = next_state;
|
p_item->state = next_state;
|
||||||
|
|
||||||
if (!self.key_callbacks || !p_entry)
|
if (!p_entry)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char chr = p_entry->chr;
|
if (p_item->effective_key == '\0') {
|
||||||
|
char key = p_entry->chr;
|
||||||
|
switch (p_entry->mod) {
|
||||||
|
case KEY_MOD_ID_ALT:
|
||||||
|
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||||
|
key = KEY_MOD_ALT;
|
||||||
|
break;
|
||||||
|
|
||||||
switch (p_entry->mod) {
|
case KEY_MOD_ID_SHL:
|
||||||
case MOD_ALT:
|
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
key = KEY_MOD_SHL;
|
||||||
chr = KEY_MOD_ALT;
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case MOD_SHL:
|
case KEY_MOD_ID_SHR:
|
||||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||||
chr = KEY_MOD_SHL;
|
key = KEY_MOD_SHR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOD_SHR:
|
case KEY_MOD_ID_SYM:
|
||||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||||
chr = KEY_MOD_SHR;
|
key = KEY_MOD_SYM;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOD_SYM:
|
default:
|
||||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
{
|
||||||
chr = KEY_MOD_SYM;
|
if (reg_is_bit_set(REG_ID_CFG, CFG_USE_MODS)) {
|
||||||
break;
|
const bool shift = (self.mods[KEY_MOD_ID_SHL] || self.mods[KEY_MOD_ID_SHR]) | self.capslock;
|
||||||
|
const bool alt = self.mods[KEY_MOD_ID_ALT] | self.numlock;
|
||||||
|
|
||||||
default:
|
if (alt) {
|
||||||
{
|
key = p_entry->alt;
|
||||||
if (reg_is_bit_set(REG_ID_CFG, CFG_USE_MODS)) {
|
} else if (!shift && (key >= 'A' && key <= 'Z')) {
|
||||||
const bool shift = (self.mods[MOD_SHL] || self.mods[MOD_SHR]) | self.capslock;
|
key = (key + ' ');
|
||||||
const bool alt = self.mods[MOD_ALT] | self.numlock;
|
}
|
||||||
|
|
||||||
if (alt) {
|
|
||||||
chr = p_entry->symb;
|
|
||||||
} else if (!shift && (chr >= 'A' && chr <= 'Z')) {
|
|
||||||
chr = (chr + ' ');
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p_item->effective_key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chr != 0) {
|
if (p_item->effective_key == '\0')
|
||||||
const struct fifo_item item = { chr, next_state };
|
return;
|
||||||
if (!fifo_enqueue(item)) {
|
|
||||||
if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_INT)) {
|
|
||||||
reg_set_bit(REG_ID_INT, INT_OVERFLOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_ON))
|
keyboard_inject_event(p_item->effective_key, next_state);
|
||||||
fifo_enqueue_force(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct key_callback *cb = self.key_callbacks;
|
|
||||||
while (cb) {
|
|
||||||
cb->func(chr, next_state);
|
|
||||||
cb = cb->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void next_item_state(struct list_item * const p_item, const bool pressed)
|
static void next_item_state(struct list_item * const p_item, const bool pressed)
|
||||||
@ -162,30 +140,30 @@ static void next_item_state(struct list_item * const p_item, const bool pressed)
|
|||||||
switch (p_item->state) {
|
switch (p_item->state) {
|
||||||
case KEY_STATE_IDLE:
|
case KEY_STATE_IDLE:
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
if (p_item->p_entry->mod != MOD_NONE)
|
if (p_item->p_entry->mod != KEY_MOD_ID_NONE)
|
||||||
self.mods[p_item->p_entry->mod] = true;
|
self.mods[p_item->p_entry->mod] = true;
|
||||||
|
|
||||||
if (!self.capslock_changed && self.mods[MOD_SHR] && self.mods[MOD_ALT]) {
|
if (!self.capslock_changed && self.mods[KEY_MOD_ID_SHR] && self.mods[KEY_MOD_ID_ALT]) {
|
||||||
self.capslock = true;
|
self.capslock = true;
|
||||||
self.capslock_changed = true;
|
self.capslock_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.numlock_changed && self.mods[MOD_SHL] && self.mods[MOD_ALT]) {
|
if (!self.numlock_changed && self.mods[KEY_MOD_ID_SHL] && self.mods[KEY_MOD_ID_ALT]) {
|
||||||
self.numlock = true;
|
self.numlock = true;
|
||||||
self.numlock_changed = true;
|
self.numlock_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.capslock_changed && (self.mods[MOD_SHL] || self.mods[MOD_SHR])) {
|
if (!self.capslock_changed && (self.mods[KEY_MOD_ID_SHL] || self.mods[KEY_MOD_ID_SHR])) {
|
||||||
self.capslock = false;
|
self.capslock = false;
|
||||||
self.capslock_changed = true;
|
self.capslock_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.numlock_changed && (self.mods[MOD_SHL] || self.mods[MOD_SHR])) {
|
if (!self.numlock_changed && (self.mods[KEY_MOD_ID_SHL] || self.mods[KEY_MOD_ID_SHR])) {
|
||||||
self.numlock = false;
|
self.numlock = false;
|
||||||
self.numlock_changed = true;
|
self.numlock_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.mods[MOD_ALT]) {
|
if (!self.mods[KEY_MOD_ID_ALT]) {
|
||||||
self.capslock_changed = false;
|
self.capslock_changed = false;
|
||||||
self.numlock_changed = false;
|
self.numlock_changed = false;
|
||||||
}
|
}
|
||||||
@ -217,22 +195,24 @@ static void next_item_state(struct list_item * const p_item, const bool pressed)
|
|||||||
if (!pressed)
|
if (!pressed)
|
||||||
transition_to(p_item, KEY_STATE_RELEASED);
|
transition_to(p_item, KEY_STATE_RELEASED);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_STATE_RELEASED:
|
case KEY_STATE_RELEASED:
|
||||||
{
|
{
|
||||||
if (p_item->p_entry->mod != MOD_NONE)
|
if (p_item->p_entry->mod != KEY_MOD_ID_NONE)
|
||||||
self.mods[p_item->p_entry->mod] = false;
|
self.mods[p_item->p_entry->mod] = false;
|
||||||
|
|
||||||
p_item->p_entry = NULL;
|
p_item->p_entry = NULL;
|
||||||
|
p_item->effective_key = '\0';
|
||||||
transition_to(p_item, KEY_STATE_IDLE);
|
transition_to(p_item, KEY_STATE_IDLE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyboard_task(void)
|
static int64_t timer_task(alarm_id_t id, void *user_data)
|
||||||
{
|
{
|
||||||
if ((to_ms_since_boot(get_absolute_time()) - self.last_process_time) <= reg_get_value(REG_ID_FRQ))
|
(void)id;
|
||||||
return;
|
(void)user_data;
|
||||||
|
|
||||||
for (uint32_t c = 0; c < NUM_OF_COLS; ++c) {
|
for (uint32_t c = 0; c < NUM_OF_COLS; ++c) {
|
||||||
gpio_pull_up(col_pins[c]);
|
gpio_pull_up(col_pins[c]);
|
||||||
@ -265,6 +245,7 @@ void keyboard_task(void)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
self.list[i].p_entry = &((const struct entry*)kbd_entries)[key_idx];
|
self.list[i].p_entry = &((const struct entry*)kbd_entries)[key_idx];
|
||||||
|
self.list[i].effective_key = '\0';
|
||||||
self.list[i].state = KEY_STATE_IDLE;
|
self.list[i].state = KEY_STATE_IDLE;
|
||||||
next_item_state(&self.list[i], pressed);
|
next_item_state(&self.list[i], pressed);
|
||||||
|
|
||||||
@ -303,6 +284,7 @@ void keyboard_task(void)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
self.list[i].p_entry = &((const struct entry*)btn_entries)[b];
|
self.list[i].p_entry = &((const struct entry*)btn_entries)[b];
|
||||||
|
self.list[i].effective_key = '\0';
|
||||||
self.list[i].state = KEY_STATE_IDLE;
|
self.list[i].state = KEY_STATE_IDLE;
|
||||||
next_item_state(&self.list[i], pressed);
|
next_item_state(&self.list[i], pressed);
|
||||||
|
|
||||||
@ -311,7 +293,52 @@ void keyboard_task(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
self.last_process_time = to_ms_since_boot(get_absolute_time());
|
// negative value means interval since last alarm time
|
||||||
|
return -(reg_get_value(REG_ID_FRQ) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard_inject_event(char key, enum key_state state)
|
||||||
|
{
|
||||||
|
const struct fifo_item item = { key, state };
|
||||||
|
if (!fifo_enqueue(item)) {
|
||||||
|
if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_INT))
|
||||||
|
reg_set_bit(REG_ID_INT, INT_OVERFLOW);
|
||||||
|
|
||||||
|
if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_ON))
|
||||||
|
fifo_enqueue_force(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct key_callback *cb = self.key_callbacks;
|
||||||
|
while (cb) {
|
||||||
|
cb->func(key, state);
|
||||||
|
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keyboard_is_key_down(char key)
|
||||||
|
{
|
||||||
|
for (int32_t i = 0; i < LIST_SIZE; ++i) {
|
||||||
|
struct list_item *item = &self.list[i];
|
||||||
|
|
||||||
|
if (item->p_entry == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((item->state != KEY_STATE_PRESSED) && (item->state != KEY_STATE_HOLD))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item->effective_key != key)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keyboard_is_mod_on(enum key_mod mod)
|
||||||
|
{
|
||||||
|
return self.mods[mod];
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyboard_add_key_callback(struct key_callback *callback)
|
void keyboard_add_key_callback(struct key_callback *callback)
|
||||||
@ -358,28 +385,30 @@ bool keyboard_get_numlock(void)
|
|||||||
|
|
||||||
void keyboard_init(void)
|
void keyboard_init(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MOD_LAST; ++i)
|
for (int i = 0; i < KEY_MOD_ID_LAST; ++i)
|
||||||
self.mods[i] = false;
|
self.mods[i] = false;
|
||||||
|
|
||||||
// Rows
|
// rows
|
||||||
for (uint32_t i = 0; i < NUM_OF_ROWS; ++i) {
|
for (uint32_t i = 0; i < NUM_OF_ROWS; ++i) {
|
||||||
gpio_init(row_pins[i]);
|
gpio_init(row_pins[i]);
|
||||||
gpio_pull_up(row_pins[i]);
|
gpio_pull_up(row_pins[i]);
|
||||||
gpio_set_dir(row_pins[i], GPIO_IN);
|
gpio_set_dir(row_pins[i], GPIO_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cols
|
// cols
|
||||||
for(uint32_t i = 0; i < NUM_OF_COLS; ++i) {
|
for(uint32_t i = 0; i < NUM_OF_COLS; ++i) {
|
||||||
gpio_init(col_pins[i]);
|
gpio_init(col_pins[i]);
|
||||||
gpio_set_dir(col_pins[i], GPIO_IN);
|
gpio_set_dir(col_pins[i], GPIO_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Btns
|
// btns
|
||||||
#if NUM_OF_BTNS > 0
|
#if NUM_OF_BTNS > 0
|
||||||
for(uint32_t i = 0; i < NUM_OF_BTNS; ++i) {
|
for(uint32_t i = 0; i < NUM_OF_BTNS; ++i) {
|
||||||
gpio_init(btn_pins[i]);
|
gpio_init(btn_pins[i]);
|
||||||
gpio_set_dir(btn_pins[i], GPIO_IN);
|
|
||||||
gpio_pull_up(btn_pins[i]);
|
gpio_pull_up(btn_pins[i]);
|
||||||
|
gpio_set_dir(btn_pins[i], GPIO_IN);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
add_alarm_in_ms(reg_get_value(REG_ID_FRQ), timer_task, NULL, true);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,17 @@ enum key_state
|
|||||||
KEY_STATE_RELEASED,
|
KEY_STATE_RELEASED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum key_mod
|
||||||
|
{
|
||||||
|
KEY_MOD_ID_NONE = 0,
|
||||||
|
KEY_MOD_ID_SYM,
|
||||||
|
KEY_MOD_ID_ALT,
|
||||||
|
KEY_MOD_ID_SHL,
|
||||||
|
KEY_MOD_ID_SHR,
|
||||||
|
|
||||||
|
KEY_MOD_ID_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
#define KEY_JOY_UP 0x01
|
#define KEY_JOY_UP 0x01
|
||||||
#define KEY_JOY_DOWN 0x02
|
#define KEY_JOY_DOWN 0x02
|
||||||
#define KEY_JOY_LEFT 0x03
|
#define KEY_JOY_LEFT 0x03
|
||||||
@ -26,8 +37,8 @@ enum key_state
|
|||||||
#define KEY_BTN_RIGHT2 0x12
|
#define KEY_BTN_RIGHT2 0x12
|
||||||
|
|
||||||
#define KEY_MOD_ALT 0x1A
|
#define KEY_MOD_ALT 0x1A
|
||||||
#define KEY_MOD_SHL 0x1B
|
#define KEY_MOD_SHL 0x1B // Left Shift
|
||||||
#define KEY_MOD_SHR 0x1C
|
#define KEY_MOD_SHR 0x1C // Right Shift
|
||||||
#define KEY_MOD_SYM 0x1D
|
#define KEY_MOD_SYM 0x1D
|
||||||
|
|
||||||
struct key_callback
|
struct key_callback
|
||||||
@ -42,7 +53,10 @@ struct key_lock_callback
|
|||||||
struct key_lock_callback *next;
|
struct key_lock_callback *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
void keyboard_task(void);
|
void keyboard_inject_event(char key, enum key_state state);
|
||||||
|
|
||||||
|
bool keyboard_is_key_down(char key);
|
||||||
|
bool keyboard_is_mod_on(enum key_mod mod);
|
||||||
|
|
||||||
void keyboard_add_key_callback(struct key_callback *callback);
|
void keyboard_add_key_callback(struct key_callback *callback);
|
||||||
void keyboard_add_lock_callback(struct key_lock_callback *callback);
|
void keyboard_add_lock_callback(struct key_lock_callback *callback);
|
||||||
|
@ -24,7 +24,6 @@ static void gpio_irq(uint gpio, uint32_t events)
|
|||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// The here order is important because it determines callback call order
|
// The here order is important because it determines callback call order
|
||||||
|
|
||||||
usb_init();
|
usb_init();
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@ -53,9 +52,7 @@ int main(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
keyboard_task();
|
__wfe();
|
||||||
|
|
||||||
// tud_task();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
130
app/puppet_i2c.c
130
app/puppet_i2c.c
@ -1,19 +1,11 @@
|
|||||||
#include "puppet_i2c.h"
|
#include "puppet_i2c.h"
|
||||||
|
|
||||||
#include "app_config.h"
|
|
||||||
#include "backlight.h"
|
|
||||||
#include "fifo.h"
|
|
||||||
#include "gpioexp.h"
|
|
||||||
#include "keyboard.h"
|
|
||||||
#include "reg.h"
|
#include "reg.h"
|
||||||
|
|
||||||
#include <hardware/i2c.h>
|
#include <hardware/i2c.h>
|
||||||
#include <hardware/irq.h>
|
#include <hardware/irq.h>
|
||||||
#include <pico/stdlib.h>
|
#include <pico/stdlib.h>
|
||||||
#include <RP2040.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define WRITE_MASK (1 << 7)
|
|
||||||
#define REG_ID_INVALID 0x00
|
#define REG_ID_INVALID 0x00
|
||||||
|
|
||||||
static i2c_inst_t *i2c_instances[2] = { i2c0, i2c1 };
|
static i2c_inst_t *i2c_instances[2] = { i2c0, i2c1 };
|
||||||
@ -32,124 +24,6 @@ static struct
|
|||||||
uint8_t write_len;
|
uint8_t write_len;
|
||||||
} self;
|
} self;
|
||||||
|
|
||||||
static void process_read(void)
|
|
||||||
{
|
|
||||||
const bool is_write = (self.read_buffer.reg & WRITE_MASK);
|
|
||||||
const uint8_t reg = (self.read_buffer.reg & ~WRITE_MASK);
|
|
||||||
|
|
||||||
// printf("read complete, is_write: %d, reg: 0x%02X\r\n", is_write, reg);
|
|
||||||
|
|
||||||
switch (reg) {
|
|
||||||
|
|
||||||
// common R/W registers
|
|
||||||
case REG_ID_CFG:
|
|
||||||
case REG_ID_INT:
|
|
||||||
case REG_ID_DEB:
|
|
||||||
case REG_ID_FRQ:
|
|
||||||
case REG_ID_BKL:
|
|
||||||
case REG_ID_BK2:
|
|
||||||
case REG_ID_GIC:
|
|
||||||
case REG_ID_GIN:
|
|
||||||
case REG_ID_HLD:
|
|
||||||
case REG_ID_ADR:
|
|
||||||
case REG_ID_IND:
|
|
||||||
case REG_ID_CF2:
|
|
||||||
{
|
|
||||||
if (is_write) {
|
|
||||||
reg_set_value(reg, self.read_buffer.data);
|
|
||||||
|
|
||||||
switch (reg) {
|
|
||||||
case REG_ID_BKL:
|
|
||||||
case REG_ID_BK2:
|
|
||||||
backlight_sync();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REG_ID_ADR:
|
|
||||||
puppet_i2c_sync_address();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.write_buffer[0] = reg_get_value(reg);
|
|
||||||
self.write_len = sizeof(uint8_t);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// special R/W registers
|
|
||||||
case REG_ID_DIR: // gpio direction
|
|
||||||
case REG_ID_PUE: // gpio input pull enable
|
|
||||||
case REG_ID_PUD: // gpio input pull direction
|
|
||||||
{
|
|
||||||
if (is_write) {
|
|
||||||
switch (reg) {
|
|
||||||
case REG_ID_DIR:
|
|
||||||
gpioexp_update_dir(self.read_buffer.data);
|
|
||||||
break;
|
|
||||||
case REG_ID_PUE:
|
|
||||||
gpioexp_update_pue_pud(self.read_buffer.data, reg_get_value(REG_ID_PUD));
|
|
||||||
break;
|
|
||||||
case REG_ID_PUD:
|
|
||||||
gpioexp_update_pue_pud(reg_get_value(REG_ID_PUE), self.read_buffer.data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.write_buffer[0] = reg_get_value(reg);
|
|
||||||
self.write_len = sizeof(uint8_t);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case REG_ID_GIO: // gpio value
|
|
||||||
{
|
|
||||||
if (is_write) {
|
|
||||||
gpioexp_set_value(self.read_buffer.data);
|
|
||||||
} else {
|
|
||||||
self.write_buffer[0] = gpioexp_get_value();
|
|
||||||
self.write_len = sizeof(uint8_t);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read-only registers
|
|
||||||
case REG_ID_TOX:
|
|
||||||
case REG_ID_TOY:
|
|
||||||
self.write_buffer[0] = reg_get_value(reg);
|
|
||||||
self.write_len = sizeof(uint8_t);
|
|
||||||
|
|
||||||
reg_set_value(reg, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REG_ID_VER:
|
|
||||||
self.write_buffer[0] = VER_VAL;
|
|
||||||
self.write_len = sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REG_ID_KEY:
|
|
||||||
self.write_buffer[0] = fifo_count();
|
|
||||||
self.write_buffer[0] |= keyboard_get_numlock() ? KEY_NUMLOCK : 0x00;
|
|
||||||
self.write_buffer[0] |= keyboard_get_capslock() ? KEY_CAPSLOCK : 0x00;
|
|
||||||
self.write_len = sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REG_ID_FIF:
|
|
||||||
{
|
|
||||||
const struct fifo_item item = fifo_dequeue();
|
|
||||||
|
|
||||||
self.write_buffer[0] = (uint8_t)item.state;
|
|
||||||
self.write_buffer[1] = (uint8_t)item.key;
|
|
||||||
self.write_len = sizeof(uint8_t) * 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case REG_ID_RST:
|
|
||||||
NVIC_SystemReset();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void irq_handler(void)
|
static void irq_handler(void)
|
||||||
{
|
{
|
||||||
// the controller sent data
|
// the controller sent data
|
||||||
@ -157,7 +31,7 @@ static void irq_handler(void)
|
|||||||
if (self.read_buffer.reg == REG_ID_INVALID) {
|
if (self.read_buffer.reg == REG_ID_INVALID) {
|
||||||
self.read_buffer.reg = self.i2c->hw->data_cmd & 0xff;
|
self.read_buffer.reg = self.i2c->hw->data_cmd & 0xff;
|
||||||
|
|
||||||
if (self.read_buffer.reg & WRITE_MASK) {
|
if (self.read_buffer.reg & PACKET_WRITE_MASK) {
|
||||||
// it'sq a reg write, we need to wait for the second byte before we process
|
// it'sq a reg write, we need to wait for the second byte before we process
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -165,7 +39,7 @@ static void irq_handler(void)
|
|||||||
self.read_buffer.data = self.i2c->hw->data_cmd & 0xff;
|
self.read_buffer.data = self.i2c->hw->data_cmd & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_read();
|
reg_process_packet(self.read_buffer.reg, self.read_buffer.data, self.write_buffer, &self.write_len);
|
||||||
|
|
||||||
// ready for the next operation
|
// ready for the next operation
|
||||||
self.read_buffer.reg = REG_ID_INVALID;
|
self.read_buffer.reg = REG_ID_INVALID;
|
||||||
|
168
app/reg.c
168
app/reg.c
@ -1,9 +1,20 @@
|
|||||||
#include "reg.h"
|
#include "reg.h"
|
||||||
|
|
||||||
|
#include "app_config.h"
|
||||||
|
#include "backlight.h"
|
||||||
|
#include "fifo.h"
|
||||||
|
#include "gpioexp.h"
|
||||||
|
#include "puppet_i2c.h"
|
||||||
|
#include "keyboard.h"
|
||||||
#include "touchpad.h"
|
#include "touchpad.h"
|
||||||
|
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
#include <RP2040.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// We don't enable this by default cause it spams quite a lot
|
||||||
|
//#define DEBUG_REGS
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
uint8_t regs[REG_ID_LAST];
|
uint8_t regs[REG_ID_LAST];
|
||||||
@ -11,14 +22,139 @@ static struct
|
|||||||
|
|
||||||
static void touch_cb(int8_t x, int8_t y)
|
static void touch_cb(int8_t x, int8_t y)
|
||||||
{
|
{
|
||||||
self.regs[REG_ID_TOX] = x;
|
const int16_t dx = (int8_t)self.regs[REG_ID_TOX] + x;
|
||||||
self.regs[REG_ID_TOY] = y;
|
const int16_t dy = (int8_t)self.regs[REG_ID_TOY] + y;
|
||||||
|
|
||||||
|
// bind to -128 to 127
|
||||||
|
self.regs[REG_ID_TOX] = MAX(INT8_MIN, MIN(dx, INT8_MAX));
|
||||||
|
self.regs[REG_ID_TOY] = MAX(INT8_MIN, MIN(dy, INT8_MAX));
|
||||||
}
|
}
|
||||||
static struct touch_callback touch_callback =
|
static struct touch_callback touch_callback =
|
||||||
{
|
{
|
||||||
.func = touch_cb
|
.func = touch_cb
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void reg_process_packet(uint8_t in_reg, uint8_t in_data, uint8_t *out_buffer, uint8_t *out_len)
|
||||||
|
{
|
||||||
|
const bool is_write = (in_reg & PACKET_WRITE_MASK);
|
||||||
|
const uint8_t reg = (in_reg & ~PACKET_WRITE_MASK);
|
||||||
|
|
||||||
|
// printf("read complete, is_write: %d, reg: 0x%02X\r\n", is_write, reg);
|
||||||
|
|
||||||
|
*out_len = 0;
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
|
||||||
|
// common R/W registers
|
||||||
|
case REG_ID_CFG:
|
||||||
|
case REG_ID_INT:
|
||||||
|
case REG_ID_DEB:
|
||||||
|
case REG_ID_FRQ:
|
||||||
|
case REG_ID_BKL:
|
||||||
|
case REG_ID_BK2:
|
||||||
|
case REG_ID_GIC:
|
||||||
|
case REG_ID_GIN:
|
||||||
|
case REG_ID_HLD:
|
||||||
|
case REG_ID_ADR:
|
||||||
|
case REG_ID_IND:
|
||||||
|
case REG_ID_CF2:
|
||||||
|
{
|
||||||
|
if (is_write) {
|
||||||
|
reg_set_value(reg, in_data);
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case REG_ID_BKL:
|
||||||
|
case REG_ID_BK2:
|
||||||
|
backlight_sync();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REG_ID_ADR:
|
||||||
|
puppet_i2c_sync_address();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out_buffer[0] = reg_get_value(reg);
|
||||||
|
*out_len = sizeof(uint8_t);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special R/W registers
|
||||||
|
case REG_ID_DIR: // gpio direction
|
||||||
|
case REG_ID_PUE: // gpio input pull enable
|
||||||
|
case REG_ID_PUD: // gpio input pull direction
|
||||||
|
{
|
||||||
|
if (is_write) {
|
||||||
|
switch (reg) {
|
||||||
|
case REG_ID_DIR:
|
||||||
|
gpioexp_update_dir(in_data);
|
||||||
|
break;
|
||||||
|
case REG_ID_PUE:
|
||||||
|
gpioexp_update_pue_pud(in_data, reg_get_value(REG_ID_PUD));
|
||||||
|
break;
|
||||||
|
case REG_ID_PUD:
|
||||||
|
gpioexp_update_pue_pud(reg_get_value(REG_ID_PUE), in_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out_buffer[0] = reg_get_value(reg);
|
||||||
|
*out_len = sizeof(uint8_t);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REG_ID_GIO: // gpio value
|
||||||
|
{
|
||||||
|
if (is_write) {
|
||||||
|
gpioexp_set_value(in_data);
|
||||||
|
} else {
|
||||||
|
out_buffer[0] = gpioexp_get_value();
|
||||||
|
*out_len = sizeof(uint8_t);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read-only registers
|
||||||
|
case REG_ID_TOX:
|
||||||
|
case REG_ID_TOY:
|
||||||
|
out_buffer[0] = reg_get_value(reg);
|
||||||
|
*out_len = sizeof(uint8_t);
|
||||||
|
|
||||||
|
reg_set_value(reg, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REG_ID_VER:
|
||||||
|
out_buffer[0] = VER_VAL;
|
||||||
|
*out_len = sizeof(uint8_t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REG_ID_KEY:
|
||||||
|
out_buffer[0] = fifo_count();
|
||||||
|
out_buffer[0] |= keyboard_get_numlock() ? KEY_NUMLOCK : 0x00;
|
||||||
|
out_buffer[0] |= keyboard_get_capslock() ? KEY_CAPSLOCK : 0x00;
|
||||||
|
*out_len = sizeof(uint8_t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REG_ID_FIF:
|
||||||
|
{
|
||||||
|
const struct fifo_item item = fifo_dequeue();
|
||||||
|
|
||||||
|
out_buffer[0] = (uint8_t)item.state;
|
||||||
|
out_buffer[1] = (uint8_t)item.key;
|
||||||
|
*out_len = sizeof(uint8_t) * 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REG_ID_RST:
|
||||||
|
NVIC_SystemReset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t reg_get_value(enum reg_id reg)
|
uint8_t reg_get_value(enum reg_id reg)
|
||||||
{
|
{
|
||||||
return self.regs[reg];
|
return self.regs[reg];
|
||||||
@ -26,8 +162,8 @@ uint8_t reg_get_value(enum reg_id reg)
|
|||||||
|
|
||||||
void reg_set_value(enum reg_id reg, uint8_t value)
|
void reg_set_value(enum reg_id reg, uint8_t value)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifdef DEBUG_REGS
|
||||||
printf("%s: reg: 0x%02X, val: 0x%02X\r\n", __func__, reg, value);
|
printf("%s: reg: 0x%02X, val: 0x%02X (%d)\r\n", __func__, reg, value, value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
self.regs[reg] = value;
|
self.regs[reg] = value;
|
||||||
@ -40,7 +176,7 @@ bool reg_is_bit_set(enum reg_id reg, uint8_t bit)
|
|||||||
|
|
||||||
void reg_set_bit(enum reg_id reg, uint8_t bit)
|
void reg_set_bit(enum reg_id reg, uint8_t bit)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifdef DEBUG_REGS
|
||||||
printf("%s: reg: 0x%02X, bit: %d\r\n", __func__, reg, bit);
|
printf("%s: reg: 0x%02X, bit: %d\r\n", __func__, reg, bit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -49,7 +185,7 @@ void reg_set_bit(enum reg_id reg, uint8_t bit)
|
|||||||
|
|
||||||
void reg_clear_bit(enum reg_id reg, uint8_t bit)
|
void reg_clear_bit(enum reg_id reg, uint8_t bit)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifdef DEBUG_REGS
|
||||||
printf("%s: reg: 0x%02X, bit: %d\r\n", __func__, reg, bit);
|
printf("%s: reg: 0x%02X, bit: %d\r\n", __func__, reg, bit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -58,16 +194,16 @@ void reg_clear_bit(enum reg_id reg, uint8_t bit)
|
|||||||
|
|
||||||
void reg_init(void)
|
void reg_init(void)
|
||||||
{
|
{
|
||||||
self.regs[REG_ID_CFG] = CFG_OVERFLOW_INT | CFG_KEY_INT | CFG_USE_MODS;
|
reg_set_value(REG_ID_CFG, CFG_OVERFLOW_INT | CFG_KEY_INT | CFG_USE_MODS);
|
||||||
self.regs[REG_ID_BKL] = 255;
|
reg_set_value(REG_ID_BKL, 255);
|
||||||
self.regs[REG_ID_DEB] = 10;
|
reg_set_value(REG_ID_DEB, 10);
|
||||||
self.regs[REG_ID_FRQ] = 10; // ms
|
reg_set_value(REG_ID_FRQ, 10); // ms
|
||||||
self.regs[REG_ID_BK2] = 255;
|
reg_set_value(REG_ID_BK2, 255);
|
||||||
self.regs[REG_ID_PUD] = 0xFF;
|
reg_set_value(REG_ID_PUD, 0xFF);
|
||||||
self.regs[REG_ID_HLD] = 30; // 10ms units
|
reg_set_value(REG_ID_HLD, 30); // 10ms units
|
||||||
self.regs[REG_ID_ADR] = 0x1F;
|
reg_set_value(REG_ID_ADR, 0x1F);
|
||||||
self.regs[REG_ID_IND] = 1; // ms
|
reg_set_value(REG_ID_IND, 1); // ms
|
||||||
self.regs[REG_ID_CF2] = CF2_TOUCH_INT | CF2_USB_KEYB_ON | CF2_USB_MOUSE_ON;
|
reg_set_value(REG_ID_CF2, CF2_TOUCH_INT | CF2_USB_KEYB_ON | CF2_USB_MOUSE_ON);
|
||||||
|
|
||||||
touchpad_add_touch_callback(&touch_callback);
|
touchpad_add_touch_callback(&touch_callback);
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ enum reg_id
|
|||||||
REG_ID_ADR = 0x12, // i2c puppet address
|
REG_ID_ADR = 0x12, // i2c puppet address
|
||||||
REG_ID_IND = 0x13, // interrupt pin assert duration
|
REG_ID_IND = 0x13, // interrupt pin assert duration
|
||||||
REG_ID_CF2 = 0x14, // config 2
|
REG_ID_CF2 = 0x14, // config 2
|
||||||
REG_ID_TOX = 0x15, // touch delta x
|
REG_ID_TOX = 0x15, // touch delta x since last read, at most (-128 to 127)
|
||||||
REG_ID_TOY = 0x16, // touch delta y
|
REG_ID_TOY = 0x16, // touch delta y since last read, at most (-128 to 127)
|
||||||
|
|
||||||
REG_ID_LAST,
|
REG_ID_LAST,
|
||||||
};
|
};
|
||||||
@ -66,6 +66,10 @@ enum reg_id
|
|||||||
|
|
||||||
#define VER_VAL ((VERSION_MAJOR << 4) | (VERSION_MINOR << 0))
|
#define VER_VAL ((VERSION_MAJOR << 4) | (VERSION_MINOR << 0))
|
||||||
|
|
||||||
|
#define PACKET_WRITE_MASK (1 << 7)
|
||||||
|
|
||||||
|
void reg_process_packet(uint8_t in_reg, uint8_t in_data, uint8_t *out_buffer, uint8_t *out_len);
|
||||||
|
|
||||||
uint8_t reg_get_value(enum reg_id reg);
|
uint8_t reg_get_value(enum reg_id reg);
|
||||||
void reg_set_value(enum reg_id reg, uint8_t value);
|
void reg_set_value(enum reg_id reg, uint8_t value);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "touchpad.h"
|
#include "touchpad.h"
|
||||||
|
|
||||||
|
#include "keyboard.h"
|
||||||
|
|
||||||
#include <hardware/i2c.h>
|
#include <hardware/i2c.h>
|
||||||
#include <pico/binary_info.h>
|
#include <pico/binary_info.h>
|
||||||
#include <pico/stdlib.h>
|
#include <pico/stdlib.h>
|
||||||
@ -27,11 +29,16 @@
|
|||||||
#define BIT_OBSERV_REST2 (2 << 6)
|
#define BIT_OBSERV_REST2 (2 << 6)
|
||||||
#define BIT_OBSERV_REST3 (3 << 6)
|
#define BIT_OBSERV_REST3 (3 << 6)
|
||||||
|
|
||||||
|
#define SWIPE_COOLDOWN_TIME_MS 100 // time to wait before generating a new swipe event
|
||||||
|
#define SWIPE_RELEASE_DELAY_MS 10 // time to wait before sending key release event
|
||||||
|
#define MOTION_IS_SWIPE(i, j) (((i >= 15) || (i <= -15)) && ((j >= -5) && (j <= 5)))
|
||||||
|
|
||||||
static i2c_inst_t *i2c_instances[2] = { i2c0, i2c1 };
|
static i2c_inst_t *i2c_instances[2] = { i2c0, i2c1 };
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
struct touch_callback *callbacks;
|
struct touch_callback *callbacks;
|
||||||
|
uint32_t last_swipe_time;
|
||||||
i2c_inst_t *i2c;
|
i2c_inst_t *i2c;
|
||||||
} self;
|
} self;
|
||||||
|
|
||||||
@ -51,6 +58,17 @@ static uint8_t read_register8(uint8_t reg)
|
|||||||
// i2c_write_blocking(self.i2c, DEV_ADDR, buffer, sizeof(buffer), false);
|
// i2c_write_blocking(self.i2c, DEV_ADDR, buffer, sizeof(buffer), false);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
int64_t release_key(alarm_id_t id, void *user_data)
|
||||||
|
{
|
||||||
|
(void)id;
|
||||||
|
|
||||||
|
const int data = (int)user_data;
|
||||||
|
|
||||||
|
keyboard_inject_event((char)data, KEY_STATE_RELEASED);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void touchpad_gpio_irq(uint gpio, uint32_t events)
|
void touchpad_gpio_irq(uint gpio, uint32_t events)
|
||||||
{
|
{
|
||||||
if (gpio != PIN_TP_MOTION)
|
if (gpio != PIN_TP_MOTION)
|
||||||
@ -67,13 +85,33 @@ void touchpad_gpio_irq(uint gpio, uint32_t events)
|
|||||||
x = ((x < 127) ? x : (x - 256)) * -1;
|
x = ((x < 127) ? x : (x - 256)) * -1;
|
||||||
y = ((y < 127) ? y : (y - 256));
|
y = ((y < 127) ? y : (y - 256));
|
||||||
|
|
||||||
if (self.callbacks) {
|
if (keyboard_is_mod_on(KEY_MOD_ID_ALT)) {
|
||||||
struct touch_callback *cb = self.callbacks;
|
if (to_ms_since_boot(get_absolute_time()) - self.last_swipe_time > SWIPE_COOLDOWN_TIME_MS) {
|
||||||
|
char key = '\0';
|
||||||
|
if (MOTION_IS_SWIPE(y, x)) {
|
||||||
|
key = (y < 0) ? KEY_JOY_UP : KEY_JOY_DOWN;
|
||||||
|
} else if (MOTION_IS_SWIPE(x, y)) {
|
||||||
|
key = (x < 0) ? KEY_JOY_LEFT : KEY_JOY_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
while (cb) {
|
if (key != '\0') {
|
||||||
cb->func(x, y);
|
keyboard_inject_event(key, KEY_STATE_PRESSED);
|
||||||
|
|
||||||
cb = cb->next;
|
// we need to allow the usb a bit of time to send the press, so schedule the release after a bit
|
||||||
|
add_alarm_in_ms(SWIPE_RELEASE_DELAY_MS, release_key, (void*)(int)key, true);
|
||||||
|
|
||||||
|
self.last_swipe_time = to_ms_since_boot(get_absolute_time());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (self.callbacks) {
|
||||||
|
struct touch_callback *cb = self.callbacks;
|
||||||
|
|
||||||
|
while (cb) {
|
||||||
|
cb->func(x, y);
|
||||||
|
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,10 @@ enum
|
|||||||
{
|
{
|
||||||
USB_ITF_KEYBOARD = 0,
|
USB_ITF_KEYBOARD = 0,
|
||||||
USB_ITF_MOUSE,
|
USB_ITF_MOUSE,
|
||||||
|
// USB_ITF_HID_GENERIC,
|
||||||
USB_ITF_CDC,
|
USB_ITF_CDC,
|
||||||
USB_ITF_CDC2,
|
USB_ITF_CDC2,
|
||||||
|
USB_ITF_VENDOR,
|
||||||
USB_ITF_MAX,
|
USB_ITF_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,13 +21,16 @@ enum
|
|||||||
|
|
||||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||||
|
|
||||||
#define CFG_TUD_HID 2
|
#define CFG_TUD_HID 2//3
|
||||||
#define CFG_TUD_CDC 1
|
#define CFG_TUD_CDC 1
|
||||||
#define CFG_TUD_MSC 0
|
#define CFG_TUD_MSC 0
|
||||||
#define CFG_TUD_MIDI 0
|
#define CFG_TUD_MIDI 0
|
||||||
#define CFG_TUD_VENDOR 0
|
#define CFG_TUD_VENDOR 1
|
||||||
|
|
||||||
#define CFG_TUD_HID_EP_BUFSIZE 8
|
#define CFG_TUD_HID_EP_BUFSIZE 8
|
||||||
|
|
||||||
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
||||||
#define CFG_TUD_CDC_TX_BUFSIZE 256
|
#define CFG_TUD_CDC_TX_BUFSIZE 256
|
||||||
|
|
||||||
|
#define CFG_TUD_VENDOR_RX_BUFSIZE 64
|
||||||
|
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
|
||||||
|
74
app/usb.c
74
app/usb.c
@ -1,5 +1,6 @@
|
|||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
|
#include "backlight.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "touchpad.h"
|
#include "touchpad.h"
|
||||||
#include "reg.h"
|
#include "reg.h"
|
||||||
@ -16,6 +17,9 @@ static struct
|
|||||||
mutex_t mutex;
|
mutex_t mutex;
|
||||||
bool mouse_moved;
|
bool mouse_moved;
|
||||||
uint8_t mouse_btn;
|
uint8_t mouse_btn;
|
||||||
|
|
||||||
|
uint8_t write_buffer[2];
|
||||||
|
uint8_t write_len;
|
||||||
} self;
|
} self;
|
||||||
|
|
||||||
// TODO: Should mods always be sent?
|
// TODO: Should mods always be sent?
|
||||||
@ -45,7 +49,12 @@ static int64_t timer_task(alarm_id_t id, void *user_data)
|
|||||||
static void key_cb(char key, enum key_state state)
|
static void key_cb(char key, enum key_state state)
|
||||||
{
|
{
|
||||||
if (tud_hid_n_ready(USB_ITF_KEYBOARD) && reg_is_bit_set(REG_ID_CF2, CF2_USB_KEYB_ON)) {
|
if (tud_hid_n_ready(USB_ITF_KEYBOARD) && reg_is_bit_set(REG_ID_CF2, CF2_USB_KEYB_ON)) {
|
||||||
uint8_t const conv_table[128][2] = { HID_ASCII_TO_KEYCODE };
|
uint8_t conv_table[128][2] = { HID_ASCII_TO_KEYCODE };
|
||||||
|
conv_table['\n'][1] = HID_KEY_ENTER; // Fixup: Enter instead of Return
|
||||||
|
conv_table[KEY_JOY_UP][1] = HID_KEY_ARROW_UP;
|
||||||
|
conv_table[KEY_JOY_DOWN][1] = HID_KEY_ARROW_DOWN;
|
||||||
|
conv_table[KEY_JOY_LEFT][1] = HID_KEY_ARROW_LEFT;
|
||||||
|
conv_table[KEY_JOY_RIGHT][1] = HID_KEY_ARROW_RIGHT;
|
||||||
|
|
||||||
uint8_t keycode[6] = { 0 };
|
uint8_t keycode[6] = { 0 };
|
||||||
uint8_t modifier = 0;
|
uint8_t modifier = 0;
|
||||||
@ -55,13 +64,10 @@ static void key_cb(char key, enum key_state state)
|
|||||||
modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
|
modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
|
||||||
|
|
||||||
keycode[0] = conv_table[(int)key][1];
|
keycode[0] = conv_table[(int)key][1];
|
||||||
|
|
||||||
// Fixup: Enter instead of Return
|
|
||||||
if (key == '\n')
|
|
||||||
keycode[0] = HID_KEY_ENTER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tud_hid_n_keyboard_report(USB_ITF_KEYBOARD, 0, modifier, keycode);
|
if (state != KEY_STATE_HOLD)
|
||||||
|
tud_hid_n_keyboard_report(USB_ITF_KEYBOARD, 0, modifier, keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tud_hid_n_ready(USB_ITF_MOUSE) && reg_is_bit_set(REG_ID_CF2, CF2_USB_MOUSE_ON)) {
|
if (tud_hid_n_ready(USB_ITF_MOUSE) && reg_is_bit_set(REG_ID_CF2, CF2_USB_MOUSE_ON)) {
|
||||||
@ -99,7 +105,7 @@ static struct touch_callback touch_callback =
|
|||||||
.func = touch_cb
|
.func = touch_cb
|
||||||
};
|
};
|
||||||
|
|
||||||
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
|
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
|
||||||
{
|
{
|
||||||
// TODO not Implemented
|
// TODO not Implemented
|
||||||
(void)itf;
|
(void)itf;
|
||||||
@ -108,21 +114,63 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
|
|||||||
(void)buffer;
|
(void)buffer;
|
||||||
(void)reqlen;
|
(void)reqlen;
|
||||||
|
|
||||||
printf("%s: itf: %d, report id: %d, type: %d, len: %d\r\n", __func__, itf, report_id, report_type, reqlen);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// if (itf != USB_ITF_HID_GENERIC)
|
||||||
|
// return 0;
|
||||||
|
|
||||||
|
// printf("%s: itf: %d, report id: %d, type: %d, len: %d\r\n", __func__, itf, report_id, report_type, reqlen);
|
||||||
|
|
||||||
|
// memcpy(buffer, self.write_buffer, self.write_len);
|
||||||
|
|
||||||
|
// return self.write_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t len)
|
||||||
{
|
{
|
||||||
// TODO set LED based on CAPLOCK, NUMLOCK etc...
|
// TODO set LED based on CAPLOCK, NUMLOCK etc...
|
||||||
(void)itf;
|
(void)itf;
|
||||||
(void)report_id;
|
(void)report_id;
|
||||||
(void)report_type;
|
(void)report_type;
|
||||||
(void)buffer;
|
(void)buffer;
|
||||||
(void)bufsize;
|
(void)len;
|
||||||
|
|
||||||
printf("%s: itf: %d, report id: %d, type: %d, size: %d\r\n", __func__, itf, report_id, report_type, bufsize);
|
// if (itf != USB_ITF_HID_GENERIC)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// printf("%s: itf: %d, report id: %d, type: %d, buff: %02X %02X %02X len: %d\r\n", __func__, itf, report_id, report_type, buffer[0], buffer[1], buffer[2], len);
|
||||||
|
|
||||||
|
// if (len < 1)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// const bool is_write = (buffer[0] & PACKET_WRITE_MASK);
|
||||||
|
// const uint8_t reg = (buffer[0] & ~PACKET_WRITE_MASK);
|
||||||
|
|
||||||
|
// printf("%s: read complete, is_write: %d, reg: 0x%02X\r\n", __func__, is_write, reg);
|
||||||
|
|
||||||
|
// if (is_write && (len < 2))
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// printf("%s: data: 0x%02X\r\n", __func__, buffer[1]);
|
||||||
|
|
||||||
|
// reg_process_packet(buffer[0], buffer[1], (uint8_t*)&self.write_buffer, &self.write_len);
|
||||||
|
|
||||||
|
// printf("%s: write_buff: %02X %02X, len: %d\r\n", __func__, self.write_buffer[0], self.write_buffer[1], self.write_len);
|
||||||
|
|
||||||
|
// tud_hid_n_report(itf, report_id, self.write_buffer, self.write_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tud_vendor_rx_cb(uint8_t itf)
|
||||||
|
{
|
||||||
|
printf("%s: itf: %d, avail: %d\r\n", __func__, itf, tud_vendor_n_available(itf));
|
||||||
|
|
||||||
|
uint8_t buff[64] = { 0 };
|
||||||
|
tud_vendor_n_read(itf, buff, 64);
|
||||||
|
// printf("%s: %02X %02X %02X\r\n", __func__, buff[0], buff[1], buff[2]);
|
||||||
|
|
||||||
|
reg_process_packet(buff[0], buff[1], self.write_buffer, &self.write_len);
|
||||||
|
|
||||||
|
tud_vendor_n_write(itf, self.write_buffer, self.write_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_init(void)
|
void usb_init(void)
|
||||||
@ -133,7 +181,7 @@ void usb_init(void)
|
|||||||
|
|
||||||
touchpad_add_touch_callback(&touch_callback);
|
touchpad_add_touch_callback(&touch_callback);
|
||||||
|
|
||||||
// create a new interrupt to call tud_task, and trigger that irq from a timer
|
// create a new interrupt that calls tud_task, and trigger that interrupt from a timer
|
||||||
irq_set_exclusive_handler(USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
|
irq_set_exclusive_handler(USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
|
||||||
irq_set_enabled(USB_LOW_PRIORITY_IRQ, true);
|
irq_set_enabled(USB_LOW_PRIORITY_IRQ, true);
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
#include <tusb.h>
|
#include <tusb.h>
|
||||||
|
|
||||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_HID_DESC_LEN + TUD_CDC_DESC_LEN)
|
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_HID_DESC_LEN /*+ TUD_HID_DESC_LEN*/ + TUD_VENDOR_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||||
|
|
||||||
#define EPNUM_HID_KEYBOARD 0x81
|
#define EPNUM_HID_KEYBOARD 0x81
|
||||||
#define EPNUM_HID_MOUSE 0x82
|
#define EPNUM_HID_MOUSE 0x82
|
||||||
|
#define EPNUM_HID_GENERIC 0x83
|
||||||
|
|
||||||
#define EPNUM_CDC_CMD 0x83
|
#define EPNUM_VENDOR_IN 0x84
|
||||||
#define EPNUM_CDC_IN 0x84
|
#define EPNUM_VENDOR_OUT 0x02
|
||||||
#define EPNUM_CDC_OUT 0x02
|
|
||||||
|
#define EPNUM_CDC_CMD 0x85
|
||||||
|
#define EPNUM_CDC_IN 0x86
|
||||||
|
#define EPNUM_CDC_OUT 0x03
|
||||||
|
|
||||||
#define CDC_CMD_MAX_SIZE 8
|
#define CDC_CMD_MAX_SIZE 8
|
||||||
#define CDC_IN_OUT_MAX_SIZE 64
|
#define CDC_IN_OUT_MAX_SIZE 64
|
||||||
@ -22,7 +26,8 @@ char const *string_descriptors[] =
|
|||||||
"123456", // 3: Serials, should use chip ID
|
"123456", // 3: Serials, should use chip ID
|
||||||
"Keyboard Interface", // 4: Interface 1 String
|
"Keyboard Interface", // 4: Interface 1 String
|
||||||
"Mouse Interface", // 5: Interface 2 String
|
"Mouse Interface", // 5: Interface 2 String
|
||||||
"Board CDC", // 6: Interface 3 String
|
"HID Interface", // 6: Interface 3 String
|
||||||
|
"CDC Interface", // 7: Interface 4 String
|
||||||
};
|
};
|
||||||
|
|
||||||
tusb_desc_device_t const device_descriptor =
|
tusb_desc_device_t const device_descriptor =
|
||||||
@ -56,14 +61,23 @@ uint8_t const hid_mouse_descriptor[] =
|
|||||||
TUD_HID_REPORT_DESC_MOUSE()
|
TUD_HID_REPORT_DESC_MOUSE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//uint8_t const hid_generic_descriptor[] =
|
||||||
|
//{
|
||||||
|
// TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_EP_BUFSIZE)
|
||||||
|
//};
|
||||||
|
|
||||||
uint8_t const config_descriptor[] =
|
uint8_t const config_descriptor[] =
|
||||||
{
|
{
|
||||||
TUD_CONFIG_DESCRIPTOR(1, USB_ITF_MAX, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
TUD_CONFIG_DESCRIPTOR(1, USB_ITF_MAX, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||||
|
|
||||||
TUD_HID_DESCRIPTOR(USB_ITF_KEYBOARD, 4, HID_ITF_PROTOCOL_NONE, sizeof(hid_keyboard_descriptor), EPNUM_HID_KEYBOARD, CFG_TUD_HID_EP_BUFSIZE, 10),
|
TUD_HID_DESCRIPTOR(USB_ITF_KEYBOARD, 4, HID_ITF_PROTOCOL_NONE, sizeof(hid_keyboard_descriptor), EPNUM_HID_KEYBOARD, CFG_TUD_HID_EP_BUFSIZE, 10),
|
||||||
TUD_HID_DESCRIPTOR(USB_ITF_MOUSE, 5, HID_ITF_PROTOCOL_NONE, sizeof(hid_mouse_descriptor), EPNUM_HID_MOUSE, CFG_TUD_HID_EP_BUFSIZE, 10),
|
TUD_HID_DESCRIPTOR(USB_ITF_MOUSE, 5, HID_ITF_PROTOCOL_NONE, sizeof(hid_mouse_descriptor), EPNUM_HID_MOUSE, CFG_TUD_HID_EP_BUFSIZE, 10),
|
||||||
|
|
||||||
TUD_CDC_DESCRIPTOR(USB_ITF_CDC, 6, EPNUM_CDC_CMD, CDC_CMD_MAX_SIZE, EPNUM_CDC_OUT, EPNUM_CDC_IN, CDC_IN_OUT_MAX_SIZE),
|
// TUD_HID_DESCRIPTOR(USB_ITF_HID_GENERIC, 6, HID_ITF_PROTOCOL_NONE, sizeof(hid_generic_descriptor), EPNUM_HID_GENERIC, CFG_TUD_HID_EP_BUFSIZE, 10),
|
||||||
|
|
||||||
|
TUD_VENDOR_DESCRIPTOR(USB_ITF_VENDOR, 7, EPNUM_VENDOR_OUT, EPNUM_VENDOR_IN, CFG_TUD_VENDOR_EPSIZE),
|
||||||
|
|
||||||
|
TUD_CDC_DESCRIPTOR(USB_ITF_CDC, 7, EPNUM_CDC_CMD, CDC_CMD_MAX_SIZE, EPNUM_CDC_OUT, EPNUM_CDC_IN, CDC_IN_OUT_MAX_SIZE),
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t const *tud_descriptor_device_cb(void)
|
uint8_t const *tud_descriptor_device_cb(void)
|
||||||
@ -79,6 +93,9 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf)
|
|||||||
if (itf == USB_ITF_MOUSE)
|
if (itf == USB_ITF_MOUSE)
|
||||||
return hid_mouse_descriptor;
|
return hid_mouse_descriptor;
|
||||||
|
|
||||||
|
// if (itf == USB_ITF_HID_GENERIC)
|
||||||
|
// return hid_generic_descriptor;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user