@@ -7,3 +7,4 @@ | |||
*.lst | |||
*.map | |||
*.sym | |||
tags |
@@ -46,13 +46,14 @@ TARGET = mykey | |||
# List C source files here. (C dependencies are automatically generated.) | |||
SRC = $(TARGET).c \ | |||
keymap.c \ | |||
matrix.c \ | |||
usb_device.c \ | |||
usb.c \ | |||
usb_keyboard.c \ | |||
usb_mouse.c \ | |||
usb_debug.c \ | |||
print.c \ | |||
jump_bootloader.c | |||
keymap.c \ | |||
matrix.c \ | |||
jump_bootloader.c \ | |||
print.c | |||
# MCU name, you MUST set this to match the board you are using |
@@ -2,7 +2,7 @@ | |||
#define KEYMAP_H 1 | |||
#include <stdint.h> | |||
#include "usbkeycodes.h" | |||
#include "usb_keycodes.h" | |||
int get_layer(void); | |||
uint8_t get_keycode(int layer, int row, int col); |
@@ -1,3 +1,6 @@ | |||
#ifndef MATRIX_H | |||
#define MATRIX_H 1 | |||
#include <stdbool.h> | |||
extern uint8_t *matrix; | |||
@@ -8,3 +11,5 @@ uint8_t matrix_scan(void); | |||
bool matrix_is_modified(void); | |||
bool matrix_has_ghost(void); | |||
bool matrix_has_ghost_in_row(uint8_t row); | |||
#endif |
@@ -30,7 +30,9 @@ | |||
#include <avr/interrupt.h> | |||
#include <util/delay.h> | |||
#include "usb_device.h" | |||
#include "usb.h" | |||
#include "usb_keyboard.h" | |||
#include "usb_mouse.h" | |||
#include "print.h" | |||
#include "matrix.h" | |||
#include "keymap.h" | |||
@@ -50,16 +52,9 @@ uint16_t idle_count=0; | |||
int main(void) | |||
{ | |||
bool modified = false; | |||
bool has_ghost = false; | |||
uint8_t key_index = 0; | |||
// set for 16 MHz clock | |||
CPU_PRESCALE(0); | |||
matrix_init(); | |||
// Initialize the USB, and then wait for the host to set configuration. | |||
// If the Teensy is powered without a PC connected to the USB port, | |||
// this will wait forever. | |||
@@ -78,99 +73,85 @@ int main(void) | |||
TCCR0B = 0x05; | |||
TIMSK0 = (1<<TOIE0); | |||
matrix_init(); | |||
print("firmware 0.2 for t.m.k.\n"); | |||
bool modified = false; | |||
bool has_ghost = false; | |||
int key_index = 0; | |||
int loop_count = 0; | |||
int layer = 0; | |||
while (1) { | |||
int layer = 0; | |||
matrix_scan(); | |||
layer = get_layer(); | |||
modified = matrix_is_modified(); | |||
has_ghost = matrix_has_ghost(); | |||
// doesnt send keys during ghost occurs | |||
if (modified && !has_ghost) { | |||
key_index = 0; | |||
keyboard_modifier_keys = 0; | |||
for (int i = 0; i < 6; i++) keyboard_keys[i] = KB_NO; | |||
// print matrix state for debug | |||
if (modified) { | |||
print_matrix(); | |||
for (int row = 0; row < MATRIX_ROWS; row++) { | |||
for (int col = 0; col < MATRIX_COLS; col++) { | |||
if (matrix[row] & 1<<col) continue; | |||
uint8_t code = get_keycode(layer, row, col); | |||
if (code == KB_NO) { | |||
continue; | |||
} else if (KB_LCTRL <= code && code <= KB_RGUI) { | |||
// modifier keycode: 0xE0-0xE7 | |||
keyboard_modifier_keys |= 1<<(code & 0x07); | |||
} else { | |||
if (key_index < 6) | |||
keyboard_keys[key_index] = code; | |||
key_index++; | |||
} | |||
// LED flush | |||
DDRD |= 1<<PD6; | |||
PORTD |= 1<<PD6; | |||
} | |||
// set matrix state to keyboard_keys, keyboard_modifier_keys | |||
key_index = 0; | |||
keyboard_modifier_keys = 0; | |||
for (int i = 0; i < 6; i++) keyboard_keys[i] = KB_NO; | |||
for (int row = 0; row < MATRIX_ROWS; row++) { | |||
for (int col = 0; col < MATRIX_COLS; col++) { | |||
if (matrix[row] & 1<<col) continue; | |||
uint8_t code = get_keycode(layer, row, col); | |||
if (code == KB_NO) { | |||
continue; | |||
} else if (KB_LCTRL <= code && code <= KB_RGUI) { | |||
// modifier keycode: 0xE0-0xE7 | |||
keyboard_modifier_keys |= 1<<(code & 0x07); | |||
} else { | |||
if (key_index < 6) | |||
keyboard_keys[key_index] = code; | |||
key_index++; | |||
} | |||
} | |||
} | |||
// run bootloader when 4 left modifier keys down | |||
if (!has_ghost) { | |||
// when 4 left modifier keys down | |||
if (keyboard_modifier_keys == (MOD_LCTRL | MOD_LSHIFT | MOD_LALT | MOD_LGUI)) { | |||
// cancel all keys | |||
keyboard_modifier_keys = 0; | |||
for (int i = 0; i < 6; i++) keyboard_keys[i] = KB_NO; | |||
usb_keyboard_send(); | |||
/* | |||
print("jump to bootloader...\n"); | |||
_delay_ms(1000); | |||
jump_bootloader(); | |||
} | |||
*/ | |||
if (key_index > 6) { | |||
//Rollover | |||
} | |||
// mouse | |||
print("usb_mouse_move\n"); | |||
usb_mouse_move(10, 0, 0); | |||
usb_keyboard_send(); | |||
// variables shared with interrupt routines must be | |||
// accessed carefully so the interrupt routine doesn't | |||
// try to use the variable in the middle of our access | |||
cli(); | |||
//idle_count = 0; | |||
sei(); | |||
} | |||
// print matrix state for debug | |||
if (modified) { | |||
print_matrix(); | |||
// LED flush | |||
DDRD |= 1<<PD6; | |||
PORTD |= 1<<PD6; | |||
} | |||
_delay_ms(100); | |||
continue; | |||
} | |||
/* | |||
// print counts for debug | |||
if ((loop_count % 0x1000) == 0) { | |||
//print("."); | |||
print("idle_count: "); phex((idle_count & 0xFF00) >> 8); phex(idle_count & 0xFF); print("\n"); | |||
print("loop_count: "); phex((loop_count & 0xFF00) >> 8); phex(loop_count & 0xFF); print("\n"); | |||
print_matrix(); | |||
} | |||
// teensy LED flush for debug | |||
if ((loop_count & 0x100) == 0) { | |||
DDRD |= 1<<PD6; | |||
PORTD |= 1<<PD6; | |||
// send keys to host | |||
if (modified) { | |||
if (key_index > 6) { | |||
//Rollover | |||
} | |||
usb_keyboard_send(); | |||
} | |||
} | |||
*/ | |||
// now the current pins will be the previous, and | |||
// wait a short delay so we're not highly sensitive | |||
// to mechanical "bounce". | |||
_delay_ms(2); | |||
loop_count++; | |||
_delay_ms(2); | |||
} | |||
} | |||
@@ -25,7 +25,6 @@ | |||
#include <avr/io.h> | |||
#include <avr/pgmspace.h> | |||
#include "print.h" | |||
void print_P(const char *s) |
@@ -1,5 +1,5 @@ | |||
#ifndef print_h__ | |||
#define print_h__ | |||
#ifndef PRINT_H__ | |||
#define PRINT_H__ 1 | |||
#include <avr/pgmspace.h> | |||
#include "usb_debug.h" |
@@ -21,10 +21,12 @@ | |||
* THE SOFTWARE. | |||
*/ | |||
#include <avr/io.h> | |||
#include <avr/pgmspace.h> | |||
#include <avr/interrupt.h> | |||
#include "usb_device.h" | |||
#include "usb.h" | |||
#include "usb_keyboard.h" | |||
#include "usb_mouse.h" | |||
#include "usb_debug.h" | |||
@@ -64,11 +66,15 @@ | |||
#define ENDPOINT0_SIZE 32 | |||
// 0:control endpoint is enabled automatically by controller. | |||
static const uint8_t PROGMEM endpoint_config_table[] = { | |||
0, | |||
0, | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER | |||
// enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation) | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 1 | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2 | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3 | |||
0, // 4 | |||
0, // 5 | |||
0, // 6 | |||
}; | |||
@@ -138,6 +144,36 @@ static uint8_t PROGMEM keyboard_hid_report_desc[] = { | |||
0xc0 // End Collection | |||
}; | |||
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | |||
static uint8_t PROGMEM mouse_hid_report_desc[] = { | |||
0x05, 0x01, // Usage Page (Generic Desktop) | |||
0x09, 0x02, // Usage (Mouse) | |||
0xA1, 0x01, // Collection (Application) | |||
0x05, 0x09, // Usage Page (Button) | |||
0x19, 0x01, // Usage Minimum (Button #1) | |||
0x29, 0x03, // Usage Maximum (Button #3) | |||
0x15, 0x00, // Logical Minimum (0) | |||
0x25, 0x01, // Logical Maximum (1) | |||
0x95, 0x03, // Report Count (3) | |||
0x75, 0x01, // Report Size (1) | |||
0x81, 0x02, // Input (Data, Variable, Absolute) | |||
0x95, 0x01, // Report Count (1) | |||
0x75, 0x05, // Report Size (5) | |||
0x81, 0x03, // Input (Constant) | |||
0x05, 0x01, // Usage Page (Generic Desktop) | |||
0x09, 0x30, // Usage (X) | |||
0x09, 0x31, // Usage (Y) | |||
0x15, 0x81, // Logical Minimum (-127) | |||
0x25, 0x7F, // Logical Maximum (127) | |||
0x75, 0x08, // Report Size (8), | |||
0x95, 0x02, // Report Count (2), | |||
0x81, 0x06, // Input (Data, Variable, Relative) | |||
0x09, 0x38, // Usage (Wheel) | |||
0x95, 0x01, // Report Count (1), | |||
0x81, 0x06, // Input (Data, Variable, Relative) | |||
0xC0 // End Collection | |||
}; | |||
static uint8_t PROGMEM debug_hid_report_desc[] = { | |||
0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined) | |||
0x09, 0x74, // Usage 0x74 | |||
@@ -151,20 +187,22 @@ static uint8_t PROGMEM debug_hid_report_desc[] = { | |||
0xC0 // end collection | |||
}; | |||
#define CONFIG1_DESC_SIZE (9+9+9+7+9+9+7) | |||
#define CONFIG1_DESC_SIZE (9+(9+9+7)+(9+9+7)+(9+9+7)) | |||
#define KEYBOARD_HID_DESC_OFFSET (9+9) | |||
#define DEBUG_HID_DESC_OFFSET (9+9+9+7+9) | |||
#define MOUSE_HID_DESC_OFFSET (9+(9+9+7)+9) | |||
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)+(9+9+7)+9) | |||
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | |||
9, // bLength; | |||
2, // bDescriptorType; | |||
LSB(CONFIG1_DESC_SIZE), // wTotalLength | |||
MSB(CONFIG1_DESC_SIZE), | |||
2, // bNumInterfaces | |||
3, // bNumInterfaces | |||
1, // bConfigurationValue | |||
0, // iConfiguration | |||
0xC0, // bmAttributes | |||
50, // bMaxPower | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -175,7 +213,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
0x01, // bInterfaceSubClass (0x01 = Boot) | |||
0x01, // bInterfaceProtocol (0x01 = Keyboard) | |||
0, // iInterface | |||
// HID interface descriptor, HID 1.11 spec, section 6.2.1 | |||
// HID descriptor, HID 1.11 spec, section 6.2.1 | |||
9, // bLength | |||
0x21, // bDescriptorType | |||
0x11, 0x01, // bcdHID | |||
@@ -191,6 +229,34 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
0x03, // bmAttributes (0x03=intr) | |||
KEYBOARD_SIZE, 0, // wMaxPacketSize | |||
1, // bInterval | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
MOUSE_INTERFACE, // bInterfaceNumber | |||
0, // bAlternateSetting | |||
1, // bNumEndpoints | |||
0x03, // bInterfaceClass (0x03 = HID) | |||
0x01, // bInterfaceSubClass (0x01 = Boot) | |||
0x02, // bInterfaceProtocol (0x02 = Mouse) | |||
0, // iInterface | |||
// HID descriptor, HID 1.11 spec, section 6.2.1 | |||
9, // bLength | |||
0x21, // bDescriptorType | |||
0x11, 0x01, // bcdHID | |||
0, // bCountryCode | |||
1, // bNumDescriptors | |||
0x22, // bDescriptorType | |||
sizeof(mouse_hid_report_desc), // wDescriptorLength | |||
0, | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
MOUSE_ENDPOINT | 0x80, // bEndpointAddress | |||
0x03, // bmAttributes (0x03=intr) | |||
4, 0, // wMaxPacketSize | |||
1, // bInterval | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -201,7 +267,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
0x00, // bInterfaceSubClass | |||
0x00, // bInterfaceProtocol | |||
0, // iInterface | |||
// HID interface descriptor, HID 1.11 spec, section 6.2.1 | |||
// HID descriptor, HID 1.11 spec, section 6.2.1 | |||
9, // bLength | |||
0x21, // bDescriptorType | |||
0x11, 0x01, // bcdHID | |||
@@ -259,6 +325,9 @@ static struct descriptor_list_struct { | |||
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | |||
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9}, | |||
// HID REPORT | |||
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, | |||
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | |||
// HID REPORT | |||
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | |||
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | |||
// STRING descriptor | |||
@@ -470,7 +539,7 @@ ISR(USB_COM_vect) | |||
usb_configuration = wValue; | |||
usb_send_in(); | |||
cfg = endpoint_config_table; | |||
for (i=1; i<5; i++) { | |||
for (i=1; i<=6; i++) { | |||
UENUM = i; | |||
en = pgm_read_byte(cfg++); | |||
UECONX = en; | |||
@@ -479,7 +548,7 @@ ISR(USB_COM_vect) | |||
UECFG1X = pgm_read_byte(cfg++); | |||
} | |||
} | |||
UERST = 0x1E; | |||
UERST = 0x7E; | |||
UERST = 0; | |||
return; | |||
} | |||
@@ -571,6 +640,32 @@ ISR(USB_COM_vect) | |||
} | |||
} | |||
} | |||
if (wIndex == MOUSE_INTERFACE) { | |||
if (bmRequestType == 0xA1) { | |||
if (bRequest == HID_GET_REPORT) { | |||
usb_wait_in_ready(); | |||
UEDATX = mouse_buttons; | |||
UEDATX = 0; | |||
UEDATX = 0; | |||
UEDATX = 0; | |||
usb_send_in(); | |||
return; | |||
} | |||
if (bRequest == HID_GET_PROTOCOL) { | |||
usb_wait_in_ready(); | |||
UEDATX = mouse_protocol; | |||
usb_send_in(); | |||
return; | |||
} | |||
} | |||
if (bmRequestType == 0x21) { | |||
if (bRequest == HID_SET_PROTOCOL) { | |||
mouse_protocol = wValue; | |||
usb_send_in(); | |||
return; | |||
} | |||
} | |||
} | |||
if (wIndex == DEBUG_INTERFACE) { | |||
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) { | |||
len = wLength; |
@@ -1,10 +1,8 @@ | |||
#ifndef USB_DEVICE_H | |||
#define USB_DEVICE_H 1 | |||
#ifndef USB_H | |||
#define USB_H 1 | |||
#include <stdint.h> | |||
#include <avr/io.h> | |||
#include "usb_keyboard.h" | |||
#include "usb_debug.h" | |||
void usb_init(void); // initialize everything |
@@ -2,11 +2,11 @@ | |||
#define USB_DEBUG_H 1 | |||
#include <stdint.h> | |||
#include "usb_device.h" | |||
#include "usb.h" | |||
#define DEBUG_INTERFACE 1 | |||
#define DEBUG_TX_ENDPOINT 4 | |||
#define DEBUG_INTERFACE 2 | |||
#define DEBUG_TX_ENDPOINT 3 | |||
#define DEBUG_TX_SIZE 32 | |||
#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER | |||
@@ -2,11 +2,11 @@ | |||
#define USB_KEYBOARD_H 1 | |||
#include <stdint.h> | |||
#include "usb_device.h" | |||
#include "usb.h" | |||
#define KEYBOARD_INTERFACE 0 | |||
#define KEYBOARD_ENDPOINT 3 | |||
#define KEYBOARD_ENDPOINT 1 | |||
#define KEYBOARD_SIZE 8 | |||
#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER | |||
@@ -1,5 +1,8 @@ | |||
/* Some modified from Keyboard Upgrade 0.3.0 | |||
* 2010/08/22 | |||
/* | |||
* Key codes from HID Keyboard/Keypad Page | |||
* http://www.usb.org/developers/devclass_docs/Hut1_12.pdf | |||
* | |||
* Based on Keyboard Upgrade v0.3.0 http://github.com/rhomann/kbupgrade | |||
*/ | |||
/* | |||
* Keyboard Upgrade -- Firmware for homebrew computer keyboard controllers. | |||
@@ -30,17 +33,10 @@ | |||
* MA 02110-1301 USA | |||
*/ | |||
#ifndef USBKEYCODES_H | |||
#define USBKEYCODES_H | |||
#ifndef USB_KEYCODES_H | |||
#define USB_KEYCODES_H | |||
/* | |||
* The USB keycodes are enumerated here - the first part is simply | |||
* an enumeration of the allowed scan-codes used for USB HID devices. | |||
*/ | |||
/* | |||
* see 10 Keyboard/Keypad Page(0x07) | |||
* http://www.usb.org/developers/devclass_docs/Hut1_12.pdf | |||
*/ | |||
enum keycodes { | |||
KB_NO = 0, | |||
KB_ROLL_OVER, | |||
@@ -265,11 +261,11 @@ enum keycodes { | |||
KB_RALT, /* 0x40 */ | |||
KB_RGUI, /* 0x80 */ | |||
/* function keys */ | |||
/* extensions for internal use */ | |||
FN_0 = 0xF0, | |||
FN_1, | |||
FN_2, | |||
FN_3, | |||
}; | |||
#endif /* USBKEYCODES_H */ | |||
#endif /* USB_KEYCODES_H */ |
@@ -0,0 +1,62 @@ | |||
#include <avr/interrupt.h> | |||
#include <util/delay.h> | |||
#include "usb_mouse.h" | |||
// which buttons are currently pressed | |||
uint8_t mouse_buttons=0; | |||
// protocol setting from the host. We use exactly the same report | |||
// either way, so this variable only stores the setting since we | |||
// are required to be able to report which setting is in use. | |||
uint8_t mouse_protocol=1; | |||
// Set the mouse buttons. To create a "click", 2 calls are needed, | |||
// one to push the button down and the second to release it | |||
int8_t usb_mouse_buttons(uint8_t left, uint8_t middle, uint8_t right) | |||
{ | |||
uint8_t mask=0; | |||
if (left) mask |= 1; | |||
if (middle) mask |= 4; | |||
if (right) mask |= 2; | |||
mouse_buttons = mask; | |||
return usb_mouse_move(0, 0, 0); | |||
} | |||
// Move the mouse. x, y and wheel are -127 to 127. Use 0 for no movement. | |||
int8_t usb_mouse_move(int8_t x, int8_t y, int8_t wheel) | |||
{ | |||
uint8_t intr_state, timeout; | |||
if (!usb_configured()) return -1; | |||
if (x == -128) x = -127; | |||
if (y == -128) y = -127; | |||
if (wheel == -128) wheel = -127; | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = MOUSE_ENDPOINT; | |||
timeout = UDFNUML + 50; | |||
while (1) { | |||
// are we ready to transmit? | |||
if (UEINTX & (1<<RWAL)) break; | |||
SREG = intr_state; | |||
// has the USB gone offline? | |||
if (!usb_configured()) return -1; | |||
// have we waited too long? | |||
if (UDFNUML == timeout) return -1; | |||
// get ready to try checking again | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = MOUSE_ENDPOINT; | |||
} | |||
UEDATX = mouse_buttons; | |||
UEDATX = x; | |||
UEDATX = y; | |||
UEDATX = wheel; | |||
UEINTX = 0x3A; | |||
SREG = intr_state; | |||
return 0; | |||
} | |||
@@ -0,0 +1,20 @@ | |||
#ifndef USB_MOUSE_H | |||
#define USB_MOUSE_H 1 | |||
#include <stdint.h> | |||
#include "usb.h" | |||
#define MOUSE_INTERFACE 1 | |||
#define MOUSE_ENDPOINT 2 | |||
#define MOUSE_SIZE 8 | |||
#define MOUSE_BUFFER EP_DOUBLE_BUFFER | |||
extern uint8_t mouse_buttons; | |||
extern uint8_t mouse_protocol; | |||
int8_t usb_mouse_buttons(uint8_t left, uint8_t middle, uint8_t right); | |||
int8_t usb_mouse_move(int8_t x, int8_t y, int8_t wheel); | |||
#endif |