This commit is contained in:
Nico 2015-02-11 16:55:39 +01:00
parent 36cba28322
commit eeb929dc8c
14 changed files with 518 additions and 80 deletions

View file

@ -1,4 +1,4 @@
Arduino HID Project 2.1
Arduino HID Project 2.2
=======================
[![Join the chat at https://gitter.im/NicoHood/HID](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/NicoHood/HID?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@ -63,6 +63,10 @@ HL2 usb hub fix (try with a bare cdc bootloader?)
Version History
===============
```
2.2 Release (xx.xx.2015)
* added HID-Bridge
* added colour highlighting (through HID-Bridge library)
2.1 Release (28.01.2015)
* Reworked the whole USB-Core from scratch
* Uses less flash if HID or Serial is not used

View file

@ -90,70 +90,3 @@ microExtended.menu.usbcore.USB_CORE.build.variant=micro
microExtended.menu.usbcore.NO_USB=No USB functions
microExtended.menu.usbcore.NO_USB.build.variant=micro_no_usb
##############################################################
uno.name=Arduino Uno HID-Project
uno.vid.0=0x2341
uno.pid.0=0x0043
uno.vid.1=0x2341
uno.pid.1=0x0001
uno.upload.tool=arduino:avrdude
uno.upload.protocol=arduino
uno.upload.maximum_size=32256
uno.upload.maximum_data_size=2048
uno.upload.speed=115200
uno.bootloader.tool=arduino:avrdude
uno.bootloader.low_fuses=0xFF
uno.bootloader.high_fuses=0xDE
uno.bootloader.extended_fuses=0x05
uno.bootloader.unlock_bits=0x3F
uno.bootloader.lock_bits=0x0F
uno.bootloader.file=arduino:optiboot/optiboot_atmega328.hex
uno.build.mcu=atmega328p
uno.build.f_cpu=16000000L
uno.build.board=AVR_UNO
uno.build.core=HID:hid
uno.build.variant=arduino:standard
##############################################################
mega.name=Arduino Mega 2560 HID-Project
mega.vid.0=0x2341
mega.pid.0=0x0010
mega.vid.1=0x2341
mega.pid.1=0x0042
mega.upload.tool=arduino:avrdude
mega.upload.maximum_data_size=8192
mega.bootloader.tool=arduino:avrdude
mega.bootloader.low_fuses=0xFF
mega.bootloader.unlock_bits=0x3F
mega.bootloader.lock_bits=0x0F
mega.build.f_cpu=16000000L
mega.build.core=HID:hid
mega.build.variant=arduino:mega
# default board may be overridden by the cpu menu
mega.build.board=AVR_MEGA2560
## Arduino Mega w/ ATmega2560
## -------------------------
mega.upload.protocol=wiring
mega.upload.maximum_size=253952
mega.upload.speed=115200
mega.bootloader.high_fuses=0xD8
mega.bootloader.extended_fuses=0xFD
mega.bootloader.file=arduino:stk500v2/stk500boot_v2_mega2560.hex
mega.build.mcu=atmega2560
mega.build.board=AVR_MEGA2560

View file

@ -131,7 +131,6 @@ public:
inline void dPad1(int8_t d){ _report.dPad1 = d; }
inline void dPad2(int8_t d){ _report.dPad2 = d; }
private:
HID_GamepadReport_Data_t _report;
};
extern Gamepad_ Gamepad;

View file

@ -91,7 +91,7 @@ const HIDDescriptor _hidInterface =
};
#if defined(HID_KEYBOARD_LEDS_ENABLED)
uint8_t hid_keyboard_leds = 0;
volatile uint8_t hid_keyboard_leds = 0;
#endif
//================================================================================

View file

@ -61,10 +61,14 @@ THE SOFTWARE.
#define HID_KEYBOARD_LEDS_ENABLED
#endif
#if defined(HID_MOUSE_ENABLE) || defined(HID_MOUSE_ABSOLUTE_ENABLE)
#if defined(HID_MOUSE_ENABLE) || defined(HID_MOUSE_ABSOLUTE_API_ENABLE)
#define HID_MOUSE_API_ENABLE
#endif
#if defined(HID_MOUSE_ABSOLUTE_ENABLE)
#define HID_MOUSE_ABSOLUTE_API_ENABLE
#endif
#if defined(HID_KEYBOARD_LEDS_ENABLE) || defined(HID_KEYBOARD_KEYS_ENABLE)
#define HID_KEYBOARD_ENABLE
#define HID_KEYBOARD_API_ENABLE
#endif
#ifdef HID_RAWHID_ENABLE
@ -82,7 +86,7 @@ THE SOFTWARE.
// extern accessible led out report
#if defined(HID_KEYBOARD_LEDS_ENABLED)
extern uint8_t hid_keyboard_leds;
extern volatile uint8_t hid_keyboard_leds;
#endif
// HID report IDs
@ -402,6 +406,7 @@ void HID_SendReport(uint8_t id, const void* data, int len);
#ifdef HID_ENABLE_ALL_APIS
// include all HID APIs
#define HID_MOUSE_API_ENABLE
#define HID_MOUSE_ABSOLUTE_API_ENABLE
#define HID_KEYBOARD_API_ENABLE
#define HID_RAWHID_API_ENABLE
#define HID_CONSUMERCONTROL_API_ENABLE
@ -409,8 +414,6 @@ void HID_SendReport(uint8_t id, const void* data, int len);
#define HID_GAMEPAD_API_ENABLE
#endif
#ifdef USBCON
#ifdef HID_MOUSE_API_ENABLE
#include "Mouse.h"
#endif
@ -434,7 +437,5 @@ void HID_SendReport(uint8_t id, const void* data, int len);
#ifdef HID_GAMEPAD_API_ENABLE
#include "Gamepad.h"
#endif
#endif
#define kkk
#endif

View file

@ -185,7 +185,7 @@ public:
size_t write(uint8_t k);
size_t press(uint8_t k);
size_t release(uint8_t k);
inline size_t release(uint8_t k);
void releaseAll(void);
size_t writeKeycode(uint8_t k);

View file

@ -138,12 +138,13 @@ public:
return true;
return false;
}
#ifdef HID_MOUSE_ABSOLUTE_API_ENABLE
inline void moveTo(int16_t x, int16_t y){
// uses different report ID and different HID mouse device!
uint32_t pos = ((uint32_t)y << 16) | x;
HID_SendReport(HID_REPORTID_MOUSE_ABSOLUTE, &pos, sizeof(pos));
}
#endif
};
extern Mouse_ Mouse;

View file

@ -0,0 +1,121 @@
/*
Copyright (c) 2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "HIDBridge.h"
//================================================================================
// HIDBridge
//================================================================================
HIDBridge_ HIDBridge;
HIDBridge_::HIDBridge_(void){
// empty
}
bool HIDBridge_::begin(void)
{
}
void HIDBridge_::err(uint8_t error)
{
}
void HIDBridge_::task(void)
{
static NHP_Read_Data_t n = { 0 };
uint8_t error = 0x00;
while (Serial.available()) {
if (NHPread(Serial.read(), &n)) {
if (n.mode == NHP_ADDRESS) {
switch (n.address) {
case 0:
// received a control address command
if (n.data == 0) {
isReady = true;
return;
}
else
error = 3;
break;
default:
error = 1;
break;
}
}
else if (n.mode == NHP_COMMAND) {
}
else {
error = 2;
}
}
}
if (error)
err(error);
}
bool HIDBridge_::ready(void)
{
//if (!hidReady) {
// // try to wait for a new request/acknowledge
// uint32_t currentMillis = millis();
// while (!hidReady) {
// readHIDReady();
// if ((millis() - currentMillis) > 1000) {
// errorHID(0);
// return;
// }
// }
//}
}
// overwrites the HID_SendReport function which is empty/not used on a 328/2560
void HID_SendReport(uint8_t reportID, const void* data, int len)
{
// check if we got a request/acknowledge
if (!HIDBridge.ready()){
HIDBridge.err(0);
return;
}
// begin transfer with reportID as command
Serial.write(NHPwriteCommand(reportID));
// send data in 4 byte packets with the address of the reportID
// the rest (if any, e.g. with 2 byte) is filled with random bytes
NHP_Write_Data_t n;
for (int i = 0; i < len; i += 4) {
NHPwriteAddress(reportID, UINT32_AT_OFFSET(data, i), &n);
Serial.write(n.writeBuffer, n.writeLength);
}
// end transfer with zero command
Serial.write(NHPwriteCommand(0));
}

View file

@ -0,0 +1,65 @@
/*
Copyright (c) 2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef HIDBRIDGE_H
#define HIDBRIDGE_H
#include <Arduino.h>
#include "NHP.h"
//================================================================================
// Settings
//================================================================================
//================================================================================
// Definitions
//================================================================================
//================================================================================
// HIDBridge
//================================================================================
class HIDBridge_{
public:
HIDBridge_(void);
bool begin(void);
bool ready(void);
bool isReady;
void task(void);
void err(uint8_t error);
inline void write(void){} // TODO
};
extern HIDBridge_ HIDBridge;
//================================================================================
// Function prototypes
//================================================================================
#endif // include guard

View file

@ -0,0 +1,288 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef NHP_H
#define NHP_H
#include <stdint.h> //uint_t definitions
#include <stdbool.h> //bool type
//================================================================================
//Settings
//================================================================================
// empty
//================================================================================
//Definitions
//================================================================================
// Header Masks
#define NHP_HEADER_MASK 0xC0 // B11|000000 the two MSB bits determine the block type
#define NHP_HEADER_LEAD 0xC0 // B11|000000 11 MSB
#define NHP_HEADER_DATA_A 0x00 // B00|000000 0X MSB only the first MSB is important
#define NHP_HEADER_DATA_B 0x40 // B01|000000 0X MSB only the first MSB is important
#define NHP_HEADER_END 0x80 // B10|000000 01 MSB
// Lead
#define NHP_LENGTH_MASK 0x38 // B00|111|000
#define NHP_LENGTH_OFFSET 3
#define NHP_COMMAND_MASK 0x0F // B0000|1111 // 4bit command(0-15) in lead block
// Data
#define NHP_DATA_7BIT_MASK 0x7F // B0|1111111 // data in data block
#define NHP_DATA_4BIT_MASK 0x0F // B0000|1111 // data in lead (32 bit special MSB case)
#define NHP_DATA_3BIT_MASK 0x07 // B00000|111 // data in lead
// End
#define NHP_ADDRESS_MASK 0x3F // B00|111111 // 6 bit address (0-63) in end block
// mode indicators
#define NHP_IN_PROGRESS 0
#define NHP_ADDRESS 1
#define NHP_COMMAND 2
#define NHP_RESET 3
// errorLevels
#define NHP_ERR_NONE 0
#define NHP_ERR_LEAD 1
#define NHP_ERR_DATA 2
#define NHP_ERR_END 3
// buffer sizes
#define NHP_BUFFER_SIZE 6
#define NHP_READ_BUFFER_SIZE NHP_BUFFER_SIZE
#define NHP_WRITE_BUFFER_SIZE NHP_BUFFER_SIZE
// definition to convert an uint8_t array to an uint16_t/uint32_t at any position (thx timeage!)
#define UINT16_AT_OFFSET(p_to_8, offset) ((uint16_t)*((const uint16_t *)((p_to_8)+(offset))))
#define UINT32_AT_OFFSET(p_to_8, offset) ((uint32_t)*((const uint32_t *)((p_to_8)+(offset))))
// protocol data for temporary variables
typedef union {
struct { //TODO change order to save flash?
// buffer for read operations
uint8_t readBuffer[NHP_READ_BUFFER_SIZE];
// in progress reading data variables
uint8_t readLength : 3; // 0-6 (7 invalid)
uint8_t mode : 2; // in progress, address, command, reset on error (except lead)
uint8_t blocks : 3; // 0-7
// 2nd byte
uint8_t errorLevel : 2; // no err, lead err, data err, end err
uint8_t address : 6; // 6 bit address (0-63)
union{
// temporary + final data
uint32_t data;
uint32_t data32;
uint16_t data16[sizeof(data) / sizeof(uint16_t)];
uint8_t data8[sizeof(data)];
uint8_t command : 4;
};
};
uint8_t raw[sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(readBuffer)];
} NHP_Read_Data_t;
// protocol data for temporary variables
typedef union {
struct{
// buffer for write operations
uint8_t writeBuffer[NHP_WRITE_BUFFER_SIZE];
uint8_t writeLength;
};
uint8_t raw[sizeof(writeBuffer) + sizeof(uint8_t)];
} NHP_Write_Data_t;
//================================================================================
// Protocol Function Prototypes
//================================================================================
static bool NHPread(uint8_t input, NHP_Read_Data_t* protocol) {
// get old protocol states and save into temporary variables (better compiler optimization)
uint8_t readLength = protocol->readLength;
uint8_t mode;
uint8_t blocks = protocol->blocks;
uint8_t errorLevel = protocol->errorLevel;
uint32_t data = protocol->data;
uint8_t address;
bool newInput = false;
// completely reset the protocol after sucessfull reading/error last time
if (protocol->mode) {
blocks = 0;
readLength = 0;
}
// check if previous reading had a lead error, copy that lead byte to the beginning
else if (errorLevel == NHP_ERR_LEAD) {
protocol->readBuffer[0] = protocol->readBuffer[readLength];
readLength = 1;
}
// write new byte input to the buffer
protocol->readBuffer[readLength++] = input;
// reset mode and errorLevel to the default (no error, no input)
errorLevel = NHP_ERR_NONE;
mode = NHP_IN_PROGRESS;
// check the header(lead/data/end) indicator
uint8_t header = input & NHP_HEADER_MASK;
if (header == NHP_HEADER_LEAD)
{
if (blocks) {
// we were still reading! Log an error but continue reading with this new lead
// set indicator to move this lead byte to the beginning next reading
errorLevel = NHP_ERR_LEAD;
// write the buffer without the new lead, move it next reading
readLength--;
}
// read command indicator or block length
blocks = (input >> NHP_LENGTH_OFFSET) & (NHP_LENGTH_MASK >> NHP_LENGTH_OFFSET);
if (blocks == 0 || blocks == 1) {
// save command in data variable
data = input & NHP_COMMAND_MASK;
// return command indicator, reset next reading
mode = NHP_COMMAND;
newInput = true;
}
// address data
else if (blocks == 7) {
// save block length + first 4 data bits (special 32 bit case)
data = input & NHP_DATA_4BIT_MASK;
blocks -= 2;
}
else {
// save block length + first 3 data bits
data = input & NHP_DATA_3BIT_MASK;
blocks--;
}
}
else if (header == NHP_HEADER_END)
{
// reset next reading on both: valid input or error
if (blocks == 1){
// valid input, save the address
address = input & NHP_ADDRESS_MASK;
mode = NHP_ADDRESS;
newInput = true;
}
else{
// too early for an end, reset next time
errorLevel = NHP_ERR_END;
mode = NHP_RESET;
}
}
else if (header == NHP_HEADER_DATA_A || header == NHP_HEADER_DATA_B)
{
if (blocks >= 2) {
// get next 7 bits of data
blocks--;
data <<= 7;
// normally dont need & NHP_DATA_7BIT_MASK because the MSB bit is zero
data |= (input & NHP_DATA_7BIT_MASK);
}
else {
// log an error, expecting a lead or end byte
errorLevel = NHP_ERR_DATA;
mode = NHP_RESET;
}
}
// save temporary values to the data struct
protocol->blocks = blocks;
protocol->mode = mode;
protocol->readLength = readLength;
protocol->address = address;
protocol->errorLevel = errorLevel;
protocol->data = data;
// return if we have a new address or command
return newInput;
}
//================================================================================
// Write NHP
//================================================================================
static uint8_t NHPwriteCommand(uint8_t command) {
// write lead mask 11 + length 00|0 or 00|1 including the last bit for the 4 bit command
// return the command with protocol around
return NHP_HEADER_LEAD | (command & NHP_COMMAND_MASK);
}
static void NHPwriteAddress(uint8_t address, uint32_t data, NHP_Write_Data_t* protocol) {
// start with the maximum size of blocks (6+1 for special MSB case)
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_DATA_3BIT_MASK) {
// data won't fit into the first 3 bits, wee need an extra block for them
// don't write them to the lead block, keep the data for the data blocks
if (blocks == 7) {
// special case for the MSB where we still want to write
// the 'too big' value into the lead block
protocol->writeBuffer[0] = nextvalue;
blocks = 6;
}
break;
}
else {
// write the possible first 3 bits and check again if the value is zero
// this also ensures that the first byte is always initialized
protocol->writeBuffer[0] = nextvalue;
blocks--;
// we have our first bits, stop
if (nextvalue)
break;
}
}
// write the rest of the data blocks
uint8_t datablocks = blocks - 2;
while (datablocks > 0) {
protocol->writeBuffer[datablocks] = data & NHP_DATA_7BIT_MASK;
data >>= 7;
datablocks--;
}
// add lead 11 + length to the first 3 (or 4 for special MSB case) data bits
protocol->writeBuffer[0] |= NHP_HEADER_LEAD | (blocks << NHP_LENGTH_OFFSET);
// write end 10 + address
protocol->writeBuffer[blocks - 1] = NHP_HEADER_END | (address & NHP_ADDRESS_MASK);
// save the number of blocks
protocol->writeLength = blocks;
}
#endif

View file

@ -0,0 +1,22 @@
#######################################
# Syntax Coloring Map For HID-Bridge
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Methods and Functions (KEYWORD2)
#######################################
Gamepad KEYWORD3
#######################################
# Instances (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################

View file

@ -9,7 +9,7 @@
# https://github.com/NicoHood
name=HID Project USB-Core
version=2.1
version=2.2
# AVR compile variables

View file

@ -76,6 +76,7 @@ HID_REPORT_MOUSE(HID_REPORTID_MOUSE)
// activate your custom HID-APIs here:
#define HID_MOUSE_API_ENABLE
//#define HID_MOUSE_ABSOLUTE_API_ENABLE
#define HID_KEYBOARD_API_ENABLE
//#define HID_RAWHID_API_ENABLE
//#define HID_CONSUMERCONTROL_API_ENABLE
@ -122,6 +123,7 @@ HID_REPORT_MOUSE(HID_REPORTID_MOUSE)
//
//// activate your custom HID-APIs here:
////#define HID_MOUSE_API_ENABLE
////#define HID_MOUSE_ABSOLUTE_API_ENABLE
////#define HID_KEYBOARD_API_ENABLE
////#define HID_RAWHID_API_ENABLE
////#define HID_CONSUMERCONTROL_API_ENABLE

View file

@ -76,6 +76,7 @@ HID_REPORT_MOUSE(HID_REPORTID_MOUSE)
// activate your custom HID-APIs here:
#define HID_MOUSE_API_ENABLE
//#define HID_MOUSE_ABSOLUTE_API_ENABLE
#define HID_KEYBOARD_API_ENABLE
//#define HID_RAWHID_API_ENABLE
//#define HID_CONSUMERCONTROL_API_ENABLE
@ -122,6 +123,7 @@ HID_REPORT_MOUSE(HID_REPORTID_MOUSE)
//
//// activate your custom HID-APIs here:
////#define HID_MOUSE_API_ENABLE
////#define HID_MOUSE_ABSOLUTE_API_ENABLE
////#define HID_KEYBOARD_API_ENABLE
////#define HID_RAWHID_API_ENABLE
////#define HID_CONSUMERCONTROL_API_ENABLE