diff --git a/app/debug.c b/app/debug.c index 3019210..76187c3 100644 --- a/app/debug.c +++ b/app/debug.c @@ -17,7 +17,7 @@ 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 = { @@ -37,7 +37,7 @@ static struct key_lock_callback key_lock_callback = 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 = { @@ -105,7 +105,7 @@ void debug_init(void) { 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); diff --git a/app/keyboard.c b/app/keyboard.c index 6f2c8ee..1509298 100644 --- a/app/keyboard.c +++ b/app/keyboard.c @@ -7,22 +7,11 @@ #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 { char chr; - char symb; - enum mod mod; + char alt; + enum key_mod mod; }; struct list_item @@ -30,7 +19,8 @@ struct list_item const struct entry *p_entry; uint32_t hold_start_time; 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] = @@ -48,13 +38,13 @@ static const uint8_t col_pins[NUM_OF_COLS] = static const struct entry kbd_entries[][NUM_OF_COLS] = { - { { KEY_JOY_CENTER }, { 'W', '1' }, { 'G', '/' }, { 'S', '4' }, { 'L', '"' }, { 'H' , ':' } }, - { { }, { 'Q', '#' }, { 'R', '3' }, { 'E', '2' }, { 'O', '+' }, { 'U', '_' } }, - { { KEY_BTN_LEFT1 }, { '~', '0' }, { 'F', '6' }, { .mod = MOD_SHL }, { 'K', '\'' }, { 'J', ';' } }, - { { }, { ' ', '\t' }, { 'C', '9' }, { 'Z', '7' }, { 'M', '.' }, { 'N', ',' } }, - { { KEY_BTN_LEFT2 }, { .mod = MOD_SYM }, { 'T', '(' }, { 'D', '5' }, { 'I', '-' }, { 'Y', ')' } }, - { { KEY_BTN_RIGHT1 }, { .mod = MOD_ALT }, { 'V', '?' }, { 'X', '8' }, { '$', '`' }, { 'B', '!' } }, - { { }, { 'A', '*' }, { .mod = MOD_SHR }, { 'P', '@' }, { '\b' }, { '\n', '|' } }, + { { KEY_JOY_CENTER }, { 'W', '1' }, { 'G', '/' }, { 'S', '4' }, { 'L', '"' }, { 'H' , ':' } }, + { { }, { 'Q', '#' }, { 'R', '3' }, { 'E', '2' }, { 'O', '+' }, { 'U', '_' } }, + { { KEY_BTN_LEFT1 }, { '~', '0' }, { 'F', '6' }, { .mod = KEY_MOD_ID_SHL }, { 'K', '\'' }, { 'J', ';' } }, + { { }, { ' ', '\t' }, { 'C', '9' }, { 'Z', '7' }, { 'M', '.' }, { 'N', ',' } }, + { { KEY_BTN_LEFT2 }, { .mod = KEY_MOD_ID_SYM }, { 'T', '(' }, { 'D', '5' }, { 'I', '-' }, { 'Y', ')' } }, + { { KEY_BTN_RIGHT1 }, { .mod = KEY_MOD_ID_ALT }, { 'V', '?' }, { 'X', '8' }, { '$', '`' }, { 'B', '!' } }, + { { }, { 'A', '*' }, { .mod = KEY_MOD_ID_SHR }, { 'P', '@' }, { '\b' }, { '\n', '|' } }, }; #if NUM_OF_BTNS > 0 @@ -78,9 +68,7 @@ static struct struct list_item list[LIST_SIZE]; - uint32_t last_process_time; - - bool mods[MOD_LAST]; + bool mods[KEY_MOD_ID_LAST]; bool capslock_changed; 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; - if (!self.key_callbacks || !p_entry) + if (!p_entry) 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 MOD_ALT: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) - chr = KEY_MOD_ALT; - break; + case KEY_MOD_ID_SHL: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + key = KEY_MOD_SHL; + break; - case MOD_SHL: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) - chr = KEY_MOD_SHL; - break; + case KEY_MOD_ID_SHR: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + key = KEY_MOD_SHR; + break; - case MOD_SHR: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) - chr = KEY_MOD_SHR; - break; + case KEY_MOD_ID_SYM: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + key = KEY_MOD_SYM; + break; - case MOD_SYM: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) - chr = KEY_MOD_SYM; - break; + default: + { + if (reg_is_bit_set(REG_ID_CFG, CFG_USE_MODS)) { + 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 (reg_is_bit_set(REG_ID_CFG, CFG_USE_MODS)) { - const bool shift = (self.mods[MOD_SHL] || self.mods[MOD_SHR]) | self.capslock; - const bool alt = self.mods[MOD_ALT] | self.numlock; - - if (alt) { - chr = p_entry->symb; - } else if (!shift && (chr >= 'A' && chr <= 'Z')) { - chr = (chr + ' '); + if (alt) { + key = p_entry->alt; + } else if (!shift && (key >= 'A' && key <= 'Z')) { + key = (key + ' '); + } } - } - break; + break; + } } + + p_item->effective_key = key; } - if (chr != 0) { - const struct fifo_item item = { chr, next_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 (p_item->effective_key == '\0') + return; - 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(chr, next_state); - cb = cb->next; - } - } + keyboard_inject_event(p_item->effective_key, next_state); } 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) { case KEY_STATE_IDLE: 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; - 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_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_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_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_changed = true; } - if (!self.mods[MOD_ALT]) { + if (!self.mods[KEY_MOD_ID_ALT]) { self.capslock_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) transition_to(p_item, KEY_STATE_RELEASED); break; + 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; p_item->p_entry = NULL; + p_item->effective_key = '\0'; transition_to(p_item, KEY_STATE_IDLE); 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)) - return; + (void)id; + (void)user_data; for (uint32_t c = 0; c < NUM_OF_COLS; ++c) { gpio_pull_up(col_pins[c]); @@ -265,6 +245,7 @@ void keyboard_task(void) continue; 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; next_item_state(&self.list[i], pressed); @@ -303,6 +284,7 @@ void keyboard_task(void) continue; self.list[i].p_entry = &((const struct entry*)btn_entries)[b]; + self.list[i].effective_key = '\0'; self.list[i].state = KEY_STATE_IDLE; next_item_state(&self.list[i], pressed); @@ -311,7 +293,52 @@ void keyboard_task(void) } #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) @@ -358,28 +385,30 @@ bool keyboard_get_numlock(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; - // Rows + // rows for (uint32_t i = 0; i < NUM_OF_ROWS; ++i) { gpio_init(row_pins[i]); gpio_pull_up(row_pins[i]); gpio_set_dir(row_pins[i], GPIO_IN); } - // Cols + // cols for(uint32_t i = 0; i < NUM_OF_COLS; ++i) { gpio_init(col_pins[i]); gpio_set_dir(col_pins[i], GPIO_IN); } - // Btns + // btns #if NUM_OF_BTNS > 0 for(uint32_t i = 0; i < NUM_OF_BTNS; ++i) { gpio_init(btn_pins[i]); - gpio_set_dir(btn_pins[i], GPIO_IN); gpio_pull_up(btn_pins[i]); + gpio_set_dir(btn_pins[i], GPIO_IN); } #endif + + add_alarm_in_ms(reg_get_value(REG_ID_FRQ), timer_task, NULL, true); } diff --git a/app/keyboard.h b/app/keyboard.h index 26aa621..fbe9531 100644 --- a/app/keyboard.h +++ b/app/keyboard.h @@ -11,6 +11,17 @@ enum key_state 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_DOWN 0x02 #define KEY_JOY_LEFT 0x03 @@ -26,8 +37,8 @@ enum key_state #define KEY_BTN_RIGHT2 0x12 #define KEY_MOD_ALT 0x1A -#define KEY_MOD_SHL 0x1B -#define KEY_MOD_SHR 0x1C +#define KEY_MOD_SHL 0x1B // Left Shift +#define KEY_MOD_SHR 0x1C // Right Shift #define KEY_MOD_SYM 0x1D struct key_callback @@ -42,7 +53,10 @@ struct key_lock_callback 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_lock_callback(struct key_lock_callback *callback); diff --git a/app/main.c b/app/main.c index 55b115a..19120fa 100644 --- a/app/main.c +++ b/app/main.c @@ -24,7 +24,6 @@ static void gpio_irq(uint gpio, uint32_t events) int main(void) { // The here order is important because it determines callback call order - usb_init(); #ifndef NDEBUG @@ -53,9 +52,7 @@ int main(void) #endif while (true) { - keyboard_task(); - -// tud_task(); + __wfe(); } return 0; diff --git a/app/puppet_i2c.c b/app/puppet_i2c.c index 0b96f58..94fe7fd 100644 --- a/app/puppet_i2c.c +++ b/app/puppet_i2c.c @@ -1,19 +1,11 @@ #include "puppet_i2c.h" -#include "app_config.h" -#include "backlight.h" -#include "fifo.h" -#include "gpioexp.h" -#include "keyboard.h" #include "reg.h" #include #include #include -#include -#include -#define WRITE_MASK (1 << 7) #define REG_ID_INVALID 0x00 static i2c_inst_t *i2c_instances[2] = { i2c0, i2c1 }; @@ -32,124 +24,6 @@ static struct uint8_t write_len; } 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) { // the controller sent data @@ -157,7 +31,7 @@ static void irq_handler(void) if (self.read_buffer.reg == REG_ID_INVALID) { 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 return; } @@ -165,7 +39,7 @@ static void irq_handler(void) 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 self.read_buffer.reg = REG_ID_INVALID; diff --git a/app/reg.c b/app/reg.c index 1f4d1a0..741369d 100644 --- a/app/reg.c +++ b/app/reg.c @@ -1,9 +1,20 @@ #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 +#include #include +// We don't enable this by default cause it spams quite a lot +//#define DEBUG_REGS + static struct { uint8_t regs[REG_ID_LAST]; @@ -11,14 +22,139 @@ static struct static void touch_cb(int8_t x, int8_t y) { - self.regs[REG_ID_TOX] = x; - self.regs[REG_ID_TOY] = y; + const int16_t dx = (int8_t)self.regs[REG_ID_TOX] + x; + 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 = { .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) { 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) { -#ifndef NDEBUG - printf("%s: reg: 0x%02X, val: 0x%02X\r\n", __func__, reg, value); +#ifdef DEBUG_REGS + printf("%s: reg: 0x%02X, val: 0x%02X (%d)\r\n", __func__, reg, value, value); #endif 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) { -#ifndef NDEBUG +#ifdef DEBUG_REGS printf("%s: reg: 0x%02X, bit: %d\r\n", __func__, reg, bit); #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) { -#ifndef NDEBUG +#ifdef DEBUG_REGS printf("%s: reg: 0x%02X, bit: %d\r\n", __func__, reg, bit); #endif @@ -58,16 +194,16 @@ void reg_clear_bit(enum reg_id reg, uint8_t bit) void reg_init(void) { - self.regs[REG_ID_CFG] = CFG_OVERFLOW_INT | CFG_KEY_INT | CFG_USE_MODS; - self.regs[REG_ID_BKL] = 255; - self.regs[REG_ID_DEB] = 10; - self.regs[REG_ID_FRQ] = 10; // ms - self.regs[REG_ID_BK2] = 255; - self.regs[REG_ID_PUD] = 0xFF; - self.regs[REG_ID_HLD] = 30; // 10ms units - self.regs[REG_ID_ADR] = 0x1F; - self.regs[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_CFG, CFG_OVERFLOW_INT | CFG_KEY_INT | CFG_USE_MODS); + reg_set_value(REG_ID_BKL, 255); + reg_set_value(REG_ID_DEB, 10); + reg_set_value(REG_ID_FRQ, 10); // ms + reg_set_value(REG_ID_BK2, 255); + reg_set_value(REG_ID_PUD, 0xFF); + reg_set_value(REG_ID_HLD, 30); // 10ms units + reg_set_value(REG_ID_ADR, 0x1F); + reg_set_value(REG_ID_IND, 1); // ms + reg_set_value(REG_ID_CF2, CF2_TOUCH_INT | CF2_USB_KEYB_ON | CF2_USB_MOUSE_ON); touchpad_add_touch_callback(&touch_callback); } diff --git a/app/reg.h b/app/reg.h index 884a283..c1c305a 100644 --- a/app/reg.h +++ b/app/reg.h @@ -25,8 +25,8 @@ enum reg_id REG_ID_ADR = 0x12, // i2c puppet address REG_ID_IND = 0x13, // interrupt pin assert duration REG_ID_CF2 = 0x14, // config 2 - REG_ID_TOX = 0x15, // touch delta x - REG_ID_TOY = 0x16, // touch delta y + REG_ID_TOX = 0x15, // touch delta x since last read, at most (-128 to 127) + REG_ID_TOY = 0x16, // touch delta y since last read, at most (-128 to 127) REG_ID_LAST, }; @@ -66,6 +66,10 @@ enum reg_id #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); void reg_set_value(enum reg_id reg, uint8_t value); diff --git a/app/touchpad.c b/app/touchpad.c index 83feb56..f8c842a 100644 --- a/app/touchpad.c +++ b/app/touchpad.c @@ -1,5 +1,7 @@ #include "touchpad.h" +#include "keyboard.h" + #include #include #include @@ -27,11 +29,16 @@ #define BIT_OBSERV_REST2 (2 << 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 struct { struct touch_callback *callbacks; + uint32_t last_swipe_time; i2c_inst_t *i2c; } self; @@ -51,6 +58,17 @@ static uint8_t read_register8(uint8_t reg) // 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) { 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; y = ((y < 127) ? y : (y - 256)); - if (self.callbacks) { - struct touch_callback *cb = self.callbacks; + if (keyboard_is_mod_on(KEY_MOD_ID_ALT)) { + 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) { - cb->func(x, y); + if (key != '\0') { + 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; + } } } } diff --git a/app/tusb_config.h b/app/tusb_config.h index ef4ee2f..3ed2c99 100644 --- a/app/tusb_config.h +++ b/app/tusb_config.h @@ -4,8 +4,10 @@ enum { USB_ITF_KEYBOARD = 0, USB_ITF_MOUSE, +// USB_ITF_HID_GENERIC, USB_ITF_CDC, USB_ITF_CDC2, + USB_ITF_VENDOR, USB_ITF_MAX, }; @@ -19,13 +21,16 @@ enum #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_MSC 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_CDC_RX_BUFSIZE 256 #define CFG_TUD_CDC_TX_BUFSIZE 256 + +#define CFG_TUD_VENDOR_RX_BUFSIZE 64 +#define CFG_TUD_VENDOR_TX_BUFSIZE 64 diff --git a/app/usb.c b/app/usb.c index c0981b0..8caa83f 100644 --- a/app/usb.c +++ b/app/usb.c @@ -1,5 +1,6 @@ #include "usb.h" +#include "backlight.h" #include "keyboard.h" #include "touchpad.h" #include "reg.h" @@ -16,6 +17,9 @@ static struct mutex_t mutex; bool mouse_moved; uint8_t mouse_btn; + + uint8_t write_buffer[2]; + uint8_t write_len; } self; // 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) { 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 modifier = 0; @@ -55,13 +64,10 @@ static void key_cb(char key, enum key_state state) modifier = KEYBOARD_MODIFIER_LEFTSHIFT; 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)) { @@ -99,7 +105,7 @@ static struct touch_callback touch_callback = .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 (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)reqlen; - printf("%s: itf: %d, report id: %d, type: %d, len: %d\r\n", __func__, itf, report_id, report_type, reqlen); - 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... (void)itf; (void)report_id; (void)report_type; (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) @@ -133,7 +181,7 @@ void usb_init(void) 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_enabled(USB_LOW_PRIORITY_IRQ, true); diff --git a/app/usb_descriptors.c b/app/usb_descriptors.c index 9d9ead7..8207628 100644 --- a/app/usb_descriptors.c +++ b/app/usb_descriptors.c @@ -1,13 +1,17 @@ #include -#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_MOUSE 0x82 +#define EPNUM_HID_GENERIC 0x83 -#define EPNUM_CDC_CMD 0x83 -#define EPNUM_CDC_IN 0x84 -#define EPNUM_CDC_OUT 0x02 +#define EPNUM_VENDOR_IN 0x84 +#define EPNUM_VENDOR_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_IN_OUT_MAX_SIZE 64 @@ -22,7 +26,8 @@ char const *string_descriptors[] = "123456", // 3: Serials, should use chip ID "Keyboard Interface", // 4: Interface 1 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 = @@ -56,14 +61,23 @@ uint8_t const hid_mouse_descriptor[] = 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[] = { 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_MOUSE, 5, HID_ITF_PROTOCOL_NONE, sizeof(hid_mouse_descriptor), EPNUM_HID_MOUSE, 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_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) @@ -79,6 +93,9 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) if (itf == USB_ITF_MOUSE) return hid_mouse_descriptor; +// if (itf == USB_ITF_HID_GENERIC) +// return hid_generic_descriptor; + return NULL; }