diff --git a/VCOM_lib/intenable.c b/VCOM_lib/intenable.c new file mode 100644 index 0000000..e810519 --- /dev/null +++ b/VCOM_lib/intenable.c @@ -0,0 +1,6 @@ +#include "LPC17xx.h" + +void enable_USB_interrupts(void) +{ + NVIC_EnableIRQ(USB_IRQn); +} diff --git a/VCOM_lib/lpcusb_type.h b/VCOM_lib/lpcusb_type.h new file mode 100644 index 0000000..1c76543 --- /dev/null +++ b/VCOM_lib/lpcusb_type.h @@ -0,0 +1,68 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/** + @file + primitive types used in the USB stack + */ + +// *********************************************** +// Code Red Technologies - port to RDB1768 board +// In order to avoid clashing with the NXP-produced type.h file, this +// one has been renamed to lpcusb_type.h, the NXP-produced type.h has +// been included, and the duplicate contents of this file commented out. +// *********************************************** + + +#ifndef _LPCUSB_TYPE_H_ +#define _LPCUSB_TYPE_H_ + +// CodeRed - include NXP-produced type.h file +#include "type.h" + +typedef unsigned char U8; /**< unsigned 8-bit */ +typedef unsigned short int U16; /**< unsigned 16-bit */ +typedef unsigned int U32; /**< unsigned 32-bit */ + + +// CodeRed - comment out defines duplicated in NXP type.h + +//typedef int BOOL; /**< #TRUE or #FALSE */ + +//#define TRUE 1 /**< TRUE */ +//#define FALSE 0 /**< FALSE */ + +//#ifndef NULL +//#define NULL ((void*)0) /**< NULL pointer */ +//#endif +//#endif + +/* some other useful macros */ +#define MIN(x,y) ((x)<(y)?(x):(y)) /**< MIN */ +#define MAX(x,y) ((x)>(y)?(x):(y)) /**< MAX */ + +#endif /* _LPCUSB_TYPE_H_ */ + diff --git a/VCOM_lib/serial_fifo.c b/VCOM_lib/serial_fifo.c new file mode 100644 index 0000000..e547502 --- /dev/null +++ b/VCOM_lib/serial_fifo.c @@ -0,0 +1,87 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// CodeRed - LPCUSB type.h renamed +//#include "type.h" +#include "lpcusb_type.h" +#include "serial_fifo.h" + +void fifo_init(fifo_t *fifo, U8 *buf) +{ + fifo->head = 0; + fifo->tail = 0; + fifo->buf = buf; +} + + +BOOL fifo_put(fifo_t *fifo, U8 c) +{ + int next; + + // check if FIFO has room + next = (fifo->head + 1) % VCOM_FIFO_SIZE; + if (next == fifo->tail) { + // full + return FALSE; + } + + fifo->buf[fifo->head] = c; + fifo->head = next; + + return TRUE; +} + + +BOOL fifo_get(fifo_t *fifo, U8 *pc) +{ + int next; + + // check if FIFO has data + if (fifo->head == fifo->tail) { + return FALSE; + } + + next = (fifo->tail + 1) % VCOM_FIFO_SIZE; + + *pc = fifo->buf[fifo->tail]; + fifo->tail = next; + + return TRUE; +} + + +int fifo_avail(fifo_t *fifo) +{ + return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE; +} + + +int fifo_free(fifo_t *fifo) +{ + return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo)); +} + diff --git a/VCOM_lib/serial_fifo.h b/VCOM_lib/serial_fifo.h new file mode 100644 index 0000000..43b998d --- /dev/null +++ b/VCOM_lib/serial_fifo.h @@ -0,0 +1,42 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "lpcusb_type.h" + +#define VCOM_FIFO_SIZE 512 + +typedef struct { + int head; + int tail; + U8 *buf; +} fifo_t; + +void fifo_init(fifo_t *fifo, U8 *buf); +BOOL fifo_put(fifo_t *fifo, U8 c); +BOOL fifo_get(fifo_t *fifo, U8 *pc); +int fifo_avail(fifo_t *fifo); +int fifo_free(fifo_t *fifo); diff --git a/VCOM_lib/usbSerial.c b/VCOM_lib/usbSerial.c new file mode 100644 index 0000000..fc3e31b --- /dev/null +++ b/VCOM_lib/usbSerial.c @@ -0,0 +1,628 @@ +//#define POLLED_USBSERIAL TRUE + + +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + Minimal implementation of a USB serial port, using the CDC class. + This example application simply echoes everything it receives right back + to the host. + + Windows: + Extract the usbser.sys file from .cab file in C:\WINDOWS\Driver Cache\i386 + and store it somewhere (C:\temp is a good place) along with the usbser.inf + file. Then plug in the LPC176x and direct windows to the usbser driver. + Windows then creates an extra COMx port that you can open in a terminal + program, like hyperterminal. + + Linux: + The device should be recognised automatically by the cdc_acm driver, + which creates a /dev/ttyACMx device file that acts just like a regular + serial port. + +*/ + +/* Modified by Sagar G V, Feb 2011 +Used the USB CDC example to create a library. Added the following functions + +void VCOM_puts(const char* str); //writes a null terminated string. +void VCOM_putc(char c); // writes a character. +void VCOM_putHex(uint8_t hex); // writes 0x.. hex value on the terminal. +char VCOM_getc(); // returns character entered in the terminal. blocking function +void VCOM_gets(char* str); // returns a string. '\r' or '\n' will terminate character collection. +char VCOM_getc_echo(); // returns character entered and echoes the same back. +void VCOM_gets_echo(char *str); // gets string terminated in '\r' or '\n' and echoes back the same. + +*/ + + +#include "usbSerial.h" + + + +// data structure for GET_LINE_CODING / SET_LINE_CODING class requests +typedef struct { + U32 dwDTERate; + U8 bCharFormat; + U8 bParityType; + U8 bDataBits; +} TLineCoding; + +static TLineCoding LineCoding = {115200, 0, 0, 8}; +static U8 abBulkBuf[64]; +static U8 abClassReqData[8]; + +static U8 txdata[VCOM_FIFO_SIZE]; +static U8 rxdata[VCOM_FIFO_SIZE]; + +static fifo_t txfifo; +static fifo_t rxfifo; + +// forward declaration of interrupt handler +void USBIntHandler(void); + +static const U8 abDescriptors[] = { + +// device descriptor + 0x12, + DESC_DEVICE, + LE_WORD(0x0101), // bcdUSB + 0x02, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + MAX_PACKET_SIZE0, // bMaxPacketSize + LE_WORD(0xFFFF), // idVendor + LE_WORD(0x0005), // idProduct + LE_WORD(0x0100), // bcdDevice + 0x01, // iManufacturer + 0x02, // iProduct + 0x03, // iSerialNumber + 0x01, // bNumConfigurations + +// configuration descriptor + 0x09, + DESC_CONFIGURATION, + LE_WORD(67), // wTotalLength + 0x02, // bNumInterfaces + 0x01, // bConfigurationValue + 0x00, // iConfiguration + 0xC0, // bmAttributes + 0x32, // bMaxPower +// control class interface + 0x09, + DESC_INTERFACE, + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x01, // bNumEndPoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubClass + 0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module + 0x00, // iInterface +// header functional descriptor + 0x05, + CS_INTERFACE, + 0x00, + LE_WORD(0x0110), +// call management functional descriptor + 0x05, + CS_INTERFACE, + 0x01, + 0x01, // bmCapabilities = device handles call management + 0x01, // bDataInterface +// ACM functional descriptor + 0x04, + CS_INTERFACE, + 0x02, + 0x02, // bmCapabilities +// union functional descriptor + 0x05, + CS_INTERFACE, + 0x06, + 0x00, // bMasterInterface + 0x01, // bSlaveInterface0 +// notification EP + 0x07, + DESC_ENDPOINT, + INT_IN_EP, // bEndpointAddress + 0x03, // bmAttributes = intr + LE_WORD(8), // wMaxPacketSize + 0x0A, // bInterval +// data class interface descriptor + 0x09, + DESC_INTERFACE, + 0x01, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndPoints + 0x0A, // bInterfaceClass = data + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface +// data EP OUT + 0x07, + DESC_ENDPOINT, + BULK_OUT_EP, // bEndpointAddress + 0x02, // bmAttributes = bulk + LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize + 0x00, // bInterval +// data EP in + 0x07, + DESC_ENDPOINT, + BULK_IN_EP, // bEndpointAddress + 0x02, // bmAttributes = bulk + LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize + 0x00, // bInterval + + // string descriptors + 0x04, + DESC_STRING, + LE_WORD(0x0409), + + 0x0E, + DESC_STRING, + 'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0, + + 0x14, + DESC_STRING, + 'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0, + + 0x12, + DESC_STRING, + 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0, + +// terminating zero + 0 +}; + + +/** + Local function to handle incoming bulk data + + @param [in] bEP + @param [in] bEPStatus + */ +static void BulkOut(U8 bEP, U8 bEPStatus) +{ + int i, iLen; + bEPStatus = bEPStatus; + if (fifo_free(&rxfifo) < MAX_PACKET_SIZE) { + // may not fit into fifo + return; + } + + // get data from USB into intermediate buffer + iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf)); + for (i = 0; i < iLen; i++) { + // put into FIFO + if (!fifo_put(&rxfifo, abBulkBuf[i])) { + // overflow... :( + ASSERT(FALSE); + break; + } + } +} + + +/** + Local function to handle outgoing bulk data + + @param [in] bEP + @param [in] bEPStatus + */ +static void BulkIn(U8 bEP, U8 bEPStatus) +{ + int i, iLen; + bEPStatus = bEPStatus; + if (fifo_avail(&txfifo) == 0) { + // no more data, disable further NAK interrupts until next USB frame + USBHwNakIntEnable(0); + return; + } + + // get bytes from transmit FIFO into intermediate buffer + for (i = 0; i < MAX_PACKET_SIZE; i++) { + if (!fifo_get(&txfifo, &abBulkBuf[i])) { + break; + } + } + iLen = i; + + // send over USB + if (iLen > 0) { + USBHwEPWrite(bEP, abBulkBuf, iLen); + } +} + + +/** + Local function to handle the USB-CDC class requests + + @param [in] pSetup + @param [out] piLen + @param [out] ppbData + */ +static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) +{ + int i; + switch (pSetup->bRequest) { + + // set line coding + case SET_LINE_CODING: + + //memcpy((U8 *)&LineCoding, *ppbData, 7); + *piLen = 7; + for(i=0;i<7;i++) + ((U8 *)&LineCoding)[i] = (*ppbData)[i]; + + break; + + // get line coding + case GET_LINE_CODING: + + *ppbData = (U8 *)&LineCoding; + *piLen = 7; + break; + + // set control line state + case SET_CONTROL_LINE_STATE: + // bit0 = DTR, bit = RTS + + break; + + default: + return FALSE; + } + return TRUE; +} + + +/** + Initialises the VCOM port. + Call this function before using VCOM_puttchar or VCOM_getchar + */ +void VCOM_init(void) +{ + fifo_init(&txfifo, txdata); + fifo_init(&rxfifo, rxdata); +} + + +/** + Writes one character to VCOM port + + @param [in] c character to write + @returns character written, or EOF if character could not be written + */ +int VCOM_putchar(int c) +{ + return fifo_put(&txfifo, c) ? c : EOF; +} + + +/** + Reads one character from VCOM port + + @returns character read, or EOF if character could not be read + */ +int VCOM_getchar(void) +{ + U8 c; + + return fifo_get(&rxfifo, &c) ? c : EOF; +} + + +/** + Interrupt handler + + Simply calls the USB ISR + */ +//void USBIntHandler(void) +void USB_IRQHandler(void) +{ + USBHwISR(); +} + + +static void USBFrameHandler(U16 wFrame) +{ + wFrame = wFrame; + if (fifo_avail(&txfifo) > 0) { + // data available, enable NAK interrupt on bulk in + USBHwNakIntEnable(INACK_BI); + } +} + +void enable_USB_interrupts(void); + + +/************************************************************************* + main + ==== +**************************************************************************/ +int usbSerialInit() +{ + // initialise stack + USBInit(); + + // register descriptors + USBRegisterDescriptors(abDescriptors); + + // register class request handler + USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData); + + // register endpoint handlers + USBHwRegisterEPIntHandler(INT_IN_EP, NULL); + USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn); + USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut); + + // register frame handler + USBHwRegisterFrameHandler(USBFrameHandler); + + // enable bulk-in interrupts on NAKs + USBHwNakIntEnable(INACK_BI); + + // initialise VCOM + VCOM_init(); + + +/* CodeRed - comment out original interrupt setup code + // set up USB interrupt + VICIntSelect &= ~(1<<22); // select IRQ for USB + VICIntEnable |= (1<<22); + + (*(&VICVectCntl0+INT_VECT_NUM)) = 0x20 | 22; // choose highest priority ISR slot + (*(&VICVectAddr0+INT_VECT_NUM)) = (int)USBIntHandler; + + enableIRQ(); +*/ + +// CodeRed - add in interrupt setup code for RDB1768 + +#ifndef POLLED_USBSERIAL + //enable_USB_interrupts(); + NVIC_EnableIRQ(USB_IRQn); + +#endif + + // connect to bus + + + USBHwConnect(TRUE); + + + return 0; +} +void VCOM_puts(const char* str) +{ + while(*str != '\0') + { + VCOM_putchar(*str++); + } +} +void VCOM_putc(char c) +{ + while(VCOM_putchar(c) == EOF); +} +char VCOM_getc() +{ + int c; + c = EOF; + while(c == EOF) + { + c = VCOM_getchar(); + } + return (char)c; +} +void VCOM_putHex(uint8_t hex) +{ + uint8_t temp; + VCOM_puts("0x"); + + temp = ((hex >> 4) & 0x0F) + 0x30;// add 0x30 to get ASCII value + if(temp > 0x39) + temp += 7; // alphabet, not numeral + VCOM_putc((char)temp); + + temp = ((hex) & 0x0F) + 0x30; + if(temp > 0x39) + temp += 7; + + VCOM_putc((char)temp); +} +void VCOM_gets(char* str) +{ + char c; + c = VCOM_getc(); + while((c != '\n') && (c != '\r')) + { + *str++ = c; + c = VCOM_getc(); + } + *str = '\0'; +} +char VCOM_getc_echo() +{ + char c; + c = VCOM_getc(); + VCOM_putc(c); + return c; +} +void VCOM_gets_echo(char *str) +{ + char c; + c = VCOM_getc_echo(); + while((c != '\n') && (c != '\r')) + { + *str++ = c; + c = VCOM_getc_echo(); + } + *str = '\0'; +} + +/* Original code by ELM_ChaN. Modified by Martin Thomas */ +int xatoi (char **str, long *res) +{ + uint32_t val; + uint8_t c, radix, s = 0; + + + while ((c = **str) == ' ') (*str)++; + if (c == '-') { + s = 1; + c = *(++(*str)); + } + if (c == '0') { + c = *(++(*str)); + if (c <= ' ') { + *res = 0; return 1; + } + if (c == 'x') { + radix = 16; + c = *(++(*str)); + } else { + if (c == 'b') { + radix = 2; + c = *(++(*str)); + } else { + if ((c >= '0')&&(c <= '9')) + radix = 8; + else + return 0; + } + } + } else { + if ((c < '1')||(c > '9')) + return 0; + radix = 10; + } + val = 0; + while (c > ' ') { + if (c >= 'a') c -= 0x20; + c -= '0'; + if (c >= 17) { + c -= 7; + if (c <= 9) return 0; + } + if (c >= radix) return 0; + val = val * radix + c; + c = *(++(*str)); + } + if (s) val = -val; + *res = val; + return 1; +} + + + +void xitoa (long val, int radix, int len) +{ + uint8_t c, r, sgn = 0, pad = ' '; + uint8_t s[20], i = 0; + uint32_t v; + + + if (radix < 0) { + radix = -radix; + if (val < 0) { + val = -val; + sgn = '-'; + } + } + v = val; + r = radix; + if (len < 0) { + len = -len; + pad = '0'; + } + if (len > 20) return; + do { + c = (uint8_t)(v % r); + if (c >= 10) c += 7; + c += '0'; + s[i++] = c; + v /= r; + } while (v); + if (sgn) s[i++] = sgn; + while (i < len) + s[i++] = pad; + do + VCOM_putc(s[--i]); + while (i); +} + +void VCOM_printf (const char* str, ...) +{ + va_list arp; + int d, r, w, s, l; + + + va_start(arp, str); + + while ((d = *str++) != 0) { + if (d != '%') { + VCOM_putc(d); continue; + } + d = *str++; w = r = s = l = 0; + if (d == '0') { + d = *str++; s = 1; + } + while ((d >= '0')&&(d <= '9')) { + w += w * 10 + (d - '0'); + d = *str++; + } + if (s) w = -w; + if (d == 'l') { + l = 1; + d = *str++; + } + if (!d) break; + if (d == 's') { + VCOM_puts(va_arg(arp, char*)); + continue; + } + if (d == 'c') { + VCOM_putc((char)va_arg(arp, int)); + continue; + } + if (d == 'u') r = 10; + if (d == 'd') r = -10; + if (d == 'X' || d == 'x') r = 16; // 'x' added by mthomas in increase compatibility + if (d == 'b') r = 2; + if (!r) break; + if (l) { + xitoa((long)va_arg(arp, long), r, w); + } else { + if (r > 0) + xitoa((unsigned long)va_arg(arp, int), r, w); + else + xitoa((long)va_arg(arp, int), r, w); + } + } + + va_end(arp); +} diff --git a/VCOM_lib/usbSerial.h b/VCOM_lib/usbSerial.h new file mode 100644 index 0000000..568cd1b --- /dev/null +++ b/VCOM_lib/usbSerial.h @@ -0,0 +1,129 @@ +//#define POLLED_USBSERIAL TRUE + + +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + Minimal implementation of a USB serial port, using the CDC class. + This example application simply echoes everything it receives right back + to the host. + + Windows: + Extract the usbser.sys file from .cab file in C:\WINDOWS\Driver Cache\i386 + and store it somewhere (C:\temp is a good place) along with the usbser.inf + file. Then plug in the LPC176x and direct windows to the usbser driver. + Windows then creates an extra COMx port that you can open in a terminal + program, like hyperterminal. + + Linux: + The device should be recognised automatically by the cdc_acm driver, + which creates a /dev/ttyACMx device file that acts just like a regular + serial port. + +*/ + +/* Modified by Sagar G V, Feb 2011 +Used the USB CDC example to create a library. Added the following functions + +void VCOM_puts(const char* str); //writes a null terminated string. +void VCOM_putc(char c); // writes a character. +void VCOM_putHex(uint8_t hex); // writes 0x.. hex value on the terminal. +char VCOM_getc(); // returns character entered in the terminal. blocking function +void VCOM_gets(char* str); // returns a string. '\r' or '\n' will terminate character collection. +char VCOM_getc_echo(); // returns character entered and echoes the same back. +void VCOM_gets_echo(char *str); // gets string terminated in '\r' or '\n' and echoes back the same. + +*/ + +#ifndef __USB_SERIAL_H__ +#define __USB_SERIAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "LPC17xx.h" + +#include "usbapi.h" +#include "usbdebug.h" + +#define BAUD_RATE 115200 + +#define INT_IN_EP 0x81 +#define BULK_OUT_EP 0x05 +#define BULK_IN_EP 0x82 + +#define MAX_PACKET_SIZE 64 + +#define LE_WORD(x) ((x)&0xFF),((x)>>8) + +// CDC definitions +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 + + +#include "serial_fifo.h" + +int usbSerialInit(); // run once in main b4 main loop starts. + + +/* + Writes one character to VCOM port + + @param [in] c character to write + @returns character written, or EOF if character could not be written + */ +int VCOM_putchar(int c); + +/** + Reads one character from VCOM port + + @returns character read, or EOF if character could not be read + */ +int VCOM_getchar(void); + +void VCOM_puts(const char* str); //writes a null terminated string. +void VCOM_putc(char c); // writes a character. +void VCOM_putHex(uint8_t hex); // writes 0x.. hex value on the terminal. +char VCOM_getc(); // returns character entered in the terminal. blocking function +void VCOM_gets(char* str); // returns a string. '\r' or '\n' will terminate character collection. +char VCOM_getc_echo(); // returns character entered and echoes the same back. +void VCOM_gets_echo(char *str); // gets string terminated in '\r' or '\n' and echoes back the same. + +void VCOM_printf(const char* str, ...); // Original code by Elm_CHaN. Modified by Martin Thomas + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/VCOM_lib/usbapi.h b/VCOM_lib/usbapi.h new file mode 100644 index 0000000..afd0ee1 --- /dev/null +++ b/VCOM_lib/usbapi.h @@ -0,0 +1,121 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + @file +*/ + +// CodeRed - include the LPCUSB type.h file rather than NXP one directly +#include "lpcusb_type.h" + +#include "usbstruct.h" // for TSetupPacket + +/************************************************************************* + USB configuration +**************************************************************************/ + +#define MAX_PACKET_SIZE0 64 /**< maximum packet size for EP 0 */ + +/************************************************************************* + USB hardware interface +**************************************************************************/ + +// endpoint status sent through callback +#define EP_STATUS_DATA (1<<0) /**< EP has data */ +#define EP_STATUS_STALLED (1<<1) /**< EP is stalled */ +#define EP_STATUS_SETUP (1<<2) /**< EP received setup packet */ +#define EP_STATUS_ERROR (1<<3) /**< EP data was overwritten by setup packet */ +#define EP_STATUS_NACKED (1<<4) /**< EP sent NAK */ + +// device status sent through callback +#define DEV_STATUS_CONNECT (1<<0) /**< device just got connected */ +#define DEV_STATUS_SUSPEND (1<<2) /**< device entered suspend state */ +#define DEV_STATUS_RESET (1<<4) /**< device just got reset */ + +// interrupt bits for NACK events in USBHwNakIntEnable +// (these bits conveniently coincide with the LPC176x USB controller bit) +#define INACK_CI (1<<1) /**< interrupt on NACK for control in */ +#define INACK_CO (1<<2) /**< interrupt on NACK for control out */ +#define INACK_II (1<<3) /**< interrupt on NACK for interrupt in */ +#define INACK_IO (1<<4) /**< interrupt on NACK for interrupt out */ +#define INACK_BI (1<<5) /**< interrupt on NACK for bulk in */ +#define INACK_BO (1<<6) /**< interrupt on NACK for bulk out */ + +BOOL USBHwInit (void); +void USBHwISR (void); + +void USBHwNakIntEnable (U8 bIntBits); + +void USBHwConnect (BOOL fConnect); + +void USBHwSetAddress (U8 bAddr); +void USBHwConfigDevice (BOOL fConfigured); + +// endpoint operations +void USBHwEPConfig (U8 bEP, U16 wMaxPacketSize); +int USBHwEPRead (U8 bEP, U8 *pbBuf, int iMaxLen); +int USBHwEPWrite (U8 bEP, U8 *pbBuf, int iLen); +void USBHwEPStall (U8 bEP, BOOL fStall); +U8 USBHwEPGetStatus (U8 bEP); + +/** Endpoint interrupt handler callback */ +typedef void (TFnEPIntHandler) (U8 bEP, U8 bEPStatus); +void USBHwRegisterEPIntHandler (U8 bEP, TFnEPIntHandler *pfnHandler); + +/** Device status handler callback */ +typedef void (TFnDevIntHandler) (U8 bDevStatus); +void USBHwRegisterDevIntHandler (TFnDevIntHandler *pfnHandler); + +/** Frame event handler callback */ +typedef void (TFnFrameHandler)(U16 wFrame); +void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler); + + +/************************************************************************* + USB application interface +**************************************************************************/ + +// initialise the complete stack, including HW +BOOL USBInit(void); + +/** Request handler callback (standard, vendor, class) */ +typedef BOOL (TFnHandleRequest)(TSetupPacket *pSetup, int *piLen, U8 **ppbData); +void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore); +void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler); + +/** Descriptor handler callback */ +typedef BOOL (TFnGetDescriptor)(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData); + +/** Default standard request handler */ +BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData); + +/** Default EP0 handler */ +void USBHandleControlTransfer(U8 bEP, U8 bEPStat); + +/** Descriptor handling */ +void USBRegisterDescriptors(const U8 *pabDescriptors); +BOOL USBGetDescriptor(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData); diff --git a/VCOM_lib/usbcontrol.c b/VCOM_lib/usbcontrol.c new file mode 100644 index 0000000..df96714 --- /dev/null +++ b/VCOM_lib/usbcontrol.c @@ -0,0 +1,234 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + Control transfer handler. + + This module handles control transfers and is normally installed on the + endpoint 0 callback. + + Control transfers can be of the following type: + 0 Standard; + 1 Class; + 2 Vendor; + 3 Reserved. + + A callback can be installed for each of these control transfers using + USBRegisterRequestHandler. + When an OUT request arrives, data is collected in the data store provided + with the USBRegisterRequestHandler call. When the transfer is done, the + callback is called. + When an IN request arrives, the callback is called immediately to either + put the control transfer data in the data store, or to get a pointer to + control transfer data. The data is then packetised and sent to the host. +*/ + +// CodeRed - include the LPCUSB type.h file rather than NXP one directly +//#include "type.h" +#include "lpcusb_type.h" + +#include "usbdebug.h" + +#include "usbstruct.h" +#include "usbapi.h" + + + +#define MAX_CONTROL_SIZE 128 /**< maximum total size of control transfer data */ +#define MAX_REQ_HANDLERS 4 /**< standard, class, vendor, reserved */ + +static TSetupPacket Setup; /**< setup packet */ + +static U8 *pbData; /**< pointer to data buffer */ +static int iResidue; /**< remaining bytes in buffer */ +static int iLen; /**< total length of control transfer */ + +/** Array of installed request handler callbacks */ +static TFnHandleRequest *apfnReqHandlers[4] = {NULL, NULL, NULL, NULL}; +/** Array of installed request data pointers */ +static U8 *apbDataStore[4] = {NULL, NULL, NULL, NULL}; + +/** + Local function to handle a request by calling one of the installed + request handlers. + + In case of data going from host to device, the data is at *ppbData. + In case of data going from device to host, the handler can either + choose to write its data at *ppbData or update the data pointer. + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in,out] ppbData Data buffer. + + @return TRUE if the request was handles successfully + */ +static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) +{ + TFnHandleRequest *pfnHandler; + int iType; + + iType = REQTYPE_GET_TYPE(pSetup->bmRequestType); + pfnHandler = apfnReqHandlers[iType]; + if (pfnHandler == NULL) { + DBG("No handler for reqtype %d\n", iType); + return FALSE; + } + + return pfnHandler(pSetup, piLen, ppbData); +} + + +/** + Local function to stall the control endpoint + + @param [in] bEPStat Endpoint status + */ +static void StallControlPipe(U8 bEPStat) +{ + U8 *pb; + int i; + bEPStat = bEPStat; + USBHwEPStall(0x80, TRUE); + +// dump setup packet + DBG("STALL on ["); + pb = (U8 *)&Setup; + for (i = 0; i < 8; i++) { + DBG(" %02x", *pb++); + } + DBG("] stat=%x\n", bEPStat); +} + + +/** + Sends next chunk of data (possibly 0 bytes) to host + */ +static void DataIn(void) +{ + int iChunk; + + iChunk = MIN(MAX_PACKET_SIZE0, iResidue); + USBHwEPWrite(0x80, pbData, iChunk); + pbData += iChunk; + iResidue -= iChunk; +} + + +/** + * Handles IN/OUT transfers on EP0 + * + * @param [in] bEP Endpoint address + * @param [in] bEPStat Endpoint status + */ +void USBHandleControlTransfer(U8 bEP, U8 bEPStat) +{ + int iChunk, iType; + + if (bEP == 0x00) { + // OUT transfer + if (bEPStat & EP_STATUS_SETUP) { + // setup packet, reset request message state machine + USBHwEPRead(0x00, (U8 *)&Setup, sizeof(Setup)); + DBG("S%x", Setup.bRequest); + + // defaults for data pointer and residue + iType = REQTYPE_GET_TYPE(Setup.bmRequestType); + pbData = apbDataStore[iType]; + iResidue = Setup.wLength; + iLen = Setup.wLength; + + if ((Setup.wLength == 0) || + (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) { + // ask installed handler to process request + if (!_HandleRequest(&Setup, &iLen, &pbData)) { + DBG("_HandleRequest1 failed\n"); + StallControlPipe(bEPStat); + return; + } + // send smallest of requested and offered length + iResidue = MIN(iLen, Setup.wLength); + // send first part (possibly a zero-length status message) + DataIn(); + } + } + else { + if (iResidue > 0) { + // store data + iChunk = USBHwEPRead(0x00, pbData, iResidue); + if (iChunk < 0) { + StallControlPipe(bEPStat); + return; + } + pbData += iChunk; + iResidue -= iChunk; + if (iResidue == 0) { + // received all, send data to handler + iType = REQTYPE_GET_TYPE(Setup.bmRequestType); + pbData = apbDataStore[iType]; + if (!_HandleRequest(&Setup, &iLen, &pbData)) { + DBG("_HandleRequest2 failed\n"); + StallControlPipe(bEPStat); + return; + } + // send status to host + DataIn(); + } + } + else { + // absorb zero-length status message + iChunk = USBHwEPRead(0x00, NULL, 0); + DBG(iChunk > 0 ? "?" : ""); + } + } + } + else if (bEP == 0x80) { + // IN transfer + // send more data if available (possibly a 0-length packet) + DataIn(); + } + else { + ASSERT(FALSE); + } +} + + +/** + Registers a callback for handling requests + + @param [in] iType Type of request, e.g. REQTYPE_TYPE_STANDARD + @param [in] *pfnHandler Callback function pointer + @param [in] *pbDataStore Data storage area for this type of request + */ +void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore) +{ + ASSERT(iType >= 0); + ASSERT(iType < 4); + apfnReqHandlers[iType] = pfnHandler; + apbDataStore[iType] = pbDataStore; +} + diff --git a/VCOM_lib/usbdebug.h b/VCOM_lib/usbdebug.h new file mode 100644 index 0000000..bb3fb15 --- /dev/null +++ b/VCOM_lib/usbdebug.h @@ -0,0 +1,44 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// CodeRed - comment out this printf, as will use real one from stdio.h +// to implement output via semihosting + +//int printf(const char *format, ...); +# include + +// CodeRed - added DEBUG_MESSAGES, so still get output for Release builds +//#define DEBUG_MESSAGES 1 +//#ifdef DEBUG +#ifdef DEBUG_MESSAGES +#define DBG printf +#define ASSERT(x) if(!(x)){DBG("\nAssertion '%s' failed in %s:%s#%d!\n",#x,__FILE__,__FUNCTION__,__LINE__);while(1);} +#else +#define DBG(x ...) +#define ASSERT(x) +#endif + diff --git a/VCOM_lib/usbhw_lpc.c b/VCOM_lib/usbhw_lpc.c new file mode 100644 index 0000000..44a5713 --- /dev/null +++ b/VCOM_lib/usbhw_lpc.c @@ -0,0 +1,627 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + USB hardware layer + */ + +// CodeRed - include the LPCUSB type.h file rather than NXP one directly +//#include "type.h" +#include "lpcusb_type.h" + +#include "usbdebug.h" +#include "usbhw_lpc.h" +#include "usbapi.h" +// Configure LED pin functions +// +// LED pin functions +// +// Function Pin Port Bits Pin Select Register +// ------------------- --- ----- ---- ------------------- +// P2.0 GPIO Port 2.0 xx P2.0 1:0 PINSEL4 +// P2.1 GPIO Port 2.1 xx P2.1 3:2 PINSEL4 +// P2.2 GPIO Port 2.2 xx P2.2 5:4 PINSEL4 +// P2.3 GPIO Port 2.3 xx P2.3 7:6 PINSEL4 +// P2.4 GPIO Port 2.4 xx P2.4 9:8 PINSEL4 +// P2.5 GPIO Port 2.5 xx P2.5 11:10 PINSEL4 +// P2.6 GPIO Port 2.6 xx P2.6 13:12 PINSEL4 +// P2.7 GPIO Port 2.7 xx P2.7 15:14 PINSEL4 +// +// OFF - LED state 0 +// ON - LED state 1 +// +// '*' as GPIO + +#define NO_LEDS 8 + +#define LED_0 (1 << 0) +#define LED_1 (1 << 1) +#define LED_2 (1 << 2) +#define LED_3 (1 << 3) +#define LED_4 (1 << 4) +#define LED_5 (1 << 5) +#define LED_6 (1 << 6) +#define LED_7 (1 << 7) + +#ifdef DEBUG +// comment out the following line if you don't want to use debug LEDs +//#define DEBUG_LED +#endif + +#ifdef DEBUG_LED +#define DEBUG_LED_ON(x) FIO2SET = (1 << x); +#define DEBUG_LED_OFF(x) FIO2CLR = (1 << x); +#define DEBUG_LED_INIT(x) PINSEL2 &= ~(0x3 << (2*x)); FIO2DIR |= (1 << x); DEBUG_LED_OFF(x); +#else +#define DEBUG_LED_INIT(x) /**< LED initialisation macro */ +#define DEBUG_LED_ON(x) /**< turn LED on */ +#define DEBUG_LED_OFF(x) /**< turn LED off */ +#endif + +/** Installed device interrupt handler */ +static TFnDevIntHandler *_pfnDevIntHandler = NULL; +/** Installed endpoint interrupt handlers */ +static TFnEPIntHandler *_apfnEPIntHandlers[16]; +/** Installed frame interrupt handlers */ +static TFnFrameHandler *_pfnFrameHandler = NULL; + +/** convert from endpoint address to endpoint index */ +#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7)) +/** convert from endpoint index to endpoint address */ +#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF)) + + + +/** + Local function to wait for a device interrupt (and clear it) + + @param [in] dwIntr Bitmask of interrupts to wait for + */ +static void Wait4DevInt(U32 dwIntr) +{ + // wait for specific interrupt + while ((LPC_USB->USBDevIntSt & dwIntr) != dwIntr); + // clear the interrupt bits + LPC_USB->USBDevIntClr = dwIntr; +} + + +/** + Local function to send a command to the USB protocol engine + + @param [in] bCmd Command to send + */ +static void USBHwCmd(U8 bCmd) +{ + // clear CDFULL/CCEMTY + LPC_USB->USBDevIntClr = CDFULL | CCEMTY; + // write command code + LPC_USB->USBCmdCode = 0x00000500 | (bCmd << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command + data to the USB protocol engine + + @param [in] bCmd Command to send + @param [in] bData Data to send + */ +static void USBHwCmdWrite(U8 bCmd, U16 bData) +{ + // write command code + USBHwCmd(bCmd); + + // write command data + LPC_USB->USBCmdCode = 0x00000100 | (bData << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command to the USB protocol engine and read data + + @param [in] bCmd Command to send + + @return the data + */ +static U8 USBHwCmdRead(U8 bCmd) +{ + // write command code + USBHwCmd(bCmd); + + // get data + LPC_USB->USBCmdCode = 0x00000200 | (bCmd << 16); + Wait4DevInt(CDFULL); + return LPC_USB->USBCmdData; +} + + +/** + 'Realizes' an endpoint, meaning that buffer space is reserved for + it. An endpoint needs to be realised before it can be used. + + From experiments, it appears that a USB reset causes USBReEP to + re-initialise to 3 (= just the control endpoints). + However, a USB bus reset does not disturb the USBMaxPSize settings. + + @param [in] idx Endpoint index + @param [in] wMaxPSize Maximum packet size for this endpoint + */ +static void USBHwEPRealize(int idx, U16 wMaxPSize) +{ + LPC_USB->USBReEP |= (1 << idx); + LPC_USB->USBEpInd = idx; + LPC_USB->USBMaxPSize = wMaxPSize; + Wait4DevInt(EP_RLZED); +} + + +/** + Enables or disables an endpoint + + @param [in] idx Endpoint index + @param [in] fEnable TRUE to enable, FALSE to disable + */ +static void USBHwEPEnable(int idx, BOOL fEnable) +{ + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA); +} + + +/** + Configures an endpoint and enables it + + @param [in] bEP Endpoint number + @param [in] wMaxPacketSize Maximum packet size for this EP + */ +void USBHwEPConfig(U8 bEP, U16 wMaxPacketSize) +{ + int idx; + + idx = EP2IDX(bEP); + + // realise EP + USBHwEPRealize(idx, wMaxPacketSize); + + // enable EP + USBHwEPEnable(idx, TRUE); +} + + +/** + Registers an endpoint event callback + + @param [in] bEP Endpoint number + @param [in] pfnHandler Callback function + */ +void USBHwRegisterEPIntHandler(U8 bEP, TFnEPIntHandler *pfnHandler) +{ + int idx; + + idx = EP2IDX(bEP); + + ASSERT(idx<32); + + /* add handler to list of EP handlers */ + _apfnEPIntHandlers[idx / 2] = pfnHandler; + + /* enable EP interrupt */ + LPC_USB->USBEpIntEn |= (1 << idx); + LPC_USB->USBDevIntEn |= EP_SLOW; + + DBG("Registered handler for EP 0x%x\n", bEP); +} + + +/** + Registers an device status callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler) +{ + _pfnDevIntHandler = pfnHandler; + + // enable device interrupt + LPC_USB->USBDevIntEn |= DEV_STAT; + + DBG("Registered handler for device status\n"); +} + + +/** + Registers the frame callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler) +{ + _pfnFrameHandler = pfnHandler; + + // enable device interrupt + LPC_USB->USBDevIntEn |= FRAME; + + DBG("Registered handler for frame\n"); +} + + +/** + Sets the USB address. + + @param [in] bAddr Device address to set + */ +void USBHwSetAddress(U8 bAddr) +{ + USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr); +} + + +/** + Connects or disconnects from the USB bus + + @param [in] fConnect If TRUE, connect, otherwise disconnect + */ +void USBHwConnect(BOOL fConnect) +{ + USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0); +} + + +/** + Enables interrupt on NAK condition + + For IN endpoints a NAK is generated when the host wants to read data + from the device, but none is available in the endpoint buffer. + For OUT endpoints a NAK is generated when the host wants to write data + to the device, but the endpoint buffer is still full. + + The endpoint interrupt handlers can distinguish regular (ACK) interrupts + from NAK interrupt by checking the bits in their bEPStatus argument. + + @param [in] bIntBits Bitmap indicating which NAK interrupts to enable + */ +void USBHwNakIntEnable(U8 bIntBits) +{ + USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits); +} + + +/** + Gets the status from a specific endpoint. + + @param [in] bEP Endpoint number + @return Endpoint status byte (containing EP_STATUS_xxx bits) + */ +U8 USBHwEPGetStatus(U8 bEP) +{ + int idx = EP2IDX(bEP); + + return USBHwCmdRead(CMD_EP_SELECT | idx); +} + + +/** + Sets the stalled property of an endpoint + + @param [in] bEP Endpoint number + @param [in] fStall TRUE to stall, FALSE to unstall + */ +void USBHwEPStall(U8 bEP, BOOL fStall) +{ + int idx = EP2IDX(bEP); + + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0); +} + + +/** + Writes data to an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iLen Number of bytes to write + + @return TRUE if the data was successfully written or <0 in case of error. +*/ +int USBHwEPWrite(U8 bEP, U8 *pbBuf, int iLen) +{ + int idx; + + idx = EP2IDX(bEP); + + // set write enable for specific endpoint + LPC_USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2); + + // set packet length + LPC_USB->USBTxPLen = iLen; + + // write data + while (LPC_USB->USBCtrl & WR_EN) { + LPC_USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0]; + pbBuf += 4; + } + + // select endpoint and validate buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_VALIDATE_BUFFER); + + return iLen; +} + + +/** + Reads data from an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iMaxLen Maximum number of bytes to read + + @return the number of bytes available in the EP (possibly more than iMaxLen), + or <0 in case of error. + */ +int USBHwEPRead(U8 bEP, U8 *pbBuf, int iMaxLen) +{ + int i, idx; + U32 dwData, dwLen; + + idx = EP2IDX(bEP); + + // set read enable bit for specific endpoint + LPC_USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2); + + // wait for PKT_RDY + do { + dwLen = LPC_USB->USBRxPLen; + } while ((dwLen & PKT_RDY) == 0); + + // packet valid? + if ((dwLen & DV) == 0) { + return -1; + } + + // get length + dwLen &= PKT_LNGTH_MASK; + + // get data + dwData = 0; + for (i = 0; i < (int)dwLen; i++) { + if ((i % 4) == 0) { + dwData = LPC_USB->USBRxData; + } + if ((pbBuf != NULL) && (i < iMaxLen)) { + pbBuf[i] = dwData & 0xFF; + } + dwData >>= 8; + } + + // make sure RD_EN is clear + LPC_USB->USBCtrl = 0; + + // select endpoint and clear buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_CLEAR_BUFFER); + + return dwLen; +} + + +/** + Sets the 'configured' state. + + All registered endpoints are 'realised' and enabled, and the + 'configured' bit is set in the device status register. + + @param [in] fConfigured If TRUE, configure device, else unconfigure + */ +void USBHwConfigDevice(BOOL fConfigured) +{ + // set configured bit + USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0); +} + + +/** + USB interrupt handler + + @todo Get all 11 bits of frame number instead of just 8 + + Endpoint interrupts are mapped to the slow interrupt + */ +void USBHwISR(void) +{ + U32 dwStatus; + U32 dwIntBit; + U8 bEPStat, bDevStat, bStat; + int i; + U16 wFrame; + + // LED9 monitors total time in interrupt routine + DEBUG_LED_ON(6); + + // handle device interrupts + dwStatus = LPC_USB->USBDevIntSt; + + // frame interrupt + if (dwStatus & FRAME) { + // clear int + LPC_USB->USBDevIntClr = FRAME; + // call handler + if (_pfnFrameHandler != NULL) { + wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR); + _pfnFrameHandler(wFrame); + } + } + + // device status interrupt + if (dwStatus & DEV_STAT) { + /* Clear DEV_STAT interrupt before reading DEV_STAT register. + This prevents corrupted device status reads, see + LPC2148 User manual revision 2, 25 july 2006. + */ + LPC_USB->USBDevIntClr = DEV_STAT; + bDevStat = USBHwCmdRead(CMD_DEV_STATUS); + if (bDevStat & (CON_CH | SUS_CH | RST)) { + // convert device status into something HW independent + bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) | + ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) | + ((bDevStat & RST) ? DEV_STATUS_RESET : 0); + // call handler + if (_pfnDevIntHandler != NULL) { + DEBUG_LED_ON(5); + _pfnDevIntHandler(bStat); + DEBUG_LED_OFF(5); + } + } + } + + // endpoint interrupt + if (dwStatus & EP_SLOW) { + // clear EP_SLOW + LPC_USB->USBDevIntClr = EP_SLOW; + // check all endpoints + for (i = 0; i < 32; i++) { + dwIntBit = (1 << i); + if (LPC_USB->USBEpIntSt & dwIntBit) { + // clear int (and retrieve status) + LPC_USB->USBEpIntClr = dwIntBit; + Wait4DevInt(CDFULL); + bEPStat = LPC_USB->USBCmdData; + // convert EP pipe stat into something HW independent + bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) | + ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) | + ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) | + ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) | + ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0); + // call handler + if (_apfnEPIntHandlers[i / 2] != NULL) { + DEBUG_LED_ON(7); + _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat); + DEBUG_LED_OFF(7); + } + } + } + } + + DEBUG_LED_OFF(6); +} + + + +/** + Initialises the USB hardware + + This function assumes that the hardware is connected as shown in + section 10.1 of the LPC2148 data sheet: + * P0.31 controls a switch to connect a 1.5k pull-up to D+ if low. + * P0.23 is connected to USB VCC. + + Embedded artists board: make sure to disconnect P0.23 LED as it + acts as a pull-up and so prevents detection of USB disconnect. + + @return TRUE if the hardware was successfully initialised + */ +BOOL USBHwInit(void) +{ +/* CodeRed - comment out original code + * + // configure P0.23 for Vbus sense + PINSEL1 = (PINSEL1 & ~(3 << 14)) | (1 << 14); // P0.23 + // configure P0.31 for CONNECT + PINSEL1 = (PINSEL1 & ~(3 << 30)) | (2 << 30); // P0.31 +*/ + + // CodeRed - set up USB pins + + // P2.9 -> USB_CONNECT + LPC_PINCON->PINSEL4 &= ~0x000C0000; + LPC_PINCON->PINSEL4 |= 0x00040000; + + // P1.18 -> USB_UP_LED + // P1.30 -> VBUS + LPC_PINCON->PINSEL3 &= ~0x30000030; + LPC_PINCON->PINSEL3 |= 0x20000010; + + // P0.29 -> USB_D+ + // P0.30 -> USB_D- + LPC_PINCON->PINSEL1 &= ~0x3C000000; + LPC_PINCON->PINSEL1 |= 0x14000000; + + + // enable PUSB + LPC_SC->PCONP |= (1 << 31); + +/* CodeRed - Comment out original PLL code + * PLL now set up by NXP code in target.c within example projects + * + // initialise PLL + PLL1CON = 1; // enable PLL + PLL1CFG = (1 << 5) | 3; // P = 2, M = 4 + PLL1FEED = 0xAA; + PLL1FEED = 0x55; + while ((PLL1STAT & (1 << 10)) == 0); + + PLL1CON = 3; // enable and connect + PLL1FEED = 0xAA; + PLL1FEED = 0x55; + +*/ + + +// AWB added USB clock enable +// These are actually the USBClkCtrl and USBClkSt registers +// OTG_CLK_CTRL = 0x12; /* Dev clock, AHB clock enable */ +// while ((OTG_CLK_STAT & 0x12) != 0x12); + + LPC_USB->USBClkCtrl = 0x1A; /* Dev clock, AHB clock enable */ + while ((LPC_USB->USBClkSt & 0x1A) != 0x1A); + + + // disable/clear all interrupts for now + LPC_USB->USBDevIntEn = 0; + LPC_USB->USBDevIntClr = 0xFFFFFFFF; + LPC_USB->USBDevIntPri = 0; + + LPC_USB->USBEpIntEn = 0; + LPC_USB->USBEpIntClr = 0xFFFFFFFF; + LPC_USB->USBEpIntPri = 0; + + // by default, only ACKs generate interrupts + USBHwNakIntEnable(0); + + // CodeRed - commented out LEDs - not used by current port + // init debug leds + /* + DEBUG_LED_INIT(5); + DEBUG_LED_INIT(6); + DEBUG_LED_INIT(7); + */ + + return TRUE; +} + diff --git a/VCOM_lib/usbhw_lpc.h b/VCOM_lib/usbhw_lpc.h new file mode 100644 index 0000000..b2071d1 --- /dev/null +++ b/VCOM_lib/usbhw_lpc.h @@ -0,0 +1,148 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** + Hardware definitions for the LPC176x USB controller + + These are private to the usbhw module +*/ + +// CodeRed - pull in defines from NXP header file +#include "LPC17xx.h" + + +// CodeRed - these registers have been renamed on LPC176x +#define USBReEP USBReEp +#define OTG_CLK_CTRL USBClkCtrl +#define OTG_CLK_STAT USBClkSt + +/* USBIntSt bits */ +#define USB_INT_REQ_LP (1<<0) +#define USB_INT_REQ_HP (1<<1) +#define USB_INT_REQ_DMA (1<<2) +#define USB_need_clock (1<<8) +#define EN_USB_BITS (1<<31) + +/* USBDevInt... bits */ +#define FRAME (1<<0) +#define EP_FAST (1<<1) +#define EP_SLOW (1<<2) +#define DEV_STAT (1<<3) +#define CCEMTY (1<<4) +#define CDFULL (1<<5) +#define RxENDPKT (1<<6) +#define TxENDPKT (1<<7) +#define EP_RLZED (1<<8) +#define ERR_INT (1<<9) + +/* USBRxPLen bits */ +#define PKT_LNGTH (1<<0) +#define PKT_LNGTH_MASK 0x3FF +#define DV (1<<10) +#define PKT_RDY (1<<11) + +/* USBCtrl bits */ +#define RD_EN (1<<0) +#define WR_EN (1<<1) +#define LOG_ENDPOINT (1<<2) + +/* protocol engine command codes */ + /* device commands */ +#define CMD_DEV_SET_ADDRESS 0xD0 +#define CMD_DEV_CONFIG 0xD8 +#define CMD_DEV_SET_MODE 0xF3 +#define CMD_DEV_READ_CUR_FRAME_NR 0xF5 +#define CMD_DEV_READ_TEST_REG 0xFD +#define CMD_DEV_STATUS 0xFE /* read/write */ +#define CMD_DEV_GET_ERROR_CODE 0xFF +#define CMD_DEV_READ_ERROR_STATUS 0xFB + /* endpoint commands */ +#define CMD_EP_SELECT 0x00 +#define CMD_EP_SELECT_CLEAR 0x40 +#define CMD_EP_SET_STATUS 0x40 +#define CMD_EP_CLEAR_BUFFER 0xF2 +#define CMD_EP_VALIDATE_BUFFER 0xFA + +/* set address command */ +#define DEV_ADDR (1<<0) +#define DEV_EN (1<<7) + +/* configure device command */ +#define CONF_DEVICE (1<<0) + +/* set mode command */ +#define AP_CLK (1<<0) +#define INAK_CI (1<<1) +#define INAK_CO (1<<2) +#define INAK_II (1<<3) +#define INAK_IO (1<<4) +#define INAK_BI (1<<5) +#define INAK_BO (1<<6) + +/* set get device status command */ +#define CON (1<<0) +#define CON_CH (1<<1) +#define SUS (1<<2) +#define SUS_CH (1<<3) +#define RST (1<<4) + +/* get error code command */ +// ... + +/* Select Endpoint command read bits */ +#define EPSTAT_FE (1<<0) +#define EPSTAT_ST (1<<1) +#define EPSTAT_STP (1<<2) +#define EPSTAT_PO (1<<3) +#define EPSTAT_EPN (1<<4) +#define EPSTAT_B1FULL (1<<5) +#define EPSTAT_B2FULL (1<<6) + +/* CMD_EP_SET_STATUS command */ +#define EP_ST (1<<0) +#define EP_DA (1<<5) +#define EP_RF_MO (1<<6) +#define EP_CND_ST (1<<7) + +/* read error status command */ +#define PID_ERR (1<<0) +#define UEPKT (1<<1) +#define DCRC (1<<2) +#define TIMEOUT (1<<3) +#define EOP (1<<4) +#define B_OVRN (1<<5) +#define BTSTF (1<<6) +#define TGL_ERR (1<<7) + + + + + + + + diff --git a/VCOM_lib/usbinit.c b/VCOM_lib/usbinit.c new file mode 100644 index 0000000..90b9341 --- /dev/null +++ b/VCOM_lib/usbinit.c @@ -0,0 +1,85 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + USB stack initialisation + */ + +// CodeRed - include the LPCUSB type.h file rather than NXP one directly +//#include "type.h" +#include "lpcusb_type.h" + +#include "usbdebug.h" +#include "usbapi.h" + + +/** data storage area for standard requests */ +static U8 abStdReqData[8]; + + +/** + USB reset handler + + @param [in] bDevStatus Device status + */ +static void HandleUsbReset(U8 bDevStatus) +{ + if (bDevStatus & DEV_STATUS_RESET) { + DBG("\n!"); + } +} + + +/** + Initialises the USB hardware and sets up the USB stack by + installing default callbacks. + + @return TRUE if initialisation was successful + */ +BOOL USBInit(void) +{ + // init hardware + USBHwInit(); + + // register bus reset handler + USBHwRegisterDevIntHandler(HandleUsbReset); + + // register control transfer handler on EP0 + USBHwRegisterEPIntHandler(0x00, USBHandleControlTransfer); + USBHwRegisterEPIntHandler(0x80, USBHandleControlTransfer); + + // setup control endpoints + USBHwEPConfig(0x00, MAX_PACKET_SIZE0); + USBHwEPConfig(0x80, MAX_PACKET_SIZE0); + + // register standard request handler + USBRegisterRequestHandler(REQTYPE_TYPE_STANDARD, USBHandleStandardRequest, abStdReqData); + + return TRUE; +} + diff --git a/VCOM_lib/usbser.inf b/VCOM_lib/usbser.inf new file mode 100644 index 0000000..1675cd6 --- /dev/null +++ b/VCOM_lib/usbser.inf @@ -0,0 +1,32 @@ +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%CodeRed% +DriverVer=05/20/2010,1.0.0.0 + +[MANUFACTURER] +%ProviderName%=DeviceList, NTx86, NTamd64 + +[DeviceList.NTx86] +%RDB1768CDC%=DriverInstall,USB\VID_FFFF&PID_0005 + +[DeviceList.NTamd64] +%RDB1768CDC%=DriverInstall,USB\VID_FFFF&PID_0005 + +[DriverInstall] +include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=LowerFilterAddReg,SerialPropPageAddReg + +[DriverInstall.Services] +include = mdmcpq.inf +AddService = usbser, 0x00000002, LowerFilter_Service_Inst + +; This adds the serial port property tab to the device properties dialog +[SerialPropPageAddReg] +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[Strings] +ProviderName = "CDC Driver" +RDB1768CDC = "LPCUSB Virtual Com Port diff --git a/VCOM_lib/usbstdreq.c b/VCOM_lib/usbstdreq.c new file mode 100644 index 0000000..237fc23 --- /dev/null +++ b/VCOM_lib/usbstdreq.c @@ -0,0 +1,434 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + Standard request handler. + + This modules handles the 'chapter 9' processing, specifically the + standard device requests in table 9-3 from the universal serial bus + specification revision 2.0 + + Specific types of devices may specify additional requests (for example + HID devices add a GET_DESCRIPTOR request for interfaces), but they + will not be part of this module. + + @todo some requests have to return a request error if device not configured: + @todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME + @todo this applies to the following if endpoint != 0: + @todo SET_FEATURE, GET_FEATURE +*/ + +// CodeRed - include the LPCUSB type.h file rather than NXP one directly +//#include "type.h" +#include "lpcusb_type.h" + +#include "usbdebug.h" +#include "usbstruct.h" +#include "usbapi.h" + +#define MAX_DESC_HANDLERS 4 /**< device, interface, endpoint, other */ + + +/* general descriptor field offsets */ +#define DESC_bLength 0 /**< length offset */ +#define DESC_bDescriptorType 1 /**< descriptor type offset */ + +/* config descriptor field offsets */ +#define CONF_DESC_wTotalLength 2 /**< total length offset */ +#define CONF_DESC_bConfigurationValue 5 /**< configuration value offset */ +#define CONF_DESC_bmAttributes 7 /**< configuration characteristics */ + +/* interface descriptor field offsets */ +#define INTF_DESC_bAlternateSetting 3 /**< alternate setting offset */ + +/* endpoint descriptor field offsets */ +#define ENDP_DESC_bEndpointAddress 2 /**< endpoint address offset */ +#define ENDP_DESC_wMaxPacketSize 4 /**< maximum packet size offset */ + + +/** Currently selected configuration */ +static U8 bConfiguration = 0; +/** Installed custom request handler */ +static TFnHandleRequest *pfnHandleCustomReq = NULL; +/** Pointer to registered descriptors */ +static const U8 *pabDescrip = NULL; + + +/** + Registers a pointer to a descriptor block containing all descriptors + for the device. + + @param [in] pabDescriptors The descriptor byte array + */ +void USBRegisterDescriptors(const U8 *pabDescriptors) +{ + pabDescrip = pabDescriptors; +} + + +/** + Parses the list of installed USB descriptors and attempts to find + the specified USB descriptor. + + @param [in] wTypeIndex Type and index of the descriptor + @param [in] wLangID Language ID of the descriptor (currently unused) + @param [out] *piLen Descriptor length + @param [out] *ppbData Descriptor data + + @return TRUE if the descriptor was found, FALSE otherwise + */ +BOOL USBGetDescriptor(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData) +{ + U8 bType, bIndex; + U8 *pab; + int iCurIndex; + wLangID = wLangID; + ASSERT(pabDescrip != NULL); + + bType = GET_DESC_TYPE(wTypeIndex); + bIndex = GET_DESC_INDEX(wTypeIndex); + + pab = (U8 *)pabDescrip; + iCurIndex = 0; + + while (pab[DESC_bLength] != 0) { + if (pab[DESC_bDescriptorType] == bType) { + if (iCurIndex == bIndex) { + // set data pointer + *ppbData = pab; + // get length from structure + if (bType == DESC_CONFIGURATION) { + // configuration descriptor is an exception, length is at offset 2 and 3 + *piLen = (pab[CONF_DESC_wTotalLength]) | + (pab[CONF_DESC_wTotalLength + 1] << 8); + } + else { + // normally length is at offset 0 + *piLen = pab[DESC_bLength]; + } + return TRUE; + } + iCurIndex++; + } + // skip to next descriptor + pab += pab[DESC_bLength]; + } + // nothing found + DBG("Desc %x not found!\n", wTypeIndex); + return FALSE; +} + + +/** + Configures the device according to the specified configuration index and + alternate setting by parsing the installed USB descriptor list. + A configuration index of 0 unconfigures the device. + + @param [in] bConfigIndex Configuration index + @param [in] bAltSetting Alternate setting number + + @todo function always returns TRUE, add stricter checking? + + @return TRUE if successfully configured, FALSE otherwise + */ +static BOOL USBSetConfiguration(U8 bConfigIndex, U8 bAltSetting) +{ + U8 *pab; + U8 bCurConfig, bCurAltSetting; + U8 bEP; + U16 wMaxPktSize; + + ASSERT(pabDescrip != NULL); + + if (bConfigIndex == 0) { + // unconfigure device + USBHwConfigDevice(FALSE); + } + else { + // configure endpoints for this configuration/altsetting + pab = (U8 *)pabDescrip; + bCurConfig = 0xFF; + bCurAltSetting = 0xFF; + + while (pab[DESC_bLength] != 0) { + + switch (pab[DESC_bDescriptorType]) { + + case DESC_CONFIGURATION: + // remember current configuration index + bCurConfig = pab[CONF_DESC_bConfigurationValue]; + break; + + case DESC_INTERFACE: + // remember current alternate setting + bCurAltSetting = pab[INTF_DESC_bAlternateSetting]; + break; + + case DESC_ENDPOINT: + if ((bCurConfig == bConfigIndex) && + (bCurAltSetting == bAltSetting)) { + // endpoint found for desired config and alternate setting + bEP = pab[ENDP_DESC_bEndpointAddress]; + wMaxPktSize = (pab[ENDP_DESC_wMaxPacketSize]) | + (pab[ENDP_DESC_wMaxPacketSize + 1] << 8); + // configure endpoint + USBHwEPConfig(bEP, wMaxPktSize); + } + break; + + default: + break; + } + // skip to next descriptor + pab += pab[DESC_bLength]; + } + + // configure device + USBHwConfigDevice(TRUE); + } + + return TRUE; +} + + +/** + Local function to handle a standard device request + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in,out] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, U8 **ppbData) +{ + U8 *pbData = *ppbData; + + switch (pSetup->bRequest) { + + case REQ_GET_STATUS: + // bit 0: self-powered + // bit 1: remote wakeup = not supported + pbData[0] = 0; + pbData[1] = 0; + *piLen = 2; + break; + + case REQ_SET_ADDRESS: + USBHwSetAddress(pSetup->wValue); + break; + + case REQ_GET_DESCRIPTOR: + DBG("D%x", pSetup->wValue); + return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData); + + case REQ_GET_CONFIGURATION: + // indicate if we are configured + pbData[0] = bConfiguration; + *piLen = 1; + break; + + case REQ_SET_CONFIGURATION: + if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) { + DBG("USBSetConfiguration failed!\n"); + return FALSE; + } + // configuration successful, update current configuration + bConfiguration = pSetup->wValue & 0xFF; + break; + + case REQ_CLEAR_FEATURE: + case REQ_SET_FEATURE: + if (pSetup->wValue == FEA_REMOTE_WAKEUP) { + // put DEVICE_REMOTE_WAKEUP code here + } + if (pSetup->wValue == FEA_TEST_MODE) { + // put TEST_MODE code here + } + return FALSE; + + case REQ_SET_DESCRIPTOR: + DBG("Device req %d not implemented\n", pSetup->bRequest); + return FALSE; + + default: + DBG("Illegal device req %d\n", pSetup->bRequest); + return FALSE; + } + + return TRUE; +} + + +/** + Local function to handle a standard interface request + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +static BOOL HandleStdInterfaceReq(TSetupPacket *pSetup, int *piLen, U8 **ppbData) +{ + U8 *pbData = *ppbData; + + switch (pSetup->bRequest) { + + case REQ_GET_STATUS: + // no bits specified + pbData[0] = 0; + pbData[1] = 0; + *piLen = 2; + break; + + case REQ_CLEAR_FEATURE: + case REQ_SET_FEATURE: + // not defined for interface + return FALSE; + + case REQ_GET_INTERFACE: // TODO use bNumInterfaces + // there is only one interface, return n-1 (= 0) + pbData[0] = 0; + *piLen = 1; + break; + + case REQ_SET_INTERFACE: // TODO use bNumInterfaces + // there is only one interface (= 0) + if (pSetup->wValue != 0) { + return FALSE; + } + *piLen = 0; + break; + + default: + DBG("Illegal interface req %d\n", pSetup->bRequest); + return FALSE; + } + + return TRUE; +} + + +/** + Local function to handle a standard endpoint request + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +static BOOL HandleStdEndPointReq(TSetupPacket *pSetup, int *piLen, U8 **ppbData) +{ + U8 *pbData = *ppbData; + + switch (pSetup->bRequest) { + case REQ_GET_STATUS: + // bit 0 = endpointed halted or not + pbData[0] = (USBHwEPGetStatus(pSetup->wIndex) & EP_STATUS_STALLED) ? 1 : 0; + pbData[1] = 0; + *piLen = 2; + break; + + case REQ_CLEAR_FEATURE: + if (pSetup->wValue == FEA_ENDPOINT_HALT) { + // clear HALT by unstalling + USBHwEPStall(pSetup->wIndex, FALSE); + break; + } + // only ENDPOINT_HALT defined for endpoints + return FALSE; + + case REQ_SET_FEATURE: + if (pSetup->wValue == FEA_ENDPOINT_HALT) { + // set HALT by stalling + USBHwEPStall(pSetup->wIndex, TRUE); + break; + } + // only ENDPOINT_HALT defined for endpoints + return FALSE; + + case REQ_SYNCH_FRAME: + DBG("EP req %d not implemented\n", pSetup->bRequest); + return FALSE; + + default: + DBG("Illegal EP req %d\n", pSetup->bRequest); + return FALSE; + } + + return TRUE; +} + + +/** + Default handler for standard ('chapter 9') requests + + If a custom request handler was installed, this handler is called first. + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) +{ + // try the custom request handler first + if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) { + return TRUE; + } + + switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) { + case REQTYPE_RECIP_DEVICE: return HandleStdDeviceReq(pSetup, piLen, ppbData); + case REQTYPE_RECIP_INTERFACE: return HandleStdInterfaceReq(pSetup, piLen, ppbData); + case REQTYPE_RECIP_ENDPOINT: return HandleStdEndPointReq(pSetup, piLen, ppbData); + default: return FALSE; + } +} + + +/** + Registers a callback for custom device requests + + In USBHandleStandardRequest, the custom request handler gets a first + chance at handling the request before it is handed over to the 'chapter 9' + request handler. + + This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR + request is sent to an interface, which is not covered by the 'chapter 9' + specification. + + @param [in] pfnHandler Callback function pointer + */ +void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler) +{ + pfnHandleCustomReq = pfnHandler; +} + diff --git a/VCOM_lib/usbstruct.h b/VCOM_lib/usbstruct.h new file mode 100644 index 0000000..b30e524 --- /dev/null +++ b/VCOM_lib/usbstruct.h @@ -0,0 +1,121 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** + Definitions of structures of standard USB packets +*/ + +#ifndef _USBSTRUCT_H_ +#define _USBSTRUCT_H_ + +// CodeRed - include the LPCUSB type.h file rather than NXP one directly +//#include "type.h" +#include "lpcusb_type.h" + + +/** setup packet definitions */ +typedef struct { + U8 bmRequestType; /**< characteristics of the specific request */ + U8 bRequest; /**< specific request */ + U16 wValue; /**< request specific parameter */ + U16 wIndex; /**< request specific parameter */ + U16 wLength; /**< length of data transfered in data phase */ +} TSetupPacket; + + +#define REQTYPE_GET_DIR(x) (((x)>>7)&0x01) +#define REQTYPE_GET_TYPE(x) (((x)>>5)&0x03) +#define REQTYPE_GET_RECIP(x) ((x)&0x1F) + +#define REQTYPE_DIR_TO_DEVICE 0 +#define REQTYPE_DIR_TO_HOST 1 + +#define REQTYPE_TYPE_STANDARD 0 +#define REQTYPE_TYPE_CLASS 1 +#define REQTYPE_TYPE_VENDOR 2 +#define REQTYPE_TYPE_RESERVED 3 + +#define REQTYPE_RECIP_DEVICE 0 +#define REQTYPE_RECIP_INTERFACE 1 +#define REQTYPE_RECIP_ENDPOINT 2 +#define REQTYPE_RECIP_OTHER 3 + +/* standard requests */ +#define REQ_GET_STATUS 0x00 +#define REQ_CLEAR_FEATURE 0x01 +#define REQ_SET_FEATURE 0x03 +#define REQ_SET_ADDRESS 0x05 +#define REQ_GET_DESCRIPTOR 0x06 +#define REQ_SET_DESCRIPTOR 0x07 +#define REQ_GET_CONFIGURATION 0x08 +#define REQ_SET_CONFIGURATION 0x09 +#define REQ_GET_INTERFACE 0x0A +#define REQ_SET_INTERFACE 0x0B +#define REQ_SYNCH_FRAME 0x0C + +/* class requests HID */ +#define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 +#define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0A +#define HID_SET_PROTOCOL 0x0B + +/* feature selectors */ +#define FEA_ENDPOINT_HALT 0x00 +#define FEA_REMOTE_WAKEUP 0x01 +#define FEA_TEST_MODE 0x02 + +/* + USB descriptors +*/ + +/** USB descriptor header */ +typedef struct { + U8 bLength; /**< descriptor length */ + U8 bDescriptorType; /**< descriptor type */ +} TUSBDescHeader; + +#define DESC_DEVICE 1 +#define DESC_CONFIGURATION 2 +#define DESC_STRING 3 +#define DESC_INTERFACE 4 +#define DESC_ENDPOINT 5 +#define DESC_DEVICE_QUALIFIER 6 +#define DESC_OTHER_SPEED 7 +#define DESC_INTERFACE_POWER 8 + +#define DESC_HID_HID 0x21 +#define DESC_HID_REPORT 0x22 +#define DESC_HID_PHYSICAL 0x23 + +#define GET_DESC_TYPE(x) (((x)>>8)&0xFF) +#define GET_DESC_INDEX(x) ((x)&0xFF) + +#endif /* _USBSTRUCT_H_ */ +