Ashwin Athani
/
mX_USB_HID
mX mbed BaseBoard USB HID
Revision 0:093612081f64, committed 2010-12-08
- Comitter:
- ashwin_athani
- Date:
- Wed Dec 08 06:30:25 2010 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r 093612081f64 USBMouse/USBMouse.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/USBMouse.cpp Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,51 @@ +#include "USBMouse.h" + +USBMouse::USBMouse() { + _buttons = 0; +} + +void USBMouse::move(int x, int y) { + while(x > 127) { + mouse(127, 0, _buttons, 0); + x = x - 127; + } + while(x < -128) { + mouse(-128, 0, _buttons, 0); + x = x + 128; + } + while(y > 127) { + mouse(0, 127, _buttons, 0); + y = y - 127; + } + while(y < -128) { + mouse(0, -128, _buttons, 0); + y = y + 128; + } + mouse(x, y, _buttons, 0); +} + +void USBMouse::scroll(int z) { + while(z > 127) { + mouse(0, 0, _buttons, 127); + z = z - 127; + } + while(z < -128) { + mouse(0, 0, _buttons, -128); + z = z + 128; + } + mouse(0, 0, _buttons, z); +} + +void USBMouse::buttons(int left, int middle, int right) { + int _buttons = 0; + if(left) { + _buttons |= MOUSE_L; + } + if(middle) { + _buttons |= MOUSE_M; + } + if(right) { + _buttons |= MOUSE_R; + } + mouse(0,0, _buttons, 0); +}
diff -r 000000000000 -r 093612081f64 USBMouse/USBMouse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/USBMouse.h Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,60 @@ +#include "usbhid.h" + +#ifndef MBED_USBMOUSE_H +#define MBED_USBMOUSE_H + +/* Class: USBMouse + * Emulate a USB Mouse HID device + * + * Example: + * > #include "mbed.h" + * > #include "USBMouse.h" + * > + * > USBMouse mouse; + * > + * > int main() { + * > while(1) { + * > mouse.move(10, 0); + * > wait(2); + * > } + * > } + */ +class USBMouse : private usbhid { +public: + /* Constructor: USBMouse + * Create a USB Mouse using the mbed USB Device interface + */ + USBMouse(); + + /* Function: move + * Move the mouse + * + * Variables: + * x - Distance to move in x-axis + * y - Distance to move in y-axis + */ + void move(int x, int y); + + /* Function: scroll + * Scroll the scroll wheel + * + * Variables: + * z - Distance to scroll scroll wheel + */ + void scroll(int z); + + /* Function: buttons + * Set the state of the buttons + * + * Variables: + * left - set the left button as down (1) or up (0) + * middle - set the middle button as down (1) or up (0) + * right - set the right button as down (1) or up (0) + */ + void buttons(int left, int middle, int right); + +private: + int _buttons; +}; + +#endif
diff -r 000000000000 -r 093612081f64 USBMouse/asciihid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/asciihid.h Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,289 @@ +/* asciihid.h */ +/* ASCII to HID Keyboard lookup table */ +/* Copyright (c) Phil Wright 2008 */ + +#ifndef HIDTABLE_H +#define HIDTABLE_H + +/* Default is UK keyboard layout */ +/* #define US_KEYBOARD */ + +/* Modifiers */ +#define SHIFT (1<<1) + +typedef struct { + unsigned char usage; + unsigned char modifier; +} KEYMAP; + +#ifdef US_KEYBOARD +/* US keyboard (as HID standard) */ +#define KEYMAP_SIZE (128) +const KEYMAP keymap[KEYMAP_SIZE] = { +{0, 0}, /* NUL */ +{0, 0}, /* SOH */ +{0, 0}, /* STX */ +{0, 0}, /* ETX */ +{0, 0}, /* EOT */ +{0, 0}, /* ENQ */ +{0, 0}, /* ACK */ +{0, 0}, /* BEL */ +{0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */ +{0x2b, 0}, /* TAB */ /* Keyboard Tab */ +{0x28, 0}, /* LF */ /* Keyboard Return (Enter) */ +{0, 0}, /* VT */ +{0, 0}, /* FF */ +{0, 0}, /* CR */ +{0, 0}, /* SO */ +{0, 0}, /* SI */ +{0, 0}, /* DEL */ +{0, 0}, /* DC1 */ +{0, 0}, /* DC2 */ +{0, 0}, /* DC3 */ +{0, 0}, /* DC4 */ +{0, 0}, /* NAK */ +{0, 0}, /* SYN */ +{0, 0}, /* ETB */ +{0, 0}, /* CAN */ +{0, 0}, /* EM */ +{0, 0}, /* SUB */ +{0, 0}, /* ESC */ +{0, 0}, /* FS */ +{0, 0}, /* GS */ +{0, 0}, /* RS */ +{0, 0}, /* US */ +{0x2c, 0}, /* */ +{0x1e, SHIFT}, /* ! */ +{0x34, SHIFT}, /* " */ +{0x20, SHIFT}, /* # */ +{0x21, SHIFT}, /* $ */ +{0x22, SHIFT}, /* % */ +{0x24, SHIFT}, /* & */ +{0x34, 0}, /* ' */ +{0x26, SHIFT}, /* ( */ +{0x27, SHIFT}, /* ) */ +{0x25, SHIFT}, /* * */ +{0x2e, SHIFT}, /* + */ +{0x36, 0}, /* , */ +{0x2d, 0}, /* - */ +{0x37, 0}, /* . */ +{0x38, 0}, /* / */ +{0x27, 0}, /* 0 */ +{0x1e, 0}, /* 1 */ +{0x1f, 0}, /* 2 */ +{0x20, 0}, /* 3 */ +{0x21, 0}, /* 4 */ +{0x22, 0}, /* 5 */ +{0x23, 0}, /* 6 */ +{0x24, 0}, /* 7 */ +{0x25, 0}, /* 8 */ +{0x26, 0}, /* 9 */ +{0x33, SHIFT}, /* : */ +{0x33, 0}, /* ; */ +{0x36, SHIFT}, /* < */ +{0x2e, 0}, /* = */ +{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, 0}, /* [ */ +{0x31, 0}, /* \ */ +{0x30, 0}, /* ] */ +{0x23, SHIFT}, /* ^ */ +{0x2d, SHIFT}, /* _ */ +{0x35, 0}, /* ` */ +{0x04, 0}, /* a */ +{0x05, 0}, /* b */ +{0x06, 0}, /* c */ +{0x07, 0}, /* d */ +{0x08, 0}, /* e */ +{0x09, 0}, /* f */ +{0x0a, 0}, /* g */ +{0x0b, 0}, /* h */ +{0x0c, 0}, /* i */ +{0x0d, 0}, /* j */ +{0x0e, 0}, /* k */ +{0x0f, 0}, /* l */ +{0x10, 0}, /* m */ +{0x11, 0}, /* n */ +{0x12, 0}, /* o */ +{0x13, 0}, /* p */ +{0x14, 0}, /* q */ +{0x15, 0}, /* r */ +{0x16, 0}, /* s */ +{0x17, 0}, /* t */ +{0x18, 0}, /* u */ +{0x19, 0}, /* v */ +{0x1a, 0}, /* w */ +{0x1b, 0}, /* x */ +{0x1c, 0}, /* y */ +{0x1d, 0}, /* z */ +{0x2f, SHIFT}, /* { */ +{0x31, SHIFT}, /* | */ +{0x30, SHIFT}, /* } */ +{0x35, SHIFT}, /* ~ */ +{0,0}, /* DEL */ +}; + +#else +/* UK keyboard */ +#define KEYMAP_SIZE (128) +const KEYMAP keymap[KEYMAP_SIZE] = { +{0, 0}, /* NUL */ +{0, 0}, /* SOH */ +{0, 0}, /* STX */ +{0, 0}, /* ETX */ +{0, 0}, /* EOT */ +{0, 0}, /* ENQ */ +{0, 0}, /* ACK */ +{0, 0}, /* BEL */ +{0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */ +{0x2b, 0}, /* TAB */ /* Keyboard Tab */ +{0x28, 0}, /* LF */ /* Keyboard Return (Enter) */ +{0, 0}, /* VT */ +{0, 0}, /* FF */ +{0, 0}, /* CR */ +{0, 0}, /* SO */ +{0, 0}, /* SI */ +{0, 0}, /* DEL */ +{0, 0}, /* DC1 */ +{0, 0}, /* DC2 */ +{0, 0}, /* DC3 */ +{0, 0}, /* DC4 */ +{0, 0}, /* NAK */ +{0, 0}, /* SYN */ +{0, 0}, /* ETB */ +{0, 0}, /* CAN */ +{0, 0}, /* EM */ +{0, 0}, /* SUB */ +{0, 0}, /* ESC */ +{0, 0}, /* FS */ +{0, 0}, /* GS */ +{0, 0}, /* RS */ +{0, 0}, /* US */ +{0x2c, 0}, /* */ +{0x1e, SHIFT}, /* ! */ +{0x1f, SHIFT}, /* " */ +{0x32, 0}, /* # */ +{0x21, SHIFT}, /* $ */ +{0x22, SHIFT}, /* % */ +{0x24, SHIFT}, /* & */ +{0x34, 0}, /* ' */ +{0x26, SHIFT}, /* ( */ +{0x27, SHIFT}, /* ) */ +{0x25, SHIFT}, /* * */ +{0x2e, SHIFT}, /* + */ +{0x36, 0}, /* , */ +{0x2d, 0}, /* - */ +{0x37, 0}, /* . */ +{0x38, 0}, /* / */ +{0x27, 0}, /* 0 */ +{0x1e, 0}, /* 1 */ +{0x1f, 0}, /* 2 */ +{0x20, 0}, /* 3 */ +{0x21, 0}, /* 4 */ +{0x22, 0}, /* 5 */ +{0x23, 0}, /* 6 */ +{0x24, 0}, /* 7 */ +{0x25, 0}, /* 8 */ +{0x26, 0}, /* 9 */ +{0x33, SHIFT}, /* : */ +{0x33, 0}, /* ; */ +{0x36, SHIFT}, /* < */ +{0x2e, 0}, /* = */ +{0x37, SHIFT}, /* > */ +{0x38, SHIFT}, /* ? */ +{0x34, 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, 0}, /* [ */ +{0x64, 0}, /* \ */ +{0x30, 0}, /* ] */ +{0x23, SHIFT}, /* ^ */ +{0x2d, SHIFT}, /* _ */ +{0x35, 0}, /* ` */ +{0x04, 0}, /* a */ +{0x05, 0}, /* b */ +{0x06, 0}, /* c */ +{0x07, 0}, /* d */ +{0x08, 0}, /* e */ +{0x09, 0}, /* f */ +{0x0a, 0}, /* g */ +{0x0b, 0}, /* h */ +{0x0c, 0}, /* i */ +{0x0d, 0}, /* j */ +{0x0e, 0}, /* k */ +{0x0f, 0}, /* l */ +{0x10, 0}, /* m */ +{0x11, 0}, /* n */ +{0x12, 0}, /* o */ +{0x13, 0}, /* p */ +{0x14, 0}, /* q */ +{0x15, 0}, /* r */ +{0x16, 0}, /* s */ +{0x17, 0}, /* t */ +{0x18, 0}, /* u */ +{0x19, 0}, /* v */ +{0x1a, 0}, /* w */ +{0x1b, 0}, /* x */ +{0x1c, 0}, /* y */ +{0x1d, 0}, /* z */ +{0x2f, SHIFT}, /* { */ +{0x64, SHIFT}, /* | */ +{0x30, SHIFT}, /* } */ +{0x32, SHIFT}, /* ~ */ +{0,0}, /* DEL */ +}; +#endif + + +#endif \ No newline at end of file
diff -r 000000000000 -r 093612081f64 USBMouse/usbdc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/usbdc.cpp Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,544 @@ +/* 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) +{ +}
diff -r 000000000000 -r 093612081f64 USBMouse/usbdc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/usbdc.h Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,65 @@ +/* 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
diff -r 000000000000 -r 093612081f64 USBMouse/usbdevice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/usbdevice.cpp Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,532 @@ +/* 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(void) +{ + /* Endpoint 0 setup event */ + if (!controlSetup()) + { + /* Protocol stall; this will stall both endpoints */ + stallEndpoint(EP0OUT); + } +} + +void usbdevice::endpointEventEP0Out(void) +{ + /* Endpoint 0 OUT data event */ + if (!controlOut()) + { + /* Protocol stall; this will stall both endpoints */ + stallEndpoint(EP0OUT); + } +} + +void usbdevice::endpointEventEP0In(void) +{ + /* Endpoint 0 IN data event */ + if (!controlIn()) + { + /* Protocol stall; this will stall both endpoints */ + stallEndpoint(EP0OUT); + } +} + +void usbdevice::deviceEventReset(void) +{ + 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(void) +{ + /* Control transfer setup stage */ + unsigned char buffer[MAX_PACKET_SIZE_EP0]; + unsigned long count; + + 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(void) +{ + /* 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(void) +{ + /* 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(void) +{ + 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(void) +{ + return true; +} + +bool usbdevice::requestSetAddress(void) +{ + /* 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(void) +{ + /* 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(void) +{ + /* Send the device configuration */ + transfer.ptr = &device.configuration; + transfer.remaining = sizeof(device.configuration); + transfer.direction = DEVICE_TO_HOST; + return true; +} + +bool usbdevice::requestGetInterface(void) +{ + 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(void) +{ + /* 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(void) +{ + 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(void) +{ + return false; +} \ No newline at end of file
diff -r 000000000000 -r 093612081f64 USBMouse/usbdevice.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/usbdevice.h Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,97 @@ +/* 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(void); + virtual void endpointEventEP0In(void); + virtual void endpointEventEP0Out(void); + virtual bool requestSetup(void); + virtual bool requestOut(void); + virtual void deviceEventReset(void); + virtual bool requestGetDescriptor(void); + bool requestSetAddress(void); + virtual bool requestSetConfiguration(void); + virtual bool requestGetConfiguration(void); + bool requestGetStatus(void); + virtual bool requestSetInterface(void); + virtual bool requestGetInterface(void); + bool requestSetFeature(void); + bool requestClearFeature(void); + CONTROL_TRANSFER transfer; + USB_DEVICE device; +private: + bool controlIn(void); + bool controlOut(void); + bool controlSetup(void); + void decodeSetupPacket(unsigned char *data, SETUP_PACKET *packet); +}; + +#endif \ No newline at end of file
diff -r 000000000000 -r 093612081f64 USBMouse/usbhid.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/usbhid.cpp Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,415 @@ +/* usbhid.cpp */ +/* USB HID class device */ +/* Copyright (c) Phil Wright 2008 */ + +#include "mbed.h" +#include "usbhid.h" +#include "asciihid.h" + +/* 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) + +/* Class requests */ +#define GET_REPORT (0x1) +#define GET_IDLE (0x2) +#define SET_REPORT (0x9) +#define SET_IDLE (0xa) + +/* Descriptors */ +unsigned char deviceDescriptor[] = { + 0x12, /* bLength */ + DEVICE_DESCRIPTOR, /* bDescriptorType */ + 0x00, /* bcdUSB (LSB) */ + 0x02, /* bcdUSB (MSB) */ + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceprotocol */ + MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */ + 0x28, /* idVendor (LSB) */ + 0x0d, /* idVendor (MSB) */ + 0x05, /* idProduct (LSB) */ + 0x02, /* idProduct (MSB) */ + 0x00, /* bcdDevice (LSB) */ + 0x00, /* bcdDevice (MSB) */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01 /* bNumConfigurations */ + }; + +unsigned char configurationDescriptor[] = { + 0x09, /* bLength */ + CONFIGURATION_DESCRIPTOR, /* bDescriptorType */ + 0x09+0x09+0x09+0x07, /* wTotalLength (LSB) */ + 0x00, /* wTotalLength (MSB) */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes */ + 0x00, /* bMaxPower */ + + 0x09, /* bLength */ + INTERFACE_DESCRIPTOR, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + HID_CLASS, /* bInterfaceClass */ + HID_SUBCLASS_NONE, /* bInterfaceSubClass */ + HID_PROTOCOL_NONE, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + 0x09, /* bLength */ + HID_DESCRIPTOR, /* bDescriptorType */ + 0x11, /* bcdHID (LSB) */ + 0x01, /* bcdHID (MSB) */ + 0x00, /* bCountryCode */ + 0x01, /* bNumDescriptors */ + REPORT_DESCRIPTOR, /* bDescriptorType */ + 0x79, /* wDescriptorLength (LSB) */ + 0x00, /* wDescriptorLength (MSB) */ + + 0x07, /* bLength */ + ENDPOINT_DESCRIPTOR, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes */ + MAX_PACKET_SIZE_EP1, /* wMaxPacketSize (LSB) */ + 0x00, /* wMaxPacketSize (MSB) */ + 0x0a, /* bInterval */ + }; + +/* HID Class Report Descriptor */ +/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes of data as per HID Class standard */ + +/* Main items */ +#define INPUT(size) (0x80 | size) +#define OUTPUT(size) (0x90 | size) +#define FEATURE(size) (0xb0 | size) +#define COLLECTION(size) (0xa0 | size) +#define END_COLLECTION(size) (0xc0 | size) + +/* Global items */ +#define USAGE_PAGE(size) (0x04 | size) +#define LOGICAL_MIN(size) (0x14 | size) +#define LOGICAL_MAX(size) (0x24 | size) +#define PHYSICAL_MIN(size) (0x34 | size) +#define PHYSICAL_MAX(size) (0x44 | size) +#define UNIT_EXPONENT(size) (0x54 | size) +#define UNIT(size) (0x64 | size) +#define REPORT_SIZE(size) (0x74 | size) +#define REPORT_ID(size) (0x84 | size) +#define REPORT_COUNT(size) (0x94 | size) +#define PUSH(size) (0xa4 | size) +#define POP(size) (0xb4 | size) + +/* Local items */ +#define USAGE(size) (0x08 | size) +#define USAGE_MIN(size) (0x18 | size) +#define USAGE_MAX(size) (0x28 | size) +#define DESIGNATOR_INDEX(size) (0x38 | size) +#define DESIGNATOR_MIN(size) (0x48 | size) +#define DESIGNATOR_MAX(size) (0x58 | size) +#define STRING_INDEX(size) (0x78 | size) +#define STRING_MIN(size) (0x88 | size) +#define STRING_MAX(size) (0x98 | size) +#define DELIMITER(size) (0xa8 | size) + +#define REPORT_ID_KEYBOARD (1) +#define REPORT_ID_MOUSE (2) + +#define MAX_REPORT_SIZE (8) + +unsigned char reportDescriptor[] = { +/* Keyboard */ +USAGE_PAGE(1), 0x01, +USAGE(1), 0x06, +COLLECTION(1), 0x01, +REPORT_ID(1), REPORT_ID_KEYBOARD, +USAGE_PAGE(1), 0x07, +USAGE_MIN(1), 0xE0, +USAGE_MAX(1), 0xE7, +LOGICAL_MIN(1), 0x00, +LOGICAL_MAX(1), 0x01, +REPORT_SIZE(1), 0x01, +REPORT_COUNT(1), 0x08, +INPUT(1), 0x02, +REPORT_COUNT(1), 0x01, +REPORT_SIZE(1), 0x08, +INPUT(1), 0x01, +REPORT_COUNT(1), 0x05, +REPORT_SIZE(1), 0x01, +USAGE_PAGE(1), 0x08, +USAGE_MIN(1), 0x01, +USAGE_MAX(1), 0x05, +OUTPUT(1), 0x02, +REPORT_COUNT(1), 0x01, +REPORT_SIZE(1), 0x03, +OUTPUT(1), 0x01, +REPORT_COUNT(1), 0x06, +REPORT_SIZE(1), 0x08, +LOGICAL_MIN(1), 0x00, +LOGICAL_MAX(2), 0xff, 0x00, +USAGE_PAGE(1), 0x07, +USAGE_MIN(1), 0x00, +USAGE_MAX(2), 0xff, 0x00, +INPUT(1), 0x00, +END_COLLECTION(0), + +/* Mouse */ +USAGE_PAGE(1), 0x01, +USAGE(1), 0x02, +COLLECTION(1), 0x01, +USAGE(1), 0x01, +COLLECTION(1), 0x00, +REPORT_ID(1), REPORT_ID_MOUSE, +REPORT_COUNT(1), 0x03, +REPORT_SIZE(1), 0x01, +USAGE_PAGE(1), 0x09, +USAGE_MIN(1), 0x1, +USAGE_MAX(1), 0x3, +LOGICAL_MIN(1), 0x00, +LOGICAL_MAX(1), 0x01, +INPUT(1), 0x02, +REPORT_COUNT(1), 0x01, +REPORT_SIZE(1), 0x05, +INPUT(1), 0x01, +REPORT_COUNT(1), 0x03, +REPORT_SIZE(1), 0x08, +USAGE_PAGE(1), 0x01, +USAGE(1), 0x30, +USAGE(1), 0x31, +USAGE(1), 0x38, +LOGICAL_MIN(1), 0x81, +LOGICAL_MAX(1), 0x7f, +INPUT(1), 0x06, +END_COLLECTION(0), +END_COLLECTION(0), +}; + +volatile bool complete; +volatile bool configured; +unsigned char outputReport[MAX_REPORT_SIZE]; + +usbhid::usbhid() +{ + configured = false; + connect(); +} + +void usbhid::deviceEventReset() +{ + configured = false; + + /* Must call base class */ + usbdevice::deviceEventReset(); +} + +bool usbhid::requestSetConfiguration(void) +{ + 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(void) +{ + 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 = 0x09; /* TODO: Fix hard coded size/offset */ + transfer.ptr = &configurationDescriptor[18]; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case REPORT_DESCRIPTOR: + transfer.remaining = sizeof(reportDescriptor); + transfer.ptr = reportDescriptor; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + default: + break; + } + + return success; +} + +bool usbhid::requestSetup(void) +{ + /* Process class requests */ + bool success = false; + + if (transfer.setup.bmRequestType.Type == CLASS_TYPE) + { + switch (transfer.setup.bRequest) + { + case SET_REPORT: + switch (transfer.setup.wValue & 0xff) + { + case REPORT_ID_KEYBOARD: + /* TODO: LED state */ + transfer.remaining = sizeof(outputReport); + transfer.ptr = outputReport; + transfer.direction = HOST_TO_DEVICE; + success = true; + break; + default: + break; + } + break; + default: + break; + } + } + + if (success) + { + /* We've handled this request */ + return true; + } + + return usbdevice::requestSetup(); +} + +bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size) +{ + /* Send an Input Report */ + /* If data is NULL an all zero report is sent */ + + static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */ + unsigned char i; + + if (size > MAX_REPORT_SIZE) + { + return false; + } + + /* Add report ID */ + report[0]=id; + + /* Add report data */ + if (data != NULL) + { + for (i=0; i<size; i++) + { + report[i+1] = *data++; + } + } + else + { + for (i=0; i<size; i++) + { + report[i+1] = 0; + } + } + + /* Block if not configured */ + while (!configured); + + /* Send report */ + complete = false; + disableEvents(); + endpointWrite(EP1IN, report, size+1); /* +1 for report ID */ + enableEvents(); + + /* Wait for completion */ + while(!complete && configured); + return true; +} + +void usbhid::endpointEventEP1In(void) +{ + complete = true; +} + +bool usbhid::keyboard(char c) +{ + /* Send a simulated keyboard keypress. Returns true if successful. */ + unsigned char report[8]={0,0,0,0,0,0,0,0}; + + report[0] = keymap[c].modifier; + report[2] = keymap[c].usage; + + /* Key down */ + if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8)) + { + return false; + } + + /* Key up */ + if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8)) + { + return false; + } + + return true; +} + +bool usbhid::keyboard(char *string) +{ + /* Send a string of characters. Returns true if successful. */ + do { + if (!keyboard(*string++)) + { + return false; + } + } while (*string != '\0'); + + return true; +} + +bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel) +{ + /* Send a simulated mouse event. Returns true if successful. */ + unsigned char report[4]={0,0,0,0}; + + report[0] = buttons; + report[1] = x; + report[2] = y; + report[3] = wheel; + + if (!sendInputReport(REPORT_ID_MOUSE, report, 4)) + { + return false; + } + + return true; +}
diff -r 000000000000 -r 093612081f64 USBMouse/usbhid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMouse/usbhid.h Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,32 @@ +/* usbhid.h */ +/* USB HID class device */ +/* Copyright (c) Phil Wright 2008 */ + +#ifndef USBHID_H +#define USBHID_H + +#include "usbdevice.h" + +/* Mouse buttons */ +#define MOUSE_L (1<<0) +#define MOUSE_M (1<<1) +#define MOUSE_R (1<<2) + +class usbhid : public usbdevice +{ +public: + usbhid(); + bool keyboard(char c); + bool keyboard(char *string); + bool mouse(signed char x, signed char y, unsigned char buttons=0, signed char wheel=0); +protected: + virtual bool requestSetConfiguration(); + virtual void endpointEventEP1In(void); + virtual void deviceEventReset(void); + virtual bool requestGetDescriptor(void); + virtual bool requestSetup(void); +private: + bool sendInputReport(unsigned char id, unsigned char *data, unsigned char size); +}; + +#endif \ No newline at end of file
diff -r 000000000000 -r 093612081f64 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,13 @@ +#include "mbed.h" +#include "USBMouse.h" + +DigitalOut led(LED1); +USBMouse mouse; + +int main() { + while(1) { + mouse.move(10, 5); + led = !led; + wait(4); + } +}
diff -r 000000000000 -r 093612081f64 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Dec 08 06:30:25 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0