- Added NKRO descriptor - Added NKRO HID descriptor - Updated boot HID descriptor - Fixed many bugs with the pjrc ARM usb stack (with USB HID)simple
@@ -29,34 +29,21 @@ | |||
* SOFTWARE. | |||
*/ | |||
// ----- Includes ----- | |||
// Local Includes | |||
#include "usb_desc.h" | |||
// USB Descriptors are binary data which the USB host reads to | |||
// automatically detect a USB device's capabilities. The format | |||
// and meaning of every field is documented in numerous USB | |||
// standards. When working with USB descriptors, despite the | |||
// complexity of the standards and poor writing quality in many | |||
// of those documents, remember descriptors are nothing more | |||
// than constant binary data that tells the USB host what the | |||
// device can do. Computers will load drivers based on this data. | |||
// Those drivers then communicate on the endpoints specified by | |||
// the descriptors. | |||
// To configure a new combination of interfaces or make minor | |||
// changes to existing configuration (eg, change the name or ID | |||
// numbers), usually you would edit "usb_desc.h". This file | |||
// is meant to be configured by the header, so generally it is | |||
// only edited to add completely new USB interfaces or features. | |||
// ----- Macros ----- | |||
#define LSB(n) ((n) & 255) | |||
#define MSB(n) (((n) >> 8) & 255) | |||
// ************************************************************** | |||
// USB Device | |||
// ************************************************************** | |||
#define LSB(n) ((n) & 255) | |||
#define MSB(n) (((n) >> 8) & 255) | |||
// ----- USB Device Descriptor ----- | |||
// USB Device Descriptor. The USB host reads this first, to learn | |||
// what type of device is connected. | |||
@@ -64,21 +51,9 @@ static uint8_t device_descriptor[] = { | |||
18, // bLength | |||
1, // bDescriptorType | |||
0x00, 0x02, // bcdUSB | |||
#ifdef DEVICE_CLASS | |||
DEVICE_CLASS, // bDeviceClass | |||
#else | |||
0, | |||
#endif | |||
#ifdef DEVICE_SUBCLASS | |||
DEVICE_SUBCLASS, // bDeviceSubClass | |||
#else | |||
0, | |||
#endif | |||
#ifdef DEVICE_PROTOCOL | |||
DEVICE_PROTOCOL, // bDeviceProtocol | |||
#else | |||
0, | |||
#endif | |||
EP0_SIZE, // bMaxPacketSize0 | |||
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor | |||
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct | |||
@@ -89,69 +64,202 @@ static uint8_t device_descriptor[] = { | |||
1 // bNumConfigurations | |||
}; | |||
// USB Device Qualifier Descriptor | |||
static uint8_t device_qualifier_descriptor[] = { | |||
0 // Indicate only single speed | |||
/* Device qualifier example (used for specifying multiple USB speeds) | |||
10, // bLength | |||
6, // bDescriptorType | |||
0x00, 0x02, // bcdUSB | |||
DEVICE_CLASS, // bDeviceClass | |||
DEVICE_SUBCLASS, // bDeviceSubClass | |||
DEVICE_PROTOCOL, // bDeviceProtocol | |||
EP0_SIZE, // bMaxPacketSize0 | |||
1, // bNumOtherSpeedConfigurations | |||
0 // bReserved | |||
*/ | |||
}; | |||
// USB Debug Descriptor | |||
// XXX Not sure of exact use, lsusb requests it | |||
static uint8_t usb_debug_descriptor[] = { | |||
0 | |||
}; | |||
// XXX | |||
// These descriptors must NOT be "const", because the USB DMA | |||
// has trouble accessing flash memory with enough bandwidth | |||
// while the processor is executing from flash. | |||
// XXX | |||
// ************************************************************** | |||
// HID Report Descriptors | |||
// ************************************************************** | |||
// ----- USB HID Report Descriptsors ----- | |||
// Each HID interface needs a special report descriptor that tells | |||
// the meaning and format of the data. | |||
#ifdef KEYBOARD_INTERFACE | |||
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 | |||
static uint8_t keyboard_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 | |||
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 | |||
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 | |||
// Keyboard Collection | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x06, // Usage (Keyboard), | |||
0xA1, 0x01, // Collection (Application) - Keyboard, | |||
// Modifier Byte | |||
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), | |||
// Reserved Byte | |||
0x75, 0x08, // Report Size (8), | |||
0x95, 0x01, // Report Count (1), | |||
0x81, 0x03, // Output (Constant), | |||
// LED Report | |||
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 | |||
0x75, 0x03, // Report Size (3), | |||
0x95, 0x01, // Report Count (1), | |||
0x91, 0x03, // Output (Constant), | |||
// Normal Keys | |||
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), | |||
0x19, 0x00, // Usage Minimum (0), | |||
0x29, 0x7F, // Usage Maximum (104), | |||
0x81, 0x00, // Input (Data, Array), | |||
0xc0, // End Collection - Keyboard | |||
}; | |||
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 | |||
static uint8_t nkro_keyboard_report_desc[] = { | |||
// 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), | |||
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), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), | |||
// LED Report | |||
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 | |||
0x75, 0x03, // Report Size (3), | |||
0x95, 0x01, // Report Count (1), | |||
0x91, 0x03, // Output (Constant), | |||
// 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, 0x01, // Logical Maximum (1), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0x04, // Usage Minimum (4), | |||
0x29, 0xA4, // Usage Maximum (164), | |||
0x81, 0x02, // Input (Data, Variable, Absolute, Bitfield), | |||
// 176-221 (45 bits) | |||
0x85, 0x04, // Report ID (4), | |||
0x75, 0x01, // Report Size (1), | |||
0x95, 0x2D, // Report Count (45), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
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 | |||
}; | |||
#endif | |||
#ifdef MOUSE_INTERFACE | |||
/* MOUSE | |||
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | |||
static uint8_t mouse_report_desc[] = { | |||
0x05, 0x01, // Usage Page (Generic Desktop) | |||
@@ -184,29 +292,92 @@ static uint8_t mouse_report_desc[] = { | |||
0x81, 0x06, // Input (Data, Variable, Relative) | |||
0xC0 // End Collection | |||
}; | |||
#endif | |||
*/ | |||
// ************************************************************** | |||
// USB Configuration | |||
// ************************************************************** | |||
// ----- USB Configuration ----- | |||
// USB Configuration Descriptor. This huge descriptor tells all | |||
// of the devices capbilities. | |||
static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
// --- Configuration --- | |||
// - 9 bytes - | |||
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | |||
9, // bLength; | |||
2, // bDescriptorType; | |||
LSB(CONFIG_DESC_SIZE), // wTotalLength | |||
LSB(CONFIG_DESC_SIZE), // wTotalLength | |||
MSB(CONFIG_DESC_SIZE), | |||
NUM_INTERFACE, // bNumInterfaces | |||
1, // bConfigurationValue | |||
0, // iConfiguration | |||
0xC0, // bmAttributes | |||
50, // bMaxPower | |||
250, // bMaxPower | |||
#ifdef CDC_IAD_DESCRIPTOR | |||
// --- Keyboard HID --- Boot Mode Keyboard Interface | |||
// - 9 bytes - | |||
// 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 (0x00 = Non-Boot, 0x01 = Boot) | |||
0x01, // bInterfaceProtocol (0x01 = Keyboard) | |||
0, // iInterface | |||
// - 9 bytes - | |||
// 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(keyboard_report_desc)), // wDescriptorLength | |||
MSB(sizeof(keyboard_report_desc)), | |||
// - 7 bytes - | |||
// 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 | |||
// --- NKRO Keyboard HID --- OS Mode Keyboard Interface | |||
// - 9 bytes - | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
NKRO_KEYBOARD_INTERFACE, // bInterfaceNumber | |||
0, // bAlternateSetting | |||
1, // bNumEndpoints | |||
0x03, // bInterfaceClass (0x03 = HID) | |||
0x00, // bInterfaceSubClass (0x00 = Non-Boot, 0x01 = Boot) | |||
0x01, // bInterfaceProtocol (0x01 = Keyboard) | |||
0, // iInterface | |||
// - 9 bytes - | |||
// 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(nkro_keyboard_report_desc)), // wDescriptorLength | |||
MSB(sizeof(nkro_keyboard_report_desc)), | |||
// - 7 bytes - | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
NKRO_KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress | |||
0x03, // bmAttributes (0x03=intr) | |||
NKRO_KEYBOARD_SIZE, 0, // wMaxPacketSize | |||
NKRO_KEYBOARD_INTERVAL, // bInterval | |||
// --- Serial CDC --- CDC IAD Descriptor | |||
// - 8 bytes - | |||
// interface association descriptor, USB ECN, Table 9-Z | |||
8, // bLength | |||
11, // bDescriptorType | |||
@@ -216,9 +387,9 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x02, // bFunctionSubClass | |||
0x01, // bFunctionProtocol | |||
4, // iFunction | |||
#endif | |||
#ifdef CDC_DATA_INTERFACE | |||
// --- Serial CDC --- CDC Data Interface | |||
// - 9 bytes - | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -229,28 +400,33 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x02, // bInterfaceSubClass | |||
0x01, // bInterfaceProtocol | |||
0, // iInterface | |||
// - 5 bytes - | |||
// CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x00, // bDescriptorSubtype | |||
0x10, 0x01, // bcdCDC | |||
// - 5 bytes - | |||
// Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x01, // bDescriptorSubtype | |||
0x01, // bmCapabilities | |||
1, // bDataInterface | |||
// - 4 bytes - | |||
// Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 | |||
4, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x02, // bDescriptorSubtype | |||
0x06, // bmCapabilities | |||
// - 5 bytes - | |||
// Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 | |||
5, // bFunctionLength | |||
0x24, // bDescriptorType | |||
0x06, // bDescriptorSubtype | |||
CDC_STATUS_INTERFACE, // bMasterInterface | |||
CDC_DATA_INTERFACE, // bSlaveInterface0 | |||
// - 7 bytes - | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
@@ -258,6 +434,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x03, // bmAttributes (0x03=intr) | |||
CDC_ACM_SIZE, 0, // wMaxPacketSize | |||
64, // bInterval | |||
// - 9 bytes - | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -268,6 +445,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x00, // bInterfaceSubClass | |||
0x00, // bInterfaceProtocol | |||
0, // iInterface | |||
// - 7 bytes - | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
@@ -275,6 +453,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x02, // bmAttributes (0x02=bulk) | |||
CDC_RX_SIZE, 0, // wMaxPacketSize | |||
0, // bInterval | |||
// - 7 bytes - | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
@@ -282,38 +461,10 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x02, // bmAttributes (0x02=bulk) | |||
CDC_TX_SIZE, 0, // wMaxPacketSize | |||
0, // bInterval | |||
#endif // CDC_DATA_INTERFACE | |||
#ifdef KEYBOARD_INTERFACE | |||
// 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 | |||
LSB(sizeof(keyboard_report_desc)), // wDescriptorLength | |||
MSB(sizeof(keyboard_report_desc)), | |||
// 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 // KEYBOARD_INTERFACE | |||
#ifdef MOUSE_INTERFACE | |||
/* | |||
// Mouse Interface | |||
// - 9 bytes - | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -324,6 +475,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x00, // bInterfaceSubClass (0x01 = Boot) | |||
0x00, // bInterfaceProtocol (0x02 = Mouse) | |||
0, // iInterface | |||
// - 9 bytes - | |||
// HID interface descriptor, HID 1.11 spec, section 6.2.1 | |||
9, // bLength | |||
0x21, // bDescriptorType | |||
@@ -333,6 +485,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
0x22, // bDescriptorType | |||
LSB(sizeof(mouse_report_desc)), // wDescriptorLength | |||
MSB(sizeof(mouse_report_desc)), | |||
// - 7 bytes - | |||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
7, // bLength | |||
5, // bDescriptorType | |||
@@ -341,13 +494,12 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
MOUSE_SIZE, 0, // wMaxPacketSize | |||
MOUSE_INTERVAL, // bInterval | |||
#endif // MOUSE_INTERFACE | |||
*/ | |||
}; | |||
// ************************************************************** | |||
// String Descriptors | |||
// ************************************************************** | |||
// ----- String Descriptors ----- | |||
// The descriptors above can provide human readable strings, | |||
// referenced by index numbers. These descriptors are the | |||
@@ -389,9 +541,8 @@ struct usb_string_descriptor_struct usb_string_serial_number_default = { | |||
}; | |||
// ************************************************************** | |||
// Descriptors List | |||
// ************************************************************** | |||
// ----- Descriptors List ----- | |||
// This table provides access to all the descriptor data above. | |||
@@ -399,14 +550,16 @@ const usb_descriptor_list_t usb_descriptor_list[] = { | |||
//wValue, wIndex, address, length | |||
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, | |||
{0x0200, 0x0000, config_descriptor, sizeof(config_descriptor)}, | |||
#ifdef KEYBOARD_INTERFACE | |||
{0x0600, 0x0000, device_qualifier_descriptor, sizeof(device_qualifier_descriptor)}, | |||
{0x0A00, 0x0000, usb_debug_descriptor, sizeof(usb_debug_descriptor)}, | |||
{0x2200, KEYBOARD_INTERFACE, keyboard_report_desc, sizeof(keyboard_report_desc)}, | |||
{0x2100, KEYBOARD_INTERFACE, config_descriptor+KEYBOARD_DESC_OFFSET, 9}, | |||
#endif | |||
#ifdef MOUSE_INTERFACE | |||
{0x2100, KEYBOARD_INTERFACE, config_descriptor + KEYBOARD_DESC_OFFSET, 9}, | |||
{0x2200, NKRO_KEYBOARD_INTERFACE, nkro_keyboard_report_desc, sizeof(nkro_keyboard_report_desc)}, | |||
{0x2100, NKRO_KEYBOARD_INTERFACE, config_descriptor + NKRO_KEYBOARD_DESC_OFFSET, 9}, | |||
/* MOUSE | |||
{0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)}, | |||
{0x2100, MOUSE_INTERFACE, config_descriptor+MOUSE_DESC_OFFSET, 9}, | |||
#endif | |||
*/ | |||
{0x0300, 0x0000, (const uint8_t *)&string0, 0}, | |||
{0x0301, 0x0409, (const uint8_t *)&usb_string_manufacturer_name, 0}, | |||
{0x0302, 0x0409, (const uint8_t *)&usb_string_product_name, 0}, | |||
@@ -415,24 +568,15 @@ const usb_descriptor_list_t usb_descriptor_list[] = { | |||
}; | |||
// ************************************************************** | |||
// Endpoint Configuration | |||
// ************************************************************** | |||
#if 0 | |||
// ----- Endpoint Configuration ----- | |||
// See usb_desc.h for Endpoint configuration | |||
// 0x00 = not used | |||
// 0x19 = Recieve only | |||
// 0x15 = Transmit only | |||
// 0x1D = Transmit & Recieve | |||
// | |||
const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = | |||
{ | |||
0x00, 0x15, 0x19, 0x15, 0x00, 0x00, 0x00, 0x00, | |||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||
}; | |||
#endif | |||
const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = | |||
{ | |||
#if (defined(ENDPOINT1_CONFIG) && NUM_ENDPOINTS >= 1) |
@@ -32,105 +32,83 @@ | |||
#ifndef _usb_desc_h_ | |||
#define _usb_desc_h_ | |||
// This header is NOT meant to be included when compiling | |||
// user sketches in Arduino. The low-level functions | |||
// provided by usb_dev.c are meant to be called only by | |||
// code which provides higher-level interfaces to the user. | |||
// ----- Includes ----- | |||
// Compiler Includes | |||
#include <stdint.h> | |||
#include <stddef.h> | |||
#include "output_com.h" | |||
#define ENDPOINT_UNUSED 0x00 | |||
#define ENDPOINT_TRANSIMIT_ONLY 0x15 | |||
#define ENDPOINT_RECEIVE_ONLY 0x19 | |||
#define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | |||
/* | |||
To modify a USB Type to have different interfaces, start in this | |||
file. Delete the XYZ_INTERFACE lines for any interfaces you | |||
wish to remove, and copy them from another USB Type for any you | |||
want to add. | |||
Give each interface a unique number, and edit NUM_INTERFACE to | |||
reflect the number of interfaces. | |||
Within each interface, make sure it uses a unique set of endpoints. | |||
Edit NUM_ENDPOINTS to be at least the largest endpoint number used. | |||
Then edit the ENDPOINT*_CONFIG lines so each endpoint is configured | |||
the proper way (transmit, receive, or both). | |||
The CONFIG_DESC_SIZE and any XYZ_DESC_OFFSET numbers must be | |||
edited to the correct sizes. See usb_desc.c for the giant array | |||
of bytes. Someday these may be done automatically..... (but how?) | |||
// Local Includes | |||
#include <output_com.h> | |||
If you are using existing interfaces, the code in each file should | |||
automatically adapt to the changes you specify. If you need to | |||
create a new type of interface, you'll need to write the code which | |||
sends and receives packets, and presents an API to the user. | |||
Finally, edit usb_inst.cpp, which creats instances of the C++ | |||
objects for each combination. | |||
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. | |||
If these instructions are missing steps or could be improved, please | |||
let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
*/ | |||
// ----- Defines ----- | |||
#define ENDPOINT_UNUSED 0x00 | |||
#define ENDPOINT_TRANSIMIT_ONLY 0x15 | |||
#define ENDPOINT_RECEIVE_ONLY 0x19 | |||
#define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | |||
#define DEVICE_CLASS 0xEF | |||
#define DEVICE_SUBCLASS 0x02 | |||
#define DEVICE_PROTOCOL 0x01 | |||
#define DEVICE_CLASS 0x03 // 0x03 = HID Class | |||
#define DEVICE_SUBCLASS 0x00 | |||
#define DEVICE_PROTOCOL 0x00 | |||
#define EP0_SIZE 64 | |||
#define NUM_ENDPOINTS 6 | |||
#define NUM_ENDPOINTS 5 | |||
#define NUM_USB_BUFFERS 30 | |||
#define NUM_INTERFACE 4 | |||
#define KEYBOARD_INTERFACE 0 // Keyboard | |||
#define KEYBOARD_ENDPOINT 1 | |||
#define KEYBOARD_SIZE 8 | |||
#define KEYBOARD_INTERVAL 1 | |||
#define NKRO_KEYBOARD_INTERFACE 1 // NKRO Keyboard | |||
#define NKRO_KEYBOARD_ENDPOINT 2 | |||
#define NKRO_KEYBOARD_SIZE 128 | |||
#define NKRO_KEYBOARD_INTERVAL 1 | |||
#define CDC_IAD_DESCRIPTOR 1 | |||
#define CDC_STATUS_INTERFACE 0 | |||
#define CDC_DATA_INTERFACE 1 // Serial | |||
#define CDC_ACM_ENDPOINT 2 | |||
#define CDC_RX_ENDPOINT 3 | |||
#define CDC_TX_ENDPOINT 4 | |||
#define CDC_STATUS_INTERFACE 2 | |||
#define CDC_DATA_INTERFACE 3 // Serial | |||
#define CDC_ACM_ENDPOINT 3 | |||
#define CDC_RX_ENDPOINT 4 | |||
#define CDC_TX_ENDPOINT 5 | |||
#define CDC_ACM_SIZE 16 | |||
#define CDC_RX_SIZE 64 | |||
#define CDC_TX_SIZE 64 | |||
#define KEYBOARD_INTERFACE 2 // Keyboard | |||
#define KEYBOARD_ENDPOINT 1 | |||
#define KEYBOARD_SIZE 8 | |||
#define KEYBOARD_INTERVAL 1 | |||
#define MOUSE_INTERFACE 3 // Mouse | |||
#define MOUSE_ENDPOINT 5 | |||
#define MOUSE_INTERFACE 4 // Mouse | |||
#define MOUSE_ENDPOINT 6 | |||
#define MOUSE_SIZE 8 | |||
#define MOUSE_INTERVAL 2 | |||
#define JOYSTICK_INTERFACE 4 // Joystick | |||
#define JOYSTICK_ENDPOINT 6 | |||
#define JOYSTICK_INTERFACE 5 // Joystick | |||
#define JOYSTICK_ENDPOINT 7 | |||
#define JOYSTICK_SIZE 16 | |||
#define JOYSTICK_INTERVAL 1 | |||
#define KEYBOARD_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9) | |||
#define MOUSE_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9) | |||
#define JOYSTICK_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9) | |||
#define CONFIG_DESC_SIZE (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9+9+7) | |||
#define KEYBOARD_DESC_OFFSET (9 + 9) | |||
#define NKRO_KEYBOARD_DESC_OFFSET (9 + 9+9+7 + 9) | |||
#define SERIAL_CDC_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8) | |||
#define CONFIG_DESC_SIZE (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7) | |||
// XXX Unused | |||
#define MOUSE_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9) | |||
#define JOYSTICK_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9+9+7 + 9) | |||
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
#define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15) | |||
extern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS]; | |||
// ----- Enumerations ----- | |||
typedef struct { | |||
uint16_t wValue; | |||
@@ -139,6 +117,13 @@ typedef struct { | |||
uint16_t length; | |||
} usb_descriptor_list_t; | |||
// ----- Variables ----- | |||
// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15) | |||
extern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS]; | |||
extern const usb_descriptor_list_t usb_descriptor_list[]; | |||
@@ -11,10 +11,10 @@ | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* 1. The above copyright notice and this permission notice shall be | |||
* 1. The above copyright notice and this permission notice shall be | |||
* included in all copies or substantial portions of the Software. | |||
* | |||
* 2. If the Software is incorporated into a build system that allows | |||
* 2. If the Software is incorporated into a build system that allows | |||
* selection among a list of target devices, then similar target | |||
* devices manufactured by PJRC.COM must be included in the list of | |||
* target devices and selectable in the same manner. | |||
@@ -32,16 +32,34 @@ | |||
#ifndef _usb_dev_h_ | |||
#define _usb_dev_h_ | |||
// This header is NOT meant to be included when compiling | |||
// user sketches in Arduino. The low-level functions | |||
// provided by usb_dev.c are meant to be called only by | |||
// code which provides higher-level interfaces to the user. | |||
// ----- Includes ----- | |||
// Local Includes | |||
#include "usb_mem.h" | |||
#include "usb_desc.h" | |||
// ----- Defines ----- | |||
#define usb_device_software_reset() SOFTWARE_RESET() | |||
// ----- Variables ----- | |||
extern volatile uint8_t usb_configuration; | |||
extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; | |||
extern volatile uint8_t usb_cdc_line_coding[7]; | |||
extern volatile uint8_t usb_cdc_line_rtsdtr; | |||
extern volatile uint8_t usb_cdc_transmit_flush_timer; | |||
// ----- Functions ----- | |||
uint8_t usb_configured(); // is the USB port configured | |||
void usb_init(); | |||
@@ -54,35 +72,19 @@ uint32_t usb_tx_packet_count( uint32_t endpoint ); | |||
usb_packet_t *usb_rx( uint32_t endpoint ); | |||
void usb_device_reload(); | |||
extern volatile uint8_t usb_configuration; | |||
extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; | |||
static inline uint32_t usb_rx_byte_count(uint32_t endpoint) __attribute__((always_inline)); | |||
static inline uint32_t usb_rx_byte_count(uint32_t endpoint) | |||
{ | |||
endpoint--; | |||
if (endpoint >= NUM_ENDPOINTS) return 0; | |||
return usb_rx_byte_count_data[endpoint]; | |||
if ( endpoint >= NUM_ENDPOINTS ) | |||
return 0; | |||
return usb_rx_byte_count_data[ endpoint ]; | |||
} | |||
#ifdef CDC_DATA_INTERFACE | |||
extern uint32_t usb_cdc_line_coding[2]; | |||
extern volatile uint8_t usb_cdc_line_rtsdtr; | |||
extern volatile uint8_t usb_cdc_transmit_flush_timer; | |||
extern void usb_serial_flush_callback(void); | |||
#endif | |||
void usb_device_reload(); | |||
extern void usb_serial_flush_callback(); | |||
#ifdef KEYBOARD_INTERFACE | |||
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; | |||
#endif | |||
#endif |
@@ -1,6 +1,7 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2013 PJRC.COM, LLC. | |||
* Modifications by Jacob Alexander (2013-2014) | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
@@ -10,10 +11,10 @@ | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* 1. The above copyright notice and this permission notice shall be | |||
* 1. The above copyright notice and this permission notice shall be | |||
* included in all copies or substantial portions of the Software. | |||
* | |||
* 2. If the Software is incorporated into a build system that allows | |||
* 2. If the Software is incorporated into a build system that allows | |||
* selection among a list of target devices, then similar target | |||
* devices manufactured by PJRC.COM must be included in the list of | |||
* target devices and selectable in the same manner. | |||
@@ -28,68 +29,78 @@ | |||
* SOFTWARE. | |||
*/ | |||
// ----- Includes ----- | |||
// Project Includes | |||
#include <Lib/OutputLib.h> | |||
// Local Includes | |||
#include "usb_dev.h" | |||
#include "usb_mem.h" | |||
// ----- Variables ----- | |||
__attribute__ ((section(".usbbuffers"), used)) | |||
unsigned char usb_buffer_memory[NUM_USB_BUFFERS * sizeof(usb_packet_t)]; | |||
unsigned char usb_buffer_memory[ NUM_USB_BUFFERS * sizeof(usb_packet_t) ]; | |||
static uint32_t usb_buffer_available = 0xFFFFFFFF; | |||
// ----- Externs ----- | |||
extern void usb_rx_memory( usb_packet_t *packet ); | |||
// for the receive endpoints to request memory | |||
extern uint8_t usb_rx_memory_needed; | |||
// ----- Functions ----- | |||
// use bitmask and CLZ instruction to implement fast free list | |||
// http://www.archivum.info/gnu.gcc.help/2006-08/00148/Re-GCC-Inline-Assembly.html | |||
// http://gcc.gnu.org/ml/gcc/2012-06/msg00015.html | |||
// __builtin_clz() | |||
usb_packet_t * usb_malloc(void) | |||
usb_packet_t *usb_malloc() | |||
{ | |||
unsigned int n, avail; | |||
uint8_t *p; | |||
__disable_irq(); | |||
avail = usb_buffer_available; | |||
n = __builtin_clz(avail); // clz = count leading zeros | |||
if (n >= NUM_USB_BUFFERS) { | |||
n = __builtin_clz( avail ); // clz = count leading zeros | |||
if ( n >= NUM_USB_BUFFERS ) | |||
{ | |||
__enable_irq(); | |||
return NULL; | |||
} | |||
//serial_print("malloc:"); | |||
//serial_phex(n); | |||
//serial_print("\n"); | |||
usb_buffer_available = avail & ~(0x80000000 >> n); | |||
__enable_irq(); | |||
p = usb_buffer_memory + (n * sizeof(usb_packet_t)); | |||
//serial_print("malloc:"); | |||
//serial_phex32((int)p); | |||
//serial_print("\n"); | |||
p = usb_buffer_memory + ( n * sizeof(usb_packet_t) ); | |||
*(uint32_t *)p = 0; | |||
*(uint32_t *)(p + 4) = 0; | |||
return (usb_packet_t *)p; | |||
} | |||
// for the receive endpoints to request memory | |||
extern uint8_t usb_rx_memory_needed; | |||
extern void usb_rx_memory(usb_packet_t *packet); | |||
void usb_free(usb_packet_t *p) | |||
void usb_free( usb_packet_t *p ) | |||
{ | |||
unsigned int n, mask; | |||
//serial_print("free:"); | |||
n = ((uint8_t *)p - usb_buffer_memory) / sizeof(usb_packet_t); | |||
if (n >= NUM_USB_BUFFERS) return; | |||
//serial_phex(n); | |||
//serial_print("\n"); | |||
n = ( (uint8_t *)p - usb_buffer_memory ) / sizeof(usb_packet_t); | |||
if ( n >= NUM_USB_BUFFERS ) | |||
return; | |||
// if any endpoints are starving for memory to receive | |||
// packets, give this memory to them immediately! | |||
if (usb_rx_memory_needed && usb_configuration) { | |||
//serial_print("give to rx:"); | |||
//serial_phex32((int)p); | |||
//serial_print("\n"); | |||
usb_rx_memory(p); | |||
if ( usb_rx_memory_needed && usb_configuration ) | |||
{ | |||
usb_rx_memory( p ); | |||
return; | |||
} | |||
@@ -97,9 +108,5 @@ void usb_free(usb_packet_t *p) | |||
__disable_irq(); | |||
usb_buffer_available |= mask; | |||
__enable_irq(); | |||
//serial_print("free:"); | |||
//serial_phex32((int)p); | |||
//serial_print("\n"); | |||
} | |||
@@ -1,6 +1,7 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2013 PJRC.COM, LLC. | |||
* Modifications by Jacob Alexander (2013-2014) | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
@@ -31,8 +32,15 @@ | |||
#ifndef _usb_mem_h_ | |||
#define _usb_mem_h_ | |||
// ----- Includes ----- | |||
// Compiler Includes | |||
#include <stdint.h> | |||
// ----- Structs ----- | |||
typedef struct usb_packet_struct { | |||
uint16_t len; | |||
uint16_t index; | |||
@@ -40,8 +48,14 @@ typedef struct usb_packet_struct { | |||
uint8_t buf[64]; | |||
} usb_packet_t; | |||
usb_packet_t * usb_malloc(void); | |||
void usb_free(usb_packet_t *p); | |||
// ----- Functions ----- | |||
usb_packet_t *usb_malloc(); | |||
void usb_free( usb_packet_t *p ); | |||
#endif | |||
@@ -29,93 +29,150 @@ | |||
* SOFTWARE. | |||
*/ | |||
// ----- Includes ----- | |||
// Compiler Includes | |||
#include <string.h> // For memcpy | |||
// Project Includes | |||
#include <Lib/OutputLib.h> | |||
// Local Includes | |||
#include "usb_dev.h" | |||
#include "usb_serial.h" | |||
#include <Lib/OutputLib.h> | |||
#include <string.h> // For memcpy | |||
// defined by usb_dev.h -> usb_desc.h | |||
#if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE) | |||
uint32_t usb_cdc_line_coding[2]; | |||
volatile uint8_t usb_cdc_line_rtsdtr=0; | |||
volatile uint8_t usb_cdc_transmit_flush_timer=0; | |||
static usb_packet_t *rx_packet=NULL; | |||
static usb_packet_t *tx_packet=NULL; | |||
static volatile uint8_t tx_noautoflush=0; | |||
// ----- Defines ----- | |||
#define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ | |||
// Maximum number of transmit packets to queue so we don't starve other endpoints for memory | |||
#define TX_PACKET_LIMIT 8 | |||
// When the PC isn't listening, how long do we wait before discarding data? If this is | |||
// too short, we risk losing data during the stalls that are common with ordinary desktop | |||
// software. If it's too long, we stall the user's program when no software is running. | |||
#define TX_TIMEOUT_MSEC 70 | |||
#if F_CPU == 96000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596) | |||
#elif F_CPU == 48000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428) | |||
#elif F_CPU == 24000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) | |||
#endif | |||
// ----- Variables ----- | |||
// serial port settings (baud rate, control signals, etc) set | |||
// by the PC. These are ignored, but kept in RAM. | |||
volatile uint8_t usb_cdc_line_coding[7] = { 0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08 }; | |||
volatile uint8_t usb_cdc_line_rtsdtr = 0; | |||
volatile uint8_t usb_cdc_transmit_flush_timer = 0; | |||
static usb_packet_t *rx_packet = NULL; | |||
static usb_packet_t *tx_packet = NULL; | |||
static volatile uint8_t tx_noautoflush = 0; | |||
// When we've suffered the transmit timeout, don't wait again until the computer | |||
// begins accepting data. If no software is running to receive, we'll just discard | |||
// data as rapidly as Serial.print() can generate it, until there's something to | |||
// actually receive it. | |||
static uint8_t transmit_previous_timeout = 0; | |||
// ----- Functions ----- | |||
// get the next character, or -1 if nothing received | |||
int usb_serial_getchar(void) | |||
int usb_serial_getchar() | |||
{ | |||
unsigned int i; | |||
int c; | |||
if (!rx_packet) { | |||
if (!usb_configuration) return -1; | |||
rx_packet = usb_rx(CDC_RX_ENDPOINT); | |||
if (!rx_packet) return -1; | |||
if ( !rx_packet ) | |||
{ | |||
if ( !usb_configuration ) | |||
return -1; | |||
rx_packet = usb_rx( CDC_RX_ENDPOINT ); | |||
if ( !rx_packet ) | |||
return -1; | |||
} | |||
i = rx_packet->index; | |||
c = rx_packet->buf[i++]; | |||
if (i >= rx_packet->len) { | |||
usb_free(rx_packet); | |||
if ( i >= rx_packet->len ) | |||
{ | |||
usb_free( rx_packet ); | |||
rx_packet = NULL; | |||
} else { | |||
} | |||
else | |||
{ | |||
rx_packet->index = i; | |||
} | |||
return c; | |||
} | |||
// peek at the next character, or -1 if nothing received | |||
int usb_serial_peekchar(void) | |||
int usb_serial_peekchar() | |||
{ | |||
if (!rx_packet) { | |||
if (!usb_configuration) return -1; | |||
rx_packet = usb_rx(CDC_RX_ENDPOINT); | |||
if (!rx_packet) return -1; | |||
if ( !rx_packet ) | |||
{ | |||
if ( !usb_configuration ) | |||
return -1; | |||
rx_packet = usb_rx( CDC_RX_ENDPOINT ); | |||
if ( !rx_packet ) | |||
return -1; | |||
} | |||
if (!rx_packet) return -1; | |||
return rx_packet->buf[rx_packet->index]; | |||
if ( !rx_packet ) | |||
return -1; | |||
return rx_packet->buf[ rx_packet->index ]; | |||
} | |||
// number of bytes available in the receive buffer | |||
int usb_serial_available(void) | |||
int usb_serial_available() | |||
{ | |||
int count; | |||
count = usb_rx_byte_count(CDC_RX_ENDPOINT); | |||
if (rx_packet) count += rx_packet->len - rx_packet->index; | |||
int count = usb_rx_byte_count( CDC_RX_ENDPOINT ); | |||
if ( rx_packet ) | |||
count += rx_packet->len - rx_packet->index; | |||
return count; | |||
} | |||
// read a block of bytes to a buffer | |||
int usb_serial_read(void *buffer, uint32_t size) | |||
int usb_serial_read( void *buffer, uint32_t size ) | |||
{ | |||
uint8_t *p = (uint8_t *)buffer; | |||
uint32_t qty, count=0; | |||
while (size) { | |||
if (!usb_configuration) break; | |||
if (!rx_packet) { | |||
while ( size ) | |||
{ | |||
if ( !usb_configuration ) | |||
break; | |||
if ( !rx_packet ) | |||
{ | |||
rx: | |||
rx_packet = usb_rx(CDC_RX_ENDPOINT); | |||
if (!rx_packet) break; | |||
if (rx_packet->len == 0) { | |||
usb_free(rx_packet); | |||
goto rx; | |||
} | |||
rx_packet = usb_rx(CDC_RX_ENDPOINT); | |||
if ( !rx_packet ) | |||
break; | |||
if ( rx_packet->len == 0 ) | |||
{ | |||
usb_free(rx_packet); | |||
goto rx; | |||
} | |||
} | |||
qty = rx_packet->len - rx_packet->index; | |||
if (qty > size) qty = size; | |||
memcpy(p, rx_packet->buf + rx_packet->index, qty); | |||
if ( qty > size ) | |||
qty = size; | |||
memcpy( p, rx_packet->buf + rx_packet->index, qty ); | |||
p += qty; | |||
count += qty; | |||
size -= qty; | |||
rx_packet->index += qty; | |||
if (rx_packet->index >= rx_packet->len) { | |||
usb_free(rx_packet); | |||
if ( rx_packet->index >= rx_packet->len ) | |||
{ | |||
usb_free( rx_packet ); | |||
rx_packet = NULL; | |||
} | |||
} | |||
@@ -123,53 +180,33 @@ int usb_serial_read(void *buffer, uint32_t size) | |||
} | |||
// discard any buffered input | |||
void usb_serial_flush_input(void) | |||
void usb_serial_flush_input() | |||
{ | |||
usb_packet_t *rx; | |||
if (!usb_configuration) return; | |||
if (rx_packet) { | |||
usb_free(rx_packet); | |||
if ( !usb_configuration ) | |||
return; | |||
if ( rx_packet ) | |||
{ | |||
usb_free( rx_packet ); | |||
rx_packet = NULL; | |||
} | |||
while (1) { | |||
rx = usb_rx(CDC_RX_ENDPOINT); | |||
if (!rx) break; | |||
usb_free(rx); | |||
while (1) | |||
{ | |||
rx = usb_rx( CDC_RX_ENDPOINT ); | |||
if ( !rx ) | |||
break; | |||
usb_free( rx ); | |||
} | |||
} | |||
// Maximum number of transmit packets to queue so we don't starve other endpoints for memory | |||
#define TX_PACKET_LIMIT 8 | |||
// When the PC isn't listening, how long do we wait before discarding data? If this is | |||
// too short, we risk losing data during the stalls that are common with ordinary desktop | |||
// software. If it's too long, we stall the user's program when no software is running. | |||
#define TX_TIMEOUT_MSEC 70 | |||
#if F_CPU == 96000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596) | |||
#elif F_CPU == 48000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428) | |||
#elif F_CPU == 24000000 | |||
#define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) | |||
#endif | |||
// When we've suffered the transmit timeout, don't wait again until the computer | |||
// begins accepting data. If no software is running to receive, we'll just discard | |||
// data as rapidly as Serial.print() can generate it, until there's something to | |||
// actually receive it. | |||
static uint8_t transmit_previous_timeout=0; | |||
// transmit a character. 0 returned on success, -1 on error | |||
int usb_serial_putchar(uint8_t c) | |||
int usb_serial_putchar( uint8_t c ) | |||
{ | |||
return usb_serial_write(&c, 1); | |||
return usb_serial_write( &c, 1 ); | |||
} | |||
int usb_serial_write(const void *buffer, uint32_t size) | |||
int usb_serial_write( const void *buffer, uint32_t size ) | |||
{ | |||
uint32_t len; | |||
uint32_t wait_count; | |||
@@ -177,21 +214,28 @@ int usb_serial_write(const void *buffer, uint32_t size) | |||
uint8_t *dest; | |||
tx_noautoflush = 1; | |||
while (size > 0) { | |||
if (!tx_packet) { | |||
while ( size > 0 ) | |||
{ | |||
if ( !tx_packet ) | |||
{ | |||
wait_count = 0; | |||
while (1) { | |||
if (!usb_configuration) { | |||
while ( 1 ) | |||
{ | |||
if ( !usb_configuration ) | |||
{ | |||
tx_noautoflush = 0; | |||
return -1; | |||
} | |||
if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) { | |||
if ( usb_tx_packet_count( CDC_TX_ENDPOINT ) < TX_PACKET_LIMIT ) | |||
{ | |||
tx_noautoflush = 1; | |||
tx_packet = usb_malloc(); | |||
if (tx_packet) break; | |||
if ( tx_packet ) | |||
break; | |||
tx_noautoflush = 0; | |||
} | |||
if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) { | |||
if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout ) | |||
{ | |||
transmit_previous_timeout = 1; | |||
return -1; | |||
} | |||
@@ -200,14 +244,17 @@ int usb_serial_write(const void *buffer, uint32_t size) | |||
} | |||
transmit_previous_timeout = 0; | |||
len = CDC_TX_SIZE - tx_packet->index; | |||
if (len > size) len = size; | |||
if ( len > size ) | |||
len = size; | |||
dest = tx_packet->buf + tx_packet->index; | |||
tx_packet->index += len; | |||
size -= len; | |||
while (len-- > 0) *dest++ = *src++; | |||
if (tx_packet->index >= CDC_TX_SIZE) { | |||
while ( len-- > 0 ) | |||
*dest++ = *src++; | |||
if ( tx_packet->index >= CDC_TX_SIZE ) | |||
{ | |||
tx_packet->len = CDC_TX_SIZE; | |||
usb_tx(CDC_TX_ENDPOINT, tx_packet); | |||
usb_tx( CDC_TX_ENDPOINT, tx_packet ); | |||
tx_packet = NULL; | |||
} | |||
usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; | |||
@@ -216,43 +263,53 @@ int usb_serial_write(const void *buffer, uint32_t size) | |||
return 0; | |||
} | |||
void usb_serial_flush_output(void) | |||
void usb_serial_flush_output() | |||
{ | |||
if (!usb_configuration) return; | |||
if ( !usb_configuration ) | |||
return; | |||
tx_noautoflush = 1; | |||
if (tx_packet) { | |||
if ( tx_packet ) | |||
{ | |||
usb_cdc_transmit_flush_timer = 0; | |||
tx_packet->len = tx_packet->index; | |||
usb_tx(CDC_TX_ENDPOINT, tx_packet); | |||
usb_tx( CDC_TX_ENDPOINT, tx_packet ); | |||
tx_packet = NULL; | |||
} else { | |||
} | |||
else | |||
{ | |||
usb_packet_t *tx = usb_malloc(); | |||
if (tx) { | |||
if ( tx ) | |||
{ | |||
usb_cdc_transmit_flush_timer = 0; | |||
usb_tx(CDC_TX_ENDPOINT, tx); | |||
} else { | |||
usb_tx( CDC_TX_ENDPOINT, tx ); | |||
} | |||
else | |||
{ | |||
usb_cdc_transmit_flush_timer = 1; | |||
} | |||
} | |||
tx_noautoflush = 0; | |||
} | |||
void usb_serial_flush_callback(void) | |||
void usb_serial_flush_callback() | |||
{ | |||
if (tx_noautoflush) return; | |||
if (tx_packet) { | |||
if ( tx_noautoflush ) | |||
return; | |||
if ( tx_packet ) | |||
{ | |||
tx_packet->len = tx_packet->index; | |||
usb_tx(CDC_TX_ENDPOINT, tx_packet); | |||
usb_tx( CDC_TX_ENDPOINT, tx_packet ); | |||
tx_packet = NULL; | |||
} else { | |||
usb_packet_t *tx = usb_malloc(); | |||
if (tx) { | |||
usb_tx(CDC_TX_ENDPOINT, tx); | |||
} else { | |||
if ( tx ) | |||
{ | |||
usb_tx( CDC_TX_ENDPOINT, tx ); | |||
} | |||
else | |||
{ | |||
usb_cdc_transmit_flush_timer = 1; | |||
} | |||
} | |||
} | |||
#endif // CDC_STATUS_INTERFACE && CDC_DATA_INTERFACE | |||
@@ -1,6 +1,7 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2013 PJRC.COM, LLC. | |||
* Modifications by Jacob Alexander (2013-2014) | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
@@ -31,29 +32,48 @@ | |||
#ifndef USBserial_h_ | |||
#define USBserial_h_ | |||
// ----- Includes ----- | |||
// Compiler Includes | |||
#include <inttypes.h> | |||
// ----- Defines ----- | |||
// Compatibility defines from AVR | |||
#define PROGMEM | |||
#define PGM_P const char * | |||
#define PSTR(str) (str) | |||
#define USB_SERIAL_DTR 0x01 | |||
#define USB_SERIAL_RTS 0x02 | |||
// ----- Variables ----- | |||
extern volatile uint8_t usb_cdc_line_coding[7]; | |||
int usb_serial_getchar(void); | |||
int usb_serial_peekchar(void); | |||
int usb_serial_available(void); | |||
int usb_serial_read(void *buffer, uint32_t size); | |||
void usb_serial_flush_input(void); | |||
int usb_serial_putchar(uint8_t c); | |||
int usb_serial_write(const void *buffer, uint32_t size); | |||
void usb_serial_flush_output(void); | |||
extern uint32_t usb_cdc_line_coding[2]; | |||
extern volatile uint8_t usb_cdc_line_rtsdtr; | |||
extern volatile uint8_t usb_cdc_transmit_flush_timer; | |||
extern volatile uint8_t usb_configuration; | |||
#define USB_SERIAL_DTR 0x01 | |||
#define USB_SERIAL_RTS 0x02 | |||
// ----- Functions ----- | |||
int usb_serial_available(); | |||
int usb_serial_getchar(); | |||
int usb_serial_peekchar(); | |||
int usb_serial_putchar( uint8_t c ); | |||
int usb_serial_read( void *buffer, uint32_t size ); | |||
int usb_serial_write( const void *buffer, uint32_t size ); | |||
void usb_serial_flush_input(); | |||
void usb_serial_flush_output(); | |||
#endif // USBserial_h_ | |||