-/* Copyright (C) 2011-2014 by Jacob Alexander
+/* Copyright (C) 2011-2016 by Jacob Alexander
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
// With an op of 1, the max number of characters is 6 + 1 for null
// e.g. "0xFFFF\0"
// op 2 and 4 require fewer characters (2+1 and 4+1 respectively)
- char tmpStr[7];
+ char tmpStr[11];
// Convert number
hex32ToStr_op( in, tmpStr, op );
break;
case 2: // 8-bit padding
case 4: // 16-bit padding
+ case 8: // 32-bit padding
while ( pos < op )
out[pos++] = '0';
break;
# Convenience script for loading firmware onto a dfu type device
# By default, initiates dfu-util
-SERIAL_PORT=""
-AUTO_SCREEN_SESSION=""
+SERIAL_PORT="/dev/kiibohd"
+AUTO_SCREEN_SESSION="/dev/kiibohd"
+NOSCREEN=0
PROG_NAME=$(basename $0)
# Parse all the command line arguments
SERIAL_PORT="$2"
shift
;;
+ -n|--noscreen)
+ NOSCREEN=1
+ shift
+ ;;
-h|--help)
echo "Usage: $PROG_NAME [options...]"
echo ""
if [[ "$SERIAL_PORT" != "" ]] && [[ -e "$SERIAL_PORT" ]]; then
echo "NOTE: This may fail if the uC is in a bad state or does not support remote flashing"
printf "reload\r" > $SERIAL_PORT
- sleep 2
fi
# Load via dfu-util
# Used for McHCK based uCs
if type dfu-util &>/dev/null; then
+ # Wait for device to appear
+ while true; do
+ dfu-util -l | grep -q "Kiibohd DFU"
+ if [ $? -eq 0 ]; then
+ break
+ fi
+ sleep 0.1
+ done
dfu-util -D @TARGET_BIN@
EXIT_STATUS=$?
else
fi
# Load Screen Session if specified
-if (( "$EXIT_STATUS" == "0" )) && [[ "$AUTO_SCREEN_SESSION" != "" ]]; then
+if (( "$EXIT_STATUS" == "0" )) && [[ "$AUTO_SCREEN_SESSION" != "" ]] && [[ $NOSCREEN -ne 1 ]]; then
if type screen &>/dev/null; then
- sleep 0.1
+ # Wait for interface
+ while [ ! -e $AUTO_SCREEN_SESSION ]; do
+ sleep 0.1
+ done
screen $AUTO_SCREEN_SESSION
else
echo "screen is not installed"
// the meaning and format of the data.
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
+#if enableKeyboard_define == 1
static uint8_t keyboard_report_desc[] = {
// Keyboard Collection
0x05, 0x01, // Usage Page (Generic Desktop),
0x81, 0x00, // Input (Data, Array),
0xc0, // End Collection - Consumer Control
};
+#endif
+
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
+#if enableMouse_define == 1
static uint8_t mouse_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xc0, // End Collection - Mouse Logical
0xc0 // End Collection - Mouse Application
};
+#endif
+
// Joystick Protocol, HID 1.11 spec, Apendix D, page 64-65
+#if enableJoystick_define == 1
static uint8_t joystick_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
+ 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
// ----- USB Configuration -----
+// Check for non-selected USB descriptors to update the total interface count
+// XXX This must be correct or some OSs/Init sequences will not initialize the keyboard/device
+#if enableKeyboard_define != 1
+#undef KEYBOARD_INTERFACES
+#define KEYBOARD_INTERFACES 0
+#endif
+
+#if enableMouse_define != 1
+#undef MOUSE_INTERFACES
+#define MOUSE_INTERFACES 0
+#endif
+
+#if enableJoystick_define != 1
+#undef JOYSTICK_INTERFACES
+#define JOYSTICK_INTERFACES 0
+#endif
+
+#if enableVirtualSerialPort_define != 1
+#undef CDC_INTERFACES
+#define CDC_INTERFACES 0
+#endif
+
+#if enableRawIO_define != 1
+#undef RAWIO_INTERFACES
+#define RAWIO_INTERFACES 0
+#endif
+
+// Determine number of interfaces
+#define NUM_INTERFACE (KEYBOARD_INTERFACES + CDC_INTERFACES + MOUSE_INTERFACES + JOYSTICK_INTERFACES + RAWIO_INTERFACES)
+
+
// USB Configuration Descriptor. This huge descriptor tells all
// of the devices capbilities.
-static uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
+static uint8_t config_descriptor[] = {
// --- 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
- MSB(CONFIG_DESC_SIZE),
+ 0xFF, // wTotalLength - XXX Set in usb_init (simplifies defines)
+ 0xFF,
NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xA0, // bmAttributes
250, // bMaxPower - Entry Index 8
+
+//
+// --- Keyboard Endpoint Descriptors ---
+//
+#if enableKeyboard_define == 1
+#define KEYBOARD_DESC_TOTAL_OFFSET (KEYBOARD_DESC_SIZE + NKRO_KEYBOARD_DESC_SIZE + SYS_CTRL_DESC_SIZE)
+#define NKRO_KEYBOARD_DESC_BASE_OFFSET (KEYBOARD_DESC_BASE_OFFSET + KEYBOARD_DESC_SIZE)
+#define SYS_CTRL_DESC_BASE_OFFSET (KEYBOARD_DESC_BASE_OFFSET + KEYBOARD_DESC_SIZE + NKRO_KEYBOARD_DESC_SIZE)
+
// --- Keyboard HID --- Boot Mode Keyboard Interface
// - 9 bytes -
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
NKRO_KEYBOARD_SIZE, 0, // wMaxPacketSize
NKRO_KEYBOARD_INTERVAL, // bInterval
+// --- System/Consumer Control ---
+// - 9 bytes -
+ // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
+ 9, // bLength
+ 4, // bDescriptorType
+ SYS_CTRL_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 1, // bNumEndpoints
+ 0x03, // bInterfaceClass (0x03 = HID)
+ 0x01, // bInterfaceSubClass (0x00 = Non-Boot, 0x01 = Boot)
+ 0x00, // bInterfaceProtocol (0x00 = None)
+ SYS_CTRL_INTERFACE + 4, // iInterface
+// - 9 bytes -
+ // HID interface descriptor, HID 1.11 spec, section 6.2.1
+ 9, // bLength
+ 0x21, // bDescriptorType
+ 0x11, 0x01, // bcdHID
+ KeyboardLocale_define, // bCountryCode
+ 1, // bNumDescriptors
+ 0x22, // bDescriptorType
+ LSB(sizeof(sys_ctrl_report_desc)), // wDescriptorLength
+ MSB(sizeof(sys_ctrl_report_desc)),
+// - 7 bytes -
+ // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+ 7, // bLength
+ 5, // bDescriptorType
+ SYS_CTRL_ENDPOINT | 0x80, // bEndpointAddress
+ 0x03, // bmAttributes (0x03=intr)
+ SYS_CTRL_SIZE, 0, // wMaxPacketSize
+ SYS_CTRL_INTERVAL, // bInterval
+#else
+#define KEYBOARD_DESC_TOTAL_OFFSET (0)
+#endif
+
+
+//
+// --- CDC / Serial Port Endpoint Descriptors ---
+//
+#if enableVirtualSerialPort_define == 1
+#define SERIAL_CDC_DESC_TOTAL_OFFSET (SERIAL_CDC_DESC_SIZE)
+
// --- Serial CDC --- CDC IAD Descriptor
// - 8 bytes -
// interface association descriptor, USB ECN, Table 9-Z
0x02, // bFunctionClass
0x02, // bFunctionSubClass
0x01, // bFunctionProtocol
- CDC_STATUS_INTERFACE + 4, // iFunction
+ 0, // iFunction (XXX No interface index, don't give string -HaaTa)
// --- Serial CDC --- CDC Data Interface
// - 9 bytes -
0x02, // bmAttributes (0x02=bulk)
CDC_TX_SIZE, 0, // wMaxPacketSize
0, // bInterval
+#else
+#define SERIAL_CDC_DESC_TOTAL_OFFSET (0)
+#endif
+
+
+//
+// --- Raw IO Endpoint Descriptors ---
+//
+#if enableRawIO_define == 1
+#define RAWIO_DESC_TOTAL_OFFSET (RAWIO_DESC_SIZE)
+
+// --- Vendor Specific / RAW I/O ---
+// - 9 bytes -
+ // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
+ 9, // bLength
+ 4, // bDescriptorType
+ RAWIO_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 2, // bNumEndpoints
+ 0xFF, // bInterfaceClass (0xFF)
+ 0xFF, // bInterfaceSubClass
+ 0xFF, // bInterfaceProtocol
+ RAWIO_INTERFACE + 4, // iInterface
+
+// - 7 bytes -
+ // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+ 7, // bLength
+ 5, // bDescriptorType
+ RAWIO_TX_ENDPOINT | 0x80, // bEndpointAddress
+ 0x02, // bmAttributes (0x02=bulk)
+ RAWIO_TX_SIZE, 0, // wMaxPacketSize
+ RAWIO_TX_INTERVAL, // bInterval
+
+// - 7 bytes -
+ // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+ 7, // bLength
+ 5, // bDescriptorType
+ RAWIO_RX_ENDPOINT, // bEndpointAddress
+ 0x02, // bmAttributes (0x02=bulk)
+ RAWIO_RX_SIZE, 0, // wMaxPacketSize
+ RAWIO_RX_INTERVAL, // bInterval
+#else
+#define RAWIO_DESC_TOTAL_OFFSET (0)
+#endif
+
+
+//
+// --- Mouse Endpoint Descriptors ---
+//
+#if enableMouse_define == 1
+#define MOUSE_DESC_TOTAL_OFFSET (MOUSE_DESC_SIZE)
// --- Mouse Interface ---
// - 9 bytes -
0x03, // bmAttributes (0x03=intr)
MOUSE_SIZE, 0, // wMaxPacketSize
MOUSE_INTERVAL, // bInterval
+#else
+#define MOUSE_DESC_TOTAL_OFFSET (0)
+#endif
+
+
+//
+// --- Joystick Endpoint Descriptors ---
+//
+#if enableJoystick_define == 1
+#define JOYSTICK_DESC_TOTAL_OFFSET (JOYSTICK_DESC_SIZE)
// --- Joystick Interface ---
// - 9 bytes -
0x03, // bmAttributes (0x03=intr)
JOYSTICK_SIZE, 0, // wMaxPacketSize
JOYSTICK_INTERVAL, // bInterval
+#else
+#define JOYSTICK_DESC_TOTAL_OFFSET (0)
+#endif
-// --- System/Consumer Control ---
-// - 9 bytes -
- // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
- 9, // bLength
- 4, // bDescriptorType
- SYS_CTRL_INTERFACE, // bInterfaceNumber
- 0, // bAlternateSetting
- 1, // bNumEndpoints
- 0x03, // bInterfaceClass (0x03 = HID)
- 0x01, // bInterfaceSubClass (0x00 = Non-Boot, 0x01 = Boot)
- 0x00, // bInterfaceProtocol (0x00 = None)
- SYS_CTRL_INTERFACE + 4, // iInterface
-// - 9 bytes -
- // HID interface descriptor, HID 1.11 spec, section 6.2.1
- 9, // bLength
- 0x21, // bDescriptorType
- 0x11, 0x01, // bcdHID
- KeyboardLocale_define, // bCountryCode
- 1, // bNumDescriptors
- 0x22, // bDescriptorType
- LSB(sizeof(sys_ctrl_report_desc)), // wDescriptorLength
- MSB(sizeof(sys_ctrl_report_desc)),
-// - 7 bytes -
- // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
- 7, // bLength
- 5, // bDescriptorType
- SYS_CTRL_ENDPOINT | 0x80, // bEndpointAddress
- 0x03, // bmAttributes (0x03=intr)
- SYS_CTRL_SIZE, 0, // wMaxPacketSize
- SYS_CTRL_INTERVAL, // bInterval
};
uint8_t *usb_bMaxPower = &config_descriptor[8];
usb_string_descriptor( usb_string_manufacturer_name_default, STR_MANUFACTURER );
usb_string_descriptor( usb_string_product_name_default, STR_PRODUCT );
usb_string_descriptor( usb_string_serial_number_default, STR_SERIAL );
+
+#if enableKeyboard_define == 1
usb_string_descriptor( usb_string_keyboard_name, KEYBOARD_NAME );
usb_string_descriptor( usb_string_nkro_keyboard_name, NKRO_KEYBOARD_NAME );
+usb_string_descriptor( usb_string_sys_ctrl_name, SYS_CTRL_NAME );
+#endif
+
+#if enableVirtualSerialPort_define == 1
usb_string_descriptor( usb_string_cdc_status_name, CDC_STATUS_NAME );
usb_string_descriptor( usb_string_cdc_data_name, CDC_DATA_NAME );
+#endif
+
+#if enableRawIO_define == 1
+usb_string_descriptor( usb_string_rawio_name, RAWIO_NAME );
+#endif
+
+#if enableMouse_define == 1
usb_string_descriptor( usb_string_mouse_name, MOUSE_NAME );
+#endif
+
+#if enableJoystick_define == 1
usb_string_descriptor( usb_string_joystick_name, JOYSTICK_NAME );
-usb_string_descriptor( usb_string_sys_ctrl_name, SYS_CTRL_NAME );
+#endif
// ----- Descriptors List -----
+#define iInterfaceString(num, var) \
+ {0x0300 + 4 + num, 0x0409, (const uint8_t *)&var, 0 }
+
// This table provides access to all the descriptor data above.
const usb_descriptor_list_t usb_descriptor_list[] = {
{0x0600, 0x0000, device_qualifier_descriptor, sizeof(device_qualifier_descriptor)},
{0x0A00, 0x0000, usb_debug_descriptor, sizeof(usb_debug_descriptor)},
+ {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},
+ {0x0303, 0x0409, (const uint8_t *)&usb_string_serial_number, 0},
+
+#if enableKeyboard_define == 1
{0x2200, KEYBOARD_INTERFACE, keyboard_report_desc, sizeof(keyboard_report_desc)},
- {0x2100, KEYBOARD_INTERFACE, config_descriptor + KEYBOARD_DESC_OFFSET, 9},
+ {0x2100, KEYBOARD_INTERFACE, config_descriptor + KEYBOARD_DESC_BASE_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},
-
- {0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)},
- {0x2100, MOUSE_INTERFACE, config_descriptor + MOUSE_DESC_OFFSET, 9},
-
- {0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)},
- {0x2100, JOYSTICK_INTERFACE, config_descriptor + JOYSTICK_DESC_OFFSET, 9},
+ {0x2100, NKRO_KEYBOARD_INTERFACE, config_descriptor + NKRO_KEYBOARD_DESC_BASE_OFFSET, 9},
{0x2200, SYS_CTRL_INTERFACE, sys_ctrl_report_desc, sizeof(sys_ctrl_report_desc)},
- {0x2100, SYS_CTRL_INTERFACE, config_descriptor + SYS_CTRL_DESC_OFFSET, 9},
-
-#define iInterfaceString(num, var) \
- {0x0300 + 4 + num, 0x409, (const uint8_t *)&var, 0 }
+ {0x2100, SYS_CTRL_INTERFACE, config_descriptor + SYS_CTRL_DESC_BASE_OFFSET, 9},
- {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},
- {0x0303, 0x0409, (const uint8_t *)&usb_string_serial_number, 0},
iInterfaceString( KEYBOARD_INTERFACE, usb_string_keyboard_name ),
iInterfaceString( NKRO_KEYBOARD_INTERFACE, usb_string_nkro_keyboard_name ),
+ iInterfaceString( SYS_CTRL_INTERFACE, usb_string_sys_ctrl_name ),
+#endif
+
+#if enableVirtualSerialPort_define == 1
iInterfaceString( CDC_STATUS_INTERFACE, usb_string_cdc_status_name ),
iInterfaceString( CDC_DATA_INTERFACE, usb_string_cdc_data_name ),
+#endif
+
+#if enableRawIO_define == 1
+ iInterfaceString( RAWIO_INTERFACE, usb_string_rawio_name ),
+#endif
+
+#if enableMouse_define == 1
+ {0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)},
+ {0x2100, MOUSE_INTERFACE, config_descriptor + MOUSE_DESC_BASE_OFFSET, 9},
iInterfaceString( MOUSE_INTERFACE, usb_string_mouse_name ),
+#endif
+
+#if enableJoystick_define == 1
+ {0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)},
+ {0x2100, JOYSTICK_INTERFACE, config_descriptor + JOYSTICK_DESC_BASE_OFFSET, 9},
iInterfaceString( JOYSTICK_INTERFACE, usb_string_joystick_name ),
- iInterfaceString( SYS_CTRL_INTERFACE, usb_string_sys_ctrl_name ),
+#endif
+
{0, 0, NULL, 0}
};
+// Simplifies defines for USB descriptors
+void usb_set_config_descriptor_size()
+{
+ config_descriptor[2] = LSB( sizeof( config_descriptor ) );
+ config_descriptor[3] = MSB( sizeof( config_descriptor ) );
+}
+
// ----- Endpoint Configuration -----
#define DEVICE_SUBCLASS 0x00
#define DEVICE_PROTOCOL 0x00
#define EP0_SIZE 64
-#define NUM_ENDPOINTS 8
+#define NUM_ENDPOINTS 10 // XXX Can save some space if this can be calculated using KLL
#define NUM_USB_BUFFERS 30
-#define NUM_INTERFACE 7
+
+// XXX Remember to update total interface count, if it isn't correct some OSs will not initialize USB
+// Linux warns in dmesg
+// Mac OSX login screen will not initialize
+#define KEYBOARD_INTERFACES 3 // Boot, NKRO, SysCtrl
+#define CDC_INTERFACES 2
+#define MOUSE_INTERFACES 1
+#define JOYSTICK_INTERFACES 1
+#define RAWIO_INTERFACES 1
+
#define KEYBOARD_INTERFACE 0 // Keyboard
#define KEYBOARD_ENDPOINT 1
#define NKRO_KEYBOARD_INTERVAL 1
#define NKRO_KEYBOARD_NAME L"NKRO Keyboard"
+#define SYS_CTRL_INTERFACE 2 // Media Keys
+#define SYS_CTRL_ENDPOINT 3
+#define SYS_CTRL_SIZE 8
+#define SYS_CTRL_INTERVAL 1
+#define SYS_CTRL_NAME L"Media Keys"
+
#define CDC_IAD_DESCRIPTOR 1
-#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_STATUS_INTERFACE 3
+#define CDC_DATA_INTERFACE 4 // Serial
+#define CDC_ACM_ENDPOINT 4
+#define CDC_RX_ENDPOINT 5
+#define CDC_TX_ENDPOINT 6
#define CDC_ACM_SIZE 16
#define CDC_RX_SIZE 64
#define CDC_TX_SIZE 64
#define CDC_STATUS_NAME L"Virtual Serial Port - Status"
#define CDC_DATA_NAME L"Virtual Serial Port - Data"
-#define MOUSE_INTERFACE 4 // Mouse
-#define MOUSE_ENDPOINT 6
+#define RAWIO_INTERFACE 5 // RawIO
+#define RAWIO_TX_ENDPOINT 7
+#define RAWIO_TX_SIZE 64
+#define RAWIO_TX_INTERVAL 1
+#define RAWIO_RX_ENDPOINT 8
+#define RAWIO_RX_SIZE 64
+#define RAWIO_RX_INTERVAL 1
+#define RAWIO_NAME L"API Interface"
+
+#define MOUSE_INTERFACE 6 // Mouse
+#define MOUSE_ENDPOINT 9
#define MOUSE_SIZE 8
#define MOUSE_INTERVAL 1
#define MOUSE_NAME L"Mouse"
-#define JOYSTICK_INTERFACE 5 // Joystick
-#define JOYSTICK_ENDPOINT 7
+#define JOYSTICK_INTERFACE 7 // Joystick
+#define JOYSTICK_ENDPOINT 10
#define JOYSTICK_SIZE 16
#define JOYSTICK_INTERVAL 1
#define JOYSTICK_NAME L"Joystick"
-#define SYS_CTRL_INTERFACE 6 // Media Keys
-#define SYS_CTRL_ENDPOINT 8
-#define SYS_CTRL_SIZE 8
-#define SYS_CTRL_INTERVAL 1
-#define SYS_CTRL_NAME L"Media Keys"
-#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 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 SYS_CTRL_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9)
-#define CONFIG_DESC_SIZE (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9+9+7)
+// Descriptor sizes
+#define BASE_DESC_SIZE (9)
+#define KEYBOARD_DESC_SIZE (9+9+7)
+#define NKRO_KEYBOARD_DESC_SIZE (9+9+7)
+#define SYS_CTRL_DESC_SIZE (9+9+7)
+#define SERIAL_CDC_DESC_SIZE (8+9+5+5+4+5+7+9+7+7)
+#define RAWIO_DESC_SIZE (9+7+7)
+#define MOUSE_DESC_SIZE (9+9+7)
+#define JOYSTICK_DESC_SIZE (9+9+7)
+
+// Descriptor offsets
+#define KEYBOARD_DESC_BASE_OFFSET ( \
+ BASE_DESC_SIZE + \
+ 9 \
+)
+#define SERIAL_CDC_DESC_BASE_OFFSET ( \
+ BASE_DESC_SIZE + \
+ KEYBOARD_DESC_TOTAL_OFFSET + \
+ 8 \
+)
+#define RAWIO_DESC_BASE_OFFSET ( \
+ BASE_DESC_SIZE + \
+ KEYBOARD_DESC_TOTAL_OFFSET + \
+ SERIAL_CDC_DESC_TOTAL_OFFSET + \
+ 9 \
+)
+#define MOUSE_DESC_BASE_OFFSET ( \
+ BASE_DESC_SIZE + \
+ KEYBOARD_DESC_TOTAL_OFFSET + \
+ SERIAL_CDC_DESC_TOTAL_OFFSET + \
+ 9 \
+)
+#define JOYSTICK_DESC_BASE_OFFSET ( \
+ BASE_DESC_SIZE + \
+ KEYBOARD_DESC_TOTAL_OFFSET + \
+ SERIAL_CDC_DESC_TOTAL_OFFSET + \
+ MOUSE_DESC_TOTAL_OFFSET + \
+ 9 \
+)
+
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
-#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY
-#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY
+#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY
+#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY
-#define ENDPOINT8_CONFIG ENDPOINT_TRANSIMIT_ONLY
+#define ENDPOINT8_CONFIG ENDPOINT_RECEIVE_ONLY
+#define ENDPOINT9_CONFIG ENDPOINT_TRANSIMIT_ONLY
+#define ENDPOINT10_CONFIG ENDPOINT_TRANSIMIT_ONLY
extern uint8_t *usb_bMaxPower;
+
+// ----- Functions -----
+
+void usb_set_config_descriptor_size();
+
#include "usb_dev.h"
#include "usb_mem.h"
+#if enableVirtualSerialPort_define == 1
+#include "usb_serial.h"
+#endif
+
// ----- Defines -----
static void endpoint0_stall()
{
#ifdef UART_DEBUG_UNKNOWN
- print("STALL" NL );
+ print("STALL : ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
+ print(NL);
#endif
USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK;
}
void usb_reinit()
{
- power_neg_delay = 0;
usb_configuration = 0; // Clear USB configuration if we have one
USB0_CONTROL = 0; // Disable D+ Pullup to simulate disconnect
delay(10); // Delay is necessary to simulate disconnect
// Check if 100 ms has elapsed
if ( systick_millis_count - power_neg_time > 100 )
{
+ power_neg_delay = 0;
+
+ // USB Low Power Negotiation
+#if enableUSBLowPowerNegotiation_define == 1
+ // Check to see if bMaxPower has already be lowered
+ // This generally points to a USB bug (host or device?)
+ if ( *usb_bMaxPower == 50 )
+ {
+ warn_msg("Power negotiation delay detected again, likely a system/device USB bug");
+ return;
+ }
+
// Update bMaxPower
// The value set is in increments of 2 mA
// So 50 * 2 mA = 100 mA
// Re-initialize USB
usb_reinit();
+#else
+ warn_msg("USB Low Power Negotation Disabled, condition detected.");
+#endif
}
}
}
const uint8_t *cfg;
int i;
+ // Reset USB Init timer
+ USBInit_TimeEnd = systick_millis_count;
+ USBInit_Ticks++;
+
// If another request is made, disable the power negotiation check
// See GET_DESCRIPTOR - Configuration
if ( power_neg_delay )
endpoint0_stall();
return;
+#if enableVirtualSerialPort_define == 1
case 0x2221: // CDC_SET_CONTROL_LINE_STATE
usb_cdc_line_rtsdtr = setup.wValue;
- //serial_print("set control line state\n");
+ //info_print("set control line state");
goto send;
case 0x21A1: // CDC_GET_LINE_CODING
- data = (uint8_t*)usb_cdc_line_coding;
+ data = (uint8_t*)&usb_cdc_line_coding;
datalen = sizeof( usb_cdc_line_coding );
goto send;
case 0x2021: // CDC_SET_LINE_CODING
- // XXX Needed?
- //serial_print("set coding, waiting...\n");
- return;
+ // ZLP Reply
+ // Settings are applied in PID=OUT
+ goto send;
+#endif
case 0x0921: // HID SET_REPORT
+ // ZLP Reply
+ // Settings are applied in PID=OUT
+
+ #ifdef UART_DEBUG
+ print("report_type(");
+ printHex( setup.wValue >> 8 );
+ print(")report_id(");
+ printHex( setup.wValue & 0xFF );
+ print(")interface(");
+ printHex( setup.wIndex );
+ print(")len(");
+ printHex( setup.wLength );
+ print(")");
+ print( NL );
+ #endif
+
// Interface
switch ( setup.wIndex & 0xFF )
{
printHex( setup.wIndex );
print( NL );
endpoint0_stall();
- break;
+ return;
}
goto send;
datalen = list->length;
goto send;
}
- }
- endpoint0_stall();
- return;
+ }
+ endpoint0_stall();
+ return;
case 0x0A21: // HID SET_IDLE
#ifdef UART_DEBUG
print(NL);
#endif
reply_buffer[0] = USBKeys_Idle_Config;
+ data = reply_buffer;
datalen = 1;
goto send;
print(NL);
#endif
reply_buffer[0] = USBKeys_Protocol;
+ data = reply_buffer;
datalen = 1;
goto send;
// case 0xC940:
default:
#ifdef UART_DEBUG_UNKNOWN
- print("UNKNOWN");
+ print("UNKNOWN: ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
endpoint0_stall();
if ( size > EP0_SIZE )
size = EP0_SIZE;
- endpoint0_transmit(data, size);
+ endpoint0_transmit( data, size );
data += size;
datalen -= size;
size = datalen;
if ( size > EP0_SIZE )
size = EP0_SIZE;
- endpoint0_transmit(data, size);
+ endpoint0_transmit( data, size );
data += size;
datalen -= size;
//to be set to their default values. This includes setting the data toggle of
//any endpoint using data toggles to the value DATA0.
-//For endpoints using data toggle, regardless of whether an endpoint has the
-//Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the
-//data toggle being reinitialized to DATA0.
+// For endpoints using data toggle, regardless of whether an endpoint has the
+// Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the
+// data toggle being reinitialized to DATA0.
static void usb_control( uint32_t stat )
{
print(" - ");
#endif
- switch (pid)
+ switch ( pid )
{
case 0x0D: // Setup received from host
- //serial_print("PID=Setup\n");
- //if (count != 8) ; // panic?
// grab the 8 byte setup info
setup.word1 = *(uint32_t *)(buf);
setup.word2 = *(uint32_t *)(buf + 4);
//}
table[index(0, TX, EVEN)].desc = 0;
table[index(0, TX, ODD)].desc = 0;
+
// first IN after Setup is always DATA1
ep0_tx_data_toggle = 1;
#ifdef UART_DEBUG_UNKNOWN
- print("bmRequestType:");
- printHex(setup.bmRequestType);
- print(", bRequest:");
- printHex(setup.bRequest);
+ printHex( stat );
+ print(" PID=SETUP wRequestAndType:");
+ printHex(setup.wRequestAndType);
print(", wValue:");
printHex(setup.wValue);
print(", wIndex:");
printHex32(setup.word1);
print(" ");
printHex32(setup.word2);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
+
// actually "do" the setup request
usb_setup();
// unfreeze the USB, now that we're ready
case 0x01: // OUT transaction received from host
case 0x02:
#ifdef UART_DEBUG_UNKNOWN
- print("PID=OUT wRequestAndType:");
+ printHex( stat );
+ print(" PID=OUT wRequestAndType:");
printHex(setup.wRequestAndType);
print(", wValue:");
printHex(setup.wValue);
printHex32(setup.word1);
print(" ");
printHex32(setup.word2);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
// CDC Interface
- if ( setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/ )
+ #if enableVirtualSerialPort_define == 1
+ // CDC_SET_LINE_CODING - PID=OUT
+ // XXX - Getting lots of NAKs in Linux
+ if ( setup.wRequestAndType == 0x2021 )
{
- int i;
- uint8_t *dst = (uint8_t *)usb_cdc_line_coding;
- //serial_print("set line coding ");
- for ( i = 0; i < 7; i++ )
- {
- //serial_phex(*buf);
- *dst++ = *buf++;
- }
- //serial_phex32(usb_cdc_line_coding[0]);
- //serial_print("\n");
- if ( usb_cdc_line_coding[0] == 134 )
- usb_reboot_timer = 15;
- endpoint0_transmit( NULL, 0 );
+ // Copy over new line coding
+ memcpy( (void*)&usb_cdc_line_coding, buf, 7 );
+
+ #ifdef UART_DEBUG
+ // - Unused, but for the readers info -
+ print("dwDTERate(");
+ printInt32( usb_cdc_line_coding.dwDTERate );
+ print(")bCharFormat(");
+ printHex( usb_cdc_line_coding.bCharFormat );
+ print(")bParityType(");
+ printHex( usb_cdc_line_coding.bParityType );
+ print(")bDataBits(");
+ printHex( usb_cdc_line_coding.bDataBits );
+ print(")");
+ print( NL );
+ #endif
+
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
}
+ #endif
- // Keyboard SET_REPORT
- if ( setup.wRequestAndType == 0x921 && setup.wValue & 0x200 )
+ // Keyboard HID SET_REPORT - PID=OUT
+ #if enableKeyboard_define == 1
+ // XXX - Getting lots of NAKs in Linux
+ if ( setup.wRequestAndType == 0x0921 && setup.wValue & 0x200 )
{
+ #ifdef UART_DEBUG
+ print("report_type(");
+ printHex( setup.wValue >> 8 );
+ print(")report_id(");
+ printHex( setup.wValue & 0xFF );
+ print(")interface(");
+ printHex( setup.wIndex );
+ print(")len(");
+ printHex( setup.wLength );
+ print(")[");
+
+ for ( size_t len = 0; len < setup.wLength; len++ )
+ {
+ printHex( buf[ len ] );
+ print(" ");
+ }
+ print("]");
+ print( NL );
+ #endif
+
// Interface
switch ( setup.wIndex & 0xFF )
{
// Keyboard Interface
case KEYBOARD_INTERFACE:
USBKeys_LEDs = buf[0];
- endpoint0_transmit( NULL, 0 );
break;
// NKRO Keyboard Interface
case NKRO_KEYBOARD_INTERFACE:
+ // Already set with the control sequence
// Only use 2nd byte, first byte is the report id
USBKeys_LEDs = buf[1];
- endpoint0_transmit( NULL, 0 );
break;
default:
warn_msg("Unknown interface - ");
break;
}
- #ifdef UART_DEBUG
- for ( size_t len = 0; len < setup.wLength; len++ )
- {
- printHex( buf[ len ] );
- print(" ");
- }
- print( NL );
- #endif
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
}
+ #endif
// give the buffer back
b->desc = BDT_DESC( EP0_SIZE, DATA1 );
break;
case 0x09: // IN transaction completed to host
- #ifdef UART_DEBUG
- print("PID=IN:");
- printHex(stat);
+ data = ep0_tx_ptr;
+
+ #ifdef UART_DEBUG_UNKNOWN
+ printHex( stat );
+ print(" PID=IN wRequestAndType:");
+ printHex(setup.wRequestAndType);
+ print(", wValue:");
+ printHex(setup.wValue);
+ print(", wIndex:");
+ printHex(setup.wIndex);
+ print(", len:");
+ printHex(setup.wLength);
+ print(" -- ");
+ printHex32(setup.word1);
+ print(" ");
+ printHex32(setup.word2);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
+ if ( data ) print(" DATA ");
print(NL);
#endif
// send remaining data, if any...
- data = ep0_tx_ptr;
if ( data )
{
size = ep0_tx_len;
- if (size > EP0_SIZE) size = EP0_SIZE;
- endpoint0_transmit(data, size);
+ if (size > EP0_SIZE)
+ {
+ size = EP0_SIZE;
+ }
+ endpoint0_transmit( data, size );
data += size;
ep0_tx_len -= size;
ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL;
USB0_ADDR = setup.wValue;
}
+ // CDC_SET_LINE_CODING - PID=IN
+ #if enableVirtualSerialPort_define == 1
+ if ( setup.wRequestAndType == 0x2021 )
+ {
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
+ }
+ #endif
+
+ // Keyboard HID SET_REPORT - PID=IN
+ #if enableKeyboard_define == 1
+ // XXX - Getting lots of NAKs in Linux
+ if ( setup.wRequestAndType == 0x0921 && setup.wValue & 0x200 )
+ {
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
+ }
+ #endif
+
break;
default:
- #ifdef UART_DEBUG
- print("PID=unknown:");
+ #ifdef UART_DEBUG_UNKNOWN
+ print("PID=unknown: ");
printHex(pid);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
break;
//print("USB RX");
usb_packet_t *ret;
endpoint--;
+
+ // Make sure this is a valid endpoint
if ( endpoint >= NUM_ENDPOINTS )
+ {
return NULL;
+ }
+
__disable_irq();
+
+ // Receive packet, check pointer
ret = rx_first[endpoint];
if ( ret )
+ {
rx_first[ endpoint ] = ret->next;
- usb_rx_byte_count_data[ endpoint ] -= ret->len;
+ usb_rx_byte_count_data[ endpoint ] -= ret->len;
+ }
+
__enable_irq();
+
//serial_print("rx, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
return;
}
-//#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd))
-//#define stat2bufferdescriptor(stat) (table + ((stat) >> 2))
-
-void usb_tx( uint32_t endpoint, usb_packet_t *packet )
+// Call whenever there's an action that may wake the host device
+void usb_resume()
{
- // Update expiry counter
- USBKeys_Idle_Expiry = systick_millis_count;
-
// If we have been sleeping, try to wake up host
- if ( usb_dev_sleep )
+ if ( usb_dev_sleep && usb_configured() )
{
+ #if enableUSBResume_define == 1
+ #if enableVirtualSerialPort_define != 1
+ info_print("Attempting to resume the host");
+ #endif
// Force wake-up for 10 ms
// According to the USB Spec a device must hold resume for at least 1 ms but no more than 15 ms
USB0_CTL |= USB_CTL_RESUME;
USB0_CTL &= ~(USB_CTL_RESUME);
delay(50); // Wait for at least 50 ms to make sure the bus is clear
usb_dev_sleep = 0; // Make sure we don't call this again, may crash system
+ #else
+ warn_print("Host Resume Disabled");
+ #endif
}
+}
+
+void usb_tx( uint32_t endpoint, usb_packet_t *packet )
+{
+ // Update expiry counter
+ USBKeys_Idle_Expiry = systick_millis_count;
+
// Since we are transmitting data, USB will be brought out of sleep/suspend
// if it's in that state
// Use the currently set descriptor value
{
uint8_t status, stat, t;
- //serial_print("isr");
- //status = USB0_ISTAT;
- //serial_phex(status);
- //serial_print("\n");
restart:
status = USB0_ISTAT;
/*
- print("USB ISR STATUS: ");
+ print(" ISR(");
printHex( status );
- print( NL );
+ print(") ");
*/
if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) )
}
// CDC Interface
+ #if enableVirtualSerialPort_define == 1
t = usb_cdc_transmit_flush_timer;
if ( t )
{
if ( t == 0 )
usb_serial_flush_callback();
}
+ #endif
}
USB0_ISTAT = USB_INTEN_SOFTOKEN;
// The USB Module triggers this interrupt when it detects the bus has been idle for 3 ms
if ( (status & USB_ISTAT_SLEEP /* 10 */ ) )
{
- //info_print("Host has requested USB sleep/suspend state");
+#if enableUSBSuspend_define == 1
+ // Can cause issues with the virtual serial port
+ #if enableVirtualSerialPort_define != 1
+ info_print("Host has requested USB sleep/suspend state");
+ #endif
Output_update_usb_current( 100 ); // Set to 100 mA
usb_dev_sleep = 1;
+#else
+ info_print("USB Suspend Detected - Firmware USB Suspend Disabled");
+#endif
USB0_ISTAT |= USB_ISTAT_SLEEP;
}
// On USB Resume, unset the usb_dev_sleep so we don't keep sending resume signals
if ( (status & USB_ISTAT_RESUME /* 20 */ ) )
{
- //info_print("Host has woken-up/resumed from sleep/suspend state");
+ // Can cause issues with the virtual serial port
+ #if enableVirtualSerialPort_define != 1
+ info_print("Host has woken-up/resumed from sleep/suspend state");
+ #endif
Output_update_usb_current( *usb_bMaxPower * 2 );
usb_dev_sleep = 0;
USB0_ISTAT |= USB_ISTAT_RESUME;
print("USB INIT"NL);
#endif
+ USBInit_TimeStart = systick_millis_count;
+ USBInit_Ticks = 0;
+
+ // XXX Set wTotalLength here instead of using defines
+ // Simplifies defines considerably
+ usb_set_config_descriptor_size();
+
// Clear out endpoints table
for ( int i = 0; i <= NUM_ENDPOINTS * 4; i++ )
{
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 -----
void usb_tx( uint32_t endpoint, usb_packet_t *packet );
void usb_tx_isr( uint32_t endpoint, usb_packet_t *packet );
+void usb_resume();
+
uint32_t usb_tx_byte_count( uint32_t endpoint );
uint32_t usb_tx_packet_count( uint32_t endpoint );
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
- * Modified by Jacob Alexander (2015)
+ * Modified by Jacob Alexander (2015-2016)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* SOFTWARE.
*/
+#if enableJoystick_define == 1
+
// ----- Includes -----
// Compiler Includes
return 0;
}
+#endif
+
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
- * Modifications by Jacob Alexander 2013-2015
+ * Modifications by Jacob Alexander 2013-2016
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* SOFTWARE.
*/
+#include <kll_defs.h>
+#if enableKeyboard_define == 1
+
// ----- Includes -----
// Compiler Includes
}
}
+ // USB Timeout, drop the packet, and potentially try something more drastic to re-enable the bus
if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout )
{
transmit_previous_timeout = 1;
- warn_print("USB Transmit Timeout...restarting device");
USBKeys_Changed = USBKeyChangeState_None; // Indicate packet lost
+ #if enableDeviceRestartOnUSBTimeout == 1
+ warn_print("USB Transmit Timeout...restarting device");
usb_device_software_reset();
+ #else
+ warn_print("USB Transmit Timeout...auto-restart disabled");
+ #endif
+ // Try to wakeup
return;
}
+
+ // Try to wake up the device if we can't allocate a packet for some reason
+ // XXX This is a bit aggressive, but seems to work well. Unfortunately, not as quick as I'd like it -HaaTa
+ usb_resume();
+
yield();
}
return;
}
+#endif
+
* SOFTWARE.
*/
+#include <kll_defs.h>
+#if enableMouse_define == 1
+
// ----- Includes -----
// Compiler Includes
}
}
+#endif
+
--- /dev/null
+/* Copyright (C) 2016 by Jacob Alexander
+ *
+ * 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.
+ */
+
+#include <kll_defs.h>
+#if enableRawIO_define == 1
+
+// ----- Includes -----
+
+// Compiler Includes
+#include <string.h> // For memcpy
+
+// Project Includes
+#include <Lib/OutputLib.h>
+#include <print.h>
+
+// Local Includes
+#include "usb_dev.h"
+#include "usb_rawio.h"
+
+
+
+// ----- Defines -----
+
+// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
+#define TX_PACKET_LIMIT 5
+
+
+
+// ----- Functions -----
+
+// Check for packets available from host
+uint32_t usb_rawio_available()
+{
+ // Error if USB isn't configured
+ if ( !usb_configuration )
+ return 0;
+
+ // Query number of bytes available from the endpoint
+ return usb_rx_byte_count( RAWIO_RX_ENDPOINT );
+}
+
+// Retrieve packets from host
+// Always returns RAWIO_RX_SIZE
+int32_t usb_rawio_rx( void *buf, uint32_t timeout )
+{
+ usb_packet_t *rx_packet;
+ uint32_t begin = millis();
+
+ // Read
+ while ( 1 )
+ {
+ // Error if USB isn't configured
+ if ( !usb_configuration )
+ return -1;
+
+ // Retrieve packet
+ rx_packet = usb_rx( RAWIO_RX_ENDPOINT );
+ if ( rx_packet )
+ break;
+
+ // Check for timeout
+ if ( millis() - begin > timeout || !timeout )
+ {
+ warn_msg("RAWIO Rx - Timeout, dropping packet.");
+ return 0;
+ }
+
+ yield();
+ }
+
+ // Transfer packet from USB buffer to given buffer
+ memcpy( buf, rx_packet->buf, RAWIO_RX_SIZE );
+ usb_free( rx_packet );
+
+ // Data sent in full packet chunks
+ return RAWIO_RX_SIZE;
+}
+
+// Send packet to host
+// XXX Only transfers RAWIO_TX_SIZE on each call (likely 64 bytes)
+// Always returns RAWIO_TX_SIZE
+int32_t usb_rawio_tx( const void *buf, uint32_t timeout )
+{
+ usb_packet_t *tx_packet;
+ uint32_t begin = millis();
+
+ while ( 1 )
+ {
+ // Error if USB isn't configured
+ if ( !usb_configuration )
+ return -1;
+
+ // Make sure we haven't exceeded the outgoing packet limit
+ if ( usb_tx_packet_count( RAWIO_TX_ENDPOINT ) < TX_PACKET_LIMIT )
+ {
+ // Allocate a packet buffer
+ tx_packet = usb_malloc();
+ if ( tx_packet )
+ break;
+ }
+
+ // Check for timeout
+ if ( millis() - begin > timeout )
+ {
+ warn_msg("RAWIO Tx - Timeout, dropping packet.");
+ return 0;
+ }
+
+ yield();
+ }
+
+ // Copy input buffer to usb packet buffer and assign length
+ memcpy( tx_packet->buf, buf, RAWIO_TX_SIZE );
+ tx_packet->len = RAWIO_TX_SIZE;
+
+ // Send USB packet
+ usb_tx( RAWIO_TX_ENDPOINT, tx_packet );
+
+ return RAWIO_TX_SIZE;
+}
+
+#endif
+
--- /dev/null
+/* Copyright (C) 2016 by Jacob Alexander
+ *
+ * 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.
+ */
+
+#pragma once
+
+// ----- Includes -----
+
+#include "usb_desc.h"
+
+
+
+// ----- Functions -----
+
+uint32_t usb_rawio_available();
+int32_t usb_rawio_rx( void *buf, uint32_t timeout );
+int32_t usb_rawio_tx( const void *buf, uint32_t timeout );
+
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
- * Modified by Jacob Alexander 2013-2015
+ * Modified by Jacob Alexander 2013-2016
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* SOFTWARE.
*/
+#include <kll_defs.h>
+#if enableVirtualSerialPort_define == 1
+
// ----- Includes -----
// Compiler Includes
// ----- 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 };
+// Serial port settings (baud rate, control signals, etc) set by the host
+// These are *ignored*, except to return back to the host if requested
+volatile USBCDCLineCoding usb_cdc_line_coding = {
+ 115200,
+ 0,
+ 0,
+ 8,
+};
+
volatile uint8_t usb_cdc_line_rtsdtr = 0;
volatile uint8_t usb_cdc_transmit_flush_timer = 0;
}
}
+#endif
+
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
- * Modifications by Jacob Alexander (2013-2015)
+ * Modifications by Jacob Alexander (2013-2016)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
+// ----- Structs -----
+
+// See: Universal Serial Bus Class Definitions for Communication Devices 1.11 Table 50
+// dwDTERate - Baud Rate : 4 bytes
+// bCharFormat - Stop Bits : 1 byte
+// 0: 1 stop bit
+// 1: 1.5 stop bits
+// 2: 2 stop bits
+// bParityType - Parity : 1 byte
+// 0: None
+// 1: Odd
+// 2: Even
+// 3: Mark
+// 4: Space
+// bDataBits - Data Bits : 1 byte
+// (5,6,7,8 or 16)
+//
+// Struct is 7 bytes wide
+typedef struct USBCDCLineCoding {
+ uint32_t dwDTERate; // Baud Rate
+ uint8_t bCharFormat; // Stop Bits
+ uint8_t bParityType; // Parity
+ uint8_t bDataBits; // Data Bits
+} USBCDCLineCoding;
+
+
+
// ----- Variables -----
-extern volatile uint8_t usb_cdc_line_coding[7];
+extern volatile USBCDCLineCoding usb_cdc_line_coding;
extern volatile uint8_t usb_cdc_line_rtsdtr;
extern volatile uint8_t usb_cdc_transmit_flush_timer;
KLL = 0.3d;
# Modified Date
-Date = 2016-03-21;
+Date = 2016-05-31;
# Output capabilities
flashMode => Output_flashMode_capability();
+
+## USB Compatibility Flags ##
+# Some OSs and USB Chipsets have issues with USB features
+# These flags are available to provide ways to debug them
+
+# Enable USB Suspend/Low Power mode
+# After a period of inactivity, the USB host may request that the device go into low power mode
+# This is different than system sleep, though it may occur around the same time
+enableUSBSuspend => enableUSBSuspend_define;
+enableUSBSuspend = 1;
+
+# Enable Low-power Negotiation
+# In order to support low-powered USB hosts, such as an Apple IPad, a low power auto-negotiation scheme has been implemented
+# Unfortunately, badly behaved USB Chipsets and OSs may not work correctly with this support enabled
+# Typical symptoms:
+# * USB constantly re-initializing when first plugging in
+enableUSBLowPowerNegotiation => enableUSBLowPowerNegotiation_define;
+enableUSBLowPowerNegotiation = 0;
+
+# Enable Device Restart on USB Timeout
+# *USE AS LAST RETORT*
+# To work around some USB OS, Chipset and Firwmare bugs, an auto-restart mechanism has been implemented
+# Depending on the situation, this can be rather aggressive.
+# This behaves differently than the Low-power negotiation restart and have very different triggering schemes.
+enableDeviceRestartOnUSBTimeout => enableDeviceRestartOnUSBTimeout_define;
+enableDeviceRestartOnUSBTimeout = 0;
+
+# Enable Host-Resume (wake-from-sleep)
+# On specific actions (such as USB key actions), will trigger the host device to wake if USB is suspended
+enableUSBResume => enableUSBResume_define;
+enableUSBResume = 1;
+
+## USB Endpoint Configuration ##
+# 1 - Enable endpoint
+# 0 - Disable endpoint
+# Any/all endpoints can be disabled
+# But you'll lose functionality for that feature
+# Disabling endpoints will save RAM and Flash on the target MCU
+
+# Joystick Endpoint
+# *Currently Unused*
+enableJoystick => enableJoystick_define;
+enableJoystick = 0;
+
+# Mouse Endpoint
+enableMouse => enableMouse_define;
+enableMouse = 1;
+
+# Keyboard Endpoint
+enableKeyboard => enableKeyboard_define;
+enableKeyboard = 1;
+
+# CDC / Serial Port Endpoint
+enableVirtualSerialPort => enableVirtualSerialPort_define;
+enableVirtualSerialPort = 1;
+
+# Raw I/O Endpoint
+# *Currently Unused*
+enableRawIO => enableRawIO_define;
+enableRawIO = 0;
+
void cliFunc_sendKeys ( char* args );
void cliFunc_setKeys ( char* args );
void cliFunc_setMod ( char* args );
+void cliFunc_usbInitTime( char* args );
CLIDict_Entry( sendKeys, "Send the prepared list of USB codes and modifier byte." );
CLIDict_Entry( setKeys, "Prepare a space separated list of USB codes (decimal). Waits until \033[35msendKeys\033[0m." );
CLIDict_Entry( setMod, "Set the modfier byte:" NL "\t\t1 LCtrl, 2 LShft, 4 LAlt, 8 LGUI, 16 RCtrl, 32 RShft, 64 RAlt, 128 RGUI" );
+CLIDict_Entry( usbInitTime, "Displays the time in ms from usb_init() till the last setup call." );
CLIDict_Def( outputCLIDict, "USB Module Commands" ) = {
CLIDict_Item( kbdProtocol ),
CLIDict_Item( sendKeys ),
CLIDict_Item( setKeys ),
CLIDict_Item( setMod ),
+ CLIDict_Item( usbInitTime ),
{ 0, 0, 0 } // Null entry for dictionary end
};
// Initially 100 mA, but may be negotiated higher (e.g. 500 mA)
uint16_t Output_USBCurrent_Available = 0;
+// USB Init Time (ms) - usb_init()
+volatile uint32_t USBInit_TimeStart;
+volatile uint32_t USBInit_TimeEnd;
+volatile uint16_t USBInit_Ticks;
+
// ----- Capabilities -----
// Set Boot Keyboard Protocol
void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set the keyboard protocol to Boot Mode
USBKeys_Protocol = 0;
+#endif
}
// Set NKRO Keyboard Protocol
void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set the keyboard protocol to NKRO Mode
USBKeys_Protocol = 1;
+#endif
}
// Toggle Keyboard Protocol
void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Toggle the keyboard protocol Mode
USBKeys_Protocol = !USBKeys_Protocol;
}
+#endif
}
// Sends a Consumer Control code to the USB Output buffer
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set consumer control code
USBKeys_ConsCtrl = *(uint16_t*)(&args[0]);
+#endif
}
// Sends a System Control code to the USB Output buffer
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set system control code
USBKeys_SysCtrl = args[0];
+#endif
}
// Argument #1: USB Code
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
break;
}
+#endif
}
void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args )
Output_firmwareReload();
}
+#if enableMouse_define == 1
// Sends a mouse command over the USB Output buffer
// XXX This function *will* be changing in the future
// If you use it, be prepared that your .kll files will break in the future (post KLL 0.5)
if ( mouse_x || mouse_y )
USBMouse_Changed |= USBMouseChangeState_Relative;
}
+#endif
// Non-standard USB state manipulation, usually does nothing
usb_device_check();
- // Boot Mode Only, unset stale keys
- if ( USBKeys_Protocol == 0 )
- for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ )
- USBKeys_Keys[c] = 0;
-
// XXX - Behaves oddly on Mac OSX, might help with corrupted packets specific to OSX? -HaaTa
/*
// Check if idle count has been exceed, this forces usb_keyboard_send and usb_mouse_send to update
}
*/
+#if enableMouse_define == 1
// Process mouse actions
while ( USBMouse_Changed )
usb_mouse_send();
+#endif
+
+#if enableKeyboard_define == 1
+ // Boot Mode Only, unset stale keys
+ if ( USBKeys_Protocol == 0 )
+ for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ )
+ USBKeys_Keys[c] = 0;
// Send keypresses while there are pending changes
while ( USBKeys_Changed )
Scan_finishedWithOutput( USBKeys_Sent );
break;
}
+#endif
}
// USB Input buffer available
inline unsigned int Output_availablechar()
{
+#if enableVirtualSerialPort_define == 1
return usb_serial_available();
+#else
+ return 0;
+#endif
}
// USB Get Character from input buffer
inline int Output_getchar()
{
+#if enableVirtualSerialPort_define == 1
// XXX Make sure to check output_availablechar() first! Information is lost with the cast (error codes) (AVR)
return (int)usb_serial_getchar();
+#else
+ return 0;
+#endif
}
// USB Send Character to output buffer
inline int Output_putchar( char c )
{
+#if enableVirtualSerialPort_define == 1
return usb_serial_putchar( c );
+#else
+ return 0;
+#endif
}
// USB Send String to output buffer, null terminated
inline int Output_putstr( char* str )
{
+#if enableVirtualSerialPort_define == 1
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR
uint16_t count = 0;
#elif defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
count++;
return usb_serial_write( str, count );
+#else
+ return 0;
+#endif
}
}
+// USB RawIO buffer available
+inline unsigned int Output_rawio_availablechar()
+{
+#if enableRawIO_define == 1
+ return usb_rawio_available();
+#else
+ return 0;
+#endif
+}
+
+
+// USB RawIO get buffer
+// XXX Must be a 64 byte buffer
+inline int Output_rawio_getbuffer( char* buffer )
+{
+#if enableRawIO_define == 1
+ // No timeout, fail immediately
+ return usb_rawio_rx( (void*)buffer, 0 );
+#else
+ return 0;
+#endif
+}
+
+
+// USB RawIO send buffer
+// XXX Must be a 64 byte buffer
+inline int Output_rawio_sendbuffer( char* buffer )
+{
+#if enableRawIO_define == 1
+ // No timeout, fail immediately
+ return usb_rawio_tx( (void*)buffer, 0 );
+#else
+ return 0;
+#endif
+}
+
+
// Update USB current (mA)
// Triggers power change event
void Output_update_usb_current( unsigned int current )
USBKeys_ModifiersCLI = numToInt( arg1Ptr );
}
+void cliFunc_usbInitTime( char* args )
+{
+ // Calculate overall USB initialization time
+ // XXX A protocol analyzer will be more accurate, however, this is built-in and easier to collect data
+ print(NL);
+ info_msg("USB Init Time: ");
+ printInt32( USBInit_TimeEnd - USBInit_TimeStart );
+ print(" ms - ");
+ printInt16( USBInit_Ticks );
+ print(" ticks");
+}
+
extern uint16_t Output_ExtCurrent_Available; // mA - Set by outside module if not using USB (i.e. Interconnect)
+extern volatile uint32_t USBInit_TimeStart; // Timetamp when usb_init was triggered
+extern volatile uint32_t USBInit_TimeEnd; // Timetamp since last call to the Configuration endpoint
+extern volatile uint16_t USBInit_Ticks; // Number of times the end time has been updated
+
// ----- Functions -----
###| CMake Kiibohd Controller USB Module |###
#
-# Written by Jacob Alexander in 2011-2015 for the Kiibohd Controller
+# Written by Jacob Alexander in 2011-2016 for the Kiibohd Controller
#
# Released into the Public Domain
#
arm/usb_keyboard.c
arm/usb_mem.c
arm/usb_mouse.c
+ arm/usb_rawio.c
arm/usb_serial.c
)
// ----- Macros -----
// Used to build a bitmap lookup table from a byte addressable array
-#define byteLookup( byte ) case (( byte ) * ( 8 )): bytePosition = byte; byteShift = 0; break; \
- case (( byte ) * ( 8 ) + ( 1 )): bytePosition = byte; byteShift = 1; break; \
- case (( byte ) * ( 8 ) + ( 2 )): bytePosition = byte; byteShift = 2; break; \
- case (( byte ) * ( 8 ) + ( 3 )): bytePosition = byte; byteShift = 3; break; \
- case (( byte ) * ( 8 ) + ( 4 )): bytePosition = byte; byteShift = 4; break; \
- case (( byte ) * ( 8 ) + ( 5 )): bytePosition = byte; byteShift = 5; break; \
- case (( byte ) * ( 8 ) + ( 6 )): bytePosition = byte; byteShift = 6; break; \
- case (( byte ) * ( 8 ) + ( 7 )): bytePosition = byte; byteShift = 7; break
+#define byteLookup( byte ) \
+ case (( byte ) * ( 8 )): bytePosition = byte; byteShift = 0; break; \
+ case (( byte ) * ( 8 ) + ( 1 )): bytePosition = byte; byteShift = 1; break; \
+ case (( byte ) * ( 8 ) + ( 2 )): bytePosition = byte; byteShift = 2; break; \
+ case (( byte ) * ( 8 ) + ( 3 )): bytePosition = byte; byteShift = 3; break; \
+ case (( byte ) * ( 8 ) + ( 4 )): bytePosition = byte; byteShift = 4; break; \
+ case (( byte ) * ( 8 ) + ( 5 )): bytePosition = byte; byteShift = 5; break; \
+ case (( byte ) * ( 8 ) + ( 6 )): bytePosition = byte; byteShift = 6; break; \
+ case (( byte ) * ( 8 ) + ( 7 )): bytePosition = byte; byteShift = 7; break
void cliFunc_sendUART ( char* args );
void cliFunc_setKeys ( char* args );
void cliFunc_setMod ( char* args );
+void cliFunc_usbInitTime( char* args );
CLIDict_Entry( sendUART, "Send characters over UART0." );
CLIDict_Entry( setKeys, "Prepare a space separated list of USB codes (decimal). Waits until \033[35msendKeys\033[0m." );
CLIDict_Entry( setMod, "Set the modfier byte:" NL "\t\t1 LCtrl, 2 LShft, 4 LAlt, 8 LGUI, 16 RCtrl, 32 RShft, 64 RAlt, 128 RGUI" );
+CLIDict_Entry( usbInitTime, "Displays the time in ms from usb_init() till the last setup call." );
CLIDict_Def( outputCLIDict, "USB Module Commands" ) = {
CLIDict_Item( kbdProtocol ),
CLIDict_Item( sendUART ),
CLIDict_Item( setKeys ),
CLIDict_Item( setMod ),
+ CLIDict_Item( usbInitTime ),
{ 0, 0, 0 } // Null entry for dictionary end
};
// Initially 100 mA, but may be negotiated higher (e.g. 500 mA)
uint16_t Output_USBCurrent_Available = 0;
+// USB Init Time (ms)
+volatile uint32_t USBInit_TimeStart;
+volatile uint32_t USBInit_TimeEnd;
+volatile uint16_t USBInit_Ticks;
+
// ----- Capabilities -----
// Set Boot Keyboard Protocol
void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set the keyboard protocol to Boot Mode
USBKeys_Protocol = 0;
+#endif
}
// Set NKRO Keyboard Protocol
void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set the keyboard protocol to NKRO Mode
USBKeys_Protocol = 1;
+#endif
}
// Toggle Keyboard Protocol
void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Toggle the keyboard protocol Mode
USBKeys_Protocol = !USBKeys_Protocol;
}
+#endif
}
// Sends a Consumer Control code to the USB Output buffer
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set consumer control code
USBKeys_ConsCtrl = *(uint16_t*)(&args[0]);
+#endif
}
// Sends a System Control code to the USB Output buffer
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
// Set system control code
USBKeys_SysCtrl = args[0];
+#endif
}
// Argument #1: USB Code
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableKeyboard_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
break;
}
+#endif
}
void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args )
// Argument #3: USB Y Axis (16 bit) relative
void Output_usbMouse_capability( uint8_t state, uint8_t stateType, uint8_t *args )
{
+#if enableMouse_define == 1
// Display capability name
if ( stateType == 0xFF && state == 0xFF )
{
if ( mouse_x || mouse_y )
USBMouse_Changed |= USBMouseChangeState_Relative;
+#endif
}
usb_device_check();
// Boot Mode Only, unset stale keys
- if ( USBKeys_Protocol == 0 )
- for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ )
- USBKeys_Keys[c] = 0;
-
// XXX - Behaves oddly on Mac OSX, might help with corrupted packets specific to OSX? -HaaTa
/*
// Check if idle count has been exceed, this forces usb_keyboard_send and usb_mouse_send to update
}
*/
+#if enableMouse_define == 1
// Process mouse actions
while ( USBMouse_Changed )
usb_mouse_send();
+#endif
+
+#if enableKeyboard_define == 1
+ if ( USBKeys_Protocol == 0 )
+ for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ )
+ USBKeys_Keys[c] = 0;
// Send keypresses while there are pending changes
while ( USBKeys_Changed )
Scan_finishedWithOutput( USBKeys_Sent );
break;
}
+#endif
}
// USB Input buffer available
inline unsigned int Output_availablechar()
{
+#if enableVirtualSerialPort_define == 1
return usb_serial_available() + uart_serial_available();
+#else
+ return uart_serial_available();
+#endif
}
// USB Get Character from input buffer
inline int Output_getchar()
{
+#if enableVirtualSerialPort_define == 1
// XXX Make sure to check output_availablechar() first! Information is lost with the cast (error codes) (AVR)
if ( usb_serial_available() > 0 )
{
return (int)usb_serial_getchar();
}
+#endif
if ( uart_serial_available() > 0 )
{
// USB Send Character to output buffer
inline int Output_putchar( char c )
{
+#if enableVirtualSerialPort_define == 1
// First send to UART
uart_serial_putchar( c );
// Then send to USB
return usb_serial_putchar( c );
+#else
+ return uart_serial_putchar( c );
+#endif
}
while ( str[count] != '\0' )
count++;
+#if enableVirtualSerialPort_define == 1
// First send to UART
uart_serial_write( str, count );
// Then send to USB
return usb_serial_write( str, count );
+#else
+ return uart_serial_write( str, count );
+#endif
}
USBKeys_ModifiersCLI = numToInt( arg1Ptr );
}
+void cliFunc_usbInitTime( char* args )
+{
+ // Calculate overall USB initialization time
+ // XXX A protocol analyzer will be more accurate, however, this is built-in and easier to collect data
+ print(NL);
+ info_msg("USB Init Time: ");
+ printInt32( USBInit_TimeEnd - USBInit_TimeStart );
+ print(" ms - ");
+ printInt16( USBInit_Ticks );
+ print(" ticks");
+}
+