/**************************************************************************/ /*! @file cdc.c @author hathach (tinyusb.org) @section LICENSE Software License Agreement (BSD License) Copyright (c) 2013, hathach (tinyusb.org) All rights reserved. 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. Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 COPYRIGHT HOLDER 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. This file is part of the tinyusb stack. */ /**************************************************************************/ #include "cdc.h" #include "common/fifo.h" #if defined TUSB_CFG_DEVICE_CDC && defined TUSB_CFG_DEVICE static USBD_HANDLE_T g_hCdc; static CDC_LINE_CODING line_coding; static uint8_t qBuffer[2][CDC_BUFFER_SIZE]; /* TX and RX buffers */ static fifo_t ffTX, ffRX; void usb_cdc_recv_isr(void) ATTR_WEAK ATTR_ALIAS(usb_cdc_recv_isr_stub); /**************************************************************************/ /*! @brief Stub for the optional CDC receive ISR that can be used to perform some action when data arrives via USB CDC */ /**************************************************************************/ void usb_cdc_recv_isr_stub (void) { return; } /**************************************************************************/ /*! @brief Adds a single byte to the transmit buffer for USB CDC @param[in] c The byte to send @returns TRUE if the byte was successfully added to the TX buffer @note See example for tusb_cdc_getc */ /**************************************************************************/ bool tusb_cdc_putc (uint8_t c) { return fifo_write(&ffTX, c); } /**************************************************************************/ /*! @brief Reads a single byte from the USB CDC buffer @param[in] c Pointer to the location where the byte should be written @returns TRUE if a byte was read from the buffer @section EXAMPLE @code // Convert incoming characters to upper case and send back via CDC if (usb_isConfigured()) { uint8_t cdc_char; if( tusb_cdc_getc(&cdc_char) ) { switch (cdc_char) { default : cdc_char = toupper(cdc_char); tusb_cdc_putc(cdc_char); break; } } } @endcode */ /**************************************************************************/ bool tusb_cdc_getc(uint8_t *c) { ASSERT(c, false); // not empty pointer return fifo_read(&ffRX, c); } /**************************************************************************/ /*! @brief Writes the supplied buffer to the USB CDC device @param[in] buffer Pointer to the buffer that should be written via USB CDC @param[in] count The number of bytes to write @returns The actual number of bytes sent out via USB CDC @section EXAMPLE @code // Capture printf output (in Red Suite) and send it to USB CDC // (Note: With newlib this function should be renamed to _write) int __sys_write(int file, char *ptr, int len) { #ifdef CFG_PRINTF_USBCDC // Handle USB CDC output if (usb_isConfigured()) { int length = len; while(length > 0) { uint16_t transferredCount; transferredCount = tusb_cdc_send( (uint8_t*) ptr, length); ptr += transferredCount; length -= transferredCount; } } #endif return len; } @endcode */ /**************************************************************************/ uint16_t tusb_cdc_send(uint8_t* buffer, uint16_t count) { uint16_t i=0; ASSERT(buffer && count, 0); while (i < count && fifo_write(&ffTX, buffer[i]) ) { i++; } return i; } /**************************************************************************/ /*! @brief Reads the incoming CDC buffer up to a maximum number of bytes @param[in] buffer Pointer to the buffer where data should be written @param[in] max The maximum number of bytes to read @returns The actual number of bytes received */ /**************************************************************************/ uint16_t tusb_cdc_recv(uint8_t* buffer, uint16_t max) { ASSERT(buffer && max, 0); return fifo_read_n(&ffRX, buffer, max); } #if 0 // ROM driver bug: cannot hook this to CIC_GetRequest // Need this to implement GetLineCode & detect ErrorCode_t CDC_Control_GetRequest(USBD_HANDLE_T hUsb, USB_SETUP_PACKET *pSetup, uint8_t **pBuffer, uint16_t *length) { return LPC_OK; } #endif /**************************************************************************/ /*! @brief TODO Add description */ /**************************************************************************/ ErrorCode_t CDC_SetLineCoding(USBD_HANDLE_T hUsb, CDC_LINE_CODING *lineCoding) { ASSERT(lineCoding, ERR_FAILED); memcpy(&line_coding, lineCoding, sizeof(CDC_LINE_CODING)); return LPC_OK; } /**************************************************************************/ /*! @brief TODO Add description */ /**************************************************************************/ ErrorCode_t CDC_SendBreak(USBD_HANDLE_T hCDC, uint16_t mstime) { return LPC_OK; } /**************************************************************************/ /*! @brief Bulk Out handler for the USB ROM drivers (UART TX) */ /**************************************************************************/ ErrorCode_t CDC_BulkIn_Hdlr(USBD_HANDLE_T hUsb, void* data, uint32_t event) { if (USB_EVT_IN == event) { uint8_t buffer[CDC_DATA_EP_MAXPACKET_SIZE]; uint16_t count; count = fifo_read_n(&ffTX, buffer, CDC_DATA_EP_MAXPACKET_SIZE); ROM_API->hw->WriteEP(hUsb, CDC_DATA_EP_IN, buffer, count); // write data to EP } return LPC_OK; } /**************************************************************************/ /*! @brief Bulk Out handler for the USB ROM drivers (UART RX) */ /**************************************************************************/ ErrorCode_t CDC_BulkOut_Hdlr(USBD_HANDLE_T hUsb, void* data, uint32_t event) { if (USB_EVT_OUT == event) { uint16_t count, i; uint8_t buffer[CDC_DATA_EP_MAXPACKET_SIZE]; count = ROM_API->hw->ReadEP(hUsb, CDC_DATA_EP_OUT, buffer); for (i=0; icore->RegisterEpHandler (hUsb , ((CDC_DATA_EP_IN & 0x0F) << 1) +1 , CDC_BulkIn_Hdlr , NULL), TUSB_ERROR_FAILED ); ASSERT ( LPC_OK == ROM_API->core->RegisterEpHandler (hUsb , (CDC_DATA_EP_OUT & 0x0F) << 1 , CDC_BulkOut_Hdlr , NULL), TUSB_ERROR_FAILED ); ASSERT ( LPC_OK == ROM_API->cdc->init(hUsb, &cdc_param, &g_hCdc), TUSB_ERROR_FAILED); /* update memory variables */ *mem_base = cdc_param.mem_base; *mem_size = cdc_param.mem_size; return TUSB_ERROR_NONE; } /**************************************************************************/ /*! @brief TODO Add description */ /**************************************************************************/ tusb_error_t tusb_cdc_configured(USBD_HANDLE_T hUsb) { uint8_t dummy=0; ROM_API->hw->WriteEP(hUsb, CDC_DATA_EP_IN, &dummy, 1); // initial packet for IN endpoint, will not work if omitted // FIXME abstract to hal #if MCU == MCU_LPC11UXX fifo_init (&ffTX, qBuffer[0], CDC_BUFFER_SIZE, false, USB_IRQn); // TX is non-overwritable fifo_init (&ffRX, qBuffer[1], CDC_BUFFER_SIZE, true, USB_IRQn); // RX is overwritable #elif MCU == MCU_LPC13UXX fifo_init (&ffTX, qBuffer[0], CDC_BUFFER_SIZE, false, USB_IRQ_IRQn); // TX is non-overwritable fifo_init (&ffRX, qBuffer[1], CDC_BUFFER_SIZE, true, USB_IRQ_IRQn); // RX is overwritable #elif MCU == MCU_LPC43XX fifo_init (&ffTX, qBuffer[0], CDC_BUFFER_SIZE, false, USB0_IRQn); // TODO USB1 TX is non-overwritable fifo_init (&ffRX, qBuffer[1], CDC_BUFFER_SIZE, true, USB0_IRQn); // RX is overwritable #else #error No MCU defined // TODO asbtract MCU #endif return TUSB_ERROR_NONE; } #endif