From 3d068a063795505a6b577e31e2955577505f3d4e Mon Sep 17 00:00:00 2001 From: Oleg Mazurov Date: Tue, 3 Apr 2012 14:09:04 -0600 Subject: [PATCH] HID joystick support and examples --- Usb.cpp | 1 + address.h | 4 +- cdcacm.cpp | 14 +- cdcacm.h | 22 +++ cdcprolific.cpp | 4 +- .../HID/USBHIDJoystick/USBHIDJoystick.pde | 46 +++++ .../USBHIDJoystick/hidjoystickrptparser.cpp | 95 +++++++++ .../HID/USBHIDJoystick/hidjoystickrptparser.h | 54 +++++ examples/HID/USBHID_desc/USBHID_desc.pde | 41 +++- examples/board_qc/board_qc.pde | 2 +- hid.h | 16 ++ hidescriptorparser.cpp | 184 ------------------ hidescriptorparser.h | 3 - hiduniversal.cpp | 10 +- hiduniversal.h | 3 +- 15 files changed, 292 insertions(+), 207 deletions(-) create mode 100644 examples/HID/USBHIDJoystick/USBHIDJoystick.pde create mode 100644 examples/HID/USBHIDJoystick/hidjoystickrptparser.cpp create mode 100644 examples/HID/USBHIDJoystick/hidjoystickrptparser.h diff --git a/Usb.cpp b/Usb.cpp index a8096cad..3552e0a8 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -391,6 +391,7 @@ uint8_t USB::dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit ) nak_count ++; if( nak_limit && ( nak_count == nak_limit )) return( rcode ); + //delay(1); break; case hrTIMEOUT: retry_count ++; diff --git a/address.h b/address.h index 5d3e31fe..19109958 100644 --- a/address.h +++ b/address.h @@ -24,8 +24,8 @@ e-mail : support@circuitsathome.com /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */ /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */ -#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value -#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up +#define USB_NAK_MAX_POWER 16 //NAK binary order maximum value +#define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up #define USB_NAK_NOWAIT 1 //Single NAK stops transfer #define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout diff --git a/cdcacm.cpp b/cdcacm.cpp index 9f9f6193..e93e61eb 100644 --- a/cdcacm.cpp +++ b/cdcacm.cpp @@ -210,9 +210,9 @@ Fail: void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { - ErrorMessage(PSTR("Conf.Val"), conf); - ErrorMessage(PSTR("Iface Num"),iface); - ErrorMessage(PSTR("Alt.Set"), alt); + //ErrorMessage(PSTR("Conf.Val"), conf); + //ErrorMessage(PSTR("Iface Num"),iface); + //ErrorMessage(PSTR("Alt.Set"), alt); bConfNum = conf; @@ -233,7 +233,7 @@ void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto bNumEP ++; - PrintEndpointDescriptor(pep); + //PrintEndpointDescriptor(pep); } uint8_t ACM::Release() @@ -298,6 +298,12 @@ uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); } +/* untested */ +uint8_t ACM::GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr ) +{ + return pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, bytes_rcvd, dataptr); +} + uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) { return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL )); diff --git a/cdcacm.h b/cdcacm.h index 062ad696..d8b8db55 100644 --- a/cdcacm.h +++ b/cdcacm.h @@ -89,6 +89,17 @@ e-mail : support@circuitsathome.com #define CDC_GET_LINE_PARMS 0x35 #define CDC_DIAL_DIGITS 0x36 +//Class-Specific Notification Codes +#define NETWORK_CONNECTION 0x00 +#define RESPONSE_AVAILABLE 0x01 +#define AUX_JACK_HOOK_STATE 0x08 +#define RING_DETECT 0x09 +#define SERIAL_STATE 0x20 +#define CALL_STATE_CHANGE 0x28 +#define LINE_STATE_CHANGE 0x29 +#define CONNECTION_SPEED_CHANGE 0x2a + + // CDC Functional Descriptor Structures typedef struct { @@ -125,6 +136,16 @@ typedef struct uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16) } LINE_CODING; +typedef struct +{ + uint8_t bmRequestType; // 0xa1 for class-specific notifications + uint8_t bNotification; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + uint16_t bmState; //UART state bitmap for SERIAL_STATE, other notifications variable length +} CLASS_NOTIFICATION; + class ACM; class CDCAsyncOper @@ -170,6 +191,7 @@ public: uint8_t GetLineCoding(LINE_CODING *dataptr); uint8_t SetControlLineState(uint8_t state); uint8_t SendBreak(uint16_t duration); + uint8_t GetNotif( uint16_t *bytes_rcvd, uint8_t *dataptr ); // Methods for recieving and sending data uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr); diff --git a/cdcprolific.cpp b/cdcprolific.cpp index 23189d6e..ec27defe 100644 --- a/cdcprolific.cpp +++ b/cdcprolific.cpp @@ -132,10 +132,10 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) for( uint8_t i=0; i HexDump; + //HexDumper HexDump; ConfigDescParser<0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this); - rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); + //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); if (bNumEP > 1) diff --git a/examples/HID/USBHIDJoystick/USBHIDJoystick.pde b/examples/HID/USBHIDJoystick/USBHIDJoystick.pde new file mode 100644 index 00000000..6ea00924 --- /dev/null +++ b/examples/HID/USBHIDJoystick/USBHIDJoystick.pde @@ -0,0 +1,46 @@ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hidjoystickrptparser.h" + +#include +#include +#include +#include + +USB Usb; +USBHub Hub(&Usb); +HIDUniversal Hid(&Usb); +JoystickEvents JoyEvents; +JoystickReportParser Joy(&JoyEvents); + +void setup() +{ + Serial.begin( 115200 ); + Serial.println("Start"); + + if (Usb.Init() == -1) + Serial.println("OSC did not start."); + + delay( 200 ); + + if (!Hid.SetReportParser(0, &Joy)) + ErrorMessage(PSTR("SetReportParser"), 1 ); +} + +void loop() +{ + Usb.Task(); +} + diff --git a/examples/HID/USBHIDJoystick/hidjoystickrptparser.cpp b/examples/HID/USBHIDJoystick/hidjoystickrptparser.cpp new file mode 100644 index 00000000..324c2f48 --- /dev/null +++ b/examples/HID/USBHIDJoystick/hidjoystickrptparser.cpp @@ -0,0 +1,95 @@ +#include "hidjoystickrptparser.h" + +JoystickReportParser::JoystickReportParser(JoystickEvents *evt) : + joyEvents(evt), + oldHat(0xDE), + oldButtons(0) +{ + for (uint8_t i=0; iOnGamePadChanged((const GamePadEventData*)buf); + + for (uint8_t i=0; iOnHatSwitch(hat); + oldHat = hat; + } + + uint16_t buttons = (0x0000 | buf[6]); + buttons <<= 4; + buttons |= (buf[5] >> 4); + uint16_t changes = (buttons ^ oldButtons); + + // Calling Button Event Handler for every button changed + if (changes) + { + for (uint8_t i=0; i<0x0C; i++) + { + uint16_t mask = (0x0001 << i); + + if (((mask & changes) > 0) && joyEvents) + if ((buttons & mask) > 0) + joyEvents->OnButtonDn(i+1); + else + joyEvents->OnButtonUp(i+1); + } + oldButtons = buttons; + } +} + +void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) +{ + Serial.print("X: "); + PrintHex(evt->X); + Serial.print("\tY: "); + PrintHex(evt->Y); + Serial.print("\tZ: "); + PrintHex(evt->Z1); + Serial.print("\tZ: "); + PrintHex(evt->Z2); + Serial.print("\tRz: "); + PrintHex(evt->Rz); + Serial.println(""); +} + +void JoystickEvents::OnHatSwitch(uint8_t hat) +{ + Serial.print("Hat Switch: "); + PrintHex(hat); + Serial.println(""); +} + +void JoystickEvents::OnButtonUp(uint8_t but_id) +{ + Serial.print("Up: "); + Serial.println(but_id, DEC); +} + +void JoystickEvents::OnButtonDn(uint8_t but_id) +{ + Serial.print("Dn: "); + Serial.println(but_id, DEC); +} \ No newline at end of file diff --git a/examples/HID/USBHIDJoystick/hidjoystickrptparser.h b/examples/HID/USBHIDJoystick/hidjoystickrptparser.h new file mode 100644 index 00000000..055dbaca --- /dev/null +++ b/examples/HID/USBHIDJoystick/hidjoystickrptparser.h @@ -0,0 +1,54 @@ +#if !defined(__HIDJOYSTICKRPTPARSER_H__) +#define __HIDJOYSTICKRPTPARSER_H__ + +#include +#include +#include "avrpins.h" +#include "max3421e.h" +#include "usbhost.h" +#include "usb_ch9.h" +#include "Usb.h" + +#if defined(ARDUINO) && ARDUINO >=100 +#include "Arduino.h" +#else +#include +#endif + +#include "printhex.h" +#include "hexdump.h" +#include "message.h" +#include "confdescparser.h" +#include "hid.h" + +struct GamePadEventData +{ + uint8_t X, Y, Z1, Z2, Rz; +}; + +class JoystickEvents +{ +public: + virtual void OnGamePadChanged(const GamePadEventData *evt); + virtual void OnHatSwitch(uint8_t hat); + virtual void OnButtonUp(uint8_t but_id); + virtual void OnButtonDn(uint8_t but_id); +}; + +#define RPT_GEMEPAD_LEN 5 + +class JoystickReportParser : public HIDReportParser +{ + JoystickEvents *joyEvents; + + uint8_t oldPad[RPT_GEMEPAD_LEN]; + uint8_t oldHat; + uint16_t oldButtons; + +public: + JoystickReportParser(JoystickEvents *evt); + + virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); +}; + +#endif // __HIDJOYSTICKRPTPARSER_H__ \ No newline at end of file diff --git a/examples/HID/USBHID_desc/USBHID_desc.pde b/examples/HID/USBHID_desc/USBHID_desc.pde index 2ba4ce3b..dee37da6 100644 --- a/examples/HID/USBHID_desc/USBHID_desc.pde +++ b/examples/HID/USBHID_desc/USBHID_desc.pde @@ -1,3 +1,4 @@ + #include #include @@ -18,9 +19,47 @@ #include "pgmstrings.h" +class HIDUniversal2 : public HIDUniversal +{ +public: + HIDUniversal2(USB *usb) : HIDUniversal(usb) {}; + +protected: + virtual uint8_t OnInitSuccessful(); +}; + +uint8_t HIDUniversal2::OnInitSuccessful() +{ + uint8_t rcode; + + HexDumper Hex; + ReportDescParser Rpt; + + if (rcode = GetReportDescr(0, &Hex)) + goto FailGetReportDescr1; + + if (rcode = GetReportDescr(0, &Rpt)) + goto FailGetReportDescr2; + + return 0; + +FailGetReportDescr1: + USBTRACE("GetReportDescr1:"); + goto Fail; + +FailGetReportDescr2: + USBTRACE("GetReportDescr2:"); + goto Fail; + +Fail: + Serial.println(rcode, HEX); + Release(); + return rcode; +} + USB Usb; USBHub Hub(&Usb); -HIDUniversal Hid(&Usb); +HIDUniversal2 Hid(&Usb); UniversalReportParser Uni; void setup() diff --git a/examples/board_qc/board_qc.pde b/examples/board_qc/board_qc.pde index d0064f65..037762a6 100644 --- a/examples/board_qc/board_qc.pde +++ b/examples/board_qc/board_qc.pde @@ -260,7 +260,7 @@ void print_hex(int v, int num_places) void press_any_key() { Notify(PSTR("\r\nPress any key to continue...")); - while( Serial.available() == 0 ); //wait for input + while( Serial.available() <= 0 ); //wait for input Serial.read(); //empty input buffer return; } diff --git a/hid.h b/hid.h index 513feb2c..28ed53a6 100644 --- a/hid.h +++ b/hid.h @@ -1,3 +1,19 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com +*/ #if !defined(__HID_H__) #define __HID_H__ diff --git a/hidescriptorparser.cpp b/hidescriptorparser.cpp index 426cbc89..af4fc55d 100644 --- a/hidescriptorparser.cpp +++ b/hidescriptorparser.cpp @@ -1555,11 +1555,8 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) else { uint8_t size = ((**pp) & DATA_SIZE_MASK); - itemPrefix = (**pp); itemSize = 1 + ((size == DATA_SIZE_4) ? 4 : size); - - //PrintItemTitle(itemPrefix); } (*pp) ++; (*pcntdn) --; @@ -1572,8 +1569,6 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) if (!pcntdn) return enErrorIncomplete; case 1: - //USBTRACE2("\r\niSz:",itemSize); - theBuffer.valueSize = itemSize; valParser.Initialize(&theBuffer); itemParseState = 2; @@ -1596,11 +1591,9 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) break; case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): rptSize = data; - //PrintByteValue(data); break; case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): rptCount = data; - //PrintByteValue(data); break; case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): rptId = data; @@ -1613,8 +1606,6 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) break; case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): SetUsagePage(data); - //PrintUsagePage(data); - //PrintByteValue(data); break; case (TYPE_MAIN | TAG_MAIN_OUTPUT): case (TYPE_MAIN | TAG_MAIN_FEATURE): @@ -1628,7 +1619,6 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) totalSize += (uint16_t)rptSize * (uint16_t)rptCount; - // Кажется это надо делать в начале, а не в конце... rptSize = 0; rptCount = 0; useMin = 0; @@ -1648,58 +1638,15 @@ void ReportDescParser2::OnInputItem(uint8_t itm) uint8_t bit_offset = totalSize - tmp; // number of bits in the current byte already handled uint8_t *p = pBuf + byte_offset; // current byte pointer - - //Serial.print("Itm:"); - //PrintHex(itm); - //Serial.println(""); - - //Serial.print(" tS:"); - //PrintHex(totalSize); - - //Serial.print(" byO:"); - //PrintHex(byte_offset); - - //Serial.print(" biO:"); - //PrintHex(bit_offset); - - //Serial.print(" rSz:"); - //PrintHex(rptSize); - - //Serial.print(" rCn:"); - //PrintHex(rptCount); - if (bit_offset) *p >>= bit_offset; uint8_t usage = useMin; - //Serial.print("\r\nUseMin:"); - //PrintHex(useMin); - //Serial.println(""); - - //Serial.print("UseMax:"); - //PrintHex(useMax); - //Serial.println(""); - - //Serial.print("pF:"); - //PrintHex(useMin); - //Serial.println(""); - bool print_usemin_usemax = ( (useMin < useMax) && ((itm & 3) == 2) && pfUsage) ? true : false; uint8_t bits_of_byte = 8; - // rptSize==1, rptCount==10i - // x x x x x x x x x x - // | | - // one bit field - // - // | | - // one byte == 8 bits - // - // | | - // field array == 10 bits - // for each field in field array defined by rptCount for (uint8_t field=0; field bits_of_byte) ? bits_of_byte : bits_left; - //bits_to_copy = (bits_left > 8) ? 8 : (bits_left > bits_of_byte) ? bits_of_byte : bits_left; result.dwResult <<= bits_to_copy; // Result buffer is shifted by the number of bits to be copied into it - //if (bits_to_copy == 8) - //{ - // result.dwResult = (uint32_t)*p; - // bits_of_byte = 8; - // p ++; - // continue; - //} - uint8_t val = *p; val >>= (8 - bits_of_byte); // Shift by the number of bits already processed - //Serial.print(" bl:"); - //PrintHex(bits_left); - - //Serial.print(" sh:"); - //PrintHex(8 - bits_of_byte); - mask = 0; for (uint8_t j=bits_to_copy; j; j--) @@ -1756,136 +1687,21 @@ void ReportDescParser2::OnInputItem(uint8_t itm) mask |= 1; } - //Serial.print(" msk:"); - //PrintHex(mask); - result.bResult[0] = (result.bResult[0] | (val & mask)); - //Serial.print(" res:"); - //Serial.print(": "); - //PrintHex(result.dwResult); - - //Serial.print(" b2c:"); - //PrintHex(bits_to_copy); - bits_of_byte -= bits_to_copy; - //Serial.print(" bob:"); - //PrintHex(bits_of_byte); - if (bits_of_byte < 1) { bits_of_byte = 8; p ++; } - //Serial.println(""); } - PrintByteValue(result.dwResult); } Serial.println(""); } -//void ReportDescParser2::OnInputItem(uint8_t itm) -//{ -// uint8_t byte_offset = (totalSize >> 3); // calculate offset to the next unhandled byte i = (int)(totalCount / 8); -// uint32_t tmp = (byte_offset << 3); -// uint8_t bit_offset = totalSize - tmp; // number of bits in the current byte already handled -// uint8_t *p = pBuf + byte_offset; // current byte pointer -// -// //Serial.print(" tS:"); -// //PrintHex(totalSize); -// -// //Serial.print(" byO:"); -// //PrintHex(byte_offset); -// -// //Serial.print(" biO:"); -// //PrintHex(bit_offset); -// -// //Serial.print(" rSz:"); -// //PrintHex(rptSize); -// -// //Serial.print(" rCn:"); -// //PrintHex(rptCount); -// -// if (bit_offset) -// *p >>= bit_offset; -// -// uint8_t usage = useMin; -// -// bool print_usemin_usemax = ( (useMin < useMax) && ((itm & 3) == 2) && pfUsage) ? true : false; -// -// uint8_t bits_of_byte = 8; -// -// for (uint8_t i=0; i 8) ? 8 : (bits_left > bits_of_byte) ? bits_of_byte : bits_left; -// -// result.dwResult <<= bits_to_copy; // Result buffer is shifted by the number of bits to be copied into it -// -// if (bits_to_copy == 8) -// { -// result.bResult[0] = *p; -// bits_of_byte = 8; -// p ++; -// continue; -// } -// -// uint8_t val = *p; -// -// val >>= (8 - bits_of_byte); // Shift by the number of bits already processed -// -// //Serial.print(" sh:"); -// //PrintHex(8 - bits_of_byte); -// -// mask = 0; -// -// for (uint8_t j=bits_to_copy; j; j--) -// { -// mask <<= 1; -// mask |= 1; -// } -// -// //Serial.print(" msk:"); -// //PrintHex(mask); -// -// result.bResult[0] = (result.bResult[0] | (val & mask)); -// -// //Serial.print(" res:"); -// //PrintHex(result.bResult[0]); -// -// //Serial.print(" b2c:"); -// //PrintHex(bits_to_copy); -// -// bits_of_byte -= bits_to_copy; -// -// //Serial.print(" bob:"); -// //PrintHex(bits_of_byte); -// } -// -// PrintByteValue(result.bResult[0]); -// } -// Serial.println(""); -//} - void UniversalReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { ReportDescParser2 prs(len, buf); diff --git a/hidescriptorparser.h b/hidescriptorparser.h index 48e232ca..119a5a66 100644 --- a/hidescriptorparser.h +++ b/hidescriptorparser.h @@ -34,11 +34,8 @@ e-mail : support@circuitsathome.com #include "printhex.h" #include "hexdump.h" #include "message.h" - #include "confdescparser.h" -//#include "hidusagestr.h" #include "hid.h" -//#include "..\ptp\simplefifo.h" class ReportDescParserBase : public USBReadParser { diff --git a/hiduniversal.cpp b/hiduniversal.cpp index 231b0955..5a56c0c5 100644 --- a/hiduniversal.cpp +++ b/hiduniversal.cpp @@ -232,16 +232,8 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) USBTRACE("HU configured\r\n"); - { - HexDumper Hex; - ReportDescParser Rpt; + OnInitSuccessful(); - if (rcode = GetReportDescr(0, &Hex)) - goto FailGetReportDescr; - - if (rcode = GetReportDescr(0, &Rpt)) - goto FailGetReportDescr; - } bPollEnable = true; return 0; diff --git a/hiduniversal.h b/hiduniversal.h index edc9ff9a..9b64af37 100644 --- a/hiduniversal.h +++ b/hiduniversal.h @@ -2,7 +2,7 @@ #define __HIDUNIVERSAL_H__ #include "hid.h" -#include "hidescriptorparser.h" +//#include "hidescriptorparser.h" class HIDUniversal : public HID { @@ -54,6 +54,7 @@ protected: // HID implementation virtual HIDReportParser* GetReportParser(uint8_t id); + virtual uint8_t OnInitSuccessful() { return 0; }; public: HIDUniversal(USB *p);