From a2ba6fde6814204c5d4a90233fa19a473ffd4f12 Mon Sep 17 00:00:00 2001 From: Nico Date: Sat, 22 Nov 2014 12:43:36 +0100 Subject: [PATCH] Added HoodLoader1&2 examples --- .../HoodLoader1_API_Legacy.ino | 163 ++++++++++++++++++ .../HoodLoader2_SerialKeyboard.ino | 52 ++++++ 2 files changed, 215 insertions(+) create mode 100644 examples/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino create mode 100644 examples/HoodLoader2_SerialKeyboard/HoodLoader2_SerialKeyboard.ino diff --git a/examples/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino b/examples/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino new file mode 100644 index 0000000..86182a8 --- /dev/null +++ b/examples/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino @@ -0,0 +1,163 @@ +/* + 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 + */ + +// 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); + } +} + +//================================================================================ +// NHP +//================================================================================ + +// 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); +} diff --git a/examples/HoodLoader2_SerialKeyboard/HoodLoader2_SerialKeyboard.ino b/examples/HoodLoader2_SerialKeyboard/HoodLoader2_SerialKeyboard.ino new file mode 100644 index 0000000..07051d9 --- /dev/null +++ b/examples/HoodLoader2_SerialKeyboard/HoodLoader2_SerialKeyboard.ino @@ -0,0 +1,52 @@ +/* + Copyright (c) 2014 NicoHood + See the readme for credit to other people. + + HoodLoader2 SerialKeyboard example + + This sketch should demonstate how to program a basic sketch with HoodLoader2. + It was used to demonstrate that Serial and HID is working properly. + + Open the Serial port, type in anything and see that Serial and Keyboard is working. + See official documentation for more infos. + + Use the F() macro to save strings in PROGMEM to keep ram usage low. + */ + +void setup() { + // start + wait for serial debug in/output + while (!Serial); + Serial.begin(115200); + Serial.println(F("Startup")); + + // Sends a clean report to the host. This is important because + // the 16u2 of the Uno/Mega is not turned off while programming + // so you want to start with a clean report to avoid strange bugs after reset. + Keyboard.begin(); +} + + +void loop() { + if (Serial.available()) { + // discard all Serial bytes to avoid multiple sendings + unsigned long currentMillis = millis(); + while (millis() - currentMillis < 100) { + if (Serial.available()) + Serial.write(Serial.read()); + } + + // print an information back to the serial port + Serial.println(); + Serial.println(F("Serial port working. Printing Text in 3 seconds.")); + + // wait 3 seconds and discard all new in bytes to not crash the Arduino + currentMillis = millis(); + while (millis() - currentMillis < 3000) { + if (Serial.available()) + Serial.write(Serial.read()); + } + + // same use as the official library, pretty much self explaining + Keyboard.print(F("This message was sent with my Arduino.")); + } +} \ No newline at end of file