diff --git a/Arduino.h b/Arduino.h new file mode 100644 index 0000000..64d156d --- /dev/null +++ b/Arduino.h @@ -0,0 +1,252 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. 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 Arduino_h +#define Arduino_h + +#include +#include +#include +#include + +#include +#include +#include + +#include "binary.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +void yield(void); + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 +#define EULER 2.718281828459045235360287471352 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) +#define DEFAULT 0 +#define EXTERNAL 1 +#define INTERNAL 2 +#else +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) +#define INTERNAL1V1 2 +#define INTERNAL2V56 3 +#else +#define INTERNAL 3 +#endif +#define DEFAULT 1 +#define EXTERNAL 0 +#endif + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() sei() +#define noInterrupts() cli() + +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +// avr-libc defines _NOP() since 1.6.2 +#ifndef _NOP +#define _NOP() do { __asm__ volatile ("nop"); } while (0) +#endif + +typedef unsigned int word; + +#define bit(b) (1UL << (b)) + +typedef uint8_t boolean; +typedef uint8_t byte; + +void init(void); +void initVariant(void); + +int atexit(void (*func)()) __attribute__((weak)); + +void pinMode(uint8_t, uint8_t); +void digitalWrite(uint8_t, uint8_t); +int digitalRead(uint8_t); +int analogRead(uint8_t); +void analogReference(uint8_t mode); +void analogWrite(uint8_t, int); + +unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t, void (*)(void), int mode); +void detachInterrupt(uint8_t); + +void setup(void); +void loop(void); + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. + +#define analogInPinToBit(P) (P) + +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; + +extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; +// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. +// +// These perform slightly better as macros compared to inline functions +// +#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) +#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +#define analogInPinToBit(P) (P) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#define NOT_AN_INTERRUPT -1 + +#ifdef ARDUINO_MAIN +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 +#endif + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER1C 5 +#define TIMER2 6 +#define TIMER2A 7 +#define TIMER2B 8 + +#define TIMER3A 9 +#define TIMER3B 10 +#define TIMER3C 11 +#define TIMER4A 12 +#define TIMER4B 13 +#define TIMER4C 14 +#define TIMER4D 15 +#define TIMER5A 16 +#define TIMER5B 17 +#define TIMER5C 18 + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#include "WCharacter.h" +#include "WString.h" +#include "HardwareSerial.h" +#include "USBAPI.h" +#include "CDC.h" +#include "HID.h" + +#if defined(HAVE_HWSERIAL0) && defined(HAVE_CDCSERIAL) +#error "Targets with both UART0 and CDC serial not supported" +#endif + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned int); +long map(long, long, long, long, long); + +#endif + +#include "pins_arduino.h" + +#endif diff --git a/CDC.cpp b/CDC.cpp index 4269118..9141091 100644 --- a/CDC.cpp +++ b/CDC.cpp @@ -16,7 +16,7 @@ ** SOFTWARE. */ -#include "USBAPI.h" +#include "CDC.h" #include #if defined(USBCON) diff --git a/CDC.h b/CDC.h new file mode 100644 index 0000000..627f69f --- /dev/null +++ b/CDC.h @@ -0,0 +1,77 @@ +/* +CDC.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 __CDC__ +#define __CDC__ + +#include "Arduino.h" + +#if defined(USBCON) + +#include "USBDesc.h" +#include "USBCore.h" + +//================================================================================ +//================================================================================ +// Serial over CDC (Serial1 is the physical port) + +struct ring_buffer; + +#if (RAMEND < 1000) +#define SERIAL_BUFFER_SIZE 16 +#else +#define SERIAL_BUFFER_SIZE 64 +#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 + uint32_t baud(void); + uint8_t stopbits(void); + uint8_t paritytype(void); + uint8_t numbits(void); + bool dtr(void); + bool rts(void); + 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 + +#endif /* if defined(USBCON) */ + +#endif \ No newline at end of file diff --git a/HID.cpp b/HID.cpp index 65d773e..48e3a0e 100644 --- a/HID.cpp +++ b/HID.cpp @@ -16,138 +16,32 @@ ** SOFTWARE. */ -#include "USBAPI.h" +#include "HID.h" + +#define WEAK __attribute__ ((weak)) #if defined(USBCON) #ifdef HID_ENABLED -//#define RAWHID_ENABLED - -// Singletons for mouse and keyboard - -Mouse_ Mouse; -Keyboard_ Keyboard; - //================================================================================ //================================================================================ -// HID report descriptor - -#define LSB(_x) ((_x) & 0xFF) -#define MSB(_x) ((_x) >> 8) - -#define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF -#define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF -#define RAWHID_TX_SIZE (USB_EP_SIZE-1) -#define RAWHID_RX_SIZE (USB_EP_SIZE-1) - -#if defined USBCON && defined(HID_KEYBOARD_ENABLED) && defined(HID_KEYBOARD_LEDS_ENABLED) -// extern accessible led out report -uint8_t hid_keyboard_leds = 0; -#endif - extern const u8 _hidReportDescriptor[] PROGMEM; const u8 _hidReportDescriptor[] = { -#ifdef HID_MOUSE_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, HID_REPORTID_MouseReport,// REPORT_ID - // 5 buttons - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x05, // USAGE_MAXIMUM (Button 5) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x95, 0x05, // REPORT_COUNT (5) - 0x75, 0x01, // REPORT_SIZE (1) - 0x81, 0x02, // INPUT (Data,Var,Abs) - // reserved - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x03, // REPORT_SIZE (3) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - // x, y, wheel - 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) - // end - 0xc0, // END_COLLECTION - 0xc0, // END_COLLECTION -#endif - -#ifdef HID_KEYBOARD_ENABLED - // Keyboard - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, HID_REPORTID_KeyboardReport, // REPORT_ID - 0x05, 0x07, // USAGE_PAGE (Keyboard) - // modifiers - 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) - // Key[6] Array - 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) + // by default use the standard HID APIs +#ifndef EXTERN_HID_REPORT #ifdef HID_KEYBOARD_LEDS_ENABLED - // 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) */ + HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), +#else + HID_REPORT_KEYBOARD_KEYS(HID_REPORTID_KEYBOARD), #endif - // end - 0xc0, // END_COLLECTION -#endif - -#ifdef HID_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, HID_REPORTID_RawKeyboardReport, // REPORT_ID - 0x75, 0x08, // report size = 8 bits - 0x15, 0x00, // logical minimum = 0 - 0x26, 0xFF, 0x00, // logical maximum = 255 - - 0x95, RAWHID_TX_SIZE, // report count TX - 0x09, 0x01, // usage - 0x81, 0x02, // Input (array) - - 0x95, RAWHID_RX_SIZE, // report count RX - 0x09, 0x02, // usage - 0x91, 0x02, // Output (array) - 0xC0, // end collection + HID_REPORT_MOUSE(HID_REPORTID_MOUSE), + HID_REPORT_MOUSE_ABSOLUTE(HID_REPORTID_MOUSE_ABSOLUTE), + //HID_REPORT_RAWHID(HID_REPORTID_RAWHID), + HID_REPORT_CONSUMERCONTROL(HID_REPORTID_CONSUMERCONTROL), + HID_REPORT_SYSTEMCONTROL(HID_REPORTID_SYSTEMCONTROL), +#else + EXTERN_HID_REPORT #endif }; @@ -167,8 +61,6 @@ const HIDDescriptor _hidInterface = u8 _hid_protocol = 1; u8 _hid_idle = 1; -#define WEAK __attribute__ ((weak)) - int WEAK HID_GetInterface(u8* interfaceNum) { interfaceNum[0] += 1; // uses 1 @@ -217,354 +109,39 @@ bool WEAK HID_Setup(Setup& setup) _hid_idle = setup.wValueL; return true; } - -#if defined(HID_KEYBOARD_ENABLED) && defined(HID_KEYBOARD_LEDS_ENABLED) +#if defined(HID_KEYBOARD_LEDS_ENABLED) if (HID_SET_REPORT == r) { //TODO check correct report ID (not needed for now, no other device has an out report) + // maybe make this a general weak implementation to use it for RAW HID later? if (setup.wLength == 2) { // write led out report data uint8_t data[2]; if (2 == USB_RecvControl(data, 2)) - hid_keyboard_leds = data[1]; + HID_SetKeyboardLedReport(data[1]); } + // else TODO check for other devices like RAW HID, not needed for now } #endif } return false; } -//================================================================================ -//================================================================================ -// Mouse - -#ifdef HID_MOUSE_ENABLED - -Mouse_::Mouse_(void) : _buttons(0) -{ +#if defined(HID_KEYBOARD_LEDS_ENABLED) +void WEAK HID_SetKeyboardLedReport(uint8_t leds){ + // weak function implemented by the Keyboard API + // to not always create the Keyboard object, if it isn't used } - -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; -} - -#endif - -//================================================================================ -//================================================================================ -// Keyboard - -#ifdef HID_KEYBOARD_ENABLED - -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 - release(c); // Keyup - return p; // just return the result of press() since release() almost always returns 1 -} - #endif #endif +#else /* if defined(USBCON) */ + +void WEAK HID_SendReport(u8 id, const void* data, int len) +{ + // empty to let the user use the HIDAPI for different use +} + #endif /* if defined(USBCON) */ diff --git a/HID.h b/HID.h new file mode 100644 index 0000000..66a86b2 --- /dev/null +++ b/HID.h @@ -0,0 +1,287 @@ +/* +HID.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 __HID__ +#define __HID__ + +#include "Arduino.h" + +// enable Led out report by default +#ifndef EXTERN_HID_REPORT +#define HID_KEYBOARD_LEDS_ENABLED +#endif + +// HID report IDs +// note by NicoHood: I would not change the current IDs, since it can confuse the OS +// I had several problems if i change the report id and its use. +// It doesnt matter if a device is not presented and there is a lack of IDs (at least number 1 must be represented) +// Report IDs and the report itself can be overwritten by the pins_arduino.h +#ifndef HID_REPORTID_MOUSE +#define HID_REPORTID_MOUSE 1 +#endif +#ifndef HID_REPORTID_KEYBOARD +#define HID_REPORTID_KEYBOARD 2 +#endif +#ifndef HID_REPORTID_RAWHID +#define HID_REPORTID_RAWHID 3 +#endif +#ifndef HID_REPORTID_CONSUMERCONTROL +#define HID_REPORTID_CONSUMERCONTROL 4 +#endif +#ifndef HID_REPORTID_SYSTEMCONTROL +#define HID_REPORTID_SYSTEMCONTROL 5 +#endif +#ifndef HID_REPORTID_GAMEPAD +#define HID_REPORTID_GAMEPAD 5 +#endif +#ifndef HID_REPORTID_MOUSE_ABSOLUTE +#define HID_REPORTID_MOUSE_ABSOLUTE 6 +#endif + +// HID reports +// Report IDs and the report itself can be overwritten by the pins_arduino.h + + +#ifndef HID_REPORT_MOUSE +#define HID_REPORT_MOUSE(report_id) /* Mouse relative */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) 54 */ \ + 0x09, 0x02, /* USAGE (Mouse) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, report_id, /* REPORT_ID */ \ +\ + /* 8 Buttons */ \ + 0x05, 0x09, /* USAGE_PAGE (Button) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Button 8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ +\ + /* X, Y, Wheel */ \ + 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) */ \ +\ + /* End */ \ + 0xc0 /* END_COLLECTION */ +#endif + +#ifndef HID_REPORT_MOUSE_ABSOLUTE +#define HID_REPORT_MOUSE_ABSOLUTE(report_id) /* Mouse absolute */ \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x02, /* Usage (Mouse) */ \ + 0xA1, 0x01, /* Collection (Application) */ \ + 0x85, report_id, /* REPORT_ID */ \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x30, /* Usage (X) */ \ + 0x09, 0x31, /* Usage (Y) */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) */ \ + 0x75, 0x10, /* Report Size (16), */ \ + 0x95, 0x02, /* Report Count (2), */ \ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ \ + 0xC0 /* End Collection */ +#endif + +#ifndef HID_REPORT_KEYBOARD_LEDS +#define HID_REPORT_KEYBOARD_LEDS(report_id) /* Keyboard */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) 47 */ \ + 0x09, 0x06, /* USAGE (Keyboard) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, report_id, /* 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 */ +#endif + +#ifndef HID_REPORT_KEYBOARD_KEYS +#define HID_REPORT_KEYBOARD_KEYS(report_id) /* Keyboard */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) 47 */ \ + 0x09, 0x06, /* USAGE (Keyboard) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, report_id, /* 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) */ \ +\ + HID_REPORT_KEYBOARD_LEDS \ + /* 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 */ +#endif + +//TODO limit to system keys only? +#ifndef HID_REPORT_SYSTEMCONTROL +#define HID_REPORT_SYSTEMCONTROL(report_id) /* System Control (Power Down, Sleep, Wakeup, ...) */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ + 0x09, 0x80, /* USAGE (System Control) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, report_id, /* REPORT_ID */ \ + /* 1 system key */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \ + 0x19, 0x00, /* USAGE_MINIMUM (Undefined) */ \ + 0x29, 0xff, /* USAGE_MAXIMUM (System Menu Down) */ \ + 0x95, 0x01, /* REPORT_COUNT (1) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \ + 0xc0 /* END_COLLECTION */ +#endif + +#ifndef HID_REPORT_CONSUMERCONTROL +#define HID_REPORT_CONSUMERCONTROL(report_id) /* Consumer Control (Sound/Media keys) */ \ + 0x05, 0x0C, /* usage page (consumer device) */ \ + 0x09, 0x01, /* usage -- consumer control */ \ + 0xA1, 0x01, /* collection (application) */ \ + 0x85, report_id, /* report id */ \ + /* 4 Media Keys */ \ + 0x15, 0x00, /* logical minimum */ \ + 0x26, 0xFF, 0x03, /* logical maximum (3ff) */ \ + 0x19, 0x00, /* usage minimum (0) */ \ + 0x2A, 0xFF, 0x03, /* usage maximum (3ff) */ \ + 0x95, 0x04, /* report count (4) */ \ + 0x75, 0x10, /* report size (16) */ \ + 0x81, 0x00, /* input */ \ + 0xC0 /* end collection */ +#endif + +// note by NicoHood: RawHID might never work with multireports, because of OS problems +// therefore we have to make it a single report with no idea. No other HID device will be supported then. +#define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF +#define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF +#define RAWHID_TX_SIZE (USB_EP_SIZE-1) +#define RAWHID_RX_SIZE (USB_EP_SIZE-1) + +#define LSB(_x) ((_x) & 0xFF) +#define MSB(_x) ((_x) >> 8) + +#ifndef HID_REPORT_RAWHID +#define HID_REPORT_RAWHID(report_id) /* RAW HID */ \ + 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), /* 30 */ \ + 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), \ +\ + 0xA1, 0x01, /* Collection 0x01 */ \ + 0x85, report_id, /* REPORT_ID */ \ + 0x75, 0x08, /* report size = 8 bits */ \ + 0x15, 0x00, /* logical minimum = 0 */ \ + 0x26, 0xFF, 0x00, /* logical maximum = 255 */ \ +\ + 0x95, RAWHID_TX_SIZE, /* report count TX */ \ + 0x09, 0x01, /* usage */ \ + 0x81, 0x02, /* Input (array) */ \ +\ + 0x95, RAWHID_RX_SIZE, /* report count RX */ \ + 0x09, 0x02, /* usage */ \ + 0x91, 0x02, /* Output (array) */ \ + 0xC0 /* end collection */ +#endif + +#if defined(USBCON) + +#include "USBDesc.h" +#include "USBCore.h" +#include "HIDAPI.h" + +//================================================================================ +//================================================================================ +// 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); +#if defined(HID_KEYBOARD_LEDS_ENABLED) +void HID_SetKeyboardLedReport(uint8_t leds); +#endif + +#else /* if defined(USBCON) */ + +// (weak) function prototype to let the user use the HIDAPI for different use +// if he include the api himself +void HID_SendReport(uint8_t id, const void* data, int len); + +#endif /* if defined(USBCON) */ + +#endif \ No newline at end of file diff --git a/HIDAPI.h b/HIDAPI.h new file mode 100644 index 0000000..6ce37be --- /dev/null +++ b/HIDAPI.h @@ -0,0 +1,28 @@ +/* +HIDAPI.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 __HIDAPI__ +#define __HIDAPI__ + +// include all HID APIs +#include "Keyboard.h" +#include "Mouse.h" +//TODO + +#endif \ No newline at end of file diff --git a/Keyboard.cpp b/Keyboard.cpp new file mode 100644 index 0000000..2ab5f77 --- /dev/null +++ b/Keyboard.cpp @@ -0,0 +1,284 @@ +/* +Keyboard.cpp +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 +*/ + +#include "Keyboard.h" + +//================================================================================ +//================================================================================ +// Keyboard + +#if defined(HID_KEYBOARD_LEDS_ENABLED) +uint8_t hid_keyboard_leds = 0; +void HID_SetKeyboardLedReport(uint8_t leds){ + hid_keyboard_leds = leds; +} +#endif + +Keyboard_ Keyboard; + +Keyboard_::Keyboard_(void) +{ +} + +void Keyboard_::begin(void) +{ +} + +void Keyboard_::end(void) +{ +} + +void Keyboard_::sendReport(KeyReport* keys) +{ + HID_SendReport(HID_REPORTID_KEYBOARD, 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 +}; + +// 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) +{ + // release all keys + memset(&_keyReport, 0x00, sizeof(_keyReport)); + sendReport(&_keyReport); +} + +size_t Keyboard_::write(uint8_t c) +{ + uint8_t p = press(c); // Keydown + release(c); // Keyup + return p; // just return the result of press() since release() almost always returns 1 +} diff --git a/Keyboard.h b/Keyboard.h new file mode 100644 index 0000000..6406245 --- /dev/null +++ b/Keyboard.h @@ -0,0 +1,110 @@ +/* +Keyboard.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 __KEYBOARDAPI__ +#define __KEYBOARDAPI__ + +// to access the HID_SendReport via USBAPI.h, report number and the Print class +#include "Arduino.h" + +//================================================================================ +//================================================================================ +// Keyboard + +#define KEY_PRINT 0xCE +#define KEY_NUM_LOCK 0xDB +#define KEY_SCROLL_LOCK 0xCF +#define KEY_PAUSE 0xD0 + +#define KEY_LEFT_CTRL 0x80 +#define KEY_LEFT_SHIFT 0x81 +#define KEY_LEFT_ALT 0x82 +#define KEY_LEFT_GUI 0x83 +#define KEY_LEFT_WINDOWS KEY_LEFT_GUI +#define KEY_RIGHT_CTRL 0x84 +#define KEY_RIGHT_SHIFT 0x85 +#define KEY_RIGHT_ALT 0x86 +#define KEY_RIGHT_GUI 0x87 +#define KEY_RIGHT_WINDOWS KEY_RIGHT_GUI + +#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 + +#define LED_NUM_LOCK 0x01 +#define LED_CAPS_LOCK 0x02 +#define LED_SCROLL_LOCK 0x04 + +// 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; + +// extern accessible led out report +extern uint8_t hid_keyboard_leds; + +class Keyboard_ : public Print +{ +protected: + KeyReport _keyReport; + void sendReport(KeyReport* keys); +public: + Keyboard_(void); + void begin(void); + void end(void); + size_t write(uint8_t k); + size_t press(uint8_t k); + size_t release(uint8_t k); + void releaseAll(void); + + //TODO +#if defined(HID_KEYBOARD_LEDS_ENABLED) + inline uint8_t getLEDs(void){ return hid_keyboard_leds; } +#endif +}; +extern Keyboard_ Keyboard; + +#endif \ No newline at end of file diff --git a/Mouse.cpp b/Mouse.cpp new file mode 100644 index 0000000..2debe1a --- /dev/null +++ b/Mouse.cpp @@ -0,0 +1,88 @@ +/* +Mouse.cpp +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 +*/ + +#include "Mouse.h" + +//================================================================================ +//================================================================================ +// Mouse + +Mouse_ 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; +} + +void Mouse_::moveTo(uint16_t x, uint16_t y) +{ + uint32_t pos = ((uint32_t)y << 16) | x; + HID_SendReport(HID_REPORTID_MOUSE_ABSOLUTE, &pos, sizeof(pos)); +} diff --git a/Mouse.h b/Mouse.h new file mode 100644 index 0000000..582f46b --- /dev/null +++ b/Mouse.h @@ -0,0 +1,56 @@ +/* +Mouse.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 __MOUSEAPI__ +#define __MOUSEAPI__ + +// to access the HID_SendReport via USBAPI.h and report number +#include "Arduino.h" + +//================================================================================ +//================================================================================ +// Mouse + +#define MOUSE_LEFT 0x01 +#define MOUSE_RIGHT 0x02 +#define MOUSE_MIDDLE 0x04 +#define MOUSE_PREV 0x08 +#define MOUSE_NEXT 0x10 +#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE | MOUSE_PREV | MOUSE_NEXT) + +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 + + void moveTo(uint16_t x, uint16_t y); +}; +extern Mouse_ Mouse; + +#endif diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..2a3b917 --- /dev/null +++ b/Readme.md @@ -0,0 +1,54 @@ +TODO +==== + +Under Construction. This is a todo list for myself and a feature list so far. + +``` +Keyboard Layout english only? +more usb definitions instead of fixed values, noone understands +someone has to add the keywords.txt definitions as well +keyboard music vol (change descriptor) +keyboard led move to usb function not to keyboard and from keyboard call this function? +weak hidsendreport implement somewhere the prototype? +move HID-Core to a seperate folder? +usb wakeup +keycode/raw for keyboard +magic key fix? +add examples +void Recv(volatile u8* data, u8 count) static inline?? + +Bugs +Mouse Abs only works with system report under special circumstances. +``` + + +``` +(flash numbers might be irrelevant due to a lot of improvements) +* Uses less flash if HID or Serial is not used +* Extended and compacter(flash) HID Report Descriptors +* Fixed USB Device Descriptor +* Added u2 compatibility with smaller USB_EP_SIZE (16u2 etc) +* Added Serial Event for LineEncoding and LineState (+12b flash) +* Added Serial Function to get dtr state, line encoding etc +* Added Keyboard Led Out report to get Led states (for numlock etc, +52b flash, 1b ram) +* Made CDC-Core independent from USB-Core +* Made HID-Core independent from USB-Core +* Made HID-API independent from HID-Core +* Removed not needed virtual functions in Keyboard +* Made HID Reports and its IDs replaceable via pins_Arduino.h +* Added Absolute Mouse +``` + +``` +Include schematic +- Arduino.h + - USBAPI.h -> Arduino.h, USBDESC.h, USBCore.h + - CDC.h -> Arduino.h, USBDESC.h, USBCore.h + - HID.h -> Arduino.h, USBDESC.h, USBCore.h, HID-API + - HID-API -> Keyboard.h, Mouse.h + - Keyboard.h -> Arduino.h + - Mouse.h -> Arduino.h + +HID.h contains all HID configuration. +Each HID-API (like Mouse) includes Arduino.h and gets these settings as well. +``` \ No newline at end of file diff --git a/USBAPI.h b/USBAPI.h index c135e52..79cbc3c 100644 --- a/USBAPI.h +++ b/USBAPI.h @@ -34,29 +34,6 @@ typedef unsigned long u32; #if defined(USBCON) -// include needed HID devices -// the more you activate, the more flash it will take -// by default only Mouse + Keyboard (without LEDs) are activated -#define HID_MOUSE_ENABLED -#define HID_KEYBOARD_ENABLED -//#define HID_KEYBOARD_LEDS_ENABLED - -//#define HID_RAWHID_ENABLED (currently broken for USB-Core) -//#define HID_MEDIA_ENABLED -//#define HID_SYSTEM_ENABLED -//#define HID_GAMEPAD_ENABLED - -/** Enum for the HID report IDs used in the device. */ -typedef enum{ - HID_REPORTID_NotAReport = 0x00, /**< first entry is always zero for multireports */ - HID_REPORTID_MouseReport = 0x01, /**< Report ID for the Mouse report within the device. */ - HID_REPORTID_KeyboardReport = 0x02, /**< Report ID for the Keyboard report within the device. */ - HID_REPORTID_RawHidReport = 0x03, /**< Report ID for the Raw Hid report within the device. */ - HID_REPORTID_MediaReport = 0x04, /**< Report ID for the Media report within the device. */ - HID_REPORTID_SystemReport = 0x05, /**< Report ID for the Power report within the device. */ - HID_REPORTID_GamepadReport = 0x06, /**< Report ID for the Gamepad report within the device. */ -} HID_Report_IDs; - #include "USBDesc.h" #include "USBCore.h" @@ -76,195 +53,6 @@ public: }; extern USBDevice_ USBDevice; -//================================================================================ -//================================================================================ -// Serial over CDC (Serial1 is the physical port) - -struct ring_buffer; - -#if (RAMEND < 1000) -#define SERIAL_BUFFER_SIZE 16 -#else -#define SERIAL_BUFFER_SIZE 64 -#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 - uint32_t baud(void); - uint8_t stopbits(void); - uint8_t paritytype(void); - uint8_t numbits(void); - bool dtr(void); - bool rts(void); - 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 - -//================================================================================ -//================================================================================ -// Mouse - -#ifdef HID_MOUSE_ENABLED - -#define MOUSE_LEFT 0x01 -#define MOUSE_RIGHT 0x02 -#define MOUSE_MIDDLE 0x04 -#define MOUSE_PREV 0x08 -#define MOUSE_NEXT 0x10 -#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE | MOUSE_PREV | MOUSE_NEXT) - -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; - -#endif - -//================================================================================ -//================================================================================ -// Keyboard - -#ifdef HID_KEYBOARD_ENABLED - -#define KEY_PRINT 0xCE -#define KEY_NUM_LOCK 0xDB -#define KEY_SCROLL_LOCK 0xCF -#define KEY_PAUSE 0xD0 - -#define KEY_LEFT_CTRL 0x80 -#define KEY_LEFT_SHIFT 0x81 -#define KEY_LEFT_ALT 0x82 -#define KEY_LEFT_GUI 0x83 -#define KEY_LEFT_WINDOWS KEY_LEFT_GUI -#define KEY_RIGHT_CTRL 0x84 -#define KEY_RIGHT_SHIFT 0x85 -#define KEY_RIGHT_ALT 0x86 -#define KEY_RIGHT_GUI 0x87 -#define KEY_RIGHT_WINDOWS KEY_RIGHT_GUI - -#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 - -#define LED_NUM_LOCK 0x01 -#define LED_CAPS_LOCK 0x02 -#define LED_SCROLL_LOCK 0x04 - -#if defined USBCON && defined(HID_KEYBOARD_ENABLED) && defined(HID_KEYBOARD_LEDS_ENABLED) -// extern accessible led out report -extern uint8_t hid_keyboard_leds; -#endif - -// 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); - -#if defined(HID_KEYBOARD_LEDS_ENABLED) - inline uint8_t getLEDs(void){ return hid_keyboard_leds; } -#endif -}; -extern Keyboard_ Keyboard; - -#endif - -//================================================================================ -//================================================================================ -// 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' diff --git a/USBCore.h b/USBCore.h index 4178b75..35d850a 100644 --- a/USBCore.h +++ b/USBCore.h @@ -317,5 +317,18 @@ typedef struct #define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } #define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } +//================================================================================ +//================================================================================ +// Low level API + +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint16_t wIndex; + uint16_t wLength; +} Setup; #endif \ No newline at end of file