Skip to content

Instantly share code, notes, and snippets.

@onebytegone
Created September 19, 2019 21:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save onebytegone/70de13831afa516dafb7e210da0f6368 to your computer and use it in GitHub Desktop.
Save onebytegone/70de13831afa516dafb7e210da0f6368 to your computer and use it in GitHub Desktop.
Patch teensyduino for NKRO on Teensy 3.2

Patching teensyduino to support NKRO for Teensy 3.2

  1. Install Arduino IDE

  2. Install teensyduino using its installer

  3. Run the following:

    cd /Applications/Arduino.app/Contents/Java/hardware/teensy
    git init
    git add -A
    git commit -m 'Initial commit'
    git apply 0001-NKRO.patch
    
  4. Example script:

    void setup() { }
    
    void loop() {
       Nkro.set_key(KEY_A);
       Nkro.send_nkro_now();
       delay(1000);
       Nkro.reset_keys();
       delay(1000);
    }

0001-NKRO.patch

From 1ba54c9a4c9ecf3565eb3a5a88a635365396d34f Mon Sep 17 00:00:00 2001
From: Ethan Smith <ethan@onebytegone.com>
Date: Thu, 19 Sep 2019 12:51:58 -0400
Subject: [PATCH] NKRO

---
 avr/cores/teensy3/WProgram.h   |   1 +
 avr/cores/teensy3/usb_desc.c   |  70 ++++++++++++++++-
 avr/cores/teensy3/usb_desc.h   |  49 +++++++++---
 avr/cores/teensy3/usb_dev.h    |   7 ++
 avr/cores/teensy3/usb_inst.cpp |   3 +
 avr/cores/teensy3/usb_nkro.c   | 132 +++++++++++++++++++++++++++++++++
 avr/cores/teensy3/usb_nkro.h   |  43 +++++++++++
 avr/cores/teensy3/usb_undef.h  |  19 ++++-
 8 files changed, 312 insertions(+), 12 deletions(-)
 create mode 100644 avr/cores/teensy3/usb_nkro.c
 create mode 100644 avr/cores/teensy3/usb_nkro.h

diff --git a/avr/cores/teensy3/WProgram.h b/avr/cores/teensy3/WProgram.h
index e67de41..6eed438 100644
--- a/avr/cores/teensy3/WProgram.h
+++ b/avr/cores/teensy3/WProgram.h
@@ -54,6 +54,7 @@
 #include "usb_serial.h"
 #include "usb_seremu.h"
 #include "usb_keyboard.h"
+#include "usb_nkro.h"
 #include "usb_mouse.h"
 #include "usb_joystick.h"
 #include "usb_midi.h"
diff --git a/avr/cores/teensy3/usb_desc.c b/avr/cores/teensy3/usb_desc.c
index 182ae6d..fe560c3 100644
--- a/avr/cores/teensy3/usb_desc.c
+++ b/avr/cores/teensy3/usb_desc.c
@@ -188,6 +188,33 @@ static uint8_t keymedia_report_desc[] = {
 };
 #endif
 
+#ifdef NKRO_INTERFACE
+static uint8_t nkro_hid_report_desc[] = {
+        0x05, 0x01, // Usage Page (Generic Desktop),
+        0x09, 0x06, // Usage (Keyboard),
+        0xA1, 0x01, // Collection (Application),
+        // bitmap of modifiers
+        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
+        // bitmap of keys
+        0x95, NKRO_REPORT_KEYS*8, // Report Count (),
+        0x75, 0x01, // Report Size (1),
+        0x15, 0x00, // Logical Minimum (0),
+        0x25, 0x01, // Logical Maximum(1),
+        0x05, 0x07, // Usage Page (Key Codes),
+        0x19, 0x00, // Usage Minimum (0),
+        0x29, NKRO_REPORT_KEYS*8-1, // Usage Maximum (),
+        0x81, 0x02, // Input (Data, Variable, Absolute),
+        0xc0 // End Collection
+};
+#endif
+
 #ifdef MOUSE_INTERFACE
 // Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
 static uint8_t mouse_report_desc[] = {
@@ -542,7 +569,15 @@ static uint8_t flightsim_report_desc[] = {
 #define JOYSTICK_INTERFACE_DESC_SIZE  0
 #endif
 
-#define MTP_INTERFACE_DESC_POS     JOYSTICK_INTERFACE_DESC_POS+JOYSTICK_INTERFACE_DESC_SIZE
+#define NKRO_INTERFACE_DESC_POS    JOYSTICK_INTERFACE_DESC_POS+JOYSTICK_INTERFACE_DESC_SIZE
+#ifdef NKRO_INTERFACE
+#define NKRO_INTERFACE_DESC_SIZE 9+9+7
+#define NKRO_DESC_OFFSET NKRO_INTERFACE_DESC_POS+9
+#else
+#define NKRO_INTERFACE_DESC_SIZE 0
+#endif
+
+#define MTP_INTERFACE_DESC_POS     NKRO_INTERFACE_DESC_POS+NKRO_INTERFACE_DESC_SIZE
 #ifdef  MTP_INTERFACE
 #define MTP_INTERFACE_DESC_SIZE    9+7+7+7
 #else
@@ -1091,6 +1126,35 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
         JOYSTICK_INTERVAL,                      // bInterval
 #endif // JOYSTICK_INTERFACE
 
+#ifdef NKRO_INTERFACE
+        // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
+        9, // bLength
+        4, // bDescriptorType
+        NKRO_INTERFACE, // bInterfaceNumber
+        0, // bAlternateSetting
+        1, // bNumEndpoints
+        0x03, // bInterfaceClass (0x03 = HID)
+        0x00, // bInterfaceSubClass (0x01 = Boot)
+        0x00, // 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(nkro_hid_report_desc)), // wDescriptorLength
+        MSB(sizeof(nkro_hid_report_desc)),
+        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+        7, // bLength
+        5, // bDescriptorType
+        NKRO_ENDPOINT | 0x80, // bEndpointAddress
+        0x03, // bmAttributes (0x03=intr)
+        NKRO_SIZE, 0, // wMaxPacketSize
+        NKRO_INTERVAL, // bInterval
+#endif // NKRO_INTERFACE
+
 #ifdef MTP_INTERFACE
         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
         9,                                      // bLength
@@ -1517,6 +1581,10 @@ const usb_descriptor_list_t usb_descriptor_list[] = {
         {0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)},
         {0x2100, JOYSTICK_INTERFACE, config_descriptor+JOYSTICK_HID_DESC_OFFSET, 9},
 #endif
+#ifdef NKRO_INTERFACE
+        {0x2200, NKRO_INTERFACE, nkro_hid_report_desc, sizeof(nkro_hid_report_desc)},
+        {0x2100, NKRO_INTERFACE, config_descriptor+NKRO_DESC_OFFSET, 9},
+#endif
 #ifdef RAWHID_INTERFACE
   {0x2200, RAWHID_INTERFACE, rawhid_report_desc, sizeof(rawhid_report_desc)},
   {0x2100, RAWHID_INTERFACE, config_descriptor+RAWHID_HID_DESC_OFFSET, 9},
diff --git a/avr/cores/teensy3/usb_desc.h b/avr/cores/teensy3/usb_desc.h
index 95de05e..abc8bbd 100644
--- a/avr/cores/teensy3/usb_desc.h
+++ b/avr/cores/teensy3/usb_desc.h
@@ -148,9 +148,9 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define PRODUCT_NAME    {'K','e','y','b','o','a','r','d'}
   #define PRODUCT_NAME_LEN   8
   #define EP0_SIZE     64
-  #define NUM_ENDPOINTS         4
+  #define NUM_ENDPOINTS         5
   #define NUM_USB_BUFFERS 14
-  #define NUM_INTERFACE      3
+  #define NUM_INTERFACE      4
   #define SEREMU_INTERFACE      1  // Serial emulation
   #define SEREMU_TX_ENDPOINT    1
   #define SEREMU_TX_SIZE        64
@@ -166,6 +166,11 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define KEYMEDIA_ENDPOINT     4
   #define KEYMEDIA_SIZE         8
   #define KEYMEDIA_INTERVAL     4
+  #define NKRO_INTERFACE        6  // N-key rollover kbd
+  #define NKRO_ENDPOINT         5
+  #define NKRO_SIZE             32
+  #define NKRO_REPORT_KEYS      ( NKRO_SIZE - 1 )
+  #define NKRO_INTERVAL         1
   #define ENDPOINT1_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT2_CONFIG   ENDPOINT_RECEIVE_ONLY
   #define ENDPOINT3_CONFIG   ENDPOINT_TRANSIMIT_ONLY
@@ -181,9 +186,9 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define PRODUCT_NAME    {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
   #define PRODUCT_NAME_LEN   23
   #define EP0_SIZE     64
-  #define NUM_ENDPOINTS         6
+  #define NUM_ENDPOINTS         7
   #define NUM_USB_BUFFERS 24
-  #define NUM_INTERFACE      5
+  #define NUM_INTERFACE      6
   #define SEREMU_INTERFACE      2  // Serial emulation
   #define SEREMU_TX_ENDPOINT    1
   #define SEREMU_TX_SIZE        64
@@ -207,12 +212,18 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define JOYSTICK_ENDPOINT     4
   #define JOYSTICK_SIZE         12 //  12 = normal, 64 = extreme joystick
   #define JOYSTICK_INTERVAL     2
+  #define NKRO_INTERFACE        5  // N-key rollover kbd
+  #define NKRO_ENDPOINT         7
+  #define NKRO_SIZE             32
+  #define NKRO_REPORT_KEYS      ( NKRO_SIZE - 1 )
+  #define NKRO_INTERVAL         1
   #define ENDPOINT1_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT2_CONFIG   ENDPOINT_RECEIVE_ONLY
   #define ENDPOINT3_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT4_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT5_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT6_CONFIG   ENDPOINT_TRANSIMIT_ONLY
+  #define ENDPOINT7_CONFIG   ENDPOINT_TRANSIMIT_ONLY
 
 #elif defined(USB_SERIAL_HID)
   #define VENDOR_ID    0x16C0
@@ -225,9 +236,9 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define PRODUCT_NAME    {'S','e','r','i','a','l','/','K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
   #define PRODUCT_NAME_LEN   30
   #define EP0_SIZE     64
-  #define NUM_ENDPOINTS      7
+  #define NUM_ENDPOINTS      8
   #define NUM_USB_BUFFERS 30
-  #define NUM_INTERFACE      6
+  #define NUM_INTERFACE      7
   #define CDC_IAD_DESCRIPTOR 1
   #define CDC_STATUS_INTERFACE  0
   #define CDC_DATA_INTERFACE 1  // Serial
@@ -253,6 +264,11 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define JOYSTICK_ENDPOINT     6
   #define JOYSTICK_SIZE         12 //  12 = normal, 64 = extreme joystick
   #define JOYSTICK_INTERVAL     1
+  #define NKRO_INTERFACE        6  // N-key rollover kbd
+  #define NKRO_ENDPOINT         8
+  #define NKRO_SIZE             32
+  #define NKRO_REPORT_KEYS      ( NKRO_SIZE - 1 )
+  #define NKRO_INTERVAL         1
   #define ENDPOINT1_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT2_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT3_CONFIG   ENDPOINT_RECEIVE_ONLY
@@ -260,6 +276,7 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define ENDPOINT5_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT6_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT7_CONFIG   ENDPOINT_TRANSIMIT_ONLY
+  #define ENDPOINT8_CONFIG   ENDPOINT_TRANSIMIT_ONLY
 
 #elif defined(USB_TOUCHSCREEN)
   #define VENDOR_ID    0x16C0
@@ -269,9 +286,9 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define PRODUCT_NAME    {'K','e','y','b','o','a','r','d','/','T','o','u','c','h','s','c','r','e','e','n'}
   #define PRODUCT_NAME_LEN   20
   #define EP0_SIZE     64
-  #define NUM_ENDPOINTS         5
+  #define NUM_ENDPOINTS         6
   #define NUM_USB_BUFFERS 15
-  #define NUM_INTERFACE      4
+  #define NUM_INTERFACE      5
   #define SEREMU_INTERFACE      1  // Serial emulation
   #define SEREMU_TX_ENDPOINT    1
   #define SEREMU_TX_SIZE        64
@@ -291,11 +308,17 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define MULTITOUCH_ENDPOINT   5
   #define MULTITOUCH_SIZE       8
   #define MULTITOUCH_FINGERS    10
+  #define NKRO_INTERFACE        4  // N-key rollover kbd
+  #define NKRO_ENDPOINT         6
+  #define NKRO_SIZE             32
+  #define NKRO_REPORT_KEYS      ( NKRO_SIZE - 1 )
+  #define NKRO_INTERVAL         1
   #define ENDPOINT1_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT2_CONFIG   ENDPOINT_RECEIVE_ONLY
   #define ENDPOINT3_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT4_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT5_CONFIG   ENDPOINT_TRANSIMIT_ONLY
+  #define ENDPOINT6_CONFIG   ENDPOINT_TRANSIMIT_ONLY
 
 #elif defined(USB_HID_TOUCHSCREEN)
   #define VENDOR_ID    0x16C0
@@ -305,9 +328,9 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define PRODUCT_NAME    {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','T','o','u','c','h','s','c','r','e','e','n'}
   #define PRODUCT_NAME_LEN   26
   #define EP0_SIZE     64
-  #define NUM_ENDPOINTS         6
+  #define NUM_ENDPOINTS         7
   #define NUM_USB_BUFFERS 20
-  #define NUM_INTERFACE      5
+  #define NUM_INTERFACE      6
   #define SEREMU_INTERFACE      2  // Serial emulation
   #define SEREMU_TX_ENDPOINT    1
   #define SEREMU_TX_SIZE        64
@@ -331,12 +354,18 @@ let me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
   #define MULTITOUCH_ENDPOINT   5
   #define MULTITOUCH_SIZE       8
   #define MULTITOUCH_FINGERS    10
+  #define NKRO_INTERFACE        5  // N-key rollover kbd
+  #define NKRO_ENDPOINT         7
+  #define NKRO_SIZE             32
+  #define NKRO_REPORT_KEYS      ( NKRO_SIZE - 1 )
+  #define NKRO_INTERVAL         1
   #define ENDPOINT1_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT2_CONFIG   ENDPOINT_RECEIVE_ONLY
   #define ENDPOINT3_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT4_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT5_CONFIG   ENDPOINT_TRANSIMIT_ONLY
   #define ENDPOINT6_CONFIG   ENDPOINT_TRANSIMIT_ONLY
+  #define ENDPOINT7_CONFIG   ENDPOINT_TRANSIMIT_ONLY
 
 #elif defined(USB_MIDI)
   #define VENDOR_ID    0x16C0
diff --git a/avr/cores/teensy3/usb_dev.h b/avr/cores/teensy3/usb_dev.h
index 1233d7f..4de8757 100644
--- a/avr/cores/teensy3/usb_dev.h
+++ b/avr/cores/teensy3/usb_dev.h
@@ -90,6 +90,13 @@ extern uint8_t keyboard_idle_count;
 extern volatile uint8_t keyboard_leds;
 #endif
 
+#ifdef NKRO_INTERFACE
+extern uint8_t nkro_report_data[NKRO_SIZE];
+extern uint8_t nkro_protocol;
+extern uint8_t nkro_idle_config;
+extern uint8_t nkro_idle_count;
+#endif
+
 #ifdef MIDI_INTERFACE
 extern void usb_midi_flush_output(void);
 #endif
diff --git a/avr/cores/teensy3/usb_inst.cpp b/avr/cores/teensy3/usb_inst.cpp
index 224c13d..8987850 100644
--- a/avr/cores/teensy3/usb_inst.cpp
+++ b/avr/cores/teensy3/usb_inst.cpp
@@ -72,6 +72,9 @@ uint8_t usb_joystick_class::manual_mode = 0;
 usb_serial_class Serial;
 #endif
 
+#ifdef NKRO_INTERFACE
+usb_nkro_class Nkro;
+#endif
 
 #else // F_CPU < 20 MHz
 
diff --git a/avr/cores/teensy3/usb_nkro.c b/avr/cores/teensy3/usb_nkro.c
new file mode 100644
index 0000000..5fc22f8
--- /dev/null
+++ b/avr/cores/teensy3/usb_nkro.c
@@ -0,0 +1,132 @@
+#include "usb_dev.h"
+#include "usb_nkro.h"
+#include "core_pins.h" // for yield()
+#include "keylayouts.h"
+//#include "HardwareSerial.h"
+#include <string.h> // for memcpy()
+
+#ifdef NKRO_INTERFACE // defined by usb_dev.h -> usb_desc.h
+
+// byte0: which modifier keys are currently pressed
+//  1=left ctrl,    2=left shift,   4=left alt,    8=left gui
+//  16=right ctrl, 32=right shift, 64=right alt, 128=right gui
+// bytes1-NKRO_SIZE: which keys are currently pressed, one bit
+// per key for codes 0 to ((8*NKRO_REPORT_SIZE) - 1)
+uint8_t nkro_report_data[NKRO_SIZE];
+
+// protocol setting from the host.  We use exactly the same report
+// either way, so this variable only stores the setting since we
+// are required to be able to report which setting is in use.
+uint8_t nkro_protocol=1;
+
+// the idle configuration, how often we send the report to the
+// host (ms * 4) even when it hasn't changed
+uint8_t nkro_idle_config=125;
+
+// count until idle timeout
+uint8_t nkro_idle_count=0;
+
+
+// NKRO Keyboard
+void usb_nkro_reset_keys()
+{
+    uint8_t index;
+    for (index=0; index < NKRO_SIZE; index++)
+    {
+        nkro_report_data[index] = 0;
+    }
+}
+
+void usb_nkro_reset_key(uint8_t usb_keycode)
+{
+    uint8_t bit = usb_keycode % 8;
+    uint8_t byte = (usb_keycode / 8) + 1;
+
+    if (usb_keycode >= 240 && usb_keycode <= 247)
+    {
+        // Reset a modifier key
+        nkro_report_data[0] &= ~(1<< bit);
+    }
+    else if (byte > 0 && byte <= NKRO_REPORT_KEYS)
+    {
+        nkro_report_data[byte] &= ~(1 << bit);
+    }
+}
+
+void usb_nkro_set_key(uint8_t usb_keycode)
+{
+    uint8_t bit = usb_keycode % 8;
+    uint8_t byte = (usb_keycode / 8) + 1;
+
+    if (usb_keycode >= 240 && usb_keycode <= 247)
+    {
+        // Reset a modifier key
+        nkro_report_data[0] |= (1 << bit);
+    }
+    else if (byte > 0 && byte <= NKRO_REPORT_KEYS)
+    {
+        nkro_report_data[byte] |= (1 << bit);
+    }
+}
+
+// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
+#define TX_PACKET_LIMIT 4
+
+static uint8_t transmit_previous_timeout=0;
+
+// When the PC isn't listening, how long do we wait before discarding data?
+#define TX_TIMEOUT_MSEC 50
+
+#if F_CPU == 240000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600)
+#elif F_CPU == 216000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440)
+#elif F_CPU == 192000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280)
+#elif F_CPU == 180000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200)
+#elif F_CPU == 168000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100)
+#elif F_CPU == 144000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932)
+#elif F_CPU == 120000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764)
+#elif F_CPU == 96000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
+#elif F_CPU == 72000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512)
+#elif F_CPU == 48000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
+#elif F_CPU == 24000000
+  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
+#endif
+
+
+int usb_nkro_send_nkro_now(void)
+{
+        uint32_t wait_count=0;
+        usb_packet_t *tx_packet;
+
+  while (1) {
+     if (!usb_configuration) {
+        return -1;
+     }
+     if (usb_tx_packet_count(NKRO_ENDPOINT) < TX_PACKET_LIMIT) {
+        tx_packet = usb_malloc();
+        if (tx_packet) break;
+     }
+     if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) {
+        transmit_previous_timeout = 1;
+        return -1;
+     }
+     yield();
+  }
+  memcpy(tx_packet->buf, nkro_report_data, NKRO_SIZE);
+  tx_packet->len = NKRO_SIZE;
+  usb_tx(NKRO_ENDPOINT, tx_packet);
+
+    return 0;
+
+}
+
+#endif // NKRO_INTERFACE
diff --git a/avr/cores/teensy3/usb_nkro.h b/avr/cores/teensy3/usb_nkro.h
new file mode 100644
index 0000000..ea1c947
--- /dev/null
+++ b/avr/cores/teensy3/usb_nkro.h
@@ -0,0 +1,43 @@
+#ifndef USBnkro_h_
+#define USBnkro_h_
+
+#include "usb_desc.h"
+#include "keylayouts.h"
+
+#if defined (NKRO_INTERFACE)
+
+#include <inttypes.h>
+
+// C language implementation
+#ifdef __cplusplus
+extern "C" {
+#endif
+void usb_nkro_reset_keys();
+void usb_nkro_reset_key(uint8_t key);
+void usb_nkro_set_key(uint8_t key);
+int usb_nkro_send_nkro_now();
+#ifdef __cplusplus
+}
+#endif
+
+
+
+// C++ interface
+#ifdef __cplusplus
+#include "Stream.h"
+
+class usb_nkro_class
+{
+        public:
+        void reset_keys() { usb_nkro_reset_keys(); }
+        void reset_key(uint8_t key) { usb_nkro_reset_key(key); }
+        void set_key(uint8_t key) { usb_nkro_set_key(key); }
+        int send_nkro_now(void) { return usb_nkro_send_nkro_now(); }
+};
+
+extern usb_nkro_class Nkro;
+
+#endif // __cplusplus
+
+#endif // NKRO_INTERFACE
+#endif // USBnkro_h_
diff --git a/avr/cores/teensy3/usb_undef.h b/avr/cores/teensy3/usb_undef.h
index cbd8c83..af1c246 100644
--- a/avr/cores/teensy3/usb_undef.h
+++ b/avr/cores/teensy3/usb_undef.h
@@ -251,6 +251,21 @@
 #ifdef MTP_EVENT_INTERVAL
 #undef MTP_EVENT_INTERVAL
 #endif
+#ifdef NKRO_INTERFACE
+#undef NKRO_INTERFACE
+#endif
+#ifdef NKRO_ENDPOINT
+#undef NKRO_ENDPOINT
+#endif
+#ifdef NKRO_SIZE
+#undef NKRO_SIZE
+#endif
+#ifdef NKRO_REPORT_KEYS
+#undef NKRO_REPORT_KEYS
+#endif
+#ifdef NKRO_INTERVAL
+#undef NKRO_INTERVAL
+#endif
 #ifdef ENDPOINT1_CONFIG
 #undef ENDPOINT1_CONFIG
 #endif
@@ -296,4 +311,6 @@
 #ifdef ENDPOINT15_CONFIG
 #undef ENDPOINT15_CONFIG
 #endif
-
+#ifdef ENDPOINT16_CONFIG
+#undef ENDPOINT16_CONFIG
+#endif
-- 
2.20.1
@Ayehavgunne
Copy link

This worked! Even though I couldn't use the patch file and had to apply the changes manually. I now have NKRO with my Teensy 3.6. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment