Improvements commited 2 months later (I really should leave notes for myself)

This commit is contained in:
arturo182 2021-11-03 19:28:01 +01:00
parent c9791af550
commit 04604f3a1c
11 changed files with 433 additions and 271 deletions

View File

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

View File

@ -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] =
@ -50,11 +40,11 @@ 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', ';' } },
{ { KEY_BTN_LEFT1 }, { '~', '0' }, { 'F', '6' }, { .mod = KEY_MOD_ID_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_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,42 +83,42 @@ 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 MOD_ALT:
case KEY_MOD_ID_ALT:
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
chr = KEY_MOD_ALT;
key = KEY_MOD_ALT;
break;
case MOD_SHL:
case KEY_MOD_ID_SHL:
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
chr = KEY_MOD_SHL;
key = KEY_MOD_SHL;
break;
case MOD_SHR:
case KEY_MOD_ID_SHR:
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
chr = KEY_MOD_SHR;
key = KEY_MOD_SHR;
break;
case MOD_SYM:
case KEY_MOD_ID_SYM:
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
chr = KEY_MOD_SYM;
key = KEY_MOD_SYM;
break;
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;
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;
if (alt) {
chr = p_entry->symb;
} else if (!shift && (chr >= 'A' && chr <= 'Z')) {
chr = (chr + ' ');
key = p_entry->alt;
} else if (!shift && (key >= 'A' && key <= 'Z')) {
key = (key + ' ');
}
}
@ -138,23 +126,13 @@ static void transition_to(struct list_item * const p_item, const enum key_state
}
}
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);
p_item->effective_key = key;
}
if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_ON))
fifo_enqueue_force(item);
}
if (p_item->effective_key == '\0')
return;
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);
}

View File

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

View File

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

View File

@ -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 <hardware/i2c.h>
#include <hardware/irq.h>
#include <pico/stdlib.h>
#include <RP2040.h>
#include <stdio.h>
#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;

168
app/reg.c
View File

@ -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 <pico/stdlib.h>
#include <RP2040.h>
#include <stdio.h>
// 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);
}

View File

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

View File

@ -1,5 +1,7 @@
#include "touchpad.h"
#include "keyboard.h"
#include <hardware/i2c.h>
#include <pico/binary_info.h>
#include <pico/stdlib.h>
@ -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,6 +85,25 @@ void touchpad_gpio_irq(uint gpio, uint32_t events)
x = ((x < 127) ? x : (x - 256)) * -1;
y = ((y < 127) ? y : (y - 256));
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;
}
if (key != '\0') {
keyboard_inject_event(key, KEY_STATE_PRESSED);
// 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;
@ -78,6 +115,7 @@ void touchpad_gpio_irq(uint gpio, uint32_t events)
}
}
}
}
void touchpad_add_touch_callback(struct touch_callback *callback)
{

View File

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

View File

@ -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,12 +64,9 @@ 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;
}
if (state != KEY_STATE_HOLD)
tud_hid_n_keyboard_report(USB_ITF_KEYBOARD, 0, modifier, keycode);
}
@ -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);

View File

@ -1,13 +1,17 @@
#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_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,6 +61,11 @@ 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),
@ -63,7 +73,11 @@ uint8_t const config_descriptor[] =
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;
}