@@ -48,7 +48,9 @@ TARGET = mykey | |||
SRC = $(TARGET).c \ | |||
keymap.c \ | |||
matrix.c \ | |||
usb_keyboard_debug.c \ | |||
usb_device.c \ | |||
usb_keyboard.c \ | |||
usb_debug.c \ | |||
print.c | |||
@@ -30,7 +30,7 @@ | |||
#include <avr/interrupt.h> | |||
#include <util/delay.h> | |||
#include "usb_keyboard_debug.h" | |||
#include "usb_device.h" | |||
#include "print.h" | |||
#include "matrix.h" | |||
#include "keymap.h" |
@@ -2,7 +2,7 @@ | |||
#define print_h__ | |||
#include <avr/pgmspace.h> | |||
#include "usb_keyboard_debug.h" | |||
#include "usb_debug.h" | |||
// this macro allows you to write print("some text") and | |||
// the string is automatically placed into flash memory :) |
@@ -0,0 +1,80 @@ | |||
#include <avr/interrupt.h> | |||
#include "usb_debug.h" | |||
// the time remaining before we transmit any partially full | |||
// packet, or send a zero length packet. | |||
volatile uint8_t debug_flush_timer=0; | |||
// transmit a character. 0 returned on success, -1 on error | |||
int8_t usb_debug_putchar(uint8_t c) | |||
{ | |||
static uint8_t previous_timeout=0; | |||
uint8_t timeout, intr_state; | |||
// if we're not online (enumerated and configured), error | |||
if (!usb_configured()) return -1; | |||
// interrupts are disabled so these functions can be | |||
// used from the main program or interrupt context, | |||
// even both in the same program! | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = DEBUG_TX_ENDPOINT; | |||
// if we gave up due to timeout before, don't wait again | |||
if (previous_timeout) { | |||
if (!(UEINTX & (1<<RWAL))) { | |||
SREG = intr_state; | |||
return -1; | |||
} | |||
previous_timeout = 0; | |||
} | |||
// wait for the FIFO to be ready to accept data | |||
timeout = UDFNUML + 4; | |||
while (1) { | |||
// are we ready to transmit? | |||
if (UEINTX & (1<<RWAL)) break; | |||
SREG = intr_state; | |||
// have we waited too long? | |||
if (UDFNUML == timeout) { | |||
previous_timeout = 1; | |||
return -1; | |||
} | |||
// has the USB gone offline? | |||
if (!usb_configured()) return -1; | |||
// get ready to try checking again | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = DEBUG_TX_ENDPOINT; | |||
} | |||
// actually write the byte into the FIFO | |||
UEDATX = c; | |||
// if this completed a packet, transmit it now! | |||
if (!(UEINTX & (1<<RWAL))) { | |||
UEINTX = 0x3A; | |||
debug_flush_timer = 0; | |||
} else { | |||
debug_flush_timer = 2; | |||
} | |||
SREG = intr_state; | |||
return 0; | |||
} | |||
// immediately transmit any buffered output. | |||
void usb_debug_flush_output(void) | |||
{ | |||
uint8_t intr_state; | |||
intr_state = SREG; | |||
cli(); | |||
if (debug_flush_timer) { | |||
UENUM = DEBUG_TX_ENDPOINT; | |||
while ((UEINTX & (1<<RWAL))) { | |||
UEDATX = 0; | |||
} | |||
UEINTX = 0x3A; | |||
debug_flush_timer = 0; | |||
} | |||
SREG = intr_state; | |||
} |
@@ -0,0 +1,20 @@ | |||
#ifndef USB_DEBUG_H | |||
#define USB_DEBUG_H 1 | |||
#include <stdint.h> | |||
#include "usb_device.h" | |||
#define DEBUG_INTERFACE 1 | |||
#define DEBUG_TX_ENDPOINT 4 | |||
#define DEBUG_TX_SIZE 32 | |||
#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER | |||
extern volatile uint8_t debug_flush_timer; | |||
int8_t usb_debug_putchar(uint8_t c); // transmit a character | |||
void usb_debug_flush_output(void); // immediately transmit any buffered output | |||
#endif |
@@ -21,11 +21,12 @@ | |||
* THE SOFTWARE. | |||
*/ | |||
// Version 1.0: Initial Release | |||
// Version 1.1: Add support for Teensy 2.0 | |||
#include <avr/pgmspace.h> | |||
#include <avr/interrupt.h> | |||
#include "usb_device.h" | |||
#include "usb_keyboard.h" | |||
#include "usb_debug.h" | |||
#define USB_SERIAL_PRIVATE_INCLUDE | |||
#include "usb_keyboard_debug.h" | |||
/************************************************************************** | |||
* | |||
@@ -63,16 +64,6 @@ | |||
#define ENDPOINT0_SIZE 32 | |||
#define KEYBOARD_INTERFACE 0 | |||
#define KEYBOARD_ENDPOINT 3 | |||
#define KEYBOARD_SIZE 8 | |||
#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER | |||
#define DEBUG_INTERFACE 1 | |||
#define DEBUG_TX_ENDPOINT 4 | |||
#define DEBUG_TX_SIZE 32 | |||
#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER | |||
static const uint8_t PROGMEM endpoint_config_table[] = { | |||
0, | |||
0, | |||
@@ -191,7 +182,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
0, // bCountryCode | |||
1, // bNumDescriptors | |||
0x22, // bDescriptorType | |||
sizeof(keyboard_hid_report_desc), // wDescriptorLength | |||
sizeof(keyboard_hid_report_desc), // wDescriptorLength | |||
0, | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
@@ -255,17 +246,22 @@ static struct usb_string_descriptor_struct PROGMEM string2 = { | |||
// This table defines which descriptor data is sent for each specific | |||
// request from the host (in wValue and wIndex). | |||
static struct descriptor_list_struct { | |||
uint16_t wValue; | |||
uint16_t wValue; // descriptor type | |||
uint16_t wIndex; | |||
const uint8_t *addr; | |||
uint8_t length; | |||
} PROGMEM descriptor_list[] = { | |||
// DEVICE descriptor | |||
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, | |||
// CONFIGURATION descriptor | |||
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, | |||
// HID REPORT | |||
{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, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | |||
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | |||
// STRING descriptor | |||
{0x0300, 0x0000, (const uint8_t *)&string0, 4}, | |||
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)}, | |||
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)} | |||
@@ -282,33 +278,6 @@ static struct descriptor_list_struct { | |||
// zero when we are not configured, non-zero when enumerated | |||
static volatile uint8_t usb_configuration=0; | |||
// the time remaining before we transmit any partially full | |||
// packet, or send a zero length packet. | |||
static volatile uint8_t debug_flush_timer=0; | |||
// which modifier keys are currently pressed | |||
// 1=left ctrl, 2=left shift, 4=left alt, 8=left gui | |||
// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui | |||
uint8_t keyboard_modifier_keys=0; | |||
// which keys are currently pressed, up to 6 keys may be down at once | |||
uint8_t keyboard_keys[6]={0,0,0,0,0,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. | |||
static uint8_t keyboard_protocol=1; | |||
// the idle configuration, how often we send the report to the | |||
// host (ms * 4) even when it hasn't changed | |||
static uint8_t keyboard_idle_config=125; | |||
// count until idle timeout | |||
static uint8_t keyboard_idle_count=0; | |||
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana | |||
volatile uint8_t keyboard_leds=0; | |||
/************************************************************************** | |||
* | |||
@@ -339,127 +308,6 @@ uint8_t usb_configured(void) | |||
} | |||
// perform a single keystroke | |||
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier) | |||
{ | |||
int8_t r; | |||
keyboard_modifier_keys = modifier; | |||
keyboard_keys[0] = key; | |||
r = usb_keyboard_send(); | |||
if (r) return r; | |||
keyboard_modifier_keys = 0; | |||
keyboard_keys[0] = 0; | |||
return usb_keyboard_send(); | |||
} | |||
// send the contents of keyboard_keys and keyboard_modifier_keys | |||
int8_t usb_keyboard_send(void) | |||
{ | |||
uint8_t i, intr_state, timeout; | |||
if (!usb_configuration) return -1; | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = KEYBOARD_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_configuration) return -1; | |||
// have we waited too long? | |||
if (UDFNUML == timeout) return -1; | |||
// get ready to try checking again | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = KEYBOARD_ENDPOINT; | |||
} | |||
UEDATX = keyboard_modifier_keys; | |||
UEDATX = 0; | |||
for (i=0; i<6; i++) { | |||
UEDATX = keyboard_keys[i]; | |||
} | |||
UEINTX = 0x3A; | |||
keyboard_idle_count = 0; | |||
SREG = intr_state; | |||
return 0; | |||
} | |||
// transmit a character. 0 returned on success, -1 on error | |||
int8_t usb_debug_putchar(uint8_t c) | |||
{ | |||
static uint8_t previous_timeout=0; | |||
uint8_t timeout, intr_state; | |||
// if we're not online (enumerated and configured), error | |||
if (!usb_configuration) return -1; | |||
// interrupts are disabled so these functions can be | |||
// used from the main program or interrupt context, | |||
// even both in the same program! | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = DEBUG_TX_ENDPOINT; | |||
// if we gave up due to timeout before, don't wait again | |||
if (previous_timeout) { | |||
if (!(UEINTX & (1<<RWAL))) { | |||
SREG = intr_state; | |||
return -1; | |||
} | |||
previous_timeout = 0; | |||
} | |||
// wait for the FIFO to be ready to accept data | |||
timeout = UDFNUML + 4; | |||
while (1) { | |||
// are we ready to transmit? | |||
if (UEINTX & (1<<RWAL)) break; | |||
SREG = intr_state; | |||
// have we waited too long? | |||
if (UDFNUML == timeout) { | |||
previous_timeout = 1; | |||
return -1; | |||
} | |||
// has the USB gone offline? | |||
if (!usb_configuration) return -1; | |||
// get ready to try checking again | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = DEBUG_TX_ENDPOINT; | |||
} | |||
// actually write the byte into the FIFO | |||
UEDATX = c; | |||
// if this completed a packet, transmit it now! | |||
if (!(UEINTX & (1<<RWAL))) { | |||
UEINTX = 0x3A; | |||
debug_flush_timer = 0; | |||
} else { | |||
debug_flush_timer = 2; | |||
} | |||
SREG = intr_state; | |||
return 0; | |||
} | |||
// immediately transmit any buffered output. | |||
void usb_debug_flush_output(void) | |||
{ | |||
uint8_t intr_state; | |||
intr_state = SREG; | |||
cli(); | |||
if (debug_flush_timer) { | |||
UENUM = DEBUG_TX_ENDPOINT; | |||
while ((UEINTX & (1<<RWAL))) { | |||
UEDATX = 0; | |||
} | |||
UEINTX = 0x3A; | |||
debug_flush_timer = 0; | |||
} | |||
SREG = intr_state; | |||
} | |||
/************************************************************************** | |||
* |
@@ -1,30 +1,18 @@ | |||
#ifndef usb_serial_h__ | |||
#define usb_serial_h__ | |||
#ifndef USB_DEVICE_H | |||
#define USB_DEVICE_H 1 | |||
#include <stdint.h> | |||
#include <avr/io.h> | |||
#include "usb_keyboard.h" | |||
#include "usb_debug.h" | |||
void usb_init(void); // initialize everything | |||
uint8_t usb_configured(void); // is the USB port configured | |||
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier); | |||
int8_t usb_keyboard_send(void); | |||
extern uint8_t keyboard_modifier_keys; | |||
extern uint8_t keyboard_keys[6]; | |||
extern volatile uint8_t keyboard_leds; | |||
int8_t usb_debug_putchar(uint8_t c); // transmit a character | |||
void usb_debug_flush_output(void); // immediately transmit any buffered output | |||
#define USB_DEBUG_HID | |||
// Everything below this point is only intended for usb_serial.c | |||
#ifdef USB_SERIAL_PRIVATE_INCLUDE | |||
#include <avr/io.h> | |||
#include <avr/pgmspace.h> | |||
#include <avr/interrupt.h> | |||
#define EP_TYPE_CONTROL 0x00 | |||
#define EP_TYPE_BULK_IN 0x81 | |||
#define EP_TYPE_BULK_OUT 0x80 | |||
@@ -89,5 +77,5 @@ void usb_debug_flush_output(void); // immediately transmit any buffered output | |||
#define CDC_SET_LINE_CODING 0x20 | |||
#define CDC_GET_LINE_CODING 0x21 | |||
#define CDC_SET_CONTROL_LINE_STATE 0x22 | |||
#endif | |||
#endif |
@@ -0,0 +1,76 @@ | |||
#include <avr/interrupt.h> | |||
#include <avr/pgmspace.h> | |||
#include "usb_keyboard.h" | |||
// which modifier keys are currently pressed | |||
// 1=left ctrl, 2=left shift, 4=left alt, 8=left gui | |||
// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui | |||
uint8_t keyboard_modifier_keys=0; | |||
// which keys are currently pressed, up to 6 keys may be down at once | |||
uint8_t keyboard_keys[6]={0,0,0,0,0,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 keyboard_protocol=1; | |||
// the idle configuration, how often we send the report to the | |||
// host (ms * 4) even when it hasn't changed | |||
uint8_t keyboard_idle_config=125; | |||
// count until idle timeout | |||
uint8_t keyboard_idle_count=0; | |||
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana | |||
volatile uint8_t keyboard_leds=0; | |||
// perform a single keystroke | |||
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier) | |||
{ | |||
int8_t r; | |||
keyboard_modifier_keys = modifier; | |||
keyboard_keys[0] = key; | |||
r = usb_keyboard_send(); | |||
if (r) return r; | |||
keyboard_modifier_keys = 0; | |||
keyboard_keys[0] = 0; | |||
return usb_keyboard_send(); | |||
} | |||
// send the contents of keyboard_keys and keyboard_modifier_keys | |||
int8_t usb_keyboard_send(void) | |||
{ | |||
uint8_t i, intr_state, timeout; | |||
if (!usb_configured()) return -1; | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = KEYBOARD_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 = KEYBOARD_ENDPOINT; | |||
} | |||
UEDATX = keyboard_modifier_keys; | |||
UEDATX = 0; | |||
for (i=0; i<6; i++) { | |||
UEDATX = keyboard_keys[i]; | |||
} | |||
UEINTX = 0x3A; | |||
keyboard_idle_count = 0; | |||
SREG = intr_state; | |||
return 0; | |||
} |
@@ -0,0 +1,25 @@ | |||
#ifndef USB_KEYBOARD_H | |||
#define USB_KEYBOARD_H 1 | |||
#include <stdint.h> | |||
#include "usb_device.h" | |||
#define KEYBOARD_INTERFACE 0 | |||
#define KEYBOARD_ENDPOINT 3 | |||
#define KEYBOARD_SIZE 8 | |||
#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER | |||
extern uint8_t keyboard_modifier_keys; | |||
extern uint8_t keyboard_keys[6]; | |||
extern uint8_t keyboard_protocol; | |||
extern uint8_t keyboard_idle_config; | |||
extern uint8_t keyboard_idle_count; | |||
extern volatile uint8_t keyboard_leds; | |||
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier); | |||
int8_t usb_keyboard_send(void); | |||
#endif |