HID/examples/Projects/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino
Nico 9340ea20c6 Added Raw HID, made Custom reports more easy
Also added a new picture and a keyboard + mouse report definition
2015-01-08 17:44:04 +01:00

165 lines
5.2 KiB
C++

/*
Copyright (c) 2014 NicoHood
See the readme for credit to other people.
Keyboard HoodLoader1 API Legacy example
Legacy Example on how to access the Serial HID API of HoodLoader1.
This methode is outdated, because you can now control the whole
16u2 with HoodLoader2. It might be still usefull if you want the 328/2560
keep control of the USB functions. Keep in mind that there is no such thing
as flushing HID reports. If the USB Host is too slow HID reports might be missed.
You can also adapt the sending method below to send Mouse/Keyboard/Media/System reports.
Gamepads/RawHID have a general problem with the original HoodLoader1 firmware, so please avoid this.
It might be compatible with the new HoodLoader2 port of the protocol later on.
HID reports are converted into a special Serial Protocol with NHP.
This sketch should only be used with a 328/2560, not a 16u2.
The 16u2 has a HoodLoader1 compatible sketch/firmware loaded and will
listen to the Serial Port for these Protocol packets on baud 115200.
The HID_SendReport function is implemented weak, so we can overwrite it
in this sketch below. A simple NHP implementation encapsulated the HID reports
into NHP packets with correct addresses and checksums.
Press a button to write some text to your pc.
See official documentation for more infos
*/
#include "USB-Core/Keyboard.h"
// Serial to write Protocol data to. Default: Serial
#define HID_SERIAL Serial
#define SERIAL_HID_BAUD 115200
// extra delay for raspberry. Only needed for Hoodloader and slow devices
//#define HID_EXTRADELAY 20
const int pinLed = 13;
const int pinButton = 8;
void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinButton, INPUT_PULLUP);
// Starts Serial at baud 115200 otherwise HID wont work with HoodLoader1.
// This is not needed for Leonado/(Pro)Micro/16u2(HoodLoader2)
Serial.begin(SERIAL_HID_BAUD);
// Sends a clean report to the host. This is important on any Arduino type.
// Make sure all desired USB functions are activated in USBAPI.h!
Keyboard.begin();
}
void loop() {
if (!digitalRead(pinButton)) {
digitalWrite(pinLed, HIGH);
// Same use as the official library, pretty much self explaining
Keyboard.println("This message was sent with my Arduino.");
Serial.println("Serial port is still working and not glitching out");
// simple debounce
delay(300);
digitalWrite(pinLed, LOW);
}
}
//================================================================================
// HoodLoader1 compatible NHP sending API
//================================================================================
// Start Mask
#define NHP_MASK_START 0xC0 //B11|000000 the two MSB bits
#define NHP_MASK_LEAD 0xC0 //B11|000000
#define NHP_MASK_DATA 0x00 //B0|0000000 only the first MSB is important
#define NHP_MASK_END 0x80 //B10|000000
// Content Mask
#define NHP_MASK_LENGTH 0x38 //B00|111|000
#define NHP_MASK_COMMAND 0x0F //B0000|1111
#define NHP_MASK_DATA_7BIT 0x7F //B0|1111111
#define NHP_MASK_DATA_4BIT 0x0F //B0000|1111
#define NHP_MASK_DATA_3BIT 0x07 //B00000|111
#define NHP_MASK_ADDRESS 0x3F //B00|111111
// Reserved Addresses
#define NHP_ADDRESS_CONTROL 0x01
// Reserved Usages
#define NHP_USAGE_ARDUINOHID 0x01
// overwrites the HID_SendReport function which is empty/not used on a 328/2560
void HID_SendReport(uint8_t id, const void* data, int len)
{
// write the Report via Protocol and checksum. 16bit for each sending
// send control address
NHPwriteChecksum(NHP_ADDRESS_CONTROL, (NHP_USAGE_ARDUINOHID << 8) | id);
const uint8_t* report = (const uint8_t*)data;
for (int i = 0; i < len; i++) {
uint8_t data0 = report[i++];
uint8_t data1 = 0;
if (i != len)
data1 = report[i];
// valid HID reports start at Address 2
NHPwriteChecksum(2 + i / 2, (data1 << 8) | data0);
}
#ifdef HID_EXTRADELAY
delay(HID_EXTRADELAY);
#endif
}
// simple copy/modification of the NicoHoodProtocol writechecksum function
void NHPwriteChecksum(uint8_t address, uint16_t indata) {
// writes two bytes with its inverse
uint32_t temp = ~indata;
uint32_t data = (temp << 16) | indata;
// buffer for write operation
uint8_t writebuffer[6];
// start with the maximum size of blocks
uint8_t blocks = 7;
// check for the first 7 bit block that doesnt fit into the first 3 bits
while (blocks > 2) {
uint8_t nextvalue = (data >> (7 * (blocks - 3)));
if (nextvalue > NHP_MASK_DATA_3BIT) {
// special case for the MSB
if (blocks == 7) {
writebuffer[0] = nextvalue;
blocks--;
}
// this block is too big, write this into the next data block
break;
}
else {
// write the possible first 3 bits and check again after if zero
writebuffer[0] = nextvalue;
blocks--;
// we have our first bits, stop (nonzero)
if (nextvalue)
break;
}
}
// write the rest of the data bits
uint8_t datablocks = blocks - 2;
while (datablocks > 0) {
writebuffer[datablocks] = data & NHP_MASK_DATA_7BIT;
data >>= 7;
datablocks--;
}
// write lead + length mask
writebuffer[0] |= NHP_MASK_LEAD | (blocks << 3);
// write end mask
writebuffer[blocks - 1] = NHP_MASK_END | ((address - 1) & NHP_MASK_ADDRESS);
// write the buffer
HID_SERIAL.write(writebuffer, blocks);
}