- NKRO for USB Codes 4 to 164, 176 to 221 and modifiers - Added System Control support codes 129 to 183 - Added Consumer Control support codes 32 to 668simple
@@ -99,7 +99,7 @@ set( DefaultMap "colemak kishsaver_unix1 stdFuncMap" ) | |||
##| ParitalMaps available on top of the BaseMap. See above for syntax on specifying multiple layers vs. layering | |||
##| Can be set to "" | |||
set( PartialMaps "hhkbpro2" ) | |||
#set( PartialMaps "hhkbpro2" ) | |||
@@ -55,46 +55,19 @@ void usb_keyboard_toHost() | |||
// Modifiers | |||
UEDATX = USBKeys_Modifiers; | |||
// LED Report spacer | |||
USBKeys_LEDs = 0; | |||
// Reserved Byte | |||
UEDATX = 0x00; | |||
// Normal Keys | |||
// Normal Keys, only supports 6 in Boot mode | |||
for ( i = 0; i < 6; i++) | |||
{ | |||
UEDATX = USBKeys_Array[i]; | |||
UEDATX = USBKeys_Keys[i]; | |||
} | |||
UEINTX = 0x3A; | |||
} | |||
// Sends NKRO keyboard out to host | |||
// NOTE: Make sure to match the descriptor | |||
void usb_nkrokeyboard_toHost() | |||
{ | |||
uint8_t i; | |||
// Modifiers | |||
/* | |||
UEDATX = 0x02; | |||
UEDATX = USBKeys_Modifiers; | |||
UEINTX = 0x3A; | |||
*/ | |||
// Media Keys | |||
UEDATX = 0x03; | |||
UEDATX = 0; | |||
UEINTX = 0x3A; | |||
// Normal Keys | |||
UEDATX = 0x04; | |||
for ( i = 0; i < 6; i++) | |||
{ | |||
UEDATX = USBKeys_Array[i]; | |||
} | |||
UEINTX = 0x3A; | |||
UEINTX = 0x00; | |||
} | |||
// send the contents of USBKeys_Array and USBKeys_Modifiers | |||
int8_t usb_keyboard_send() | |||
// send the contents of USBKeys_Keys and USBKeys_Modifiers | |||
inline void usb_keyboard_send() | |||
{ | |||
uint8_t intr_state, timeout; | |||
@@ -108,26 +81,88 @@ int8_t usb_keyboard_send() | |||
// has the USB gone offline? or exceeded timeout? | |||
if ( !usb_configuration || UDFNUML == timeout ) | |||
return -1; | |||
{ | |||
erro_print("USB Offline? Timeout?"); | |||
return; | |||
} | |||
// get ready to try checking again | |||
intr_state = SREG; | |||
cli(); | |||
// If not using Boot protocol, send NKRO | |||
UENUM = KEYBOARD_ENDPOINT; | |||
//UENUM = USBKeys_Protocol ? KEYBOARD_NKRO_ENDPOINT : KEYBOARD_ENDPOINT; | |||
UENUM = USBKeys_Protocol ? KEYBOARD_NKRO_ENDPOINT : KEYBOARD_ENDPOINT; | |||
} while ( !( UEINTX & (1 << RWAL) ) ); | |||
// Send normal keyboard interrupt packet(s) | |||
//switch ( USBKeys_Protocol ) | |||
//{ | |||
//} | |||
usb_keyboard_toHost(); | |||
switch ( USBKeys_Protocol ) | |||
{ | |||
// Send boot keyboard interrupt packet(s) | |||
case 0: | |||
usb_keyboard_toHost(); | |||
break; | |||
// Send NKRO keyboard interrupts packet(s) | |||
case 1: | |||
// Check modifiers | |||
if ( USBKeys_Changed & USBKeyChangeState_Modifiers ) | |||
{ | |||
UEDATX = 0x01; // ID | |||
UEDATX = USBKeys_Modifiers; | |||
UEINTX = 0; // Finished with ID | |||
USBKeys_Changed &= ~USBKeyChangeState_Modifiers; // Mark sent | |||
} | |||
// Check main key section | |||
else if ( USBKeys_Changed & USBKeyChangeState_MainKeys ) | |||
{ | |||
UEDATX = 0x03; // ID | |||
// 4-164 (first 20 bytes) | |||
for ( uint8_t byte = 0; byte < 20; byte++ ) | |||
UEDATX = USBKeys_Keys[ byte ]; | |||
UEINTX = 0; // Finished with ID | |||
USBKeys_Changed &= ~USBKeyChangeState_MainKeys; // Mark sent | |||
} | |||
// Check secondary key section | |||
else if ( USBKeys_Changed & USBKeyChangeState_SecondaryKeys ) | |||
{ | |||
UEDATX = 0x04; // ID | |||
// 176-221 (last 6 bytes) | |||
for ( uint8_t byte = 20; byte < 26; byte++ ) | |||
UEDATX = USBKeys_Keys[ byte ]; | |||
UEINTX = 0; // Finished with ID | |||
USBKeys_Changed &= ~USBKeyChangeState_SecondaryKeys; // Mark sent | |||
} | |||
// Check system control keys | |||
else if ( USBKeys_Changed & USBKeyChangeState_System ) | |||
{ | |||
UEDATX = 0x05; // ID | |||
UEDATX = USBKeys_SysCtrl; | |||
UEINTX = 0; // Finished with ID | |||
USBKeys_Changed &= ~USBKeyChangeState_System; // Mark sent | |||
} | |||
// Check consumer control keys | |||
else if ( USBKeys_Changed & USBKeyChangeState_Consumer ) | |||
{ | |||
UEDATX = 0x06; // ID | |||
UEDATX = (uint8_t)(USBKeys_ConsCtrl & 0x00FF); | |||
UEDATX = (uint8_t)(USBKeys_ConsCtrl >> 8); | |||
UEINTX = 0; // Finished with ID | |||
USBKeys_Changed &= ~USBKeyChangeState_Consumer; // Mark sent | |||
} | |||
break; | |||
} | |||
USBKeys_Idle_Count = 0; | |||
SREG = intr_state; | |||
return 0; | |||
} | |||
@@ -622,7 +657,13 @@ ISR( USB_GEN_vect ) | |||
// XXX TODO Is this even used? If so, when? -Jacob | |||
// From hasu's code, this section looks like it could fix the Mac SET_IDLE problem | |||
// Send normal keyboard interrupt packet(s) | |||
//usb_keyboard_toHost(); | |||
switch ( USBKeys_Protocol ) | |||
{ | |||
// Send boot keyboard interrupt packet(s) | |||
case 0: usb_keyboard_toHost(); break; | |||
// Send NKRO keyboard interrupts packet(s) | |||
//case 1: usb_nkrokeyboard_toHost(); break; // XXX Not valid anymore | |||
} | |||
print("IDLE"); | |||
} | |||
} | |||
@@ -673,7 +714,8 @@ ISR(USB_COM_vect) | |||
UENUM = 0; | |||
intbits = UEINTX; | |||
if (intbits & (1<<RXSTPI)) { | |||
if (intbits & (1<<RXSTPI)) | |||
{ | |||
bmRequestType = UEDATX; | |||
bRequest = UEDATX; | |||
wValue = UEDATX; | |||
@@ -770,8 +812,8 @@ ISR(USB_COM_vect) | |||
return; | |||
} | |||
//if ( wIndex == KEYBOARD_INTERFACE ) | |||
if ( wIndex == KEYBOARD_INTERFACE || wIndex == KEYBOARD_NKRO_INTERFACE ) | |||
if ( ( wIndex == KEYBOARD_INTERFACE && USBKeys_Protocol == 0 ) | |||
|| ( wIndex == KEYBOARD_NKRO_INTERFACE && USBKeys_Protocol == 1 ) ) | |||
{ | |||
if ( bmRequestType == 0xA1) | |||
{ | |||
@@ -779,10 +821,14 @@ ISR(USB_COM_vect) | |||
{ | |||
usb_wait_in_ready(); | |||
// XXX TODO Is this even used? If so, when? -Jacob | |||
// Send normal keyboard interrupt packet(s) | |||
usb_keyboard_toHost(); | |||
//print("GET REPORT"); | |||
switch ( USBKeys_Protocol ) | |||
{ | |||
// Send boot keyboard interrupt packet(s) | |||
case 0: usb_keyboard_toHost(); break; | |||
// Send NKRO keyboard interrupts packet(s) | |||
//case 1: usb_nkrokeyboard_toHost(); break; // XXX Not valid anymore | |||
} | |||
usb_send_in(); | |||
return; | |||
@@ -814,17 +860,19 @@ ISR(USB_COM_vect) | |||
} | |||
if ( bRequest == HID_SET_IDLE ) | |||
{ | |||
usb_wait_in_ready(); | |||
USBKeys_Idle_Config = (wValue >> 8); | |||
USBKeys_Idle_Count = 0; | |||
//usb_wait_in_ready(); | |||
usb_send_in(); | |||
print("HID IDLE"); | |||
return; | |||
} | |||
if ( bRequest == HID_SET_PROTOCOL ) | |||
{ | |||
usb_wait_in_ready(); | |||
USBKeys_Protocol = wValue; // 0 - Boot Mode, 1 - NKRO Mode | |||
//usb_wait_in_ready(); | |||
usb_send_in(); | |||
print("HID SET"); | |||
return; | |||
} | |||
} |
@@ -43,33 +43,32 @@ | |||
// ----- Function Declarations ----- | |||
// Basic USB Configuration | |||
void usb_init(void); // initialize everything | |||
uint8_t usb_configured(void); // is the USB port configured | |||
void usb_init(); // initialize everything | |||
uint8_t usb_configured(); // is the USB port configured | |||
// Keyboard HID Functions | |||
int8_t usb_keyboard_send(void); | |||
void usb_keyboard_send(); | |||
// Chip Level Functions | |||
void usb_device_reload(); // Enable firmware reflash mode | |||
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3"))); // Needed for software reset | |||
// USB Serial CDC Functions | |||
int16_t usb_serial_getchar(void); // receive a character (-1 if timeout/error) | |||
uint8_t usb_serial_available(void); // number of bytes in receive buffer | |||
void usb_serial_flush_input(void); // discard any buffered input | |||
int16_t usb_serial_getchar(); // receive a character (-1 if timeout/error) | |||
uint8_t usb_serial_available(); // number of bytes in receive buffer | |||
void usb_serial_flush_input(); // discard any buffered input | |||
// transmitting data | |||
int8_t usb_serial_putchar(uint8_t c); // transmit a character | |||
int8_t usb_serial_putchar_nowait(uint8_t c); // transmit a character, do not wait | |||
int8_t usb_serial_putchar(uint8_t c); // transmit a character | |||
int8_t usb_serial_putchar_nowait(uint8_t c); // transmit a character, do not wait | |||
int8_t usb_serial_write(const char *buffer, uint16_t size); // transmit a buffer | |||
void usb_serial_flush_output(void); // immediately transmit any buffered output | |||
void usb_serial_flush_output(); // immediately transmit any buffered output | |||
// serial parameters | |||
uint32_t usb_serial_get_baud(void); // get the baud rate | |||
uint8_t usb_serial_get_stopbits(void); // get the number of stop bits | |||
uint8_t usb_serial_get_paritytype(void);// get the parity type | |||
uint8_t usb_serial_get_numbits(void); // get the number of data bits | |||
uint8_t usb_serial_get_control(void); // get the RTS and DTR signal state | |||
uint32_t usb_serial_get_baud(); // get the baud rate | |||
uint8_t usb_serial_get_stopbits(); // get the number of stop bits | |||
uint8_t usb_serial_get_paritytype(); // get the parity type | |||
uint8_t usb_serial_get_numbits(); // get the number of data bits | |||
uint8_t usb_serial_get_control(); // get the RTS and DTR signal state | |||
int8_t usb_serial_set_control(uint8_t signals); // set DSR, DCD, RI, etc | |||
@@ -201,7 +200,7 @@ int8_t usb_serial_set_control(uint8_t signals); // set DSR, DCD, RI, etc | |||
#define KEYBOARD_NKRO_INTERFACE 0 | |||
#define KEYBOARD_NKRO_ENDPOINT 1 | |||
#define KEYBOARD_NKRO_SIZE 16 | |||
#define KEYBOARD_NKRO_SIZE 128 | |||
#define KEYBOARD_NKRO_HID_BUFFER EP_DOUBLE_BUFFER | |||
#define KEYBOARD_INTERFACE 1 | |||
@@ -288,22 +287,27 @@ static const uint8_t PROGMEM keyboard_hid_report_desc[] = { | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), | |||
// Reserved Byte | |||
0x75, 0x08, // Report Size (8), | |||
0x95, 0x01, // Report Count (1), | |||
0x81, 0x03, // Output (Constant), | |||
// LED Report | |||
0x95, 0x05, // Report Count (5), | |||
0x75, 0x01, // Report Size (1), | |||
0x95, 0x05, // Report Count (5), | |||
0x05, 0x08, // Usage Page (LEDs), | |||
0x19, 0x01, // Usage Minimum (1), | |||
0x29, 0x05, // Usage Maximum (5), | |||
0x91, 0x02, // Output (Data, Variable, Absolute), | |||
// LED Report Padding | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x03, // Report Size (3), | |||
0x95, 0x01, // Report Count (1), | |||
0x91, 0x03, // Output (Constant), | |||
// Normal Keys | |||
0x95, 0x06, // Report Count (6), | |||
0x75, 0x08, // Report Size (8), | |||
0x95, 0x06, // Report Count (6), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x7F, // Logical Maximum(104), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
@@ -315,95 +319,115 @@ static const uint8_t PROGMEM keyboard_hid_report_desc[] = { | |||
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 | |||
static const uint8_t PROGMEM keyboard_nkro_hid_report_desc[] = { | |||
/* | |||
// System Control Collection | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x80, // Usage (System Control), | |||
0xA1, 0x01, // Collection (Application), | |||
0x85, 0x01, // Report ID (1), | |||
0x95, 0x06, // Report Count (6), | |||
0x75, 0x08, // Report Size (8), | |||
0x19, 0x81, // Usage Minimum (129), | |||
0x29, 0x83, // Usage Maximum (131), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), | |||
0x95, 0x05, // Report Count (5), | |||
0x75, 0x01, // Report Size (1), | |||
0x81, 0x03, // Input (Constant, Data, Variable, Absolute), | |||
0xc0, 0x00, // End Collection - System Control | |||
*/ | |||
// Keyboard Collection | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x06, // Usage (Keyboard), | |||
0xA1, 0x01, // Collection (Application) - Keyboard, | |||
// Modifier Byte | |||
0x85, 0x01, // Report ID (1), | |||
0x75, 0x01, // Report Size (1), | |||
0x85, 0x02, // Report ID (2), | |||
0x95, 0x08, // Report Count (8), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0xE0, // Usage Minimum (224), | |||
0x29, 0xE7, // Usage Maximum (231), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), | |||
// Media Keys | |||
0x95, 0x08, // Report Count (8), | |||
0x85, 0x03, // Report ID (3), | |||
0x75, 0x01, // Report Size (1), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x05, 0x0C, // Usage Page (Consumer), | |||
0x09, 0xE9, // Usage (Volume Increment), | |||
0x09, 0xEA, // Usage (Volume Decrement), | |||
0x09, 0xE2, // Usage (Mute), | |||
0x09, 0xCD, // Usage (Play/Pause), | |||
0x09, 0xB5, // Usage (Scan Next Track), | |||
0x09, 0xB6, // Usage (Scan Previous Track), | |||
0x09, 0xB7, // Usage (Stop), | |||
0x09, 0xB8, // Usage (Eject), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), | |||
// LED Report | |||
0x95, 0x05, // Report Count (5), | |||
0x85, 0x01, // Report ID (1), | |||
0x85, 0x02, // Report ID (2), | |||
0x75, 0x01, // Report Size (1), | |||
0x95, 0x05, // Report Count (5), | |||
0x05, 0x08, // Usage Page (LEDs), | |||
0x19, 0x01, // Usage Minimum (1), | |||
0x29, 0x05, // Usage Maximum (5), | |||
0x91, 0x02, // Output (Data, Variable, Absolute), | |||
// LED Report Padding | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x03, // Report Size (3), | |||
0x95, 0x01, // Report Count (1), | |||
0x91, 0x03, // Output (Constant), | |||
/* | |||
// Misc Keys | |||
0x95, 0x06, // Report Count (6), | |||
// Normal Keys - Using an NKRO Bitmap | |||
// | |||
// NOTES: | |||
// Supports all keys defined by the spec, except 1-3 which define error events | |||
// and 0 which is "no keys pressed" | |||
// See http://www.usb.org/developers/hidpage/Hut1_12v2.pdf Chapter 10 | |||
// Or Macros/PartialMap/usb_hid.h | |||
// | |||
// 165-175 are reserved/unused as well as 222-223 and 232-65535 | |||
// 224-231 are used for modifiers (see above) | |||
// | |||
// Packing of bitmaps are as follows: | |||
// 4-164 : 20 bytes + 1 Report ID byte (0x04-0xA4) | |||
// 176-221 : 6 bytes + 1 Report ID byte (0xB0-0xDD) (45 bits + 3 padding bits for 6 bytes total) | |||
// | |||
// 4-164 (20 bytes/160 bits) | |||
0x85, 0x03, // Report ID (3), | |||
0x75, 0x01, // Report Size (1), | |||
0x95, 0xA0, // Report Count (160), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x7F, // Logical Maximum(104), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0x00, // Usage Minimum (0), | |||
0x29, 0x7F, // Usage Maximum (104), | |||
0x81, 0x00, // Input (Data, Array), | |||
*/ | |||
0x19, 0x04, // Usage Minimum (4), | |||
0x29, 0xA4, // Usage Maximum (164), | |||
0x81, 0x02, // Input (Data, Variable, Absolute, Bitfield), | |||
// Normal Keys | |||
0x95, 0x06, // Report Count (6), | |||
// 176-221 (45 bits) | |||
0x85, 0x04, // Report ID (4), | |||
0x75, 0x08, // Report Size (8), | |||
0x75, 0x01, // Report Size (1), | |||
0x95, 0x2D, // Report Count (45), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x7F, // Logical Maximum(104), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0x00, // Usage Minimum (0), | |||
0x29, 0x7F, // Usage Maximum (104), | |||
0x81, 0x00, // Input (Data, Array), | |||
0x19, 0xB0, // Usage Minimum (176), | |||
0x29, 0xDD, // Usage Maximum (221), | |||
0x81, 0x02, // Input (Data, Variable, Absolute, Bitfield), | |||
// 176-221 Padding (3 bits) | |||
0x75, 0x03, // Report Size (3), | |||
0x95, 0x01, // Report Count (1), | |||
0x81, 0x03, // Input (Constant), | |||
0xc0, // End Collection - Keyboard | |||
// System Control Collection | |||
// | |||
// NOTES: | |||
// Not bothering with NKRO for this table. If there's need, I can implement it. -HaaTa | |||
// Using a 1KRO scheme | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x80, // Usage (System Control), | |||
0xA1, 0x01, // Collection (Application), | |||
0x85, 0x05, // Report ID (5), | |||
0x75, 0x08, // Report Size (8), | |||
0x95, 0x01, // Report Count (1), | |||
0x16, 0x81, 0x00, // Logical Minimum (129), | |||
0x26, 0xB7, 0x00, // Logical Maximum (183), | |||
0x19, 0x81, // Usage Minimum (129), | |||
0x29, 0xB7, // Usage Maximum (183), | |||
0x81, 0x00, // Input (Data, Array), | |||
0xc0, // End Collection - System Control | |||
// Consumer Control Collection - Media Keys | |||
// | |||
// NOTES: | |||
// Not bothering with NKRO for this table. If there's a need, I can implement it. -HaaTa | |||
// Using a 1KRO scheme | |||
0x05, 0x0c, // Usage Page (Consumer), | |||
0x09, 0x01, // Usage (Consumer Control), | |||
0xA1, 0x01, // Collection (Application), | |||
0x85, 0x06, // Report ID (6), | |||
0x75, 0x10, // Report Size (16), | |||
0x95, 0x01, // Report Count (1), | |||
0x16, 0x20, 0x00, // Logical Minimum (32), | |||
0x26, 0x9C, 0x02, // Logical Maximum (668), | |||
0x05, 0x0C, // Usage Page (Consumer), | |||
0x19, 0x20, // Usage Minimum (32), | |||
0x2A, 0x9C, 0x02, // Usage Maximum (668), | |||
0x81, 0x00, // Input (Data, Array), | |||
0xc0, // End Collection - Consumer Control | |||
}; | |||
// <Configuration> + <Keyboard HID> + <NKRO Keyboard HID> + <Serial CDC> | |||
@@ -442,7 +466,7 @@ static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
9, // bLength | |||
0x21, // bDescriptorType | |||
0x11, 0x01, // bcdHID | |||
33, // bCountryCode - Defaulting to US for now. TODO | |||
0, // bCountryCode - Setting to 0/Undefined | |||
1, // bNumDescriptors | |||
0x22, // bDescriptorType | |||
LSB(sizeof(keyboard_hid_report_desc)), // wDescriptorLength | |||
@@ -473,7 +497,7 @@ static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
9, // bLength | |||
0x21, // bDescriptorType | |||
0x11, 0x01, // bcdHID | |||
33, // bCountryCode - Defaulting to US for now. TODO | |||
33, // bCountryCode - Setting to 0/Undefined | |||
1, // bNumDescriptors | |||
0x22, // bDescriptorType | |||
// wDescriptorLength |
@@ -1,12 +1,14 @@ | |||
Name = pjrcUSBCapabilities; | |||
Version = 0.1; | |||
Version = 0.2; | |||
Author = "HaaTa (Jacob Alexander) 2014"; | |||
KLL = 0.3; | |||
# Modified Date | |||
Date = 2014-09-14; | |||
Date = 2014-09-20; | |||
# Capabilties available to the pjrcUSB output module | |||
usbKeyOut => Output_usbCodeSend_capability( usbCode : 1 ); | |||
consCtrlOut => Output_consCtrlSend_capability( consCode : 2 ); | |||
sysCtrlOut => Output_sysCtrlSend_capability( sysCode : 1 ); | |||
usbKeyOut => Output_usbCodeSend_capability( usbCode : 1 ); | |||
@@ -44,6 +44,20 @@ | |||
// ----- Macros ----- | |||
// Used to build a bitmap lookup table from a byte addressable array | |||
#define byteLookup( byte ) case (( byte ) * ( 8 )): bytePosition = byte; byteShift = 0; break; \ | |||
case (( byte ) * ( 8 ) + ( 1 )): bytePosition = byte; byteShift = 1; break; \ | |||
case (( byte ) * ( 8 ) + ( 2 )): bytePosition = byte; byteShift = 2; break; \ | |||
case (( byte ) * ( 8 ) + ( 3 )): bytePosition = byte; byteShift = 3; break; \ | |||
case (( byte ) * ( 8 ) + ( 4 )): bytePosition = byte; byteShift = 4; break; \ | |||
case (( byte ) * ( 8 ) + ( 5 )): bytePosition = byte; byteShift = 5; break; \ | |||
case (( byte ) * ( 8 ) + ( 6 )): bytePosition = byte; byteShift = 6; break; \ | |||
case (( byte ) * ( 8 ) + ( 7 )): bytePosition = byte; byteShift = 7; break | |||
// ----- Function Declarations ----- | |||
void cliFunc_kbdProtocol( char* args ); | |||
@@ -53,6 +67,7 @@ void cliFunc_setKeys ( char* args ); | |||
void cliFunc_setMod ( char* args ); | |||
// ----- Variables ----- | |||
// Output Module command dictionary | |||
@@ -70,79 +85,272 @@ const CLIDictItem outputCLIDict[] = { | |||
// 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 USBKeys_Modifiers = 0; | |||
uint8_t USBKeys_ModifiersCLI = 0; // Separate CLI send buffer | |||
uint8_t USBKeys_Modifiers = 0; | |||
uint8_t USBKeys_ModifiersCLI = 0; // Separate CLI send buffer | |||
// Currently pressed keys, max is defined by USB_MAX_KEY_SEND | |||
uint8_t USBKeys_Array [USB_MAX_KEY_SEND]; | |||
uint8_t USBKeys_ArrayCLI[USB_MAX_KEY_SEND]; // Separate CLI send buffer | |||
uint8_t USBKeys_Keys [USB_NKRO_BITFIELD_SIZE_KEYS]; | |||
uint8_t USBKeys_KeysCLI[USB_NKRO_BITFIELD_SIZE_KEYS]; // Separate CLI send buffer | |||
// System Control and Consumer Control 1KRO containers | |||
uint8_t USBKeys_SysCtrl; | |||
uint16_t USBKeys_ConsCtrl; | |||
// The number of keys sent to the usb in the array | |||
uint8_t USBKeys_Sent = 0; | |||
uint8_t USBKeys_SentCLI = 0; | |||
uint8_t USBKeys_Sent = 0; | |||
uint8_t USBKeys_SentCLI = 0; | |||
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana | |||
volatile uint8_t USBKeys_LEDs = 0; | |||
volatile uint8_t USBKeys_LEDs = 0; | |||
// Protocol setting from the host. | |||
// 0 - Boot Mode (Default, until set by the host) | |||
// 1 - NKRO Mode | |||
volatile uint8_t USBKeys_Protocol = 1; | |||
// 0 - Boot Mode | |||
// 1 - NKRO Mode (Default, unless set by a BIOS or boot interface) | |||
volatile uint8_t USBKeys_Protocol = 1; | |||
// Indicate if USB should send update | |||
// OS only needs update if there has been a change in state | |||
uint8_t USBKeys_Changed = 0; | |||
USBKeyChangeState USBKeys_Changed = USBKeyChangeState_None; | |||
// the idle configuration, how often we send the report to the | |||
// host (ms * 4) even when it hasn't changed | |||
uint8_t USBKeys_Idle_Config = 125; | |||
uint8_t USBKeys_Idle_Config = 125; | |||
// count until idle timeout | |||
uint8_t USBKeys_Idle_Count = 0; | |||
uint8_t USBKeys_Idle_Count = 0; | |||
// ----- Capabilities ----- | |||
// Adds a single USB Code to the USB Output buffer | |||
// Argument #1: USB Code | |||
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
// Sends a Consumer Control code to the USB Output buffer | |||
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
print("Output_usbCodeSend(usbCode)"); | |||
print("Output_consCtrlSend(consCode)"); | |||
return; | |||
} | |||
// Not implemented in Boot Mode | |||
if ( USBKeys_Protocol == 0 ) | |||
{ | |||
warn_print("Consumer Control is not implemented for Boot Mode"); | |||
return; | |||
} | |||
// TODO Analog inputs | |||
// Only indicate USB has changed if either a press or release has occured | |||
if ( state == 0x01 || state == 0x03 ) | |||
USBKeys_Changed = 1; | |||
USBKeys_Changed |= USBKeyChangeState_Consumer; | |||
// Only send keypresses if press or hold state | |||
if ( stateType == 0x00 && state == 0x03 ) // Release state | |||
return; | |||
// Get the keycode from arguments | |||
uint8_t key = args[0]; | |||
// Set consumer control code | |||
USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | |||
} | |||
// Set the modifier bit if this key is a modifier | |||
if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) | |||
// Sends a System Control code to the USB Output buffer | |||
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
USBKeys_Modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 | |||
print("Output_sysCtrlSend(sysCode)"); | |||
return; | |||
} | |||
// Normal USB Code | |||
else | |||
// Not implemented in Boot Mode | |||
if ( USBKeys_Protocol == 0 ) | |||
{ | |||
// USB Key limit reached (important for Boot Mode) | |||
if ( USBKeys_Sent >= USBKeys_MaxSize ) | |||
{ | |||
warn_msg("USB Key limit reached"); | |||
errorLED( 1 ); | |||
warn_print("System Control is not implemented for Boot Mode"); | |||
return; | |||
} | |||
// TODO Analog inputs | |||
// Only indicate USB has changed if either a press or release has occured | |||
if ( state == 0x01 || state == 0x03 ) | |||
USBKeys_Changed |= USBKeyChangeState_System; | |||
// Only send keypresses if press or hold state | |||
if ( stateType == 0x00 && state == 0x03 ) // Release state | |||
return; | |||
// Set system control code | |||
USBKeys_SysCtrl = args[0]; | |||
} | |||
// Adds a single USB Code to the USB Output buffer | |||
// Argument #1: USB Code | |||
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
print("Output_usbCodeSend(usbCode)"); | |||
return; | |||
} | |||
// Depending on which mode the keyboard is in the USB needs Press/Hold/Release events | |||
uint8_t keyPress = 0; // Default to key release, only used for NKRO | |||
switch ( USBKeys_Protocol ) | |||
{ | |||
case 0: // Boot Mode | |||
// TODO Analog inputs | |||
// Only indicate USB has changed if either a press or release has occured | |||
if ( state == 0x01 || state == 0x03 ) | |||
USBKeys_Changed = USBKeyChangeState_MainKeys; | |||
// Only send keypresses if press or hold state | |||
if ( stateType == 0x00 && state == 0x03 ) // Release state | |||
return; | |||
break; | |||
case 1: // NKRO Mode | |||
// Only send press and release events | |||
if ( stateType == 0x00 && state == 0x02 ) // Hold state | |||
return; | |||
// Determine if setting or unsetting the bitfield (press == set) | |||
if ( stateType == 0x00 && state == 0x01 ) // Press state | |||
keyPress = 1; | |||
break; | |||
} | |||
// Get the keycode from arguments | |||
uint8_t key = args[0]; | |||
// Depending on which mode the keyboard is in, USBKeys_Keys array is used differently | |||
// Boot mode - Maximum of 6 byte codes | |||
// NKRO mode - Each bit of the 26 byte corresponds to a key | |||
// Bits 0 - 160 (first 20 bytes) correspond to USB Codes 4 - 164 | |||
// Bits 161 - 205 (last 6 bytes) correspond to USB Codes 176 - 221 | |||
// Bits 206 - 208 (last byte) correspond to the 3 padded bits in USB (unused) | |||
uint8_t bytePosition = 0; | |||
uint8_t byteShift = 0; | |||
switch ( USBKeys_Protocol ) | |||
{ | |||
case 0: // Boot Mode | |||
// Set the modifier bit if this key is a modifier | |||
if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) | |||
{ | |||
USBKeys_Modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 | |||
} | |||
// Normal USB Code | |||
else | |||
{ | |||
// USB Key limit reached | |||
if ( USBKeys_Sent >= USB_BOOT_MAX_KEYS ) | |||
{ | |||
warn_print("USB Key limit reached"); | |||
return; | |||
} | |||
// Make sure key is within the USB HID range | |||
if ( key <= 104 ) | |||
{ | |||
USBKeys_Keys[USBKeys_Sent++] = key; | |||
} | |||
// Invalid key | |||
else | |||
{ | |||
warn_msg("USB Code above 104/0x68 in Boot Mode: "); | |||
printHex( key ); | |||
print( NL ); | |||
} | |||
} | |||
break; | |||
case 1: // NKRO Mode | |||
// Set the modifier bit if this key is a modifier | |||
if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) | |||
{ | |||
if ( keyPress ) | |||
{ | |||
USBKeys_Modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 | |||
} | |||
else // Release | |||
{ | |||
USBKeys_Modifiers &= ~(1 << (key ^ 0xE0)); // Left shift 1 by key XOR 0xE0 | |||
} | |||
USBKeys_Changed |= USBKeyChangeState_Modifiers; | |||
break; | |||
} | |||
// First 20 bytes | |||
else if ( key >= 4 && key <= 164 ) | |||
{ | |||
// Lookup (otherwise division or multiple checks are needed to do alignment) | |||
uint8_t keyPos = key - 4; // Starting position in array | |||
switch ( keyPos ) | |||
{ | |||
byteLookup( 0 ); | |||
byteLookup( 1 ); | |||
byteLookup( 2 ); | |||
byteLookup( 3 ); | |||
byteLookup( 4 ); | |||
byteLookup( 5 ); | |||
byteLookup( 6 ); | |||
byteLookup( 7 ); | |||
byteLookup( 8 ); | |||
byteLookup( 9 ); | |||
byteLookup( 10 ); | |||
byteLookup( 11 ); | |||
byteLookup( 12 ); | |||
byteLookup( 13 ); | |||
byteLookup( 14 ); | |||
byteLookup( 15 ); | |||
byteLookup( 16 ); | |||
byteLookup( 17 ); | |||
byteLookup( 18 ); | |||
byteLookup( 19 ); | |||
} | |||
USBKeys_Changed |= USBKeyChangeState_MainKeys; | |||
} | |||
// Last 6 bytes | |||
else if ( key >= 176 && key <= 221 ) | |||
{ | |||
// Lookup (otherwise division or multiple checks are needed to do alignment) | |||
uint8_t keyPos = key - 176; // Starting position in array | |||
switch ( keyPos ) | |||
{ | |||
byteLookup( 20 ); | |||
byteLookup( 21 ); | |||
byteLookup( 22 ); | |||
byteLookup( 23 ); | |||
byteLookup( 24 ); | |||
byteLookup( 25 ); | |||
} | |||
USBKeys_Changed |= USBKeyChangeState_SecondaryKeys; | |||
} | |||
// Invalid key | |||
else | |||
{ | |||
warn_msg("USB Code not within 4-164 (0x4-0xA4) or 176-221 (0xB0-0xDD) NKRO Mode: "); | |||
printHex( key ); | |||
print( NL ); | |||
break; | |||
} | |||
// Set/Unset | |||
if ( keyPress ) | |||
{ | |||
USBKeys_Keys[bytePosition] |= (1 << byteShift); | |||
USBKeys_Sent++; | |||
} | |||
else // Release | |||
{ | |||
USBKeys_Keys[bytePosition] &= ~(1 << byteShift); | |||
USBKeys_Sent++; | |||
} | |||
USBKeys_Array[USBKeys_Sent++] = key; | |||
break; | |||
} | |||
} | |||
@@ -154,23 +362,22 @@ void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *a | |||
inline void Output_setup() | |||
{ | |||
// 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. | |||
// This will hang forever if USB does not initialize | |||
usb_init(); | |||
while ( !usb_configured() ) /* wait */ ; | |||
while ( !usb_configured() ); | |||
// Register USB Output CLI dictionary | |||
CLI_registerDictionary( outputCLIDict, outputCLIDictName ); | |||
// Wait an extra second for the PC's operating system to load drivers | |||
// and do whatever it does to actually be ready for input | |||
//_delay_ms(1000); // TODO (is this actually necessary?) | |||
// Zero out USBKeys_Keys array | |||
for ( uint8_t c = 0; c < USB_NKRO_BITFIELD_SIZE_KEYS; c++ ) | |||
USBKeys_Keys[ c ] = 0; | |||
} | |||
// USB Data Send | |||
inline void Output_send(void) | |||
inline void Output_send() | |||
{ | |||
// Don't send update if USB has not changed | |||
if ( !USBKeys_Changed ) | |||
@@ -181,21 +388,31 @@ inline void Output_send(void) | |||
return; | |||
} | |||
USBKeys_Changed = 0; | |||
// TODO undo potentially old keys | |||
for ( uint8_t c = USBKeys_Sent; c < USBKeys_MaxSize; c++ ) | |||
USBKeys_Array[c] = 0; | |||
// Boot Mode Only, unset stale keys | |||
if ( USBKeys_Protocol == 0 ) | |||
for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ ) | |||
USBKeys_Keys[c] = 0; | |||
// Send keypresses | |||
usb_keyboard_send(); | |||
while ( USBKeys_Changed ) | |||
usb_keyboard_send(); | |||
// Clear modifiers and keys | |||
USBKeys_Modifiers = 0; | |||
USBKeys_Sent = 0; | |||
USBKeys_Changed = USBKeyChangeState_None; | |||
// Signal Scan Module we are finished | |||
Scan_finishedWithOutput( USBKeys_Sent <= USBKeys_MaxSize ? USBKeys_Sent : USBKeys_MaxSize ); | |||
switch ( USBKeys_Protocol ) | |||
{ | |||
case 0: // Boot Mode | |||
Scan_finishedWithOutput( USBKeys_Sent <= USB_BOOT_MAX_KEYS ? USBKeys_Sent : USB_BOOT_MAX_KEYS ); | |||
break; | |||
case 1: // NKRO Mode | |||
Scan_finishedWithOutput( USBKeys_Sent ); | |||
break; | |||
} | |||
} | |||
@@ -271,10 +488,11 @@ void cliFunc_readLEDs( char* args ) | |||
void cliFunc_sendKeys( char* args ) | |||
{ | |||
// Copy USBKeys_ArrayCLI to USBKeys_Array | |||
// Copy USBKeys_KeysCLI to USBKeys_Keys | |||
for ( uint8_t key = 0; key < USBKeys_SentCLI; ++key ) | |||
{ | |||
USBKeys_Array[key] = USBKeys_ArrayCLI[key]; | |||
// TODO | |||
//USBKeys_Keys[key] = USBKeys_KeysCLI[key]; | |||
} | |||
USBKeys_Sent = USBKeys_SentCLI; | |||
@@ -290,7 +508,7 @@ void cliFunc_setKeys( char* args ) | |||
char* arg2Ptr = args; | |||
// Parse up to USBKeys_MaxSize args (whichever is least) | |||
for ( USBKeys_SentCLI = 0; USBKeys_SentCLI < USBKeys_MaxSize; ++USBKeys_SentCLI ) | |||
for ( USBKeys_SentCLI = 0; USBKeys_SentCLI < USB_BOOT_MAX_KEYS; ++USBKeys_SentCLI ) | |||
{ | |||
curArgs = arg2Ptr; | |||
CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr ); | |||
@@ -300,7 +518,8 @@ void cliFunc_setKeys( char* args ) | |||
break; | |||
// Add the USB code to be sent | |||
USBKeys_ArrayCLI[USBKeys_SentCLI] = numToInt( arg1Ptr ); | |||
// TODO | |||
//USBKeys_KeysCLI[USBKeys_SentCLI] = numToInt( arg1Ptr ); | |||
} | |||
} | |||
@@ -34,8 +34,25 @@ | |||
// ----- Defines ----- | |||
// Indicator for other modules through USBKeys_MaxSize for how capable the USB module is when sending large number of keypresses | |||
#define USB_MAX_KEY_SEND 6 | |||
// Max size of key buffer needed for NKRO | |||
// Boot mode uses only the first 6 bytes | |||
#define USB_NKRO_BITFIELD_SIZE_KEYS 26 | |||
#define USB_BOOT_MAX_KEYS 6 | |||
// ----- Enumerations ----- | |||
// USB NKRO state transitions (indicates which Report ID's need refreshing) | |||
// Boot mode just checks if any keys were changed (as everything is sent every time) | |||
typedef enum USBKeyChangeState { | |||
USBKeyChangeState_None = 0x00, | |||
USBKeyChangeState_Modifiers = 0x01, | |||
USBKeyChangeState_MainKeys = 0x02, | |||
USBKeyChangeState_SecondaryKeys = 0x04, | |||
USBKeyChangeState_System = 0x08, | |||
USBKeyChangeState_Consumer = 0x10, | |||
} USBKeyChangeState; | |||
@@ -43,23 +60,28 @@ | |||
// Variables used to communciate to the output module | |||
// XXX Even if the output module is not USB, this is internally understood keymapping scheme | |||
extern uint8_t USBKeys_Modifiers; | |||
extern uint8_t USBKeys_Array[USB_MAX_KEY_SEND]; | |||
extern uint8_t USBKeys_Sent; | |||
extern volatile uint8_t USBKeys_LEDs; | |||
extern uint8_t USBKeys_Changed; | |||
extern uint8_t USBKeys_Modifiers; | |||
extern uint8_t USBKeys_Keys[USB_NKRO_BITFIELD_SIZE_KEYS]; | |||
extern uint8_t USBKeys_Sent; | |||
extern volatile uint8_t USBKeys_LEDs; | |||
extern uint8_t USBKeys_SysCtrl; // 1KRO container for System Control HID table | |||
extern uint16_t USBKeys_ConsCtrl; // 1KRO container for Consumer Control HID table | |||
static const uint8_t USBKeys_MaxSize = USB_MAX_KEY_SEND; | |||
extern volatile uint8_t USBKeys_Protocol; // 0 - Boot Mode, 1 - NKRO Mode | |||
extern volatile uint8_t USBKeys_Protocol; // 0 - Boot Mode, 1 - NKRO Mode | |||
// Misc variables (XXX Some are only properly utilized using AVR) | |||
extern uint8_t USBKeys_Idle_Config; | |||
extern uint8_t USBKeys_Idle_Count; | |||
extern uint8_t USBKeys_Idle_Config; | |||
extern uint8_t USBKeys_Idle_Count; | |||
extern USBKeyChangeState USBKeys_Changed; | |||
// ----- Capabilities ----- | |||
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | |||
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | |||
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ); | |||