Skip to content

Commit

Permalink
Added KeyboardLeds/HID Out Report
Browse files Browse the repository at this point in the history
This also enables the option for further raw HID development.
  • Loading branch information
NicoHood committed Sep 19, 2015
1 parent 02684ed commit f34df6e
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 70 deletions.
43 changes: 43 additions & 0 deletions examples/KeyboardLed/KeyboardLed.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
KeyboardLed example
Press a button to toogle caps lock.
Caps lock state is represented by the onboard led.
See HID Project documentation for more information.
https://github.com/NicoHood/HID/wiki/Keyboard-API
*/

#include "HID-Project.h"

const int pinLed = LED_BUILTIN;
const int pinButton = 2;

void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinButton, INPUT_PULLUP);

// Sends a clean report to the host. This is important on any Arduino type.
Keyboard.begin();
}


void loop() {
// Update Led equal to the caps lock state.
// Keep in mind that on a 16u2 and Arduino Micro HIGH and LOW for TX/RX Leds are inverted.
if (Keyboard.getLeds()&LED_CAPS_LOCK)
digitalWrite(pinLed, HIGH);
else
digitalWrite(pinLed, LOW);

// Trigger caps lock manually via button
if (!digitalRead(pinButton)) {
Keyboard.write(KEY_CAPS_LOCK);

// Simple debounce
delay(300);
}
}
8 changes: 4 additions & 4 deletions src/HID-Project.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ extern HID_ HID;
#include "HID-Tables.h"

// Include all HID libraries (.a linkage required to work) properly
#include "AbsoluteMouse.h"
#include "Consumer.h"
#include "Gamepad.h"
#include "System.h"
//#include "AbsoluteMouse.h"
//#include "Consumer.h"
//#include "Gamepad.h"
//#include "System.h"

// Include Teensy HID afterwards to overwrite key definitions if used
#ifdef USE_TEENSY_KEYBOARD
Expand Down
101 changes: 63 additions & 38 deletions src/ImprovedKeyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,46 +30,58 @@ THE SOFTWARE.
// Keyboard

static const u8 _hidReportDescriptor[] PROGMEM = {

// Keyboard
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x85, HID_REPORTID_KEYBOARD, // REPORT_ID
0x05, 0x07, // USAGE_PAGE (Keyboard)

0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)

0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)

0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)

0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0, // END_COLLECTION
// Keyboard
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) 47 */
0x09, 0x06, /* USAGE (Keyboard) */
0xa1, 0x01, /* COLLECTION (Application) */
0x85, HID_REPORTID_KEYBOARD, /* REPORT_ID */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */

/* Keyboard Modifiers (shift, alt, ...) */
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x95, 0x08, /* REPORT_COUNT (8) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */

/* Reserved byte */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */

/* 5 LEDs for num lock etc */
0x05, 0x08, /* USAGE_PAGE (LEDs) */
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
0x95, 0x05, /* REPORT_COUNT (5) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* Reserved 3 bits */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x03, /* REPORT_SIZE (3) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */

/* 6 Keyboard keys */
0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x26, 0xE7, 0x00, /* LOGICAL_MAXIMUM (231) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */
0x29, 0xE7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */

/* End */
0xc0 /* END_COLLECTION */
};

Keyboard_::Keyboard_(void)
Keyboard_::Keyboard_(void) :
HIDDevice((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor), HID_REPORTID_KEYBOARD),
leds(0)
{
static HID_Descriptor cb = {
.length = sizeof(_hidReportDescriptor),
.descriptor = _hidReportDescriptor,
};
static HIDDescriptorListNode node(&cb);
HID.AppendDescriptor(&node);
// HID Descriptor is appended via the inherited HIDDevice class
}

void Keyboard_::begin(void)
Expand All @@ -82,9 +94,22 @@ void Keyboard_::end(void)

void Keyboard_::sendReport(HID_KeyboardReport_Data_t* keys)
{
HID.SendReport(HID_REPORTID_KEYBOARD,keys,sizeof(HID_KeyboardReport_Data_t));
// Call the inherited function.
// This wrapper still saves us some bytes
SendReport(keys,sizeof(HID_KeyboardReport_Data_t));
}

void Keyboard_::setReportData(const void* data, int len){
// Save led state
if(len == 1)
leds = *(uint8_t*)data;
}

uint8_t Keyboard_::getLeds(void){
return leds;
}


// press() adds the specified key (printing, non-printing, or modifier)
// to the persistent key report and sends the report. Because of the way
// USB HID works, the host acts like the key remains pressed until we
Expand Down
7 changes: 6 additions & 1 deletion src/ImprovedKeyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ THE SOFTWARE.
// Keyboard

#include "HID-Project.h"
#include "PluggableHID/HIDDevice.h"
#include "ImprovedKeylayouts.h"

// Low level key report: up to 6 keys and shift, ctrl etc at once
Expand All @@ -51,11 +52,13 @@ typedef union{
};
} HID_KeyboardReport_Data_t;

class Keyboard_ : public Print
class Keyboard_ : public Print, public HIDDevice
{
private:
HID_KeyboardReport_Data_t _keyReport;
void sendReport(HID_KeyboardReport_Data_t* keys);
virtual void setReportData(const void* data, int len);
uint8_t leds;
public:
Keyboard_(void);
void begin(void);
Expand All @@ -70,6 +73,8 @@ class Keyboard_ : public Print
size_t releaseKeycode(uint8_t k);
size_t addKeycodeToReport(uint8_t k);
size_t removeKeycodeFromReport(uint8_t k);

uint8_t getLeds(void);
};
extern Keyboard_ Keyboard;

Expand Down
2 changes: 1 addition & 1 deletion src/ImprovedKeylayouts.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ THE SOFTWARE.
#define KEY_RIGHT_WINDOWS KEY_RIGHT_GUI
#define KEY_PRINTSCREEN KEY_PRINT

// TODO implement Leds
// Keyboard Leds
#define LED_NUM_LOCK 0x01
#define LED_CAPS_LOCK 0x02
#define LED_SCROLL_LOCK 0x04
Expand Down
50 changes: 40 additions & 10 deletions src/PluggableHID/HID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "PluggableUSB.h"
#include "HID.h"
#include "HIDDevice.h"

#if defined(USBCON)

Expand All @@ -42,7 +43,7 @@ static u8 HID_INTERFACE;

HIDDescriptor _hidInterface;

static HIDDescriptorListNode* rootNode = NULL;
static HIDDevice* rootDevice = NULL;
static uint16_t sizeof_hidReportDescriptor = 0;
static uint8_t modules_count = 0;
//================================================================================
Expand All @@ -67,10 +68,10 @@ int HID_GetInterface(u8* interfaceNum)
int HID_GetDescriptor(int8_t t)
{
if (HID_REPORT_DESCRIPTOR_TYPE == t) {
HIDDescriptorListNode* current = rootNode;
HIDDevice* current = rootDevice;
int total = 0;
while(current != NULL) {
total += USB_SendControl(TRANSFER_PGM,current->cb->descriptor,current->cb->length);
total += USB_SendControl(TRANSFER_PGM,current->descriptorData,current->descriptorLength);
current = current->next;
}
return total;
Expand All @@ -79,19 +80,19 @@ int HID_GetDescriptor(int8_t t)
}
}

void HID_::AppendDescriptor(HIDDescriptorListNode *node)
void HID_::AppendDescriptor(HIDDevice *device)
{
if (modules_count == 0) {
rootNode = node;
rootDevice = device;
} else {
HIDDescriptorListNode *current = rootNode;
HIDDevice *current = rootDevice;
while(current->next != NULL) {
current = current->next;
}
current->next = node;
current->next = device;
}
modules_count++;
sizeof_hidReportDescriptor += (uint16_t)node->cb->length;
sizeof_hidReportDescriptor += (uint16_t)device->descriptorLength;
}

void HID_::SendReport(u8 id, const void* data, int len)
Expand All @@ -100,7 +101,7 @@ void HID_::SendReport(u8 id, const void* data, int len)
USB_Send(HID_TX | TRANSFER_RELEASE,data,len);
}

bool HID_Setup(USBSetup& setup, u8 i)
bool HID_::HID_Setup(USBSetup& setup, u8 i)
{
if (HID_INTERFACE != i) {
return false;
Expand Down Expand Up @@ -134,6 +135,35 @@ bool HID_Setup(USBSetup& setup, u8 i)
_hid_idle = setup.wValueL;
return true;
}

if (HID_SET_REPORT == r)
{
// Get reportID and search for the suited HIDDevice
uint8_t ID = setup.wIndex;
HIDDevice *current = rootDevice;
while(current != NULL)
{
// TODO implementation for non reportID HID devices
// This would could make rawHID work. reportID 0 could be used as indicator
if(current->reportID == ID)
{
// Get the data length information and the corresponding bytes
uint8_t length = setup.wLength;
uint8_t data[length];
USB_RecvControl(data, length);

// Skip report ID data
current->setReportData(data+1, length-1);

// Dont search any further
break;
}
current = current->next;
}
//TODO return true??
// https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/USBCore.cpp#L613-L618
return true;
}
}
return false;
}
Expand All @@ -146,7 +176,7 @@ HID_::HID_(void)
endpointType[0] = EP_TYPE_INTERRUPT_IN;

static PUSBCallbacks cb = {
.setup = &HID_Setup,
.setup = HID_Setup,
.getInterface = &HID_GetInterface,
.getDescriptor = &HID_GetDescriptor,
.numEndpoints = 1,
Expand Down
22 changes: 6 additions & 16 deletions src/PluggableHID/HID.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef HID_h
#pragma once

#define HID_h

#include <stdint.h>
Expand All @@ -44,25 +45,17 @@
#define HID_REPORT_DESCRIPTOR_TYPE 0x22
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23

typedef struct __attribute__((packed)) {
uint16_t length;
const void* descriptor;
} HID_Descriptor;

class HIDDescriptorListNode {
public:
HIDDescriptorListNode *next = NULL;
const HID_Descriptor * cb;
HIDDescriptorListNode(const HID_Descriptor *ncb) {cb = ncb;}
};
class HIDDevice;

class HID_
{
public:
HID_(void);
int begin(void);
void SendReport(uint8_t id, const void* data, int len);
void AppendDescriptor(HIDDescriptorListNode* node);
void AppendDescriptor(HIDDevice* device);
private:
static bool HID_Setup(USBSetup& setup, u8 i);
};

typedef struct
Expand Down Expand Up @@ -93,6 +86,3 @@ typedef struct
#define WEAK __attribute__ ((weak))

#endif

#endif

Loading

0 comments on commit f34df6e

Please sign in to comment.