mirror of
				https://github.com/grymoire/i2c_puppet-Linux.git
				synced 2025-10-31 10:25:58 +01:00 
			
		
		
		
	Improvements commited 2 months later (I really should leave notes for myself)
This commit is contained in:
		| @@ -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); | ||||
|  | ||||
|   | ||||
							
								
								
									
										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 | ||||
|  | ||||
| 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); | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
							
								
								
									
										130
									
								
								app/puppet_i2c.c
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								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 <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
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								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 <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); | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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,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; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										74
									
								
								app/usb.c
									
									
									
									
									
								
							
							
						
						
									
										74
									
								
								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); | ||||
|  | ||||
|   | ||||
| @@ -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,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; | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user