diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 3d0b83a01..aa8a0eb7a 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -10,6 +10,7 @@ TMK_COMMON_SRC += $(COMMON_DIR)/host.c \ $(COMMON_DIR)/action_util.c \ $(COMMON_DIR)/print.c \ $(COMMON_DIR)/debug.c \ + $(COMMON_DIR)/sendchar_null.c \ $(COMMON_DIR)/util.c \ $(COMMON_DIR)/eeconfig.c \ $(COMMON_DIR)/report.c \ diff --git a/tmk_core/common/sendchar_null.c b/tmk_core/common/sendchar_null.c index f6cab1b9d..fb67f7086 100644 --- a/tmk_core/common/sendchar_null.c +++ b/tmk_core/common/sendchar_null.c @@ -16,4 +16,4 @@ along with this program. If not, see . */ #include "sendchar.h" -int8_t sendchar(uint8_t c) { return 0; } +__attribute__((weak)) int8_t sendchar(uint8_t c) { return 0; } diff --git a/tmk_core/protocol/ibm4704.c b/tmk_core/protocol/ibm4704.c index fd8fc4dbd..a19443976 100644 --- a/tmk_core/protocol/ibm4704.c +++ b/tmk_core/protocol/ibm4704.c @@ -161,7 +161,9 @@ ISR(IBM4704_INT_VECT) { case STOP: // Data:Low WAIT(data_lo, 100, state); - rbuf_enqueue(data); + if (!rbuf_enqueue(data)) { + print("rbuf: full\n"); + } ibm4704_error = IBM4704_ERR_NONE; goto DONE; break; diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index d673841fd..374add20f 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -801,8 +801,6 @@ ERROR_EXIT: Endpoint_SelectEndpoint(ep); return -1; } -#else -int8_t sendchar(uint8_t c) { return 0; } #endif /******************************************************************************* diff --git a/tmk_core/protocol/vusb.mk b/tmk_core/protocol/vusb.mk index 897b833e1..6df0d0d33 100644 --- a/tmk_core/protocol/vusb.mk +++ b/tmk_core/protocol/vusb.mk @@ -9,13 +9,12 @@ SRC += $(VUSB_DIR)/main.c \ $(VUSB_DIR)/usbdrv/oddebug.c -ifdef NO_UART -SRC += $(COMMON_DIR)/sendchar_null.c -else +ifneq ($(strip $(CONSOLE_ENABLE)), yes) +ifndef NO_UART SRC += $(COMMON_DIR)/sendchar_uart.c \ $(COMMON_DIR)/uart.c endif - +endif # Search Path VPATH += $(TMK_PATH)/$(VUSB_DIR) diff --git a/tmk_core/protocol/vusb/main.c b/tmk_core/protocol/vusb/main.c index 610638e7d..7dc16926d 100644 --- a/tmk_core/protocol/vusb/main.c +++ b/tmk_core/protocol/vusb/main.c @@ -21,12 +21,23 @@ #include "uart.h" #include "debug.h" #include "suspend.h" +#include "wait.h" +#include "sendchar.h" + #ifdef SLEEP_LED_ENABLE # include "sleep_led.h" #endif #define UART_BAUD_RATE 115200 +#ifdef CONSOLE_ENABLE +void console_task(void); +#endif + +#ifdef RAW_ENABLE +void raw_hid_task(void); +#endif + /* This is from main.c of USBaspLoader */ static void initForUsbConnectivity(void) { uint8_t i = 0; @@ -39,10 +50,9 @@ static void initForUsbConnectivity(void) { _delay_ms(1); } usbDeviceConnect(); - sei(); } -void usb_remote_wakeup(void) { +static void usb_remote_wakeup(void) { cli(); int8_t ddr_orig = USBDDR; @@ -59,6 +69,23 @@ void usb_remote_wakeup(void) { sei(); } +/** \brief Setup USB + * + * FIXME: Needs doc + */ +static void setup_usb(void) { + // debug("initForUsbConnectivity()\n"); + initForUsbConnectivity(); + + // for Console_Task + print_set_sendchar(sendchar); +} + +/** \brief Main + * + * FIXME: Needs doc + */ +int main(void) __attribute__((weak)); int main(void) { bool suspended = false; #if USB_COUNT_SOF @@ -76,8 +103,10 @@ int main(void) { keyboard_setup(); host_set_driver(vusb_driver()); - debug("initForUsbConnectivity()\n"); - initForUsbConnectivity(); + setup_usb(); + sei(); + + wait_ms(50); keyboard_init(); #ifdef SLEEP_LED_ENABLE @@ -120,18 +149,26 @@ int main(void) { if (!suspended) { usbPoll(); - // TODO: configuration process is incosistent. it sometime fails. + // TODO: configuration process is inconsistent. it sometime fails. // To prevent failing to configure NOT scan keyboard during configuration if (usbConfiguration && usbInterruptIsReady()) { keyboard_task(); } vusb_transfer_keyboard(); + #ifdef RAW_ENABLE usbPoll(); if (usbConfiguration && usbInterruptIsReady3()) { raw_hid_task(); } +#endif +#ifdef CONSOLE_ENABLE + usbPoll(); + + if (usbConfiguration && usbInterruptIsReady3()) { + console_task(); + } #endif } else if (suspend_wakeup_condition()) { usb_remote_wakeup(); diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c index c4baf5ab0..e8aed6f5d 100644 --- a/tmk_core/protocol/vusb/vusb.c +++ b/tmk_core/protocol/vusb/vusb.c @@ -15,25 +15,50 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include #include +#include #include #include "usbdrv.h" #include "usbconfig.h" #include "host.h" #include "report.h" -#include "print.h" -#include "debug.h" #include "host_driver.h" #include "vusb.h" -#include +#include "print.h" +#include "debug.h" #ifdef RAW_ENABLE # include "raw_hid.h" #endif -#if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)) && defined(RAW_ENABLE) -# error "Enabling Mousekeys/Extrakeys and Raw HID at the same time is not currently supported on V-USB." +#if defined(CONSOLE_ENABLE) +# define RBUF_SIZE 128 +# include "ring_buffer.h" +#endif + +#define NEXT_INTERFACE __COUNTER__ + +/* + * Interface indexes + */ +enum usb_interfaces { + KEYBOARD_INTERFACE = NEXT_INTERFACE, +#if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)) + MOUSE_EXTRA_INTERFACE = NEXT_INTERFACE, +#endif +#ifdef RAW_ENABLE + RAW_INTERFACE = NEXT_INTERFACE, +#endif +#ifdef CONSOLE_ENABLE + CONSOLE_INTERFACE = NEXT_INTERFACE, +#endif + TOTAL_INTERFACES = NEXT_INTERFACE, +}; + +#define MAX_INTERFACES 2 + +#if (NEXT_INTERFACE - 1) > MAX_INTERFACES +# error There are not enough available interfaces to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Raw HID, Console #endif static uint8_t vusb_keyboard_leds = 0; @@ -120,7 +145,60 @@ void raw_hid_task(void) { raw_output_received_bytes = 0; } } +#endif +/*------------------------------------------------------------------* + * Console + *------------------------------------------------------------------*/ +#ifdef CONSOLE_ENABLE +# define CONSOLE_BUFFER_SIZE 32 +# define CONSOLE_EPSIZE 8 + +int8_t sendchar(uint8_t c) { + rbuf_enqueue(c); + return 0; +} + +static inline bool usbSendData3(char *data, uint8_t len) { + uint8_t retries = 5; + while (!usbInterruptIsReady3()) { + if (!(retries--)) { + return false; + } + usbPoll(); + } + + usbSetInterrupt3((unsigned char *)data, len); + return true; +} + +void console_task(void) { + if (!usbConfiguration) { + return; + } + + if (!rbuf_has_data()) { + return; + } + + // Send in chunks of 8 padded to 32 + char send_buf[CONSOLE_BUFFER_SIZE] = {0}; + uint8_t send_buf_count = 0; + while (rbuf_has_data() && send_buf_count < CONSOLE_EPSIZE) { + send_buf[send_buf_count++] = rbuf_dequeue(); + } + + char *temp = send_buf; + for (uint8_t i = 0; i < 4; i++) { + if (!usbSendData3(temp, 8)) { + break; + } + temp += 8; + } + + usbSendData3(0, 0); + usbPoll(); +} #endif /*------------------------------------------------------------------* @@ -429,7 +507,30 @@ const PROGMEM uchar raw_hid_report[] = { 0x95, RAW_BUFFER_SIZE, // Report Count 0x75, 0x08, // Report Size (8) 0x91, 0x02, // Output (Data, Variable, Absolute) - 0xC0, // End Collection + 0xC0 // End Collection +}; +#endif + +#if defined(CONSOLE_ENABLE) +const PROGMEM uchar console_hid_report[] = { + 0x06, 0x31, 0xFF, // Usage Page (Vendor Defined - PJRC Teensy compatible) + 0x09, 0x74, // Usage (Vendor Defined - PJRC Teensy compatible) + 0xA1, 0x01, // Collection (Application) + // Data to host + 0x09, 0x75, // Usage (Vendor Defined) + 0x15, 0x00, // Logical Minimum (0x00) + 0x26, 0xFF, 0x00, // Logical Maximum (0x00FF) + 0x95, CONSOLE_BUFFER_SIZE, // Report Count + 0x75, 0x08, // Report Size (8) + 0x81, 0x02, // Input (Data, Variable, Absolute) + // Data from host + 0x09, 0x76, // Usage (Vendor Defined) + 0x15, 0x00, // Logical Minimum (0x00) + 0x26, 0xFF, 0x00, // Logical Maximum (0x00FF) + 0x95, CONSOLE_BUFFER_SIZE, // Report Count + 0x75, 0x08, // Report Size (8) + 0x91, 0x02, // Output (Data) + 0xC0 // End Collection }; #endif @@ -511,11 +612,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = { .bDescriptorType = USBDESCR_CONFIG }, .wTotalLength = sizeof(usbConfigurationDescriptor_t), -# if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) || defined(RAW_ENABLE) - .bNumInterfaces = 2, -# else - .bNumInterfaces = 1, -# endif + .bNumInterfaces = TOTAL_INTERFACES, .bConfigurationValue = 0x01, .iConfiguration = 0x00, .bmAttributes = (1 << 7) | USBATTR_REMOTEWAKE, @@ -530,7 +627,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = { .bLength = sizeof(usbInterfaceDescriptor_t), .bDescriptorType = USBDESCR_INTERFACE }, - .bInterfaceNumber = 0, + .bInterfaceNumber = KEYBOARD_INTERFACE, .bAlternateSetting = 0x00, .bNumEndpoints = 1, .bInterfaceClass = 0x03, @@ -569,7 +666,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = { .bLength = sizeof(usbInterfaceDescriptor_t), .bDescriptorType = USBDESCR_INTERFACE }, - .bInterfaceNumber = 1, + .bInterfaceNumber = MOUSE_EXTRA_INTERFACE, .bAlternateSetting = 0x00, .bNumEndpoints = 1, .bInterfaceClass = 0x03, @@ -597,14 +694,15 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = { .bmAttributes = 0x03, .wMaxPacketSize = 8, .bInterval = USB_POLLING_INTERVAL_MS - } -# elif defined(RAW_ENABLE) + }, +# endif +# if defined(RAW_ENABLE) .rawInterface = { .header = { .bLength = sizeof(usbInterfaceDescriptor_t), .bDescriptorType = USBDESCR_INTERFACE }, - .bInterfaceNumber = 1, + .bInterfaceNumber = RAW_INTERFACE, .bAlternateSetting = 0x00, .bNumEndpoints = 2, .bInterfaceClass = 0x03, @@ -642,7 +740,56 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = { .bmAttributes = 0x03, .wMaxPacketSize = RAW_EPSIZE, .bInterval = USB_POLLING_INTERVAL_MS - } + }, +# endif +# if defined(CONSOLE_ENABLE) + /* + * Console + */ + .consoleInterface = { + .header = { + .bLength = sizeof(usbInterfaceDescriptor_t), + .bDescriptorType = USBDESCR_INTERFACE + }, + .bInterfaceNumber = CONSOLE_INTERFACE, + .bAlternateSetting = 0x00, + .bNumEndpoints = 2, + .bInterfaceClass = 0x03, + .bInterfaceSubClass = 0x00, + .bInterfaceProtocol = 0x00, + .iInterface = 0x00 + }, + .consoleHID = { + .header = { + .bLength = sizeof(usbHIDDescriptor_t), + .bDescriptorType = USBDESCR_HID + }, + .bcdHID = 0x0111, + .bCountryCode = 0x00, + .bNumDescriptors = 1, + .bDescriptorType = USBDESCR_HID_REPORT, + .wDescriptorLength = sizeof(console_hid_report) + }, + .consoleINEndpoint = { + .header = { + .bLength = sizeof(usbEndpointDescriptor_t), + .bDescriptorType = USBDESCR_ENDPOINT + }, + .bEndpointAddress = (USBRQ_DIR_DEVICE_TO_HOST | USB_CFG_EP3_NUMBER), + .bmAttributes = 0x03, + .wMaxPacketSize = CONSOLE_EPSIZE, + .bInterval = 0x01 + }, + .consoleOUTEndpoint = { + .header = { + .bLength = sizeof(usbEndpointDescriptor_t), + .bDescriptorType = USBDESCR_ENDPOINT + }, + .bEndpointAddress = (USBRQ_DIR_HOST_TO_DEVICE | USB_CFG_EP3_NUMBER), + .bmAttributes = 0x03, + .wMaxPacketSize = CONSOLE_EPSIZE, + .bInterval = 0x01 + }, # endif }; @@ -690,40 +837,54 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) { break; case USBDESCR_HID: switch (rq->wValue.bytes[0]) { - case 0: + case KEYBOARD_INTERFACE: usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.keyboardHID; len = sizeof(usbHIDDescriptor_t); break; #if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) - case 1: + case MOUSE_EXTRA_INTERFACE: usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.mouseExtraHID; len = sizeof(usbHIDDescriptor_t); break; -#elif defined(RAW_ENABLE) - case 1: +#endif +#if defined(RAW_ENABLE) + case RAW_INTERFACE: usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.rawHID; len = sizeof(usbHIDDescriptor_t); break; +#endif +#if defined(CONSOLE_ENABLE) + case CONSOLE_INTERFACE: + usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.consoleHID; + len = sizeof(usbHIDDescriptor_t); + break; #endif } break; case USBDESCR_HID_REPORT: /* interface index */ switch (rq->wIndex.word) { - case 0: + case KEYBOARD_INTERFACE: usbMsgPtr = (unsigned char *)keyboard_hid_report; len = sizeof(keyboard_hid_report); break; #if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) - case 1: + case MOUSE_EXTRA_INTERFACE: usbMsgPtr = (unsigned char *)mouse_extra_hid_report; len = sizeof(mouse_extra_hid_report); break; -#elif defined(RAW_ENABLE) - case 1: +#endif +#if defined(RAW_ENABLE) + case RAW_INTERFACE: usbMsgPtr = (unsigned char *)raw_hid_report; len = sizeof(raw_hid_report); break; +#endif +#if defined(CONSOLE_ENABLE) + case CONSOLE_INTERFACE: + usbMsgPtr = (unsigned char *)console_hid_report; + len = sizeof(console_hid_report); + break; #endif } break; diff --git a/tmk_core/protocol/vusb/vusb.h b/tmk_core/protocol/vusb/vusb.h index e097323fd..96471433c 100644 --- a/tmk_core/protocol/vusb/vusb.h +++ b/tmk_core/protocol/vusb/vusb.h @@ -93,19 +93,24 @@ typedef struct usbConfigurationDescriptor { usbInterfaceDescriptor_t mouseExtraInterface; usbHIDDescriptor_t mouseExtraHID; usbEndpointDescriptor_t mouseExtraINEndpoint; -#elif defined(RAW_ENABLE) +#endif + +#if defined(RAW_ENABLE) usbInterfaceDescriptor_t rawInterface; usbHIDDescriptor_t rawHID; usbEndpointDescriptor_t rawINEndpoint; usbEndpointDescriptor_t rawOUTEndpoint; #endif + +#if defined(CONSOLE_ENABLE) + usbInterfaceDescriptor_t consoleInterface; + usbHIDDescriptor_t consoleHID; + usbEndpointDescriptor_t consoleINEndpoint; + usbEndpointDescriptor_t consoleOUTEndpoint; +#endif } __attribute__((packed)) usbConfigurationDescriptor_t; #define USB_STRING_LEN(s) (sizeof(usbDescriptorHeader_t) + ((s) << 1)) host_driver_t *vusb_driver(void); void vusb_transfer_keyboard(void); - -#ifdef RAW_ENABLE -void raw_hid_task(void); -#endif diff --git a/tmk_core/ring_buffer.h b/tmk_core/ring_buffer.h index 6bea3509b..25fab638e 100644 --- a/tmk_core/ring_buffer.h +++ b/tmk_core/ring_buffer.h @@ -3,21 +3,26 @@ /*-------------------------------------------------------------------- * Ring buffer to store scan codes from keyboard *------------------------------------------------------------------*/ -#define RBUF_SIZE 32 +#ifndef RBUF_SIZE +# define RBUF_SIZE 32 +#endif #include +#include +#include static uint8_t rbuf[RBUF_SIZE]; static uint8_t rbuf_head = 0; static uint8_t rbuf_tail = 0; -static inline void rbuf_enqueue(uint8_t data) { +static inline bool rbuf_enqueue(uint8_t data) { + bool ret = false; ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { uint8_t next = (rbuf_head + 1) % RBUF_SIZE; if (next != rbuf_tail) { rbuf[rbuf_head] = data; rbuf_head = next; - } else { - print("rbuf: full\n"); + ret = true; } } + return ret; } static inline uint8_t rbuf_dequeue(void) { uint8_t val = 0;