diff --git a/teensy/core_id.h b/teensy/core_id.h index 583dfa43c..51ca61593 100644 --- a/teensy/core_id.h +++ b/teensy/core_id.h @@ -4,6 +4,8 @@ #include "../usb_serial/core_id.h" #elif defined(USB_HID) #include "../usb_hid/core_id.h" +#elif defined(USB_MIX_AND_MATCH) +#include "../usb_mix_and_match/core_id.h" #elif defined(USB_SERIAL_HID) #include "../usb_serial_hid/core_id.h" #elif defined(USB_DISK) || defined(USB_DISK_SDFLASH) diff --git a/teensy/usb.c b/teensy/usb.c index ca9dcbce3..d246c3f54 100644 --- a/teensy/usb.c +++ b/teensy/usb.c @@ -4,6 +4,8 @@ #include "../usb_hid/usb.c" #elif defined(USB_SERIAL_HID) #include "../usb_serial_hid/usb.c" +#elif defined(USB_MIX_AND_MATCH) +#include "../usb_mix_and_match/usb.c" #elif defined(USB_DISK) || defined(USB_DISK_SDFLASH) #include "../usb_disk/usb.c" #elif defined(USB_MIDI) diff --git a/teensy/usb_api.cpp b/teensy/usb_api.cpp index ea7249a4a..47857aaf1 100644 --- a/teensy/usb_api.cpp +++ b/teensy/usb_api.cpp @@ -4,6 +4,8 @@ #include "../usb_hid/usb_api.cpp" #elif defined(USB_SERIAL_HID) #include "../usb_serial_hid/usb_api.cpp" +#elif defined(USB_MIX_AND_MATCH) +#include "../usb_mix_and_match/usb_api.cpp" #elif defined(USB_DISK) || defined(USB_DISK_SDFLASH) #include "../usb_disk/usb_api.cpp" #elif defined(USB_MIDI) diff --git a/teensy/usb_api.h b/teensy/usb_api.h index 818094f14..64b7853b4 100644 --- a/teensy/usb_api.h +++ b/teensy/usb_api.h @@ -4,6 +4,8 @@ #include "../usb_hid/usb_api.h" #elif defined(USB_SERIAL_HID) #include "../usb_serial_hid/usb_api.h" +#elif defined(USB_MIX_AND_MATCH) +#include "../usb_mix_and_match/usb_api.h" #elif defined(USB_DISK) || defined(USB_DISK_SDFLASH) #include "../usb_disk/usb_api.h" #elif defined(USB_MIDI) diff --git a/teensy/usb_private.h b/teensy/usb_private.h index da6809ddb..ae72a8a0e 100644 --- a/teensy/usb_private.h +++ b/teensy/usb_private.h @@ -4,6 +4,8 @@ #include "../usb_hid/usb_private.h" #elif defined(USB_SERIAL_HID) #include "../usb_serial_hid/usb_private.h" +#elif defined(USB_MIX_AND_MATCH) +#include "../usb_mix_and_match/usb_private.h" #elif defined(USB_DISK) || defined(USB_DISK_SDFLASH) #include "../usb_disk/usb_private.h" #elif defined(USB_MIDI) diff --git a/usb_mix_and_match/core_id.h b/usb_mix_and_match/core_id.h new file mode 100644 index 000000000..81b3543c5 --- /dev/null +++ b/usb_mix_and_match/core_id.h @@ -0,0 +1,3 @@ +#pragma once + +#include "defines.h" \ No newline at end of file diff --git a/usb_mix_and_match/defines.h b/usb_mix_and_match/defines.h new file mode 100644 index 000000000..cf78d7a15 --- /dev/null +++ b/usb_mix_and_match/defines.h @@ -0,0 +1,41 @@ +#pragma once + +#ifdef USB_MAM_SERIAL_1 +#define CORE_TEENSY_SERIAL +#endif + +#if defined USB_MAM_KEYBOARD_1 || defined USB_MAM_MOUSE_1 || defined USB_MAM_JOYSTICK_1 +#define CORE_TEENSY_HID +#endif + +#ifdef USB_MAM_KEYBOARD_1 +#define CORE_TEENSY_KEYBOARD +#endif + +#ifdef USB_MAM_JOYSTICK_1 +#define CORE_TEENSY_JOYSTICK +#endif + +#ifdef USB_MAM_MULTIMEDIA_1 +#define CORE_TEENSY_MULTIMEDIA +#endif + +#ifdef USB_MAM_MOUSE_1 +#define CORE_TEENSY_MOUSE +#endif + +#ifdef USB_MAM_DEBUG_1 +#define CORE_TEENSY_DEBUG +#endif + +#ifdef CORE_TEENSY_SERIAL +#ifdef CORE_TEENSY_DEBUG +#error CORE_TEENSY_SERIAL and CORE_TEENSY_DEBUG must not be defined at the same time +#endif +#endif + +#ifdef CORE_TEENSY_MULTIMEDIA +#ifndef CORE_TEENSY_KEYBOARD +#error CORE_TEENSY_MULTIMEDIA requires CORE_TEENSY_KEYBOARD to be defined too +#endif +#endif \ No newline at end of file diff --git a/usb_mix_and_match/usb.c b/usb_mix_and_match/usb.c new file mode 100644 index 000000000..a53192358 --- /dev/null +++ b/usb_mix_and_match/usb.c @@ -0,0 +1,1249 @@ +/* USB Serial for Teensy USB Development Board + * http://www.pjrc.com/teensy/ + * Copyright (c) 2008 PJRC.COM, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This file is used only for Teensy 2.0 and Teensy++ 2.0 + +#include "usb_common.h" +#include "usb_private.h" + + +/************************************************************************** + * + * Endpoint Buffer Configuration + * + **************************************************************************/ + + +static const uint8_t PROGMEM endpoint_config_table[] = { +#ifdef CORE_TEENSY_DEBUG + EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, + EP_TYPE_INTERRUPT_OUT, EP_SIZE(DEBUG_RX_SIZE) | DEBUG_RX_BUFFER, +#endif +#ifdef CORE_TEENSY_KEYBOARD + EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, +#endif +#ifdef CORE_TEENSY_SERIAL + EP_TYPE_INTERRUPT_IN, EP_SIZE(CDC_ACM_SIZE) | CDC_ACM_BUFFER, + EP_TYPE_BULK_OUT, EP_SIZE(CDC_RX_SIZE) | CDC_RX_BUFFER, + EP_TYPE_BULK_IN, EP_SIZE(CDC_TX_SIZE) | CDC_TX_BUFFER, +#endif +#ifdef CORE_TEENSY_MOUSE + EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, +#endif +#ifdef CORE_TEENSY_JOYSTICK + EP_TYPE_INTERRUPT_IN, EP_SIZE(JOYSTICK_SIZE) | JOYSTICK_BUFFER, +#endif +#ifdef CORE_TEENSY_MULTIMEDIA + EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYMEDIA_SIZE) | KEYMEDIA_BUFFER, +#endif +}; + + +/************************************************************************** + * + * Descriptor Data + * + **************************************************************************/ + +// Descriptors are the data that your computer reads when it auto-detects +// this USB device (called "enumeration" in USB lingo). The most commonly +// changed items are editable at the top of this file. Changing things +// in here should only be done by those who've read chapter 9 of the USB +// spec and relevant portions of any USB class specifications! + +static const uint8_t PROGMEM device_descriptor[] = { + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB +#ifdef CORE_TEENSY_SERIAL + 0xEF, // bDeviceClass + 0x02, // bDeviceSubClass + 0x01, // bDeviceProtocol +#else + 0, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol +#endif + ENDPOINT0_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct +#if defined(__AVR_ATmega32U4__) + 0x71, 0x02, +#elif defined(__AVR_AT90USB1286__) + 0x72, 0x02, +#else +#ifdef CORE_TEENSY_SERIAL + 0x02, 0x01, // bcdDevice +#else + 0x05, 0x01, // bcdDevice +#endif +#endif + 1, // iManufacturer + 2, // iProduct + 3, // iSerialNumber + 1 // bNumConfigurations +}; + +#ifdef CORE_TEENSY_KEYBOARD +// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 +static const uint8_t PROGMEM keyboard_hid_report_desc[] = { + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x06, // Usage (Keyboard), + 0xA1, 0x01, // Collection (Application), + 0x75, 0x01, // Report Size (1), + 0x95, 0x08, // Report Count (8), + 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), ;Modifier byte +#ifdef CORE_TEENSY_MULTIMEDIA + 0x95, 0x01, // Report Count (1), + 0x75, 0x08, // Report Size (8), + 0x81, 0x03, // Input (Constant), ;Reserved byte +#else + 0x95, 0x08, // Report Count (8), + 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), ;Media keys +#endif + 0x95, 0x05, // Report Count (5), + 0x75, 0x01, // Report Size (1), + 0x05, 0x08, // Usage Page (LEDs), + 0x19, 0x01, // Usage Minimum (1), + 0x29, 0x05, // Usage Maximum (5), + 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report + 0x95, 0x01, // Report Count (1), + 0x75, 0x03, // Report Size (3), + 0x91, 0x03, // Output (Constant), ;LED report padding + 0x95, 0x06, // Report Count (6), + 0x75, 0x08, // Report Size (8), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x7F, // Logical Maximum(104), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0x00, // Usage Minimum (0), + 0x29, 0x7F, // Usage Maximum (104), + 0x81, 0x00, // Input (Data, Array), ;Normal keys + 0xc0 // End Collection +}; +#endif + +#ifdef CORE_TEENSY_MULTIMEDIA +static const uint8_t PROGMEM keymedia_hid_report_desc[] = { + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Controls) + 0xA1, 0x01, // Collection (Application) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x04, // Report Count (4) + 0x19, 0x00, // Usage Minimum (0) + 0x2A, 0x9C, 0x02, // Usage Maximum (0x29C) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0x9C, 0x02, // Logical Maximum (0x29C) + 0x81, 0x00, // Input (Data, Array) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x75, 0x08, // Report Size (8) + 0x95, 0x03, // Report Count (3) + 0x19, 0x00, // Usage Minimum (0) + 0x29, 0xB7, // Usage Maximum (0xB7) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xB7, 0x00, // Logical Maximum (0xB7) + 0x81, 0x00, // Input (Data, Array) + 0xC0 // End Collection +}; +#endif + +#ifdef CORE_TEENSY_MOUSE +// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension +static const 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, 0x08, // Usage Maximum (Button #8) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x08, // Report Count (8) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8), + 0x95, 0x03, // Report Count (3), + 0x81, 0x06, // Input (Data, Variable, Relative) + 0x05, 0x0C, // Usage Page (Consumer) + 0x0A, 0x38, 0x02, // Usage (AC Pan) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8), + 0x95, 0x01, // Report Count (1), + 0x81, 0x06, // Input (Data, Variable, Relative) + 0xC0 // End Collection +}; +#endif + +#ifdef CORE_TEENSY_JOYSTICK +static const uint8_t PROGMEM joystick_hid_report_desc[] = { + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x20, // Report Count (32) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (Button #1) + 0x29, 0x20, // Usage Maximum (Button #32) + 0x81, 0x02, // Input (variable,absolute) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x07, // Logical Maximum (7) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x65, 0x14, // Unit (20) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (variable,absolute,null_state) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection () + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x04, // Report Count (4) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (variable,absolute) + 0xC0, // End Collection + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x02, // Report Count (2) + 0x09, 0x36, // Usage (Slider) + 0x09, 0x36, // Usage (Slider) + 0x81, 0x02, // Input (variable,absolute) + 0xC0 // End Collection +}; +#endif + +#ifdef CORE_TEENSY_DEBUG +static const uint8_t PROGMEM debug_hid_report_desc[] = { + 0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined) + 0x09, 0x04, // Usage 0x04 + 0xA1, 0x5C, // Collection 0x5C + 0x75, 0x08, // report size = 8 bits (global) + 0x15, 0x00, // logical minimum = 0 (global) + 0x26, 0xFF, 0x00, // logical maximum = 255 (global) + 0x95, DEBUG_TX_SIZE, // report count (global) + 0x09, 0x75, // usage (local) + 0x81, 0x02, // Input + 0x95, DEBUG_RX_SIZE, // report count (global) + 0x09, 0x76, // usage (local) + 0x91, 0x02, // Output + 0x95, 0x04, // report count (global) + 0x09, 0x76, // usage (local) + 0xB1, 0x02, // Feature + 0xC0 // end collection +}; +#endif + +#define HID_DESC_OFFSET_SERIAL 9 + +#ifdef CORE_TEENSY_SERIAL +#define HID_DESC_OFFSET_KEYBOARD (HID_DESC_OFFSET_SERIAL + 8+9+5+5+4+5+7+9+7+7) +#else +#define HID_DESC_OFFSET_KEYBOARD HID_DESC_OFFSET_SERIAL +#endif + +#ifdef CORE_TEENSY_KEYBOARD +#define HID_DESC_OFFSET_MOUSE (HID_DESC_OFFSET_KEYBOARD + 9+9+7) +#else +#define HID_DESC_OFFSET_MOUSE HID_DESC_OFFSET_KEYBOARD +#endif + +#ifdef CORE_TEENSY_MOUSE +#define HID_DESC_OFFSET_DEBUG (HID_DESC_OFFSET_MOUSE + 9+9+7) +#else +#define HID_DESC_OFFSET_DEBUG HID_DESC_OFFSET_MOUSE +#endif + +#ifdef CORE_TEENSY_DEBUG +#define HID_DESC_OFFSET_JOYSTICK (HID_DESC_OFFSET_DEBUG + 9+9+7+7) +#else +#define HID_DESC_OFFSET_JOYSTICK HID_DESC_OFFSET_DEBUG +#endif + +#ifdef CORE_TEENSY_JOYSTICK +#define HID_DESC_OFFSET_MULTIMEDIA (HID_DESC_OFFSET_JOYSTICK + 9+9+7) +#else +#define HID_DESC_OFFSET_MULTIMEDIA HID_DESC_OFFSET_JOYSTICK +#endif + +#ifdef CORE_TEENSY_MULTIMEDIA +#define CONFIG1_DESC_SIZE ( HID_DESC_OFFSET_MULTIMEDIA + 9+9+7 ) +#else +#define CONFIG1_DESC_SIZE ( HID_DESC_OFFSET_MULTIMEDIA ) +#endif + +static const 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), + NUM_INTERFACES, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0xC0, // bmAttributes + 50, // bMaxPower +#ifdef CORE_TEENSY_SERIAL + // interface association descriptor, USB ECN, Table 9-Z + 8, // bLength + 11, // bDescriptorType + CDC_INTERFACE, // bFirstInterface + 2, // bInterfaceCount + 0x02, // bFunctionClass + 0x02, // bFunctionSubClass + 0x01, // bFunctionProtocol + 4, // iFunction + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + CDC_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0, // iInterface + // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x00, // bDescriptorSubtype + 0x10, 0x01, // bcdCDC + // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x01, // bDescriptorSubtype + 0x00, // bmCapabilities + 1, // bDataInterface + // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 + 4, // bFunctionLength + 0x24, // bDescriptorType + 0x02, // bDescriptorSubtype + 0x06, // bmCapabilities + // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x06, // bDescriptorSubtype + 0, // bMasterInterface + 1, // bSlaveInterface0 + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_ACM_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + CDC_ACM_SIZE, 0, // wMaxPacketSize + 64, // bInterval + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + (CDC_INTERFACE+1), // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_RX_ENDPOINT, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + CDC_RX_SIZE, 0, // wMaxPacketSize + 0, // bInterval + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + CDC_TX_SIZE, 0, // wMaxPacketSize + 0, // bInterval +#endif // CORE_TEENSY_SERIAL + +#ifdef CORE_TEENSY_KEYBOARD + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + KEYBOARD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x01, // bInterfaceSubClass (0x01 = Boot) + 0x01, // bInterfaceProtocol (0x01 = Keyboard) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(keyboard_hid_report_desc), // wDescriptorLength + 0, + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + KEYBOARD_SIZE, 0, // wMaxPacketSize + KEYBOARD_INTERVAL, // bInterval +#endif // CORE_TEENSY_KEYBOARD + +#ifdef CORE_TEENSY_MOUSE + // 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 interface 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) + MOUSE_SIZE, 0, // wMaxPacketSize + MOUSE_INTERVAL, // bInterval +#endif // CORE_TEENSY_MOUSE + +#ifdef CORE_TEENSY_DEBUG + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + DEBUG_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(debug_hid_report_desc), // wDescriptorLength + 0, + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + DEBUG_TX_SIZE, 0, // wMaxPacketSize + DEBUG_TX_INTERVAL, // bInterval + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + DEBUG_RX_ENDPOINT, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + DEBUG_RX_SIZE, 0, // wMaxPacketSize + DEBUG_RX_INTERVAL, // bInterval +#endif // CORE_TEENSY_DEBUG + +#ifdef CORE_TEENSY_JOYSTICK +// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + JOYSTICK_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(joystick_hid_report_desc), // wDescriptorLength + 0, + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + JOYSTICK_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + 12, 0, // wMaxPacketSize + JOYSTICK_INTERVAL, // bInterval +#endif // CORE_TEENSY_JOYSTICK + +#ifdef CORE_TEENSY_MULTIMEDIA + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + KEYMEDIA_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(keymedia_hid_report_desc)), // wDescriptorLength + MSB(sizeof(keymedia_hid_report_desc)), + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + KEYMEDIA_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + KEYMEDIA_SIZE, 0, // wMaxPacketSize + KEYMEDIA_INTERVAL, // bInterval +#endif // CORE_TEENSY_MULTIMEDIA +}; + +// If you're desperate for a little extra code memory, these strings +// can be completely removed if iManufacturer, iProduct, iSerialNumber +// in the device desciptor are changed to zeros. +struct usb_string_descriptor_struct { + uint8_t bLength; + uint8_t bDescriptorType; + int16_t wString[]; +}; +static const struct usb_string_descriptor_struct PROGMEM string0 = { + 4, + 3, + {0x0409} +}; +static const struct usb_string_descriptor_struct PROGMEM string1 = { + sizeof(STR_MANUFACTURER), + 3, + STR_MANUFACTURER +}; +static const struct usb_string_descriptor_struct PROGMEM string2 = { + sizeof(STR_PRODUCT), + 3, + STR_PRODUCT +}; +static const struct usb_string_descriptor_struct PROGMEM string3 = { + sizeof(STR_SERIAL_NUMBER), + 3, + STR_SERIAL_NUMBER +}; +static const struct usb_string_descriptor_struct PROGMEM string4 = { + sizeof(STR_SERIAL), + 3, + STR_SERIAL +}; + +// This table defines which descriptor data is sent for each specific +// request from the host (in wValue and wIndex). +static const struct descriptor_list_struct { + uint16_t wValue; + uint16_t wIndex; + const uint8_t *addr; + uint8_t length; +} PROGMEM descriptor_list[] = { + {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, + {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, +#ifdef CORE_TEENSY_KEYBOARD + {0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, + {0x2100, KEYBOARD_INTERFACE, config1_descriptor+(HID_DESC_OFFSET_KEYBOARD+9), 9}, +#endif +#ifdef CORE_TEENSY_MOUSE + {0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, + {0x2100, MOUSE_INTERFACE, config1_descriptor+(HID_DESC_OFFSET_MOUSE+9), 9}, +#endif +#ifdef CORE_TEENSY_DEBUG + {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, + {0x2100, DEBUG_INTERFACE, config1_descriptor+(HID_DESC_OFFSET_DEBUG+9), 9}, +#endif +#ifdef CORE_TEENSY_JOYSTICK + {0x2200, JOYSTICK_INTERFACE, joystick_hid_report_desc, sizeof(joystick_hid_report_desc)}, + {0x2100, JOYSTICK_INTERFACE, config1_descriptor+(HID_DESC_OFFSET_JOYSTICK+9), 9}, +#endif +#ifdef CORE_TEENSY_MULTIMEDIA + {0x2200, KEYMEDIA_INTERFACE, keymedia_hid_report_desc, sizeof(keymedia_hid_report_desc)}, + {0x2100, KEYMEDIA_INTERFACE, config1_descriptor+(HID_DESC_OFFSET_MULTIMEDIA+9), 9}, +#endif + {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)}, + {0x0303, 0x0409, (const uint8_t *)&string3, sizeof(STR_SERIAL_NUMBER)}, + {0x0304, 0x0409, (const uint8_t *)&string4, sizeof(STR_SERIAL)}, +}; +#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct)) + + +/************************************************************************** + * + * Variables - these are the only non-stack RAM usage + * + **************************************************************************/ + +// zero when we are not configured, non-zero when enumerated +volatile uint8_t usb_configuration USBSTATE; +volatile uint8_t usb_suspended USBSTATE; + +// the time remaining before we transmit any partially full +// packet, or send a zero length packet. +volatile uint8_t transmit_flush_timer=0; +volatile uint8_t reboot_timer=0; +uint8_t transmit_previous_timeout=0; + +#ifdef CORE_TEENSY_SERIAL +// serial port settings (baud rate, control signals, etc) set +// by the PC. These are ignored, but kept in RAM because the +// CDC spec requires a read that returns the current settings. +volatile uint8_t cdc_line_coding[7]={0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08}; +volatile uint8_t cdc_line_rtsdtr USBSTATE; +#endif + +#ifdef CORE_TEENSY_KEYBOARD +// byte0: 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 +// byte1: media keys (TODO: document these) +// bytes2-7: which keys are currently pressed, up to 6 keys may be down at once +uint8_t keyboard_report_data[8] USBSTATE; + +// 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 USBSTATE; + +// 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 USBSTATE; + +// count until idle timeout +uint8_t keyboard_idle_count USBSTATE; + +// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana +volatile uint8_t keyboard_leds USBSTATE; +#endif + +#ifdef CORE_TEENSY_MOUSE +// which buttons are currently pressed +uint8_t mouse_buttons USBSTATE; + +// 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 mouse_protocol USBSTATE; +#endif + +#ifdef CORE_TEENSY_JOYSTICK +// joystick data +uint8_t joystick_report_data[12] USBSTATE; +#endif + +#ifdef CORE_TEENSY_MULTIMEDIA +// keyboard media keys data +uint8_t keymedia_report_data[8] USBSTATE; +uint16_t keymedia_consumer_keys[4] USBSTATE; +uint8_t keymedia_system_keys[3] USBSTATE; +#endif + + +/************************************************************************** + * + * Public Functions - these are the API intended for the user + * + **************************************************************************/ + + + +// initialize USB serial +void usb_init(void) +{ + uint8_t u; + + u = USBCON; + if ((u & (1<= 8000000L) + // WAKEUPI does not work with USB clock freeze + // when CPU is running less than 8 MHz. + // Is this a hardware bug? + USB_FREEZE(); // shut off USB + PLLCSR = 0; // shut off PLL + #endif + // to properly meet the USB spec, current must + // reduce to less than 2.5 mA, which means using + // powerdown mode, but that breaks the Arduino + // user's paradigm.... + } + if (usb_suspended && (intbits & (1<= 8000000L) + PLL_CONFIG(); + while (!(PLLCSR & (1<= NUM_DESC_LIST) { + UECONX = (1< desc_length) len = desc_length; + list = desc_addr; + do { + // wait for host ready for IN packet + do { + i = UEINTX; + } while (!(i & ((1<= 1 && i <= MAX_ENDPOINT) { + usb_send_in(); + UENUM = i; + if (bRequest == SET_FEATURE) { + UECONX = (1<> 8); + keyboard_idle_count = 0; + //usb_wait_in_ready(); + usb_send_in(); + return; + } + if (bRequest == HID_SET_PROTOCOL) { + keyboard_protocol = wValue; + //usb_wait_in_ready(); + usb_send_in(); + return; + } + } + } +#endif +#ifdef CORE_TEENSY_MOUSE + 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; + 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; + } + } + } +#endif +#ifdef CORE_TEENSY_JOYSTICK + if (wIndex == JOYSTICK_INTERFACE) { + if (bmRequestType == 0xA1) { + if (bRequest == HID_GET_REPORT) { + usb_wait_in_ready(); + for (i=0; i<12; i++) { + UEDATX = joystick_report_data[i]; + } + usb_send_in(); + return; + } + } + } +#endif +#ifdef CORE_TEENSY_MULTIMEDIA + if (wIndex == KEYMEDIA_INTERFACE) { + if (bmRequestType == 0xA1) { + if (bRequest == HID_GET_REPORT) { + usb_wait_in_ready(); + for (i=0; i<8; i++) { + UEDATX = keymedia_report_data[i]; + } + usb_send_in(); + return; + } + } + } +#endif +#ifdef CORE_TEENSY_DEBUG + if (wIndex == DEBUG_INTERFACE) { + if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) { + len = wLength; + do { + // wait for host ready for IN packet + do { + i = UEINTX; + } while (!(i & ((1< +#include +#include +#include "usb_common.h" +#include "usb_private.h" +#include "usb_api.h" +#include "wiring.h" + +// This file is used only for Teensy 2.0 and Teensy++ 2.0 + +// Public Methods ////////////////////////////////////////////////////////////// + +#ifdef CORE_TEENSY_SERIAL +void usb_serial_class::begin(long speed) +{ + // make sure USB is initialized + peek_buf = -1; + usb_init(); + uint16_t begin_wait = (uint16_t)millis(); + while (1) { + // wait for the host to finish enumeration + if (usb_configuration) { + delay(200); // a little time for host to load a driver + return; + } + // or for suspend mode (powered without USB) + if (usb_suspended) { + uint16_t begin_suspend = (uint16_t)millis(); + while (usb_suspended) { + // must remain suspended for a while, because + // normal USB enumeration causes brief suspend + // states, typically under 0.1 second + if ((uint16_t)millis() - begin_suspend > 250) { + return; + } + } + } + // ... or a timout (powered by a USB power adaptor that + // wiggles the data lines to keep a USB device charging) + if ((uint16_t)millis() - begin_wait > 2500) return; + } +} + +void usb_serial_class::end() +{ + usb_shutdown(); + delay(25); +} + +// number of bytes available in the receive buffer +int usb_serial_class::available() +{ + uint8_t n=0, i, intr_state; + + intr_state = SREG; + cli(); + if (usb_configuration) { + UENUM = CDC_RX_ENDPOINT; + n = UEBCLX; + if (!n) { + i = UEINTX; + if (i & (1<= 0 && n < 255) n++; + return n; +} + +int usb_serial_class::peek() +{ + if (peek_buf < 0) peek_buf = read(); + return peek_buf; +} + +// get the next character, or -1 if nothing received +int usb_serial_class::read(void) +{ + uint8_t c, intr_state; + + if (peek_buf >= 0) { + c = peek_buf; + peek_buf = -1; + return c; + } + // 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(); + if (!usb_configuration) { + SREG = intr_state; + return -1; + } + UENUM = CDC_RX_ENDPOINT; + retry: + c = UEINTX; + if (!(c & (1< size) write_size = size; + size -= write_size; + count += write_size; + +#define ASM_COPY1(src, dest, tmp) "ld " tmp ", " src "\n\t" "st " dest ", " tmp "\n\t" +#define ASM_COPY2(src, dest, tmp) ASM_COPY1(src, dest, tmp) ASM_COPY1(src, dest, tmp) +#define ASM_COPY4(src, dest, tmp) ASM_COPY2(src, dest, tmp) ASM_COPY2(src, dest, tmp) +#define ASM_COPY8(src, dest, tmp) ASM_COPY4(src, dest, tmp) ASM_COPY4(src, dest, tmp) + +#if 1 + // write the packet + do { + uint8_t tmp; + asm volatile( + "L%=begin:" "\n\t" + "ldi r30, %4" "\n\t" + "sub r30, %3" "\n\t" + "cpi r30, %4" "\n\t" + "brsh L%=err" "\n\t" + "lsl r30" "\n\t" + "clr r31" "\n\t" + "subi r30, lo8(-(pm(L%=table)))" "\n\t" + "sbci r31, hi8(-(pm(L%=table)))" "\n\t" + "ijmp" "\n\t" + "L%=err:" "\n\t" + "rjmp L%=end" "\n\t" + "L%=table:" "\n\t" + #if (CDC_TX_SIZE == 64) + ASM_COPY8("Y+", "X", "%1") + ASM_COPY8("Y+", "X", "%1") + ASM_COPY8("Y+", "X", "%1") + ASM_COPY8("Y+", "X", "%1") + #endif + #if (CDC_TX_SIZE >= 32) + ASM_COPY8("Y+", "X", "%1") + ASM_COPY8("Y+", "X", "%1") + #endif + #if (CDC_TX_SIZE >= 16) + ASM_COPY8("Y+", "X", "%1") + #endif + ASM_COPY8("Y+", "X", "%1") + "L%=end:" "\n\t" + : "+y" (buffer), "=r" (tmp) + : "x" (&UEDATX), "r" (write_size), "M" (CDC_TX_SIZE) + : "r30", "r31" + ); + } while (0); +#endif + // if this completed a packet, transmit it now! + if (!(UEINTX & (1<> 8; + if (msb >= 0xC2) { + if (msb <= 0xDF) { + n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); + } else if (msb == 0xF0) { + presskey(n, 0); + return; + } else if (msb == 0xE0) { + presskey(0, n); + return; + } else if (msb == 0xE2) { +#ifdef CORE_TEENSY_MULTIMEDIA + press_system_key(n); +#endif + return; + } else if (msb >= 0xE4 && msb <= 0xE7) { +#ifdef CORE_TEENSY_MULTIMEDIA + press_consumer_key(n & 0x3FF); +#endif + return; + } else { + return; + } + } + KEYCODE_TYPE keycode = unicode_to_keycode(n); + if (!keycode) return; +#ifdef DEADKEYS_MASK + KEYCODE_TYPE deadkeycode = deadkey_to_keycode(keycode); + if (deadkeycode) { + modrestore = keyboard_report_data[0]; + if (modrestore) { + keyboard_report_data[0] = 0; + send_now(); + } + // TODO: test if operating systems recognize + // deadkey sequences when other keys are held + mod = keycode_to_modifier(deadkeycode); + key = keycode_to_key(deadkeycode); + presskey(key, mod); + releasekey(key, mod); + } +#endif + mod = keycode_to_modifier(keycode); + key = keycode_to_key(keycode); + presskey(key, mod | modrestore); +} + +void usb_keyboard_class::release(uint16_t n) +{ + uint8_t key, mod, msb; + + msb = n >> 8; + if (msb >= 0xC2) { + if (msb <= 0xDF) { + n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); + } else if (msb == 0xF0) { + releasekey(n, 0); + return; + } else if (msb == 0xE0) { + releasekey(0, n); + return; + } else if (msb == 0xE2) { +#ifdef CORE_TEENSY_MULTIMEDIA + release_system_key(n); +#endif + return; + } else if (msb >= 0xE4 && msb <= 0xE7) { +#ifdef CORE_TEENSY_MULTIMEDIA + release_consumer_key(n & 0x3FF); +#endif + return; + } else { + return; + } + } + KEYCODE_TYPE keycode = unicode_to_keycode(n); + if (!keycode) return; + mod = keycode_to_modifier(keycode); + key = keycode_to_key(keycode); + releasekey(key, mod); +} + +void usb_keyboard_class::presskey(uint8_t key, uint8_t modifier) +{ + bool send_required = false; + uint8_t i; + + if (modifier) { + if ((keyboard_report_data[0] & modifier) != modifier) { + keyboard_report_data[0] |= modifier; + send_required = true; + } + } + if (key) { + for (i=2; i < 8; i++) { + if (keyboard_report_data[i] == key) goto end; + } + for (i=2; i < 8; i++) { + if (keyboard_report_data[i] == 0) { + keyboard_report_data[i] = key; + send_required = true; + goto end; + } + } + } + end: + if (send_required) send_now(); +} + +void usb_keyboard_class::releasekey(uint8_t key, uint8_t modifier) +{ + bool send_required = false; + uint8_t i; + + if (modifier) { + if ((keyboard_report_data[0] & modifier) != 0) { + keyboard_report_data[0] &= ~modifier; + send_required = true; + } + } + if (key) { + for (i=2; i < 8; i++) { + if (keyboard_report_data[i] == key) { + keyboard_report_data[i] = 0; + send_required = true; + } + } + } + if (send_required) send_now(); +} + +void usb_keyboard_class::releaseAll(void) +{ + uint8_t i, anybits; + + anybits = keyboard_report_data[0]; + for (i=2; i < 8; i++) { + anybits |= keyboard_report_data[i]; + keyboard_report_data[i] = 0; + } + if (!anybits) return; + keyboard_report_data[0] = 0; + send_now(); +} +#endif + +#ifdef CORE_TEENSY_MULTIMEDIA +void usb_keyboard_class::press_consumer_key(uint16_t key) +{ + if (key == 0) return; + for (uint8_t i=0; i < 4; i++) { + if (keymedia_consumer_keys[i] == key) return; + } + for (uint8_t i=0; i < 4; i++) { + if (keymedia_consumer_keys[i] == 0) { + keymedia_consumer_keys[i] = key; + keymedia_send(); + return; + } + } +} + +void usb_keyboard_class::release_consumer_key(uint16_t key) +{ + if (key == 0) return; + for (uint8_t i=0; i < 4; i++) { + if (keymedia_consumer_keys[i] == key) { + keymedia_consumer_keys[i] = 0; + keymedia_send(); + return; + } + } +} + +void usb_keyboard_class::press_system_key(uint8_t key) +{ + if (key == 0) return; + for (uint8_t i=0; i < 3; i++) { + if (keymedia_system_keys[i] == key) return; + } + for (uint8_t i=0; i < 3; i++) { + if (keymedia_system_keys[i] == 0) { + keymedia_system_keys[i] = key; + keymedia_send(); + return; + } + } +} + +void usb_keyboard_class::release_system_key(uint8_t key) +{ + if (key == 0) return; + for (uint8_t i=0; i < 3; i++) { + if (keymedia_system_keys[i] == key) { + keymedia_system_keys[i] = 0; + keymedia_send(); + return; + } + } +} + +void usb_keyboard_class::keymedia_release_all(void) +{ + uint8_t anybits = 0; + for (uint8_t i=0; i < 4; i++) { + if (keymedia_consumer_keys[i] != 0) anybits = 1; + keymedia_consumer_keys[i] = 0; + } + for (uint8_t i=0; i < 3; i++) { + if (keymedia_system_keys[i] != 0) anybits = 1; + keymedia_system_keys[i] = 0; + } + if (anybits) keymedia_send(); +} + +// send the contents of keyboard_keys and keyboard_modifier_keys +void usb_keyboard_class::keymedia_send(void) +{ + uint8_t intr_state, timeout; + + if (!usb_configuration) return; + intr_state = SREG; + cli(); + UENUM = KEYMEDIA_ENDPOINT; + timeout = UDFNUML + 50; + while (1) { + // are we ready to transmit? + if (UEINTX & (1<> 8) & 0x03); + UEDATX = (keymedia_consumer_keys[2] << 4) | ((keymedia_consumer_keys[1] >> 6) & 0x0F); + UEDATX = (keymedia_consumer_keys[3] << 6) | ((keymedia_consumer_keys[2] >> 4) & 0x3F); + UEDATX = keymedia_consumer_keys[3] >> 2; + UEDATX = keymedia_system_keys[0]; + UEDATX = keymedia_system_keys[1]; + UEDATX = keymedia_system_keys[2]; + UEINTX = 0x3A; + SREG = intr_state; +} +#endif + + +#ifdef CORE_TEENSY_MOUSE +void usb_mouse_class::move(int8_t x, int8_t y, int8_t wheel, int8_t horiz) +{ + uint8_t intr_state, timeout; + + if (!usb_configuration) return; + if (x == -128) x = -127; + if (y == -128) y = -127; + if (wheel == -128) wheel = -127; + if (horiz == -128) horiz = -127; + intr_state = SREG; + cli(); + UENUM = MOUSE_ENDPOINT; + timeout = UDFNUML + 50; + while (1) { + // are we ready to transmit? + if (UEINTX & (1< 250) { + return; + } + } + } + // ... or a timout (powered by a USB power adaptor that + // wiggles the data lines to keep a USB device charging) + if ((uint16_t)millis() - begin_wait > 2500) return; + } + prev_byte = 0; +} + +void usb_serial_class::end() +{ + usb_shutdown(); + delay(25); +} + + + +// number of bytes available in the receive buffer +int usb_serial_class::available() +{ + uint8_t c; + + c = prev_byte; // assume 1 byte static volatile access is atomic + if (c) return 1; + c = readnext(); + if (c) { + prev_byte = c; + return 1; + } + return 0; +} + +// get the next character, or -1 if nothing received +int usb_serial_class::read() +{ + uint8_t c; + + c = prev_byte; + if (c) { + prev_byte = 0; + return c; + } + c = readnext(); + if (c) return c; + return -1; +} + +int usb_serial_class::peek() +{ + uint8_t c; + + c = prev_byte; + if (c) return c; + c = readnext(); + if (c) { + prev_byte = c; + return c; + } + return -1; +} + +// get the next character, or 0 if nothing +uint8_t usb_serial_class::readnext(void) +{ + uint8_t c, intr_state; + + // 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(); + if (!usb_configuration) { + SREG = intr_state; + return 0; + } + UENUM = DEBUG_RX_ENDPOINT; +try_again: + if (!(UEINTX & (1< + +#include "keylayouts.h" +#include "Print.h" +#include "Stream.h" +#include "defines.h" + +#ifdef CORE_TEENSY_SERIAL +class usb_serial_class : public Stream +{ +public: + void begin(long); + void end(); + virtual int available(); + virtual int read(); + virtual int peek(); + virtual void flush(); +#if ARDUINO >= 100 + virtual size_t write(uint8_t c) { return write(&c, 1); } + virtual size_t write(const uint8_t *buffer, uint16_t size); + using Print::write; +#else + virtual void write(uint8_t c) { write(&c, 1); } + virtual void write(const uint8_t *buffer, uint16_t size); + virtual void write(const char *s) { write((const uint8_t *)s, strlen(s)); } +#endif + void send_now(void); + uint32_t baud(void); + uint8_t stopbits(void); + uint8_t paritytype(void); + uint8_t numbits(void); + uint8_t dtr(void); + uint8_t rts(void); + operator bool(); +private: + int16_t peek_buf; +}; + +extern usb_serial_class Serial; +#endif + + +#ifdef CORE_TEENSY_KEYBOARD +class usb_keyboard_class : public Print +{ + public: + void begin(void) { } + void end(void) { } +#if ARDUINO >= 100 + virtual size_t write(uint8_t); +#else + virtual void write(uint8_t); +#endif + using Print::write; + void write_unicode(uint16_t unicode) { write_keycode(unicode_to_keycode(unicode)); } + void set_modifier(uint16_t); + void set_key1(uint8_t); + void set_key2(uint8_t); + void set_key3(uint8_t); + void set_key4(uint8_t); + void set_key5(uint8_t); + void set_key6(uint8_t); +#ifdef CORE_TEENSY_MULTIMEDIA + void set_media(uint16_t c) { + if (c == 0) { + keymedia_release_all(); + } else if (c >= 0xE400 && c <= 0xE7FF) { + press(c); + } + } +#else + void set_media(uint8_t) { + } +#endif + void send_now(void); + void press(uint16_t n); + void release(uint16_t n); + void releaseAll(void); + private: + KEYCODE_TYPE unicode_to_keycode(uint16_t unicode); + KEYCODE_TYPE deadkey_to_keycode(KEYCODE_TYPE keycode); + uint8_t keycode_to_modifier(KEYCODE_TYPE keycode); + uint8_t keycode_to_key(KEYCODE_TYPE keycode); + void presskey(uint8_t key, uint8_t modifier); + void releasekey(uint8_t key, uint8_t modifier); + void write_keycode(KEYCODE_TYPE key); + void write_key(KEYCODE_TYPE code); +#ifdef CORE_TEENSY_MULTIMEDIA + void press_consumer_key(uint16_t key); + void release_consumer_key(uint16_t key); + void press_system_key(uint8_t key); + void release_system_key(uint8_t key); + void keymedia_release_all(void); + void keymedia_send(void); +#endif + uint8_t utf8_state; + uint16_t unicode_wchar; +}; + +extern usb_keyboard_class Keyboard; +#endif + + +#ifdef CORE_TEENSY_MOUSE +#define MOUSE_LEFT 1 +#define MOUSE_MIDDLE 4 +#define MOUSE_RIGHT 2 +#define MOUSE_BACK 8 +#define MOUSE_FORWARD 16 +#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE | MOUSE_BACK | MOUSE_FORWARD) + +class usb_mouse_class +{ + public: + void begin(void) { } + void end(void) { } + void move(int8_t x, int8_t y, int8_t wheel=0, int8_t horiz=0); + void click(uint8_t b = MOUSE_LEFT); + void scroll(int8_t wheel, int8_t horiz=0); + void set_buttons(uint8_t left, uint8_t middle=0, uint8_t right=0, uint8_t back=0, uint8_t forward=0); + void press(uint8_t b = MOUSE_LEFT); + void release(uint8_t b = MOUSE_LEFT); + bool isPressed(uint8_t b = MOUSE_ALL); +}; + +extern usb_mouse_class Mouse; +#endif + + +#ifdef CORE_TEENSY_JOYSTICK +extern uint8_t joystick_report_data[12]; + +class usb_joystick_class +{ + public: + usb_joystick_class() { manual_mode = 0; } + inline void button(uint8_t button, bool val) { + button--; + uint8_t mask = (1 << (button & 7)); + if (val) { + if (button < 8) joystick_report_data[0] |= mask; + else if (button < 16) joystick_report_data[1] |= mask; + else if (button < 24) joystick_report_data[2] |= mask; + else if (button < 32) joystick_report_data[3] |= mask; + } else { + mask = ~mask; + if (button < 8) joystick_report_data[0] &= mask; + else if (button < 16) joystick_report_data[1] &= mask; + else if (button < 24) joystick_report_data[2] &= mask; + else if (button < 32) joystick_report_data[3] &= mask; + } + if (!manual_mode) send_now(); + } + inline void X(uint16_t val) { + if (val > 1023) val = 1023; + joystick_report_data[4] = (joystick_report_data[4] & 0x0F) | (val << 4); + joystick_report_data[5] = (joystick_report_data[5] & 0xC0) | (val >> 4); + if (!manual_mode) send_now(); + } + inline void Y(uint16_t val) { + if (val > 1023) val = 1023; + joystick_report_data[5] = (joystick_report_data[5] & 0x3F) | (val << 6); + joystick_report_data[6] = (val >> 2); + if (!manual_mode) send_now(); + } + inline void position(uint16_t x, uint16_t y) { + if (x > 1023) x = 1023; + if (y > 1023) y = 1023; + joystick_report_data[4] = (joystick_report_data[4] & 0x0F) | (x << 4); + joystick_report_data[5] = (x >> 4) | (y << 6); + joystick_report_data[6] = (y >> 2); + if (!manual_mode) send_now(); + } + inline void Z(uint16_t val) { + if (val > 1023) val = 1023; + joystick_report_data[7] = val; + joystick_report_data[8] = (joystick_report_data[8] & 0xFC) | (val >> 8); + if (!manual_mode) send_now(); + } + inline void Zrotate(uint16_t val) { + if (val > 1023) val = 1023; + joystick_report_data[8] = (joystick_report_data[8] & 0x03) | (val << 2); + joystick_report_data[9] = (joystick_report_data[9] & 0xF0) | (val >> 6); + if (!manual_mode) send_now(); + } + inline void sliderLeft(uint16_t val) { + if (val > 1023) val = 1023; + joystick_report_data[9] = (joystick_report_data[9] & 0x0F) | (val << 4); + joystick_report_data[10] = (joystick_report_data[10] & 0xC0) | (val >> 4); + if (!manual_mode) send_now(); + } + inline void sliderRight(uint16_t val) { + if (val > 1023) val = 1023; + joystick_report_data[10] = (joystick_report_data[10] & 0x3F) | (val << 6); + joystick_report_data[11] = (val >> 2); + if (!manual_mode) send_now(); + } + inline void slider(uint16_t val) { + if (val > 1023) val = 1023; + joystick_report_data[9] = (joystick_report_data[9] & 0x0F) | (val << 4); + joystick_report_data[10] = (val >> 4) | (val << 6); + joystick_report_data[11] = (val >> 2); + if (!manual_mode) send_now(); + } + inline void hat(int16_t dir) { + uint8_t val; + if (dir < 0) val = 15; + else if (dir < 23) val = 0; + else if (dir < 68) val = 1; + else if (dir < 113) val = 2; + else if (dir < 158) val = 3; + else if (dir < 203) val = 4; + else if (dir < 245) val = 5; + else if (dir < 293) val = 6; + else if (dir < 338) val = 7; + joystick_report_data[4] = (joystick_report_data[4] & 0xF0) | val; + if (!manual_mode) send_now(); + } + inline void useManualSend(bool mode) { + manual_mode = mode; + } + void send_now(void); + private: + //static uint8_t manual_mode; + uint8_t manual_mode; +}; + +extern usb_joystick_class Joystick; +#endif + + +#ifdef CORE_TEENSY_DEBUG +#ifndef CORE_TEENSY_SERIAL +class usb_serial_class : public Stream +{ + public: + // standard Arduino functions + void begin(long); + void end(); + virtual int available(); + virtual int read(); + virtual int peek(); + virtual void flush(); + virtual size_t write(uint8_t); + using Print::write; + operator bool(); + // Teensy extensions + void send_now(void); + uint32_t baud(void); + uint8_t stopbits(void); + uint8_t paritytype(void); + uint8_t numbits(void); + uint8_t dtr(void); + uint8_t rts(void); + private: + uint8_t readnext(void); +}; + +extern usb_serial_class Serial; +#endif +#endif + + +#endif diff --git a/usb_mix_and_match/usb_private.h b/usb_mix_and_match/usb_private.h new file mode 100644 index 000000000..21af03a56 --- /dev/null +++ b/usb_mix_and_match/usb_private.h @@ -0,0 +1,265 @@ +#ifndef usb_mix_and_match_h__ +#define usb_mix_and_match_h__ + +#include +#include "defines.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/************************************************************************** + * + * Configurable Options + * + **************************************************************************/ + +// You can change these to give your code its own name. On Windows, +// these are only used before an INF file (driver install) is loaded. + +#ifndef STR_MANUFACTURER +#define STR_MANUFACTURER L"Teensyduino" +#endif + +#ifndef STR_PRODUCT +#ifdef CORE_TEENSY_KEYBOARD +#define STR_PRODUCT1 L"Keyboard;" +#else +#define STR_PRODUCT1 L"" +#endif +#ifdef CORE_TEENSY_MOUSE +#define STR_PRODUCT2 STR_PRODUCT1 L"Mouse;" +#else +#define STR_PRODUCT2 STR_PRODUCT1 +#endif +#ifdef CORE_TEENSY_JOYSTICK +#define STR_PRODUCT3 STR_PRODUCT2 L"Joystick;" +#else +#define STR_PRODUCT3 STR_PRODUCT2 +#endif +#ifdef CORE_TEENSY_MULTIMEDIA +#define STR_PRODUCT4 STR_PRODUCT3 L"Multimedia;" +#else +#define STR_PRODUCT4 STR_PRODUCT3 +#endif +#ifdef CORE_TEENSY_DEBUG +#define STR_PRODUCT5 STR_PRODUCT4 L"Debug;" +#else +#define STR_PRODUCT5 STR_PRODUCT4 +#endif +#ifdef CORE_TEENSY_SERIAL +#define STR_PRODUCT STR_PRODUCT5 L"Serial;" +#else +#define STR_PRODUCT STR_PRODUCT5 +#endif +#endif +#ifndef STR_SERIAL +#define STR_SERIAL L"Serial" +#endif + +// Some operating systems, especially Windows, may cache USB device +// info. Changes to the device name may not update on the same +// computer unless the vendor or product ID numbers change, or the +// "bcdDevice" revision code is increased. + + +// All USB serial devices are supposed to have a serial number +// (according to Microsoft). On windows, a new COM port is created +// for every unique serial/vendor/product number combination. If +// you program 2 identical boards with 2 different serial numbers +// and they are assigned COM7 and COM8, each will always get the +// same COM port number because Windows remembers serial numbers. +// +// On Mac OS-X, a device file is created automatically which +// incorperates the serial number, eg, /dev/cu-usbmodem12341 +// +// Linux by default ignores the serial number, and creates device +// files named /dev/ttyACM0, /dev/ttyACM1... in the order connected. +// Udev rules (in /etc/udev/rules.d) can define persistent device +// names linked to this serial number, as well as permissions, owner +// and group settings. +#ifndef STR_SERIAL_NUMBER +#define STR_SERIAL_NUMBER L"12345" +#endif + +// Mac OS-X and Linux automatically load the correct drivers. On +// Windows, even though the driver is supplied by Microsoft, an +// INF file is needed to load the driver. These numbers need to +// match the INF file. +#define VENDOR_ID 0x16C0 +#define PRODUCT_ID 0x0487 + +// When you write data, it goes into a USB endpoint buffer, which +// is transmitted to the PC when it becomes full, or after a timeout +// with no more writes. Even if you write in exactly packet-size +// increments, this timeout is used to send a "zero length packet" +// that tells the PC no more data is expected and it should pass +// any buffered data to the application that may be waiting. If +// you want data sent immediately, call usb_serial_flush_output(). +#define TRANSMIT_FLUSH_TIMEOUT 3 /* in milliseconds */ + +// If the PC is connected but not "listening", this is the length +// of time before usb_serial_getchar() returns with an error. This +// is roughly equivilant to a real UART simply transmitting the +// bits on a wire where nobody is listening, except you get an error +// code which you can ignore for serial-like discard of data, or +// use to know your data wasn't sent. +#define TRANSMIT_TIMEOUT 15 /* in milliseconds */ + + +/************************************************************************** + * + * Endpoint Buffer Configuration + * + **************************************************************************/ + +#define ENDPOINT0_SIZE 64 +#define ENDPOINT_COUNTER0 1 +#define INTERFACE_COUNTER0 0 + +#ifdef CORE_TEENSY_SERIAL +#define CDC_ACM_ENDPOINT ENDPOINT_COUNTER0 +#define CDC_ACM_SIZE 16 +#define CDC_ACM_BUFFER EP_SINGLE_BUFFER +#define CDC_RX_ENDPOINT (ENDPOINT_COUNTER0 + 1) +#define CDC_RX_SIZE 64 +#define CDC_RX_BUFFER EP_DOUBLE_BUFFER +#define CDC_TX_ENDPOINT (ENDPOINT_COUNTER0 + 2) +#define CDC_TX_BUFFER EP_DOUBLE_BUFFER +#define CDC_TX_SIZE 64 +#define CDC_INTERFACE INTERFACE_COUNTER0 +#define ENDPOINT_COUNTER1 (ENDPOINT_COUNTER0 + 3) +#define INTERFACE_COUNTER1 (INTERFACE_COUNTER0 + 2) +#else +#define ENDPOINT_COUNTER1 (ENDPOINT_COUNTER0) +#define INTERFACE_COUNTER1 (INTERFACE_COUNTER0) +#endif + + +#ifdef CORE_TEENSY_KEYBOARD +#define KEYBOARD_INTERFACE INTERFACE_COUNTER1 +#define KEYBOARD_ENDPOINT ENDPOINT_COUNTER1 +#define KEYBOARD_SIZE 8 +#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER +#define KEYBOARD_INTERVAL 1 +#define ENDPOINT_COUNTER2 (ENDPOINT_COUNTER1 + 1) +#define INTERFACE_COUNTER2 (INTERFACE_COUNTER1 + 1) +#else +#define ENDPOINT_COUNTER2 (ENDPOINT_COUNTER1) +#define INTERFACE_COUNTER2 (INTERFACE_COUNTER1) +#endif + +#ifdef CORE_TEENSY_MOUSE +#define MOUSE_INTERFACE INTERFACE_COUNTER2 +#define MOUSE_ENDPOINT ENDPOINT_COUNTER2 +#define MOUSE_SIZE 8 +#define MOUSE_BUFFER EP_DOUBLE_BUFFER +#define MOUSE_INTERVAL 2 +#define ENDPOINT_COUNTER3 (ENDPOINT_COUNTER2 + 1) +#define INTERFACE_COUNTER3 (INTERFACE_COUNTER2 + 1) +#else +#define ENDPOINT_COUNTER3 (ENDPOINT_COUNTER2) +#define INTERFACE_COUNTER3 (INTERFACE_COUNTER2) +#endif + +#ifdef CORE_TEENSY_DEBUG +#define DEBUG_INTERFACE INTERFACE_COUNTER3 +#define DEBUG_TX_ENDPOINT ENDPOINT_COUNTER3 +#define DEBUG_TX_SIZE 64 +#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER +#define DEBUG_TX_INTERVAL 1 +#define DEBUG_RX_ENDPOINT (ENDPOINT_COUNTER3 + 1) +#define DEBUG_RX_SIZE 32 +#define DEBUG_RX_BUFFER EP_DOUBLE_BUFFER +#define DEBUG_RX_INTERVAL 2 +#define ENDPOINT_COUNTER1 (ENDPOINT_COUNTER3 + 2) +#define INTERFACE_COUNTER1 (INTERFACE_COUNTER3 + 1) +#else +#define ENDPOINT_COUNTER4 (ENDPOINT_COUNTER3) +#define INTERFACE_COUNTER4 (INTERFACE_COUNTER3) +#endif + +#ifdef CORE_TEENSY_JOYSTICK +#define JOYSTICK_INTERFACE INTERFACE_COUNTER4 +#define JOYSTICK_ENDPOINT 6 +#define JOYSTICK_SIZE 16 +#define JOYSTICK_BUFFER EP_DOUBLE_BUFFER +#define JOYSTICK_INTERVAL 1 +#define ENDPOINT_COUNTER5 (ENDPOINT_COUNTER4 + 1) +#define INTERFACE_COUNTER5 (INTERFACE_COUNTER4 + 1) +#else +#define ENDPOINT_COUNTER5 (ENDPOINT_COUNTER4) +#define INTERFACE_COUNTER5 (INTERFACE_COUNTER4) +#endif + +#ifdef CORE_TEENSY_MULTIMEDIA +#define KEYMEDIA_INTERFACE INTERFACE_COUNTER5 +#define KEYMEDIA_ENDPOINT ENDPOINT_COUNTER5 +#define KEYMEDIA_SIZE 8 +#define KEYMEDIA_BUFFER EP_DOUBLE_BUFFER +#define KEYMEDIA_INTERVAL 4 +#define ENDPOINT_COUNTER6 (ENDPOINT_COUNTER5 + 1) +#define INTERFACE_COUNTER6 (INTERFACE_COUNTER5 + 1) +#else +#define ENDPOINT_COUNTER6 (ENDPOINT_COUNTER5) +#define INTERFACE_COUNTER6 (INTERFACE_COUNTER5) +#endif + +#define NUM_ENDPOINTS ENDPOINT_COUNTER6 +#define NUM_INTERFACES INTERFACE_COUNTER6 + +#if NUM_ENDPOINTS > 7 +#error Too many endpoints. Remove USB devices +#endif + + +// setup +void usb_init(void); // initialize everything +void usb_shutdown(void); // shut off USB + +// variables +// zero when we are not configured, non-zero when enumerated +extern volatile uint8_t usb_configuration; +extern volatile uint8_t usb_suspended; + +// the time remaining before we transmit any partially full +// packet, or send a zero length packet. +extern volatile uint8_t transmit_flush_timer; +extern uint8_t transmit_previous_timeout; +#ifdef CORE_TEENSY_DEBUG +extern volatile uint8_t debug_flush_timer; +#endif + +// serial port settings (baud rate, control signals, etc) set +// by the PC. These are ignored, but kept in RAM because the +// CDC spec requires a read that returns the current settings. +#ifdef CORE_TEENSY_SERIAL +extern volatile uint8_t cdc_line_coding[7]; +extern volatile uint8_t cdc_line_rtsdtr; +#endif + +#ifdef CORE_TEENSY_KEYBOARD +extern uint8_t keyboard_report_data[]; +extern uint8_t keyboard_idle_count; +extern volatile uint8_t keyboard_leds; +#endif + +#ifdef CORE_TEENSY_MOUSE +extern uint8_t mouse_buttons; +#endif + +#ifdef CORE_TEENSY_JOYSTICK +extern uint8_t joystick_report_data[12]; +#endif + +#ifdef CORE_TEENSY_MULTIMEDIA +extern uint8_t keymedia_report_data[8]; +extern uint16_t keymedia_consumer_keys[4]; +extern uint8_t keymedia_system_keys[3]; +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif