A fully-Android-compatible two joysticks USB driver for LPC1768. The joysticks have 1 hat, 6 buttons, and there are 1P, 2P buttons.
Fork of app-board-Joystick by
Revision 1:76c47d2ba442, committed 2016-12-16
- Comitter:
- Alberto_Wino
- Date:
- Fri Dec 16 18:17:42 2016 +0000
- Parent:
- 0:0e4db18afd77
- Child:
- 2:84ea6e2fb4b6
- Commit message:
- Import for dual joystick support, suitable for an arcade machine.; Based on code from Phil Wright.
Changed in this revision
--- a/main.cpp Mon Oct 15 13:37:36 2012 +0000 +++ b/main.cpp Fri Dec 16 18:17:42 2016 +0000 @@ -1,18 +1,54 @@ #include "mbed.h" +#include "usbhid.h" + +#define IGN p5 /* ignore */ + +BusIn buttonsL +( + p17, p16, p15, p20, // 3 top row, bottom-left + p19, p18, p14, IGN, // 2 bottom right, 1p + IGN, IGN, IGN, IGN +); -BusIn joy(p15,p12,p13,p16); -DigitalIn fire(p14); +BusIn buttonsR +( + p9, p8, p7, p12, // 3 top row, bottom-left + p11, p10, p6, IGN, // 2 bottom right, 2p + IGN, IGN, IGN, IGN +); -BusOut leds(LED1,LED2,LED3,LED4); +BusIn stickL(p21, p22, p23, p24); +BusIn stickR(p28, p26, p27, p29); + +USBJoystick joysticks; // left and right pads int main() { - while(1) { - if (fire) { - leds=0xf; - } else { - leds=joy; + unsigned char stickL_old = 0; + unsigned char stickR_old = 0; + unsigned char buttonsL_old = 0; + unsigned char buttonsR_old = 0; + + while(1) + { + const unsigned char stickL_new = stickL.read(); + const unsigned char stickR_new = stickR.read(); + const unsigned long buttonsL_new = buttonsL.read(); + const unsigned long buttonsR_new = buttonsR.read(); + + if ((stickL_old != stickL_new) || (buttonsL_old != buttonsL_new)) + { + stickL_old = stickL_new; + buttonsL_old = buttonsL_new; + joysticks.update(1, stickL_old, buttonsL_old); } - wait(0.1); + + if ((stickR_old != stickR_new) || (buttonsR_old != buttonsR_new)) + { + stickR_old = stickR_new; + buttonsR_old = buttonsR_new; + joysticks.update(2, stickR_old, buttonsR_old); + } + wait(0.016666); /* 60 Hz */ } -} +} \ No newline at end of file
--- a/mbed.bld Mon Oct 15 13:37:36 2012 +0000 +++ b/mbed.bld Fri Dec 16 18:17:42 2016 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/cd19af002ccc \ No newline at end of file +http://mbed.org/users/mbed_official/code/mbed/builds/d75b3fe1f5cb \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdc.cpp Fri Dec 16 18:17:42 2016 +0000 @@ -0,0 +1,545 @@ +/* usbdc.cpp */ +/* USB device controller */ +/* Copyright (c) Phil Wright 2008 */ + +#include "mbed.h" +#include "usbdc.h" +#include "cmsis.h" + +#ifdef TARGET_LPC2368 +#undef LPC_USB_BASE +#define LPC_USB_BASE (0xFFE0C000) /* TODO */ +#endif + +/* Power Control for Peripherals register */ +#define PCUSB ((unsigned long)1<<31) + +/* USB Clock Control register */ +#define DEV_CLK_EN ((unsigned long)1<<1) +#define AHB_CLK_EN ((unsigned long)1<<4) + +/* USB Clock Status register */ +#define DEV_CLK_ON ((unsigned long)1<<1) +#define AHB_CLK_ON ((unsigned long)1<<4) + +/* USB Device Interupt registers */ +#define FRAME ((unsigned long)1<<0) +#define EP_FAST ((unsigned long)1<<1) +#define EP_SLOW ((unsigned long)1<<2) +#define DEV_STAT ((unsigned long)1<<3) +#define CCEMPTY ((unsigned long)1<<4) +#define CDFULL ((unsigned long)1<<5) +#define RxENDPKT ((unsigned long)1<<6) +#define TxENDPKT ((unsigned long)1<<7) +#define EP_RLZED ((unsigned long)1<<8) +#define ERR_INT ((unsigned long)1<<9) + +/* Endpoint Interrupt Registers */ +#define EP(endpoint) (1<<endpoint) + +/* USB Control register */ +#define RD_EN (1<<0) +#define WR_EN (1<<1) +#define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2) + +/* USB Receive Packet Length register */ +#define DV ((unsigned long)1<<10) +#define PKT_RDY ((unsigned long)1<<11) +#define PKT_LNGTH_MASK (0x3ff) + +/* Serial Interface Engine (SIE) */ +#define SIE_WRITE (0x01) +#define SIE_READ (0x02) +#define SIE_COMMAND (0x05) +#define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16)) + +/* SIE Command codes */ +#define SIE_CMD_SET_ADDRESS (0xD0) +#define SIE_CMD_CONFIGURE_DEVICE (0xD8) +#define SIE_CMD_SET_MODE (0xF3) +#define SIE_CMD_READ_FRAME_NUMBER (0xF5) +#define SIE_CMD_READ_TEST_REGISTER (0xFD) +#define SIE_CMD_SET_DEVICE_STATUS (0xFE) +#define SIE_CMD_GET_DEVICE_STATUS (0xFE) +#define SIE_CMD_GET_ERROR_CODE (0xFF) +#define SIE_CMD_READ_ERROR_STATUS (0xFB) + +#define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint) +#define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint) +#define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint) + +#define SIE_CMD_CLEAR_BUFFER (0xF2) +#define SIE_CMD_VALIDATE_BUFFER (0xFA) + +/* SIE Device Status register */ +#define SIE_DS_CON (1<<0) +#define SIE_DS_CON_CH (1<<1) +#define SIE_DS_SUS (1<<2) +#define SIE_DS_SUS_CH (1<<3) +#define SIE_DS_RST (1<<4) + +/* SIE Device Set Address register */ +#define SIE_DSA_DEV_EN (1<<7) + +/* SIE Configue Device register */ +#define SIE_CONF_DEVICE (1<<0) + +/* Select Endpoint register */ +#define SIE_SE_FE (1<<0) +#define SIE_SE_ST (1<<1) +#define SIE_SE_STP (1<<2) +#define SIE_SE_PO (1<<3) +#define SIE_SE_EPN (1<<4) +#define SIE_SE_B_1_FULL (1<<5) +#define SIE_SE_B_2_FULL (1<<6) + +/* Set Endpoint Status command */ +#define SIE_SES_ST (1<<0) +#define SIE_SES_DA (1<<5) +#define SIE_SES_RF_MO (1<<6) +#define SIE_SES_CND_ST (1<<7) + +usbdc *usbdc::instance; + +usbdc::usbdc() +{ +#ifdef TARGET_LPC1768 + LPC_SC->USBCLKCFG = 5; /* TODO */ +#endif + + /* Enable power to USB device controller */ + LPC_SC->PCONP |= PCUSB; + + /* Enable USB clocks */ + LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN; + while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); + + /* Configure pins P0.29 and P0.30 to be USB D+ and USB D- */ + LPC_PINCON->PINSEL1 &= 0xc3ffffff; + LPC_PINCON->PINSEL1 |= 0x14000000; + +#ifdef ENABLE_VBUS + /* Configure pin P1.30 to be VBUS */ + LPC_PINCON->PINSEL3 &= 0xcfffffff; + LPC_PINCON->PINSEL3 |= 0x20000000; + + /* Configure pin P1.30 to have pull-down */ + LPC_PINCON->PINMODE3 |= 0x30000000; +#endif + + /* Configure pin P2.9 to be Connect */ + LPC_PINCON->PINSEL4 &= 0xfffcffff; + LPC_PINCON->PINSEL4 |= 0x00040000; + + /* Connect must be low for at least 2.5uS */ + wait_ms(1); + + /* Attach IRQ */ + instance = this; + NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); + NVIC_EnableIRQ(USB_IRQn); + + /* Enable device interrupts */ + enableEvents(); +} + +void usbdc::connect(void) +{ + /* Connect USB device */ + unsigned char status; + + status = getDeviceStatus(); + setDeviceStatus(status | SIE_DS_CON); +} + +void usbdc::disconnect(void) +{ + /* Disconnect USB device */ + unsigned char status; + + status = getDeviceStatus(); + setDeviceStatus(status & ~SIE_DS_CON); +} + +void usbdc::SIECommand(unsigned long command) +{ + /* The command phase of a SIE transaction */ + LPC_USB->USBDevIntClr = CCEMPTY; + LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command); + while (!(LPC_USB->USBDevIntSt & CCEMPTY)); +} + +void usbdc::SIEWriteData(unsigned char data) +{ + /* The data write phase of a SIE transaction */ + LPC_USB->USBDevIntClr = CCEMPTY; + LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data); + while (!(LPC_USB->USBDevIntSt & CCEMPTY)); +} + +unsigned char usbdc::SIEReadData(unsigned long command) +{ + /* The data read phase of a SIE transaction */ + LPC_USB->USBDevIntClr = CDFULL; + LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command); + while (!(LPC_USB->USBDevIntSt & CDFULL)); + return (unsigned char)LPC_USB->USBCmdData; +} + +void usbdc::setDeviceStatus(unsigned char status) +{ + /* Write SIE device status register */ + SIECommand(SIE_CMD_SET_DEVICE_STATUS); + SIEWriteData(status); +} + +unsigned char usbdc::getDeviceStatus(void) +{ + /* Read SIE device status register */ + SIECommand(SIE_CMD_GET_DEVICE_STATUS); + return SIEReadData(SIE_CMD_GET_DEVICE_STATUS); +} + +void usbdc::setAddress(unsigned char address) +{ + /* Write SIE device address register */ + SIECommand(SIE_CMD_SET_ADDRESS); + SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN); +} + +unsigned char usbdc::selectEndpoint(unsigned char endpoint) +{ + /* SIE select endpoint command */ + SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint)); + return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint)); +} + +#if 1 +unsigned char usbdc::selectEndpointClearInterrupt(unsigned char endpoint) +{ + /* SIE select endpoint and clear interrupt command */ + /* Using the Select Endpoint / Clear Interrupt SIE command does not seem */ + /* to clear the appropriate bit in EP_INT_STAT? - using EP_INT_CLR instead */ + LPC_USB->USBEpIntClr = EP(endpoint); + while (!(LPC_USB->USBDevIntSt & CDFULL)); + return (unsigned char)LPC_USB->USBCmdData; +} +#else +unsigned char usbdc::selectEndpointClearInterrupt(unsigned char endpoint) +{ + /* SIE select endpoint and clear interrupt command */ + SIECommand(SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint)); + return SIEReadData(SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint)); +} +#endif + +unsigned char usbdc::clearBuffer(void) +{ + /* SIE clear buffer command */ + SIECommand(SIE_CMD_CLEAR_BUFFER); + return SIEReadData(SIE_CMD_CLEAR_BUFFER); +} + +void usbdc::validateBuffer(void) +{ + /* SIE validate buffer command */ + SIECommand(SIE_CMD_VALIDATE_BUFFER); +} + +void usbdc::setEndpointStatus(unsigned char endpoint, unsigned char status) +{ + /* SIE set endpoint status command */ + SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint)); + SIEWriteData(status); +} + +void usbdc::realiseEndpoint(unsigned char endpoint, unsigned long maxPacket) +{ + /* Realise an endpoint */ + LPC_USB->USBDevIntClr = EP_RLZED; + LPC_USB->USBReEp |= EP(endpoint); + LPC_USB->USBEpInd = endpoint; + LPC_USB->USBMaxPSize = maxPacket; + + while (!(LPC_USB->USBDevIntSt & EP_RLZED)); + LPC_USB->USBDevIntClr = EP_RLZED; + + /* Clear stall state */ + endpointStallState &= ~EP(endpoint); +} + +void usbdc::enableEndpointEvent(unsigned char endpoint) +{ + /* Enable an endpoint interrupt */ + LPC_USB->USBEpIntEn |= EP(endpoint); +} + +void usbdc::disableEndpointEvent(unsigned char endpoint) +{ + /* Disable an endpoint interrupt */ + LPC_USB->USBEpIntEn &= ~EP(endpoint); +} + +void usbdc::stallEndpoint(unsigned char endpoint) +{ + /* Stall an endpoint */ + if ( (endpoint==EP0IN) || (endpoint==EP0OUT) ) + { + /* Conditionally stall both control endpoints */ + setEndpointStatus(EP0OUT, SIE_SES_CND_ST); + } + else + { + setEndpointStatus(endpoint, SIE_SES_ST); + + /* Update stall state */ + endpointStallState |= EP(endpoint); + } +} + +void usbdc::unstallEndpoint(unsigned char endpoint) +{ + /* Unstall an endpoint. The endpoint will also be reinitialised */ + setEndpointStatus(endpoint, 0); + + /* Update stall state */ + endpointStallState &= ~EP(endpoint); +} + +bool usbdc::getEndpointStallState(unsigned char endpoint) +{ + /* Returns true if endpoint stalled */ + return endpointStallState & EP(endpoint); +} + +void usbdc::configureDevice(void) +{ + /* SIE Configure device command */ + SIECommand(SIE_CMD_CONFIGURE_DEVICE); + SIEWriteData(SIE_CONF_DEVICE); +} + +void usbdc::unconfigureDevice(void) +{ + /* SIE Configure device command */ + SIECommand(SIE_CMD_CONFIGURE_DEVICE); + SIEWriteData(0); +} + +unsigned long usbdc::endpointRead(unsigned char endpoint, unsigned char *buffer) +{ + /* Read from an OUT endpoint */ + unsigned long size; + unsigned long i; + unsigned long data; + unsigned char offset; + + LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN; + while (!(LPC_USB->USBRxPLen & PKT_RDY)); + + size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK; + + offset = 0; + + for (i=0; i<size; i++) + { + if (offset==0) + { + /* Fetch up to four bytes of data as a word */ + data = LPC_USB->USBRxData; + } + + /* extract a byte */ + *buffer++ = data>>offset; + + /* move on to the next byte */ + offset = (offset + 8) % 32; + } + + /* Clear RD_EN to cover zero length packet case */ + LPC_USB->USBCtrl=0; + + selectEndpoint(endpoint); + clearBuffer(); + + return size; +} + +void usbdc::endpointWrite(unsigned char endpoint, unsigned char *buffer, unsigned long size) +{ + /* Write to an IN endpoint */ + unsigned long temp, data; + unsigned char offset; + + LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN; + + LPC_USB->USBTxPLen = size; + offset = 0; + data = 0; + + if (size>0) + { + do + { + /* Fetch next data byte into a word-sized temporary variable */ + temp = *buffer++; + + /* Add to current data word */ + temp = temp << offset; + data = data | temp; + + /* move on to the next byte */ + offset = (offset + 8) % 32; + size--; + + if ((offset==0) || (size==0)) + { + /* Write the word to the endpoint */ + LPC_USB->USBTxData = data; + data = 0; + } + } while (size>0); + } + + /* Clear WR_EN to cover zero length packet case */ + LPC_USB->USBCtrl=0; + + selectEndpoint(endpoint); + validateBuffer(); +} + +void usbdc::enableEvents(void) +{ + /* Enable interrupt sources */ + LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT; +} + +void usbdc::disableEvents(void) +{ + /* Disable interrupt sources */ + LPC_USB->USBDevIntClr = EP_SLOW | DEV_STAT; +} + +void usbdc::usbisr(void) +{ + unsigned char devStat; + + if (LPC_USB->USBDevIntSt & FRAME) + { + /* Frame event */ + deviceEventFrame(); + /* Clear interrupt status flag */ + LPC_USB->USBDevIntClr = FRAME; + } + + if (LPC_USB->USBDevIntSt & DEV_STAT) + { + /* Device Status interrupt */ + /* Must clear the interrupt status flag before reading the device status from the SIE */ + LPC_USB->USBDevIntClr = DEV_STAT; + + /* Read device status from SIE */ + devStat = getDeviceStatus(); + + if (devStat & SIE_DS_RST) + { + /* Bus reset */ + deviceEventReset(); + } + } + + if (LPC_USB->USBDevIntSt & EP_SLOW) + { + /* (Slow) Endpoint Interrupt */ + + /* Process each endpoint interrupt */ + if (LPC_USB->USBEpIntSt & EP(EP0OUT)) + { + if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) + { + /* this is a setup packet */ + endpointEventEP0Setup(); + } + else + { + endpointEventEP0Out(); + } + } + + if (LPC_USB->USBEpIntSt & EP(EP0IN)) + { + selectEndpointClearInterrupt(EP0IN); + endpointEventEP0In(); + } + + if (LPC_USB->USBEpIntSt & EP(EP1OUT)) + { + selectEndpointClearInterrupt(EP1OUT); + endpointEventEP1Out(); + } + + if (LPC_USB->USBEpIntSt & EP(EP1IN)) + { + selectEndpointClearInterrupt(EP1IN); + endpointEventEP1In(); + } + + if (LPC_USB->USBEpIntSt & EP(EP2OUT)) + { + selectEndpointClearInterrupt(EP2OUT); + endpointEventEP2Out(); + } + + if (LPC_USB->USBEpIntSt & EP(EP2IN)) + { + selectEndpointClearInterrupt(EP2IN); + endpointEventEP2In(); + } + + /* Clear interrupt status flag */ + /* EP_SLOW and EP_FAST interrupt bits should be cleared after the corresponding endpoint interrupts are cleared. */ + LPC_USB->USBDevIntClr = EP_SLOW; + } +} + + +void usbdc::_usbisr(void) +{ + instance->usbisr(); +} + +void usbdc::deviceEventReset(void) +{ +} + +void usbdc::deviceEventFrame(void) +{ +} + +void usbdc::endpointEventEP0Setup(void) +{ +} + +void usbdc::endpointEventEP0In(void) +{ +} + +void usbdc::endpointEventEP0Out(void) +{ +} + +void usbdc::endpointEventEP1In(void) +{ +} + +void usbdc::endpointEventEP1Out(void) +{ +} + +void usbdc::endpointEventEP2In(void) +{ +} + +void usbdc::endpointEventEP2Out(void) +{ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdc.h Fri Dec 16 18:17:42 2016 +0000 @@ -0,0 +1,64 @@ +/* usbdc.h */ +/* USB device controller */ +/* Copyright (c) Phil Wright 2008 */ + +#ifndef USBDC_H +#define USBDC_H + +/* Endpoints */ +#define EP0OUT (0) /* Control */ +#define EP0IN (1) /* Control */ +#define EP1OUT (2) /* Interrupt */ +#define EP1IN (3) /* Interrupt */ +#define EP2OUT (4) /* Bulk */ +#define EP2IN (5) /* Bulk */ + +#include "mbed.h" + +class usbdc //: public Base +{ +public: + usbdc(); + void connect(void); + void disconnect(void); +protected: + void setAddress(unsigned char address); + void realiseEndpoint(unsigned char endpoint, unsigned long maxPacket); + void enableEndpointEvent(unsigned char endpoint); + void disableEndpointEvent(unsigned char endpoint); + void stallEndpoint(unsigned char endpoint); + void unstallEndpoint(unsigned char endpoint); + bool getEndpointStallState(unsigned char endpoint); + void configureDevice(void); + void unconfigureDevice(void); + unsigned long endpointRead(unsigned char endpoint, unsigned char *buffer); + void endpointWrite(unsigned char endpoint, unsigned char *buffer, unsigned long size); + void enableEvents(void); + void disableEvents(void); + virtual void deviceEventReset(void); + virtual void deviceEventFrame(void); + virtual void endpointEventEP0Setup(void); + virtual void endpointEventEP0In(void); + virtual void endpointEventEP0Out(void); + virtual void endpointEventEP1In(void); + virtual void endpointEventEP1Out(void); + virtual void endpointEventEP2In(void); + virtual void endpointEventEP2Out(void); +private: + void SIECommand(unsigned long command); + void SIEWriteData(unsigned char data); + unsigned char SIEReadData(unsigned long command); + void setDeviceStatus(unsigned char status); + void setEndpointStatus(unsigned char endpoint, unsigned char status); + unsigned char getDeviceStatus(void); + unsigned char selectEndpoint(unsigned char endpoint); + unsigned char selectEndpointClearInterrupt(unsigned char endpoint); + unsigned char clearBuffer(void); + void validateBuffer(void); + void usbisr(void); + unsigned long endpointStallState; + static void _usbisr(void); + static usbdc *instance; +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdevice.cpp Fri Dec 16 18:17:42 2016 +0000 @@ -0,0 +1,495 @@ +/* usbdevice.cpp */ +/* Generic USB device */ +/* Copyright (c) Phil Wright 2008 */ + +#include "mbed.h" +#include "usbdevice.h" + +/* Standard requests */ +#define GET_STATUS (0) +#define CLEAR_FEATURE (1) +#define SET_FEATURE (3) +#define SET_ADDRESS (5) +#define GET_DESCRIPTOR (6) +#define SET_DESCRIPTOR (7) +#define GET_CONFIGURATION (8) +#define SET_CONFIGURATION (9) +#define GET_INTERFACE (10) +#define SET_INTERFACE (11) + +/* Device status */ +#define DEVICE_STATUS_SELF_POWERED (1<<0) +#define DEVICE_STATUS_REMOTE_WAKEUP (1<<1) + +/* Endpoint status */ +#define ENDPOINT_STATUS_HALT (1<<0) + +/* Standard feature selectors */ +#define DEVICE_REMOTE_WAKEUP (1) +#define ENDPOINT_HALT (0) + +/* Macro to convert wIndex endpoint number to physical endpoint number */ +#define WINDEX_TO_PHYSICAL(endpoint) (((endpoint & 0x0f) << 1) + ((endpoint & 0x80) ? 1 : 0)) + +CONTROL_TRANSFER transfer; +USB_DEVICE device; + +usbdevice::usbdevice() +{ + /* Set initial device state */ + device.state = POWERED; + device.configuration = 0; + device.suspended = false; + + /* Set the maximum packet size for the control endpoints */ + realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0); + realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0); + + /* Enable endpoint events for EP0 */ + enableEndpointEvent(EP0IN); + enableEndpointEvent(EP0OUT); +} + +void usbdevice::endpointEventEP0Setup() +{ + /* Endpoint 0 setup event */ + if (!controlSetup()) + { + /* Protocol stall; this will stall both endpoints */ + stallEndpoint(EP0OUT); + } +} + +void usbdevice::endpointEventEP0Out() +{ + /* Endpoint 0 OUT data event */ + if (!controlOut()) + { + /* Protocol stall; this will stall both endpoints */ + stallEndpoint(EP0OUT); + } +} + +void usbdevice::endpointEventEP0In() +{ + /* Endpoint 0 IN data event */ + if (!controlIn()) + { + /* Protocol stall; this will stall both endpoints */ + stallEndpoint(EP0OUT); + } +} + +void usbdevice::deviceEventReset() +{ + device.state = DEFAULT; + device.configuration = 0; + device.suspended = false; +} + +void usbdevice::decodeSetupPacket(unsigned char *data, SETUP_PACKET *packet) +{ + /* Fill in the elements of a SETUP_PACKET structure from raw data */ + packet->bmRequestType.dataTransferDirection = (data[0] & 0x80) >> 7; + packet->bmRequestType.Type = (data[0] & 0x60) >> 5; + packet->bmRequestType.Recipient = data[0] & 0x1f; + packet->bRequest = data[1]; + packet->wValue = (data[2] | (unsigned short)data[3] << 8); + packet->wIndex = (data[4] | (unsigned short)data[5] << 8); + packet->wLength = (data[6] | (unsigned short)data[7] << 8); +} + +bool usbdevice::controlSetup() +{ + /* Control transfer setup stage */ + unsigned char buffer[MAX_PACKET_SIZE_EP0]; + unsigned long count = endpointRead(EP0OUT, buffer); + + /* Must be 8 bytes of data */ + if (count != 8) + return false; + + /* Initialise control transfer state */ + decodeSetupPacket(buffer, &transfer.setup); + transfer.ptr = NULL; + transfer.remaining = 0; + transfer.direction = 0; + transfer.zlp = false; + + /* Process request */ + if (!requestSetup()) + return false; + + /* Check transfer size and direction */ + if (transfer.setup.wLength > 0) + { + if (transfer.setup.bmRequestType.dataTransferDirection==DEVICE_TO_HOST) + { + /* IN data stage is required */ + if (transfer.direction != DEVICE_TO_HOST) + return false; + + /* Transfer must be less than or equal to the size requested by the host */ + if (transfer.remaining > transfer.setup.wLength) + transfer.remaining = transfer.setup.wLength; + } + else + { + /* OUT data stage is required */ + if (transfer.direction != HOST_TO_DEVICE) + return false; + + /* Transfer must be equal to the size requested by the host */ + if (transfer.remaining != transfer.setup.wLength) + return false; + } + } + else + { + /* No data stage; transfer size must be zero */ + if (transfer.remaining != 0) + return false; + } + + /* Data or status stage if applicable */ + if (transfer.setup.wLength > 0) + { + if (transfer.setup.bmRequestType.dataTransferDirection == DEVICE_TO_HOST) + { + /* Check if we'll need to send a zero length packet at the end of this transfer */ + if (transfer.setup.wLength > transfer.remaining) + { + /* Device wishes to transfer less than host requested */ + if ((transfer.remaining % MAX_PACKET_SIZE_EP0) == 0) + { + /* Transfer is a multiple of EP0 max packet size */ + transfer.zlp = true; + } + } + + /* IN stage */ + controlIn(); + } + } + else + { + /* Status stage */ + endpointWrite(EP0IN, NULL, 0); + } + + return true; +} + +bool usbdevice::controlOut() +{ + /* Control transfer data OUT stage */ + unsigned char buffer[MAX_PACKET_SIZE_EP0]; + unsigned long packetSize; + + /* Check we should be transferring data OUT */ + if (transfer.direction != HOST_TO_DEVICE) + return false; + + /* Read from endpoint */ + packetSize = endpointRead(EP0OUT, buffer); + + /* Check if transfer size is valid */ + if (packetSize > transfer.remaining) + { + /* Too big */ + return false; + } + + /* Update transfer */ + transfer.ptr += packetSize; + transfer.remaining -= packetSize; + + /* Check if transfer has completed */ + if (transfer.remaining == 0) + { + /* Process request */ + if (!requestOut()) + return false; + + /* Status stage */ + endpointWrite(EP0IN, NULL, 0); + } + + return true; +} + +bool usbdevice::controlIn() +{ + /* Control transfer data IN stage */ + unsigned packetSize; + + /* Check if transfer has completed (status stage transactions also have transfer.remaining == 0) */ + if (transfer.remaining == 0) + { + if (transfer.zlp) + { + /* Send zero length packet */ + endpointWrite(EP0IN, NULL, 0); + transfer.zlp = false; + } + + /* Completed */ + return true; + } + + /* Check we should be transferring data IN */ + if (transfer.direction != DEVICE_TO_HOST) + return false; + + packetSize = transfer.remaining; + if (packetSize > MAX_PACKET_SIZE_EP0) + packetSize = MAX_PACKET_SIZE_EP0; + + /* Write to endpoint */ + endpointWrite(EP0IN, transfer.ptr, packetSize); + + /* Update transfer */ + transfer.ptr += packetSize; + transfer.remaining -= packetSize; + + return true; +} + +bool usbdevice::requestSetup() +{ + bool success = false; + + /* Process standard requests */ + if ((transfer.setup.bmRequestType.Type == STANDARD_TYPE)) + { + switch (transfer.setup.bRequest) + { + case GET_STATUS: + success = requestGetStatus(); + break; + case CLEAR_FEATURE: + success = requestClearFeature(); + break; + case SET_FEATURE: + success = requestSetFeature(); + break; + case SET_ADDRESS: + success = requestSetAddress(); + break; + case GET_DESCRIPTOR: + success = requestGetDescriptor(); + break; + case SET_DESCRIPTOR: + /* TODO: Support is optional, not implemented here */ + success = false; + break; + case GET_CONFIGURATION: + success = requestGetConfiguration(); + break; + case SET_CONFIGURATION: + success = requestSetConfiguration(); + break; + case GET_INTERFACE: + success = requestGetInterface(); + break; + case SET_INTERFACE: + success = requestSetInterface(); + break; + default: + break; + } + } + + return success; +} + +bool usbdevice::requestOut() +{ + return true; +} + +bool usbdevice::requestSetAddress() +{ + /* Set the device address */ + setAddress(transfer.setup.wValue); + + if (transfer.setup.wValue == 0) + device.state = DEFAULT; + else + device.state = ADDRESS; + + return true; +} + +bool usbdevice::requestSetConfiguration() +{ + /* Set the device configuration */ + if (transfer.setup.wValue == 0) + { + /* Not configured */ + unconfigureDevice(); + device.state = ADDRESS; + } + else + { + configureDevice(); + device.state = CONFIGURED; + } + + /* TODO: We do not currently support multiple configurations, just keep a record of the configuration value */ + device.configuration = transfer.setup.wValue; + + return true; +} + +bool usbdevice::requestGetConfiguration() +{ + /* Send the device configuration */ + transfer.ptr = &device.configuration; + transfer.remaining = sizeof(device.configuration); + transfer.direction = DEVICE_TO_HOST; + return true; +} + +bool usbdevice::requestGetInterface() +{ + static unsigned char alternateSetting; + + /* Return the selected alternate setting for an interface */ + + if (device.state != CONFIGURED) + { + return false; + } + + /* TODO: We currently do not support alternate settings so always return zero */ + /* TODO: Should check that the interface number is valid */ + alternateSetting = 0; + + /* Send the alternate setting */ + transfer.ptr = &alternateSetting; + transfer.remaining = sizeof(alternateSetting); + transfer.direction = DEVICE_TO_HOST; + return true; +} + +bool usbdevice::requestSetInterface() +{ + /* TODO: We currently do not support alternate settings, return false */ + return false; +} + +bool usbdevice::requestSetFeature() +{ + bool success = false; + + if (device.state != CONFIGURED) + { + /* Endpoint or interface must be zero */ + if (transfer.setup.wIndex != 0) + return false; + } + + switch (transfer.setup.bmRequestType.Recipient) + { + case DEVICE_RECIPIENT: + /* TODO: Remote wakeup feature not supported */ + break; + case ENDPOINT_RECIPIENT: + if (transfer.setup.wValue == ENDPOINT_HALT) + { + /* TODO: We should check that the endpoint number is valid */ + stallEndpoint(WINDEX_TO_PHYSICAL(transfer.setup.wIndex)); + success = true; + } + break; + default: + break; + } + + return success; +} + +bool usbdevice::requestClearFeature() +{ + bool success = false; + + if (device.state != CONFIGURED) + { + /* Endpoint or interface must be zero */ + if (transfer.setup.wIndex != 0) + return false; + } + + switch (transfer.setup.bmRequestType.Recipient) + { + case DEVICE_RECIPIENT: + /* TODO: Remote wakeup feature not supported */ + break; + case ENDPOINT_RECIPIENT: + /* TODO: We should check that the endpoint number is valid */ + if (transfer.setup.wValue == ENDPOINT_HALT) + { + unstallEndpoint(WINDEX_TO_PHYSICAL(transfer.setup.wIndex)); + success = true; + } + break; + default: + break; + } + + return success; +} + +bool usbdevice::requestGetStatus() +{ + static unsigned short status; + bool success = false; + + if (device.state != CONFIGURED) + { + /* Endpoint or interface must be zero */ + if (transfer.setup.wIndex != 0) + { + return false; + } + } + + switch (transfer.setup.bmRequestType.Recipient) + { + case DEVICE_RECIPIENT: + /* TODO: Currently only supports self powered devices */ + status = DEVICE_STATUS_SELF_POWERED; + success = true; + break; + case INTERFACE_RECIPIENT: + status = 0; + success = true; + break; + case ENDPOINT_RECIPIENT: + /* TODO: We should check that the endpoint number is valid */ + if (getEndpointStallState(WINDEX_TO_PHYSICAL(transfer.setup.wIndex))) + status = ENDPOINT_STATUS_HALT; + else + status = 0; + success = true; + break; + default: + break; + } + + if (success) + { + /* Send the status */ + transfer.ptr = (unsigned char *)&status; /* Assumes little endian */ + transfer.remaining = sizeof(status); + transfer.direction = DEVICE_TO_HOST; + } + + return success; +} + +bool usbdevice::requestGetDescriptor() +{ + return false; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdevice.h Fri Dec 16 18:17:42 2016 +0000 @@ -0,0 +1,101 @@ +/* usbdevice.h */ +/* Generic USB device */ +/* Copyright (c) Phil Wright 2008 */ + +#ifndef USBDEVICE_H +#define USBDEVICE_H + +#include "usbdc.h" + +/* Endpoint packet sizes */ +#define MAX_PACKET_SIZE_EP0 (64) + +/* bmRequestType.dataTransferDirection */ +#define HOST_TO_DEVICE (0) +#define DEVICE_TO_HOST (1) + +/* bmRequestType.Type*/ +#define STANDARD_TYPE (0) +#define CLASS_TYPE (1) +#define VENDOR_TYPE (2) +#define RESERVED_TYPE (3) + +/* bmRequestType.Recipient */ +#define DEVICE_RECIPIENT (0) +#define INTERFACE_RECIPIENT (1) +#define ENDPOINT_RECIPIENT (2) +#define OTHER_RECIPIENT (3) + +/* Descriptors */ +#define DESCRIPTOR_TYPE(wValue) (wValue >> 8) +#define DESCRIPTOR_INDEX(wValue) (wValue & 0xf) + +/* Descriptor type */ +#define DEVICE_DESCRIPTOR (1) +#define CONFIGURATION_DESCRIPTOR (2) +#define STRING_DESCRIPTOR (3) +#define INTERFACE_DESCRIPTOR (4) +#define ENDPOINT_DESCRIPTOR (5) + +typedef struct +{ + struct + { + unsigned char dataTransferDirection; + unsigned char Type; + unsigned char Recipient; + } bmRequestType; + unsigned char bRequest; + unsigned short wValue; + unsigned short wIndex; + unsigned short wLength; +} SETUP_PACKET; + +typedef struct +{ + SETUP_PACKET setup; + unsigned char *ptr; + unsigned long remaining; + unsigned char direction; + bool zlp; +} CONTROL_TRANSFER; + +typedef enum { ATTACHED, POWERED, DEFAULT, ADDRESS, CONFIGURED } DEVICE_STATE; + +typedef struct +{ + DEVICE_STATE state; + unsigned char configuration; + bool suspended; +} USB_DEVICE; + +class usbdevice : public usbdc +{ +public: + usbdevice(); +protected: + virtual void endpointEventEP0Setup(); + virtual void endpointEventEP0In(); + virtual void endpointEventEP0Out(); + virtual bool requestSetup(); + virtual bool requestOut(); + virtual void deviceEventReset(); + virtual bool requestGetDescriptor(); + bool requestSetAddress(); + virtual bool requestSetConfiguration(); + virtual bool requestGetConfiguration(); + bool requestGetStatus(); + virtual bool requestSetInterface(); + virtual bool requestGetInterface(); + bool requestSetFeature(); + bool requestClearFeature(); + CONTROL_TRANSFER transfer; + USB_DEVICE device; +private: + bool controlIn(); + bool controlOut(); + bool controlSetup(); + void decodeSetupPacket(unsigned char *data, SETUP_PACKET *packet); +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbhid.cpp Fri Dec 16 18:17:42 2016 +0000 @@ -0,0 +1,314 @@ +/* usbhid.cpp */ +/* USB HID class device */ +/* Copyright (c) Phil Wright 2008 */ + +/* Modified by yours truly */ + +#include "mbed.h" +#include "usbhid.h" + +/* Report for 2 arcade joysticks */ +static uint8_t report_descriptor_joystick[] = +{ +0x05, 0x01, // USAGE_PAGE (Generic Desktop) +0x09, 0x05, // USAGE (Gamepad) +0xa1, 0x01, // COLLECTION (Application) + +0xa1, 0x00, // COLLECTION (Physical) +0x85, 0x01, // REPORT ID 1 +0x15, 0x00, // LOGICAL_MINIMUM (0) +0x25, 0x01, // LOGICAL_MAXIMUM (1) +0x35, 0x00, // PHYSICAL_MINIMUM (0) +0x45, 0x01, // PHYSICAL_MAXIMUM (1) +0x75, 0x01, // REPORT_SIZE (1) +0x95, 0x08, // REPORT_COUNT (8) +0x05, 0x09, // USAGE_PAGE (Button) +0x19, 0x01, // USAGE_MINIMUM (Button 1) +0x29, 0x08, // USAGE_MAXIMUM (Button 8) +0x81, 0x02, // INPUT (Data,Var,Abs) +0x05, 0x01, // USAGE_PAGE (Generic Desktop) +0x25, 0x07, // LOGICAL_MAXIMUM (7) +0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) +0x75, 0x04, // REPORT_SIZE (4) +0x95, 0x01, // REPORT_COUNT (1) +0x65, 0x14, // UNIT (Eng Rot:Angular Pos) +0x09, 0x39, // USAGE (Hat switch) +0x81, 0x42, // INPUT (Data,Var,Abs,Null) +0x65, 0x00, // UNIT (None) +0x95, 0x01, // REPORT_COUNT (1) +0x81, 0x01, // INPUT (Cnst,Ary,Abs) +0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) +0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) + +/* For some reason, this is necessary (though we never put it in the report). */ +0x09, 0x30, // USAGE (X) +0x09, 0x31, // USAGE (Y) +0x75, 0x04, // REPORT_SIZE (4) +0x95, 0x02, // REPORT_COUNT (2) +0x81, 0x02, // INPUT (Data,Var,Abs) + +0xc0, // END_COLLECTION -- physical + +/* second report */ +0xa1, 0x00, // COLLECTION (Physical) +0x85, 0x02, // REPORT ID 2 +0x15, 0x00, // LOGICAL_MINIMUM (0) +0x25, 0x01, // LOGICAL_MAXIMUM (1) +0x35, 0x00, // PHYSICAL_MINIMUM (0) +0x45, 0x01, // PHYSICAL_MAXIMUM (1) + +0x75, 0x01, // REPORT_SIZE (1) +0x95, 0x08, // REPORT_COUNT (8) +0x05, 0x09, // USAGE_PAGE (Button) +0x19, 0x01, // USAGE_MINIMUM (Button 1) +0x29, 0x08, // USAGE_MAXIMUM (Button 8) +0x81, 0x02, // INPUT (Data,Var,Abs) +0x05, 0x01, // USAGE_PAGE (Generic Desktop) +0x25, 0x07, // LOGICAL_MAXIMUM (7) + +0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) + +0x75, 0x04, // REPORT_SIZE (4) +0x95, 0x01, // REPORT_COUNT (1) +0x65, 0x14, // UNIT (Eng Rot:Angular Pos) +0x09, 0x39, // USAGE (Hat switch) +0x81, 0x42, // INPUT (Data,Var,Abs,Null) +0x65, 0x00, // UNIT (None) +#if 0 /* For some reason, this is not necessary! */ +0x95, 0x01, // REPORT_COUNT (1) +0x81, 0x01, // INPUT (Cnst,Ary,Abs) +0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) +0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) +0x09, 0x30, // USAGE (X) +0x09, 0x31, // USAGE (Y) +0x75, 0x04, // REPORT_SIZE (4) +0x95, 0x02, // REPORT_COUNT (2) +0x81, 0x02, // INPUT (Data,Var,Abs) +#endif +0xc0, // END_COLLECTION -- physical + +0xc0, // END_COLLECTION -- application +}; + +/* Endpoint packet sizes */ +#define MAX_PACKET_SIZE_EP1 64 + +/* HID Class */ +#define HID_CLASS 3 +#define HID_SUBCLASS_NONE 0 +#define HID_PROTOCOL_NONE 0 +#define HID_DESCRIPTOR 33 +#define REPORT_DESCRIPTOR 34 + +/* Descriptors */ +unsigned char deviceDescriptor[] = +{ + 0x12, /* bLength */ + DEVICE_DESCRIPTOR, /* bDescriptorType */ + 0x10, /* bcdUSB (LSB) */ + 0x01, /* bcdUSB (MSB) */ // USB release 1.1 + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceprotocol */ + MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */ + 0xFE, /* idVendor (LSB) */ + 0xCA, /* idVendor (MSB) */ + 0xBE, /* idProduct (LSB) */ + 0xBA, /* idProduct (MSB) */ + 0x01, /* bcdDevice (LSB) */ + 0x00, /* bcdDevice (MSB) */ // device version number + 0x01, /* iManufacturer */ // string index (0 = none) + 0x02, /* iProduct */ // string index + 0x00, /* iSerialNumber */ // string index + 0x01 /* bNumConfigurations */ +}; + +unsigned char configurationDescriptor[] = +{ + 0x09, /* bLength */ + CONFIGURATION_DESCRIPTOR, /* bDescriptorType */ + 0x00, /* wTotalLength (LSB), set later */ + 0x00, /* wTotalLength (MSB), set later */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0x80, /* bmAttributes */ + 0x32, /* bMaxPower */ +/*9*/ + 0x09, /* bLength */ + INTERFACE_DESCRIPTOR, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + HID_CLASS, /* bInterfaceClass */ + HID_SUBCLASS_NONE, /* bInterfaceSubClass */ + HID_PROTOCOL_NONE, /* bInterfaceProtocol */ + 0x00, /* iInterface */ +/*18*/ + 0x09, /* bLength */ + HID_DESCRIPTOR, /* bDescriptorType */ + 0x11, /* bcdHID (LSB) */ + 0x01, /* bcdHID (MSB) */ + 0x00, /* bCountryCode */ + 0x01, /* bNumDescriptors */ + REPORT_DESCRIPTOR, /* bDescriptorType */ + sizeof(report_descriptor_joystick) & 0xff, /* wDescriptorLength (LSB) */ + (sizeof(report_descriptor_joystick) >> 8) & 0xff, /* wDescriptorLength (MSB) */ +/*27*/ + 0x07, /* bLength */ + ENDPOINT_DESCRIPTOR, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes */ + MAX_PACKET_SIZE_EP1, /* wMaxPacketSize (LSB) */ + 0x00, /* wMaxPacketSize (MSB) */ + 0x05 /* bInterval */ +}; + +static volatile bool complete; +static volatile bool configured; + +/* */ +usbhid::usbhid() +{ + configured = false; + connect(); +} + +void usbhid::deviceEventReset() +{ + configured = false; + + /* Must call base class */ + usbdevice::deviceEventReset(); +} + +bool usbhid::requestSetConfiguration() +{ + bool result; + + /* Configure IN interrupt endpoint */ + realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1); + enableEndpointEvent(EP1IN); + + /* Must call base class */ + result = usbdevice::requestSetConfiguration(); + + if (result) + { + /* Now configured */ + configured = true; + } + + return result; +} + +bool usbhid::requestGetDescriptor() +{ + bool success = false; + + switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) + { + case DEVICE_DESCRIPTOR: + transfer.remaining = sizeof(deviceDescriptor); + transfer.ptr = deviceDescriptor; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case CONFIGURATION_DESCRIPTOR: + transfer.remaining = sizeof(configurationDescriptor); + transfer.ptr = configurationDescriptor; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case STRING_DESCRIPTOR: + case INTERFACE_DESCRIPTOR: + case ENDPOINT_DESCRIPTOR: + /* TODO: Support is optional, not implemented here */ + break; + case HID_DESCRIPTOR: + transfer.remaining = configurationDescriptor[18]; + transfer.ptr = configurationDescriptor + 18; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + // case REPORT_DESCRIPTOR: /* Handled in the derived class */ + default: + break; + } + + return success; +} + +void usbhid::endpointEventEP1In() +{ + complete = true; +} + +/* */ +USBJoystick::USBJoystick() +{ + const unsigned config_descriptor_size = sizeof(configurationDescriptor); + configurationDescriptor[2] = config_descriptor_size & 0xff; + configurationDescriptor[3] = (config_descriptor_size >> 8) & 0xff; +} + +bool USBJoystick::requestGetDescriptor() +{ + switch(DESCRIPTOR_TYPE(transfer.setup.wValue)) + { + case REPORT_DESCRIPTOR: + transfer.remaining = sizeof(report_descriptor_joystick); + transfer.ptr = report_descriptor_joystick; + transfer.direction = DEVICE_TO_HOST; + return true; + default: + return usbhid::requestGetDescriptor(); + } +} + +bool USBJoystick::update(unsigned char gamepad_id, unsigned char stick, unsigned char buttons) +{ + unsigned char hatswitch; + if (stick & JOYSTICK_UP) + { + hatswitch = 0; + if (stick & JOYSTICK_RIGHT) + hatswitch = 1; + if (stick & JOYSTICK_LEFT) + hatswitch = 7; + } + else + if (stick & JOYSTICK_RIGHT) + { + hatswitch = (stick & JOYSTICK_DOWN) ? 3 : 2; + } + else + if (stick & JOYSTICK_DOWN) + { + hatswitch = (stick & JOYSTICK_LEFT) ? 5 : 4; + } + else + if (stick & JOYSTICK_LEFT) + hatswitch = 6; + else + hatswitch = 0xf; + + /* Prepare report */ + unsigned char report[3]; + report[0] = gamepad_id; + report[1] = buttons; + report[2] = hatswitch; + + /* Block if not configured */ + while(!configured) ; + + /* Send report */ + complete = false; + disableEvents(); + endpointWrite(EP1IN, report, 3); + enableEvents(); + + /* Wait for completion */ + while(!complete && configured) ; + return true; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbhid.h Fri Dec 16 18:17:42 2016 +0000 @@ -0,0 +1,36 @@ +/* usbhid.h */ +/* USB HID class device */ +/* Copyright (c) Phil Wright 2008 */ + +#ifndef USBHID_H +#define USBHID_H + +#include "usbdevice.h" + +class usbhid : public usbdevice +{ +public: + usbhid(); + +protected: + virtual void deviceEventReset(); + virtual void endpointEventEP1In(); + virtual bool requestGetDescriptor(); + virtual bool requestSetConfiguration(); +}; + +#define JOYSTICK_UP (1<<0) +#define JOYSTICK_DOWN (1<<1) +#define JOYSTICK_LEFT (1<<2) +#define JOYSTICK_RIGHT (1<<3) + +class USBJoystick : public usbhid +{ +public: + USBJoystick(); + bool update(unsigned char gamepad_id, unsigned char stick, unsigned char buttons); +protected: + virtual bool requestGetDescriptor(); +}; + +#endif /* USBHID_H */ \ No newline at end of file