Last active
August 29, 2015 14:23
-
-
Save bryan-lunt/1324cf6471991aaa8d59 to your computer and use it in GitHub Desktop.
Arduino HID altered to handle joysticks. ( I took the files from here and merged their changes with the newer Arduino headers. http://www.imaginaryindustries.com/blog/?p=80 )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright (c) 2011, Peter Barrett | |
** | |
** Permission to use, copy, modify, and/or distribute this software for | |
** any purpose with or without fee is hereby granted, provided that the | |
** above copyright notice and this permission notice appear in all copies. | |
** | |
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | |
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | |
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR | |
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES | |
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
** SOFTWARE. | |
*/ | |
#include "USBAPI.h" | |
#if defined(USBCON) | |
#ifdef HID_ENABLED | |
// *** This used to be RAWHID_ENABLED | |
//#define RAWHID_ENABLED | |
//#define KBAM_ENABLED | |
#define JOYHID_ENABLED | |
// Singletons for mouse and keyboard | |
Mouse_ Mouse; | |
Keyboard_ Keyboard; | |
// *** Add a joystick too | |
Joystick_ Joystick; | |
//================================================================================ | |
//================================================================================ | |
// HID report descriptor | |
#define LSB(_x) ((_x) & 0xFF) | |
#define MSB(_x) ((_x) >> 8) | |
#define RAWHID_USAGE_PAGE 0xFFC0 | |
#define RAWHID_USAGE 0x0C00 | |
#define RAWHID_TX_SIZE 64 | |
#define RAWHID_RX_SIZE 64 | |
extern const u8 _hidReportDescriptor[] PROGMEM; | |
const u8 _hidReportDescriptor[] = { | |
#if KBAM_ENABLED | |
// Mouse | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 | |
0x09, 0x02, // USAGE (Mouse) | |
0xa1, 0x01, // COLLECTION (Application) | |
0x09, 0x01, // USAGE (Pointer) | |
0xa1, 0x00, // COLLECTION (Physical) | |
0x85, 0x01, // REPORT_ID (1) | |
0x05, 0x09, // USAGE_PAGE (Button) | |
0x19, 0x01, // USAGE_MINIMUM (Button 1) | |
0x29, 0x03, // USAGE_MAXIMUM (Button 3) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |
0x95, 0x03, // REPORT_COUNT (3) | |
0x75, 0x01, // REPORT_SIZE (1) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x75, 0x05, // REPORT_SIZE (5) | |
0x81, 0x03, // INPUT (Cnst,Var,Abs) | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
0x09, 0x30, // USAGE (X) | |
0x09, 0x31, // USAGE (Y) | |
0x09, 0x38, // USAGE (Wheel) | |
0x15, 0x81, // LOGICAL_MINIMUM (-127) | |
0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x95, 0x03, // REPORT_COUNT (3) | |
0x81, 0x06, // INPUT (Data,Var,Rel) | |
0xc0, // END_COLLECTION | |
0xc0, // END_COLLECTION | |
// Keyboard | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 | |
0x09, 0x06, // USAGE (Keyboard) | |
0xa1, 0x01, // COLLECTION (Application) | |
0x85, 0x02, // REPORT_ID (2) | |
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 | |
#endif | |
#if RAWHID_ENABLED | |
// RAW HID | |
0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 | |
0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), | |
0xA1, 0x01, // Collection 0x01 | |
0x85, 0x03, // REPORT_ID (3) | |
0x75, 0x08, // report size = 8 bits | |
0x15, 0x00, // logical minimum = 0 | |
0x26, 0xFF, 0x00, // logical maximum = 255 | |
0x95, 64, // report count TX | |
0x09, 0x01, // usage | |
0x81, 0x02, // Input (array) | |
0x95, 64, // report count RX | |
0x09, 0x02, // usage | |
0x91, 0x02, // Output (array) | |
0xC0 // end collection | |
#endif | |
// *** Here is where the RAW_HID has been converted to a Joystick device | |
// *** Inspired by helmpcb.com/electronics/usb-joystick | |
// *** Check out www.usb.org/developers/hidpage/ for more than you'll ever need to know about USB HID | |
// *** HID descriptor created using the HID descriptor tool from www.usb.org/developers/hidpage/dt2_4.zip (win32) | |
#ifdef JOYHID_ENABLED | |
// 32 buttons (and a throttle - just in case the game doesn't recognise a joystick with no analog axis) | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
0x09, 0x04, // USAGE (Joystick) | |
0xa1, 0x01, // COLLECTION (Application) | |
0x85, 0x03, // REPORT_ID (3) (This is important when HID_SendReport() is called) | |
//Buttons: | |
0x05, 0x09, // USAGE_PAGE (Button) | |
0x19, 0x01, // USAGE_MINIMUM (Button 1) | |
0x29, 0x20, // USAGE_MAXIMUM (Button 32) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |
0x75, 0x01, // REPORT_SIZE (1) | |
0x95, 0x20, // REPORT_COUNT (32) | |
0x55, 0x00, // UNIT_EXPONENT (0) | |
0x65, 0x00, // UNIT (None) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
// 8 bit Throttle and Steering | |
0x05, 0x02, // USAGE_PAGE (Simulation Controls) | |
0xA1, 0x00, // COLLECTION (Physical) | |
0x09, 0xBB, // USAGE (Throttle) | |
0x09, 0xBA, // USAGE (Steering) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x95, 0x02, // REPORT_COUNT (2) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0xc0, // END_COLLECTION | |
// Two Hat switches | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
0x09, 0x39, // USAGE (Hat switch) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x07, // LOGICAL_MAXIMUM (7) | |
0x35, 0x00, // PHYSICAL_MINIMUM (0) | |
0x46, 0x3B, 0x01, // PHYSICAL_MAXIMUM (315) | |
0x65, 0x14, // UNIT (Eng Rot:Angular Pos) | |
0x75, 0x04, // REPORT_SIZE (4) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0x09, 0x39, // USAGE (Hat switch) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x07, // LOGICAL_MAXIMUM (7) | |
0x35, 0x00, // PHYSICAL_MINIMUM (0) | |
0x46, 0x3B, 0x01, // PHYSICAL_MAXIMUM (315) | |
0x65, 0x14, // UNIT (Eng Rot:Angular Pos) | |
0x75, 0x04, // REPORT_SIZE (4) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0x09, 0x01, // USAGE (Pointer) | |
0xA1, 0x00, // COLLECTION (Physical) | |
0x09, 0x30, // USAGE (x) | |
0x09, 0x31, // USAGE (y) | |
0x09, 0x32, // USAGE (z) | |
0x09, 0x33, // USAGE (rx) | |
0x09, 0x34, // USAGE (ry) | |
0x09, 0x35, // USAGE (rz) | |
0x15, 0x81, // LOGICAL_MINIMUM (-127) | |
0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x95, 0x06, // REPORT_COUNT (6) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0xc0, // END_COLLECTION | |
0xc0 // END_COLLECTION | |
#endif | |
}; | |
extern const HIDDescriptor _hidInterface PROGMEM; | |
const HIDDescriptor _hidInterface = | |
{ | |
D_INTERFACE(HID_INTERFACE,1,3,0,0), | |
D_HIDREPORT(sizeof(_hidReportDescriptor)), | |
D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) | |
}; | |
//================================================================================ | |
//================================================================================ | |
// Driver | |
u8 _hid_protocol = 1; | |
u8 _hid_idle = 1; | |
#define WEAK __attribute__ ((weak)) | |
int WEAK HID_GetInterface(u8* interfaceNum) | |
{ | |
interfaceNum[0] += 1; // uses 1 | |
return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); | |
} | |
int WEAK HID_GetDescriptor(int i) | |
{ | |
return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); | |
} | |
void WEAK HID_SendReport(u8 id, const void* data, int len) | |
{ | |
USB_Send(HID_TX, &id, 1); | |
USB_Send(HID_TX | TRANSFER_RELEASE,data,len); | |
} | |
bool WEAK HID_Setup(Setup& setup) | |
{ | |
u8 r = setup.bRequest; | |
u8 requestType = setup.bmRequestType; | |
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) | |
{ | |
if (HID_GET_REPORT == r) | |
{ | |
//HID_GetReport(); | |
return true; | |
} | |
if (HID_GET_PROTOCOL == r) | |
{ | |
//Send8(_hid_protocol); // TODO | |
return true; | |
} | |
} | |
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) | |
{ | |
if (HID_SET_PROTOCOL == r) | |
{ | |
_hid_protocol = setup.wValueL; | |
return true; | |
} | |
if (HID_SET_IDLE == r) | |
{ | |
_hid_idle = setup.wValueL; | |
return true; | |
} | |
} | |
return false; | |
} | |
//================================================================================ | |
//================================================================================ | |
// Joystick | |
// Usage: Joystick.move(inputs go here) | |
// | |
// The report data format must match the one defined in the descriptor exactly | |
// or it either won't work, or the pc will make a mess of unpacking the data | |
// | |
Joystick_::Joystick_() | |
{ | |
} | |
#define joyBytes 13 // should be equivalent to sizeof(JoyState_t) | |
void Joystick_::setState(JoyState_t *joySt) | |
{ | |
uint8_t data[joyBytes]; | |
uint32_t buttonTmp; | |
buttonTmp = joySt->buttons; | |
data[0] = buttonTmp & 0xFF; // Break 32 bit button-state out into 4 bytes, to send over USB | |
buttonTmp >>= 8; | |
data[1] = buttonTmp & 0xFF; | |
buttonTmp >>= 8; | |
data[2] = buttonTmp & 0xFF; | |
buttonTmp >>= 8; | |
data[3] = buttonTmp & 0xFF; | |
data[4] = joySt->throttle; // Throttle | |
data[5] = joySt->rudder; // Steering | |
data[6] = (joySt->hatSw2 << 4) | joySt->hatSw1; // Pack hat-switch states into a single byte | |
data[7] = joySt->xAxis; // X axis | |
data[8] = joySt->yAxis; // Y axis | |
data[9] = joySt->zAxis; // Z axis | |
data[10] = joySt->xRotAxis; // rX axis | |
data[11] = joySt->yRotAxis; // rY axis | |
data[12] = joySt->zRotAxis; // rZ axis | |
//HID_SendReport(Report number, array of values in same order as HID descriptor, length) | |
HID_SendReport(3, data, joyBytes); | |
// The joystick is specified as using report 3 in the descriptor. That's where the "3" comes from | |
} | |
//================================================================================ | |
//================================================================================ | |
// Mouse | |
Mouse_::Mouse_(void) : _buttons(0) | |
{ | |
} | |
void Mouse_::begin(void) | |
{ | |
} | |
void Mouse_::end(void) | |
{ | |
} | |
void Mouse_::click(uint8_t b) | |
{ | |
_buttons = b; | |
move(0,0,0); | |
_buttons = 0; | |
move(0,0,0); | |
} | |
void Mouse_::move(signed char x, signed char y, signed char wheel) | |
{ | |
u8 m[4]; | |
m[0] = _buttons; | |
m[1] = x; | |
m[2] = y; | |
m[3] = wheel; | |
HID_SendReport(1,m,4); | |
} | |
void Mouse_::buttons(uint8_t b) | |
{ | |
if (b != _buttons) | |
{ | |
_buttons = b; | |
move(0,0,0); | |
} | |
} | |
void Mouse_::press(uint8_t b) | |
{ | |
buttons(_buttons | b); | |
} | |
void Mouse_::release(uint8_t b) | |
{ | |
buttons(_buttons & ~b); | |
} | |
bool Mouse_::isPressed(uint8_t b) | |
{ | |
if ((b & _buttons) > 0) | |
return true; | |
return false; | |
} | |
//================================================================================ | |
//================================================================================ | |
// Keyboard | |
Keyboard_::Keyboard_(void) | |
{ | |
} | |
void Keyboard_::begin(void) | |
{ | |
} | |
void Keyboard_::end(void) | |
{ | |
} | |
void Keyboard_::sendReport(KeyReport* keys) | |
{ | |
HID_SendReport(2,keys,sizeof(KeyReport)); | |
} | |
extern | |
const uint8_t _asciimap[128] PROGMEM; | |
#define SHIFT 0x80 | |
const uint8_t _asciimap[128] = | |
{ | |
0x00, // NUL | |
0x00, // SOH | |
0x00, // STX | |
0x00, // ETX | |
0x00, // EOT | |
0x00, // ENQ | |
0x00, // ACK | |
0x00, // BEL | |
0x2a, // BS Backspace | |
0x2b, // TAB Tab | |
0x28, // LF Enter | |
0x00, // VT | |
0x00, // FF | |
0x00, // CR | |
0x00, // SO | |
0x00, // SI | |
0x00, // DEL | |
0x00, // DC1 | |
0x00, // DC2 | |
0x00, // DC3 | |
0x00, // DC4 | |
0x00, // NAK | |
0x00, // SYN | |
0x00, // ETB | |
0x00, // CAN | |
0x00, // EM | |
0x00, // SUB | |
0x00, // ESC | |
0x00, // FS | |
0x00, // GS | |
0x00, // RS | |
0x00, // US | |
0x2c, // ' ' | |
0x1e|SHIFT, // ! | |
0x34|SHIFT, // " | |
0x20|SHIFT, // # | |
0x21|SHIFT, // $ | |
0x22|SHIFT, // % | |
0x24|SHIFT, // & | |
0x34, // ' | |
0x26|SHIFT, // ( | |
0x27|SHIFT, // ) | |
0x25|SHIFT, // * | |
0x2e|SHIFT, // + | |
0x36, // , | |
0x2d, // - | |
0x37, // . | |
0x38, // / | |
0x27, // 0 | |
0x1e, // 1 | |
0x1f, // 2 | |
0x20, // 3 | |
0x21, // 4 | |
0x22, // 5 | |
0x23, // 6 | |
0x24, // 7 | |
0x25, // 8 | |
0x26, // 9 | |
0x33|SHIFT, // : | |
0x33, // ; | |
0x36|SHIFT, // < | |
0x2e, // = | |
0x37|SHIFT, // > | |
0x38|SHIFT, // ? | |
0x1f|SHIFT, // @ | |
0x04|SHIFT, // A | |
0x05|SHIFT, // B | |
0x06|SHIFT, // C | |
0x07|SHIFT, // D | |
0x08|SHIFT, // E | |
0x09|SHIFT, // F | |
0x0a|SHIFT, // G | |
0x0b|SHIFT, // H | |
0x0c|SHIFT, // I | |
0x0d|SHIFT, // J | |
0x0e|SHIFT, // K | |
0x0f|SHIFT, // L | |
0x10|SHIFT, // M | |
0x11|SHIFT, // N | |
0x12|SHIFT, // O | |
0x13|SHIFT, // P | |
0x14|SHIFT, // Q | |
0x15|SHIFT, // R | |
0x16|SHIFT, // S | |
0x17|SHIFT, // T | |
0x18|SHIFT, // U | |
0x19|SHIFT, // V | |
0x1a|SHIFT, // W | |
0x1b|SHIFT, // X | |
0x1c|SHIFT, // Y | |
0x1d|SHIFT, // Z | |
0x2f, // [ | |
0x31, // bslash | |
0x30, // ] | |
0x23|SHIFT, // ^ | |
0x2d|SHIFT, // _ | |
0x35, // ` | |
0x04, // a | |
0x05, // b | |
0x06, // c | |
0x07, // d | |
0x08, // e | |
0x09, // f | |
0x0a, // g | |
0x0b, // h | |
0x0c, // i | |
0x0d, // j | |
0x0e, // k | |
0x0f, // l | |
0x10, // m | |
0x11, // n | |
0x12, // o | |
0x13, // p | |
0x14, // q | |
0x15, // r | |
0x16, // s | |
0x17, // t | |
0x18, // u | |
0x19, // v | |
0x1a, // w | |
0x1b, // x | |
0x1c, // y | |
0x1d, // z | |
0x2f|SHIFT, // | |
0x31|SHIFT, // | | |
0x30|SHIFT, // } | |
0x35|SHIFT, // ~ | |
0 // DEL | |
}; | |
uint8_t USBPutChar(uint8_t c); | |
// 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 | |
// call release(), releaseAll(), or otherwise clear the report and resend. | |
size_t Keyboard_::press(uint8_t k) | |
{ | |
uint8_t i; | |
if (k >= 136) { // it's a non-printing key (not a modifier) | |
k = k - 136; | |
} else if (k >= 128) { // it's a modifier key | |
_keyReport.modifiers |= (1<<(k-128)); | |
k = 0; | |
} else { // it's a printing key | |
k = pgm_read_byte(_asciimap + k); | |
if (!k) { | |
setWriteError(); | |
return 0; | |
} | |
if (k & 0x80) { // it's a capital letter or other character reached with shift | |
_keyReport.modifiers |= 0x02; // the left shift modifier | |
k &= 0x7F; | |
} | |
} | |
// Add k to the key report only if it's not already present | |
// and if there is an empty slot. | |
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && | |
_keyReport.keys[2] != k && _keyReport.keys[3] != k && | |
_keyReport.keys[4] != k && _keyReport.keys[5] != k) { | |
for (i=0; i<6; i++) { | |
if (_keyReport.keys[i] == 0x00) { | |
_keyReport.keys[i] = k; | |
break; | |
} | |
} | |
if (i == 6) { | |
setWriteError(); | |
return 0; | |
} | |
} | |
sendReport(&_keyReport); | |
return 1; | |
} | |
// release() takes the specified key out of the persistent key report and | |
// sends the report. This tells the OS the key is no longer pressed and that | |
// it shouldn't be repeated any more. | |
size_t Keyboard_::release(uint8_t k) | |
{ | |
uint8_t i; | |
if (k >= 136) { // it's a non-printing key (not a modifier) | |
k = k - 136; | |
} else if (k >= 128) { // it's a modifier key | |
_keyReport.modifiers &= ~(1<<(k-128)); | |
k = 0; | |
} else { // it's a printing key | |
k = pgm_read_byte(_asciimap + k); | |
if (!k) { | |
return 0; | |
} | |
if (k & 0x80) { // it's a capital letter or other character reached with shift | |
_keyReport.modifiers &= ~(0x02); // the left shift modifier | |
k &= 0x7F; | |
} | |
} | |
// Test the key report to see if k is present. Clear it if it exists. | |
// Check all positions in case the key is present more than once (which it shouldn't be) | |
for (i=0; i<6; i++) { | |
if (0 != k && _keyReport.keys[i] == k) { | |
_keyReport.keys[i] = 0x00; | |
} | |
} | |
sendReport(&_keyReport); | |
return 1; | |
} | |
void Keyboard_::releaseAll(void) | |
{ | |
_keyReport.keys[0] = 0; | |
_keyReport.keys[1] = 0; | |
_keyReport.keys[2] = 0; | |
_keyReport.keys[3] = 0; | |
_keyReport.keys[4] = 0; | |
_keyReport.keys[5] = 0; | |
_keyReport.modifiers = 0; | |
sendReport(&_keyReport); | |
} | |
size_t Keyboard_::write(uint8_t c) | |
{ | |
uint8_t p = press(c); // Keydown | |
uint8_t r = release(c); // Keyup | |
return (p); // just return the result of press() since release() almost always returns 1 | |
} | |
#endif | |
#endif /* if defined(USBCON) */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
USBAPI.h | |
Copyright (c) 2005-2014 Arduino. All right reserved. | |
This library is free software; you can redistribute it and/or | |
modify it under the terms of the GNU Lesser General Public | |
License as published by the Free Software Foundation; either | |
version 2.1 of the License, or (at your option) any later version. | |
This library is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
Lesser General Public License for more details. | |
You should have received a copy of the GNU Lesser General Public | |
License along with this library; if not, write to the Free Software | |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
*/ | |
#ifndef __USBAPI__ | |
#define __USBAPI__ | |
#include <inttypes.h> | |
#include <avr/pgmspace.h> | |
#include <avr/eeprom.h> | |
#include <avr/interrupt.h> | |
#include <util/delay.h> | |
typedef unsigned char u8; | |
typedef unsigned short u16; | |
typedef unsigned long u32; | |
#include "Arduino.h" | |
#if defined(USBCON) | |
#include "USBDesc.h" | |
#include "USBCore.h" | |
//================================================================================ | |
//================================================================================ | |
// USB | |
class USBDevice_ | |
{ | |
public: | |
USBDevice_(); | |
bool configured(); | |
void attach(); | |
void detach(); // Serial port goes down too... | |
void poll(); | |
}; | |
extern USBDevice_ USBDevice; | |
//================================================================================ | |
//================================================================================ | |
// Serial over CDC (Serial1 is the physical port) | |
struct ring_buffer; | |
#ifndef SERIAL_BUFFER_SIZE | |
#if (RAMEND < 1000) | |
#define SERIAL_BUFFER_SIZE 16 | |
#else | |
#define SERIAL_BUFFER_SIZE 64 | |
#endif | |
#endif | |
#if (SERIAL_BUFFER_SIZE>256) | |
#error Please lower the CDC Buffer size | |
#endif | |
class Serial_ : public Stream | |
{ | |
private: | |
int peek_buffer; | |
public: | |
Serial_() { peek_buffer = -1; }; | |
void begin(unsigned long); | |
void begin(unsigned long, uint8_t); | |
void end(void); | |
virtual int available(void); | |
virtual int peek(void); | |
virtual int read(void); | |
virtual void flush(void); | |
virtual size_t write(uint8_t); | |
virtual size_t write(const uint8_t*, size_t); | |
using Print::write; // pull in write(str) and write(buf, size) from Print | |
operator bool(); | |
volatile uint8_t _rx_buffer_head; | |
volatile uint8_t _rx_buffer_tail; | |
unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; | |
}; | |
extern Serial_ Serial; | |
#define HAVE_CDCSERIAL | |
//================================================================================ | |
//================================================================================ | |
// Joystick | |
// Implemented in HID.cpp | |
// The list of parameters here needs to match the implementation in HID.cpp | |
typedef struct JoyState // Pretty self explanitory. Simple state to store all the joystick parameters | |
{ | |
uint8_t xAxis; | |
uint8_t yAxis; | |
uint8_t zAxis; | |
uint8_t xRotAxis; | |
uint8_t yRotAxis; | |
uint8_t zRotAxis; | |
uint8_t throttle; | |
uint8_t rudder; | |
uint8_t hatSw1; | |
uint8_t hatSw2; | |
uint32_t buttons; // 32 general buttons | |
} JoyState_t; | |
class Joystick_ | |
{ | |
public: | |
Joystick_(); | |
void setState(JoyState_t *joySt); | |
}; | |
extern Joystick_ Joystick; | |
//================================================================================ | |
//================================================================================ | |
// Mouse | |
#define MOUSE_LEFT 1 | |
#define MOUSE_RIGHT 2 | |
#define MOUSE_MIDDLE 4 | |
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) | |
class Mouse_ | |
{ | |
private: | |
uint8_t _buttons; | |
void buttons(uint8_t b); | |
public: | |
Mouse_(void); | |
void begin(void); | |
void end(void); | |
void click(uint8_t b = MOUSE_LEFT); | |
void move(signed char x, signed char y, signed char wheel = 0); | |
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default | |
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default | |
bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default | |
}; | |
extern Mouse_ Mouse; | |
//================================================================================ | |
//================================================================================ | |
// Keyboard | |
#define KEY_LEFT_CTRL 0x80 | |
#define KEY_LEFT_SHIFT 0x81 | |
#define KEY_LEFT_ALT 0x82 | |
#define KEY_LEFT_GUI 0x83 | |
#define KEY_RIGHT_CTRL 0x84 | |
#define KEY_RIGHT_SHIFT 0x85 | |
#define KEY_RIGHT_ALT 0x86 | |
#define KEY_RIGHT_GUI 0x87 | |
#define KEY_UP_ARROW 0xDA | |
#define KEY_DOWN_ARROW 0xD9 | |
#define KEY_LEFT_ARROW 0xD8 | |
#define KEY_RIGHT_ARROW 0xD7 | |
#define KEY_BACKSPACE 0xB2 | |
#define KEY_TAB 0xB3 | |
#define KEY_RETURN 0xB0 | |
#define KEY_ESC 0xB1 | |
#define KEY_INSERT 0xD1 | |
#define KEY_DELETE 0xD4 | |
#define KEY_PAGE_UP 0xD3 | |
#define KEY_PAGE_DOWN 0xD6 | |
#define KEY_HOME 0xD2 | |
#define KEY_END 0xD5 | |
#define KEY_CAPS_LOCK 0xC1 | |
#define KEY_F1 0xC2 | |
#define KEY_F2 0xC3 | |
#define KEY_F3 0xC4 | |
#define KEY_F4 0xC5 | |
#define KEY_F5 0xC6 | |
#define KEY_F6 0xC7 | |
#define KEY_F7 0xC8 | |
#define KEY_F8 0xC9 | |
#define KEY_F9 0xCA | |
#define KEY_F10 0xCB | |
#define KEY_F11 0xCC | |
#define KEY_F12 0xCD | |
// Low level key report: up to 6 keys and shift, ctrl etc at once | |
typedef struct | |
{ | |
uint8_t modifiers; | |
uint8_t reserved; | |
uint8_t keys[6]; | |
} KeyReport; | |
class Keyboard_ : public Print | |
{ | |
private: | |
KeyReport _keyReport; | |
void sendReport(KeyReport* keys); | |
public: | |
Keyboard_(void); | |
void begin(void); | |
void end(void); | |
virtual size_t write(uint8_t k); | |
virtual size_t press(uint8_t k); | |
virtual size_t release(uint8_t k); | |
virtual void releaseAll(void); | |
}; | |
extern Keyboard_ Keyboard; | |
//================================================================================ | |
//================================================================================ | |
// Low level API | |
typedef struct | |
{ | |
uint8_t bmRequestType; | |
uint8_t bRequest; | |
uint8_t wValueL; | |
uint8_t wValueH; | |
uint16_t wIndex; | |
uint16_t wLength; | |
} Setup; | |
//================================================================================ | |
//================================================================================ | |
// HID 'Driver' | |
int HID_GetInterface(uint8_t* interfaceNum); | |
int HID_GetDescriptor(int i); | |
bool HID_Setup(Setup& setup); | |
void HID_SendReport(uint8_t id, const void* data, int len); | |
//================================================================================ | |
//================================================================================ | |
// MSC 'Driver' | |
int MSC_GetInterface(uint8_t* interfaceNum); | |
int MSC_GetDescriptor(int i); | |
bool MSC_Setup(Setup& setup); | |
bool MSC_Data(uint8_t rx,uint8_t tx); | |
//================================================================================ | |
//================================================================================ | |
// CSC 'Driver' | |
int CDC_GetInterface(uint8_t* interfaceNum); | |
int CDC_GetDescriptor(int i); | |
bool CDC_Setup(Setup& setup); | |
//================================================================================ | |
//================================================================================ | |
#define TRANSFER_PGM 0x80 | |
#define TRANSFER_RELEASE 0x40 | |
#define TRANSFER_ZERO 0x20 | |
int USB_SendControl(uint8_t flags, const void* d, int len); | |
int USB_RecvControl(void* d, int len); | |
uint8_t USB_Available(uint8_t ep); | |
int USB_Send(uint8_t ep, const void* data, int len); // blocking | |
int USB_Recv(uint8_t ep, void* data, int len); // non-blocking | |
int USB_Recv(uint8_t ep); // non-blocking | |
void USB_Flush(uint8_t ep); | |
#endif | |
#endif /* if defined(USBCON) */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment