USB Keyboard and mouse Example. Based on USBMouse

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
zackc
Date:
Tue Jan 18 02:16:00 2011 +0000
Commit message:

Changed in this revision

USBKeyboardMouse/USBKeyboard.cpp Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/USBKeyboard.h Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/USBMouse.cpp Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/USBMouse.h Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/asciihid.h Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/usbdc.cpp Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/usbdc.h Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/usbdevice.cpp Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/usbdevice.h Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/usbhid.cpp Show annotated file Show diff for this revision Revisions of this file
USBKeyboardMouse/usbhid.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/USBKeyboard.cpp	Tue Jan 18 02:16:00 2011 +0000
@@ -0,0 +1,13 @@
+#include "USBKeyboard.h"
+
+USBKeyboard::USBKeyboard() {
+//    _buttons = 0;
+}
+
+void USBKeyboard::sendKeys(char *szString) {
+    keyboard(szString);
+}
+
+void USBKeyboard::sendKey(char c) {
+    keyboard(c);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/USBKeyboard.h	Tue Jan 18 02:16:00 2011 +0000
@@ -0,0 +1,37 @@
+#include "usbhid.h"
+
+#ifndef MBED_USBKEYBOARD_H
+#define MBED_USBKEYBOARD_H
+
+/* Class: USBKeyboard
+ * Emulate a USB Keyboard HID device
+ *
+ * Example:
+ * > #include "mbed.h"
+ * > #include "USBKeyboard.h"
+ * > 
+ * > USBKeyboard kb;
+ * >
+ * > int main() {
+ * >     while(1) {
+ * >         kb.sendKeys("Foo goes here!");
+ * >         wait(2);
+ * >     }
+ * > }
+ */
+class USBKeyboard : private usbhid {
+public:
+    /* Constructor: USBKeyboard
+     * Create a USB Keyboard using the mbed USB Device interface
+     */
+    USBKeyboard();
+
+    void sendKeys(char *szString);
+    void sendKey(char c);
+    
+
+private:
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/USBMouse.cpp	Tue Jan 18 02:16:00 2011 +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);    
+}    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/USBMouse.h	Tue Jan 18 02:16:00 2011 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/asciihid.h	Tue Jan 18 02:16:00 2011 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/usbdc.cpp	Tue Jan 18 02:16:00 2011 +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)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/usbdc.h	Tue Jan 18 02:16:00 2011 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/usbdevice.cpp	Tue Jan 18 02:16:00 2011 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/usbdevice.h	Tue Jan 18 02:16:00 2011 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/usbhid.cpp	Tue Jan 18 02:16:00 2011 +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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBKeyboardMouse/usbhid.h	Tue Jan 18 02:16:00 2011 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jan 18 02:16:00 2011 +0000
@@ -0,0 +1,17 @@
+#include "mbed.h"
+#include "USBMouse.h"
+#include "USBKeyboard.h"
+
+DigitalOut led(LED1);
+USBMouse mouse;
+USBKeyboard keyboard;
+
+int main() {
+    while(1) {
+        mouse.move(18, 10);     //moves the mouse down and to the left
+        keyboard.sendKeys("foo");     //sends the word "foo" through the keyboard
+
+        led = !led;     //cycles the LED on/off
+        wait(2);        //waits 2 seconds, then repeats
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jan 18 02:16:00 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0