firmware/cdc.c
changeset 2 2f55e5dd591d
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/firmware/cdc.c	Tue Jan 29 22:31:52 2008 +0100
     1.3 @@ -0,0 +1,540 @@
     1.4 +/*********************************************************************
     1.5 + *
     1.6 + *             Microchip USB C18 Firmware -  CDC Version 1.0
     1.7 + *
     1.8 + *********************************************************************
     1.9 + * FileName:        cdc.c
    1.10 + * Dependencies:    See INCLUDES section below
    1.11 + * Processor:       PIC18
    1.12 + * Compiler:        C18 2.30.01+
    1.13 + * Company:         Microchip Technology, Inc.
    1.14 + *
    1.15 + * Software License Agreement
    1.16 + *
    1.17 + * The software supplied herewith by Microchip Technology Incorporated
    1.18 + * (the “Company”) for its PICmicro® Microcontroller is intended and
    1.19 + * supplied to you, the Company’s customer, for use solely and
    1.20 + * exclusively on Microchip PICmicro Microcontroller products. The
    1.21 + * software is owned by the Company and/or its supplier, and is
    1.22 + * protected under applicable copyright laws. All rights are reserved.
    1.23 + * Any use in violation of the foregoing restrictions may subject the
    1.24 + * user to criminal sanctions under applicable laws, as well as to
    1.25 + * civil liability for the breach of the terms and conditions of this
    1.26 + * license.
    1.27 + *
    1.28 + * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
    1.29 + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
    1.30 + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    1.31 + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
    1.32 + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
    1.33 + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
    1.34 + *
    1.35 + * Author               Date        Comment
    1.36 + *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1.37 + * Rawin Rojvanit       11/19/04    Original. RS-232 Emulation Subset
    1.38 + ********************************************************************/
    1.39 +
    1.40 +/** I N C L U D E S **********************************************************/
    1.41 +#include <p18cxxx.h>
    1.42 +#include "typedefs.h"
    1.43 +#include "usb.h"
    1.44 +
    1.45 +#ifdef USB_USE_CDC
    1.46 +
    1.47 +/** V A R I A B L E S ********************************************************/
    1.48 +#pragma udata
    1.49 +byte cdc_rx_len;            // total rx length
    1.50 +
    1.51 +byte cdc_trf_state;         // States are defined cdc.h
    1.52 +POINTER pCDCSrc;            // Dedicated source pointer
    1.53 +POINTER pCDCDst;            // Dedicated destination pointer
    1.54 +byte cdc_tx_len;            // total tx length
    1.55 +byte cdc_mem_type;          // _ROM, _RAM
    1.56 +
    1.57 +LINE_CODING line_coding;    // Buffer to store line coding information
    1.58 +CONTROL_SIGNAL_BITMAP control_signal_bitmap;
    1.59 +
    1.60 +/*
    1.61 + * SEND_ENCAPSULATED_COMMAND and GET_ENCAPSULATED_RESPONSE are required
    1.62 + * requests according to the CDC specification.
    1.63 + * However, it is not really being used here, therefore a dummy buffer is
    1.64 + * used for conformance.
    1.65 + */
    1.66 +#define dummy_length    0x08
    1.67 +byte dummy_encapsulated_cmd_response[dummy_length];
    1.68 +
    1.69 +/** P R I V A T E  P R O T O T Y P E S ***************************************/
    1.70 +
    1.71 +/** D E C L A R A T I O N S **************************************************/
    1.72 +#pragma code
    1.73 +
    1.74 +/** C L A S S  S P E C I F I C  R E Q ****************************************/
    1.75 +/******************************************************************************
    1.76 + * Function:        void USBCheckCDCRequest(void)
    1.77 + *
    1.78 + * PreCondition:    None
    1.79 + *
    1.80 + * Input:           None
    1.81 + *
    1.82 + * Output:          None
    1.83 + *
    1.84 + * Side Effects:    None
    1.85 + *
    1.86 + * Overview:        This routine checks the setup data packet to see if it
    1.87 + *                  knows how to handle it
    1.88 + *
    1.89 + * Note:            None
    1.90 + *****************************************************************************/
    1.91 +void USBCheckCDCRequest(void)
    1.92 +{
    1.93 +    /*
    1.94 +     * If request recipient is not an interface then return
    1.95 +     */
    1.96 +    if(SetupPkt.Recipient != RCPT_INTF) return;
    1.97 +
    1.98 +    /*
    1.99 +     * If request type is not class-specific then return
   1.100 +     */
   1.101 +    if(SetupPkt.RequestType != CLASS) return;
   1.102 +
   1.103 +    /*
   1.104 +     * Interface ID must match interface numbers associated with
   1.105 +     * CDC class, else return
   1.106 +     */
   1.107 +    if((SetupPkt.bIntfID != CDC_COMM_INTF_ID)&&
   1.108 +       (SetupPkt.bIntfID != CDC_DATA_INTF_ID)) return;
   1.109 +    
   1.110 +    switch(SetupPkt.bRequest)
   1.111 +    {
   1.112 +        case SEND_ENCAPSULATED_COMMAND:
   1.113 +            ctrl_trf_session_owner = MUID_CDC;
   1.114 +            pSrc.bRam = (byte*)&dummy_encapsulated_cmd_response;
   1.115 +            usb_stat.ctrl_trf_mem = _RAM;
   1.116 +            LSB(wCount) = dummy_length;
   1.117 +            break;
   1.118 +        case GET_ENCAPSULATED_RESPONSE:
   1.119 +            ctrl_trf_session_owner = MUID_CDC;
   1.120 +            // Populate dummy_encapsulated_cmd_response first.
   1.121 +            pDst.bRam = (byte*)&dummy_encapsulated_cmd_response;
   1.122 +            break;
   1.123 +        case SET_COMM_FEATURE:                  // Optional
   1.124 +            break;
   1.125 +        case GET_COMM_FEATURE:                  // Optional
   1.126 +            break;
   1.127 +        case CLEAR_COMM_FEATURE:                // Optional
   1.128 +            break;
   1.129 +        case SET_LINE_CODING:
   1.130 +            ctrl_trf_session_owner = MUID_CDC;
   1.131 +            pDst.bRam = (byte*)&line_coding;    // Set destination
   1.132 +            break;
   1.133 +        case GET_LINE_CODING:
   1.134 +            ctrl_trf_session_owner = MUID_CDC;
   1.135 +            pSrc.bRam = (byte*)&line_coding;    // Set source
   1.136 +            usb_stat.ctrl_trf_mem = _RAM;       // Set memory type
   1.137 +            LSB(wCount) = LINE_CODING_LENGTH;   // Set data count
   1.138 +            break;
   1.139 +        case SET_CONTROL_LINE_STATE:
   1.140 +            ctrl_trf_session_owner = MUID_CDC;
   1.141 +            control_signal_bitmap._byte = LSB(SetupPkt.W_Value);
   1.142 +            break;
   1.143 +        case SEND_BREAK:                        // Optional
   1.144 +            break;
   1.145 +        default:
   1.146 +            break;
   1.147 +    }//end switch(SetupPkt.bRequest)
   1.148 +
   1.149 +}//end USBCheckCDCRequest
   1.150 +
   1.151 +/** U S E R  A P I ***********************************************************/
   1.152 +
   1.153 +/******************************************************************************
   1.154 + * Function:        void CDCInitEP(void)
   1.155 + *
   1.156 + * PreCondition:    None
   1.157 + *
   1.158 + * Input:           None
   1.159 + *
   1.160 + * Output:          None
   1.161 + *
   1.162 + * Side Effects:    None
   1.163 + *
   1.164 + * Overview:        CDCInitEP initializes CDC endpoints, buffer descriptors,
   1.165 + *                  internal state-machine, and variables.
   1.166 + *                  It should be called after the USB host has sent out a
   1.167 + *                  SET_CONFIGURATION request.
   1.168 + *                  See USBStdSetCfgHandler() in usb9.c for examples.
   1.169 + *
   1.170 + * Note:            None
   1.171 + *****************************************************************************/
   1.172 +void CDCInitEP(void)
   1.173 +{
   1.174 +    //Abstract line coding information
   1.175 +    line_coding.dwDTERate._dword = 115200;      // baud rate
   1.176 +    line_coding.bCharFormat = 0x00;             // 1 stop bit
   1.177 +    line_coding.bParityType = 0x00;             // None
   1.178 +    line_coding.bDataBits = 0x08;               // 5,6,7,8, or 16
   1.179 +
   1.180 +    cdc_trf_state = CDC_TX_READY;
   1.181 +    cdc_rx_len = 0;
   1.182 +    
   1.183 +    CDC_COMM_UEP = EP_IN|HSHK_EN;               // Enable 1 Comm pipe
   1.184 +    CDC_DATA_UEP = EP_OUT_IN|HSHK_EN;           // Enable 2 data pipes
   1.185 +
   1.186 +    /*
   1.187 +     * Do not have to init Cnt of IN pipes here.
   1.188 +     * Reason:  Number of bytes to send to the host
   1.189 +     *          varies from one transaction to
   1.190 +     *          another. Cnt should equal the exact
   1.191 +     *          number of bytes to transmit for
   1.192 +     *          a given IN transaction.
   1.193 +     *          This number of bytes will only
   1.194 +     *          be known right before the data is
   1.195 +     *          sent.
   1.196 +     */
   1.197 +    CDC_INT_BD_IN.ADR = (byte*)&cdc_notice;     // Set buffer address
   1.198 +    CDC_INT_BD_IN.Stat._byte = _UCPU|_DAT1;     // Set status
   1.199 +
   1.200 +    CDC_BULK_BD_OUT.Cnt = sizeof(cdc_data_rx);  // Set buffer size
   1.201 +    CDC_BULK_BD_OUT.ADR = (byte*)&cdc_data_rx;  // Set buffer address
   1.202 +    CDC_BULK_BD_OUT.Stat._byte = _USIE|_DAT0|_DTSEN;// Set status
   1.203 +
   1.204 +    CDC_BULK_BD_IN.ADR = (byte*)&cdc_data_tx;   // Set buffer size
   1.205 +    CDC_BULK_BD_IN.Stat._byte = _UCPU|_DAT1;    // Set buffer address
   1.206 +
   1.207 +}//end CDCInitEP
   1.208 +
   1.209 +/******************************************************************************
   1.210 + * Function:        byte getsUSBUSART(char *buffer,
   1.211 + *                                    byte len)
   1.212 + *
   1.213 + * PreCondition:    Value of input argument 'len' should be smaller than the
   1.214 + *                  maximum endpoint size responsible for receiving bulk
   1.215 + *                  data from USB host for CDC class.
   1.216 + *                  Input argument 'buffer' should point to a buffer area that
   1.217 + *                  is bigger or equal to the size specified by 'len'.
   1.218 + *
   1.219 + * Input:           buffer  : Pointer to where received bytes are to be stored
   1.220 + *                  len     : The number of bytes expected.
   1.221 + *
   1.222 + * Output:          The number of bytes copied to buffer.
   1.223 + *
   1.224 + * Side Effects:    Publicly accessible variable cdc_rx_len is updated with
   1.225 + *                  the number of bytes copied to buffer.
   1.226 + *                  Once getsUSBUSART is called, subsequent retrieval of
   1.227 + *                  cdc_rx_len can be done by calling macro mCDCGetRxLength().
   1.228 + *
   1.229 + * Overview:        getsUSBUSART copies a string of bytes received through
   1.230 + *                  USB CDC Bulk OUT endpoint to a user's specified location. 
   1.231 + *                  It is a non-blocking function. It does not wait
   1.232 + *                  for data if there is no data available. Instead it returns
   1.233 + *                  '0' to notify the caller that there is no data available.
   1.234 + *
   1.235 + * Note:            If the actual number of bytes received is larger than the
   1.236 + *                  number of bytes expected (len), only the expected number
   1.237 + *                  of bytes specified will be copied to buffer.
   1.238 + *                  If the actual number of bytes received is smaller than the
   1.239 + *                  number of bytes expected (len), only the actual number
   1.240 + *                  of bytes received will be copied to buffer.
   1.241 + *****************************************************************************/
   1.242 +byte getsUSBUSART(char *buffer, byte len)
   1.243 +{
   1.244 +    cdc_rx_len = 0;
   1.245 +    
   1.246 +    if(!mCDCUsartRxIsBusy())
   1.247 +    {
   1.248 +        /*
   1.249 +         * Adjust the expected number of bytes to equal
   1.250 +         * the actual number of bytes received.
   1.251 +         */
   1.252 +        if(len > CDC_BULK_BD_OUT.Cnt)
   1.253 +            len = CDC_BULK_BD_OUT.Cnt;
   1.254 +        
   1.255 +        /*
   1.256 +         * Copy data from dual-ram buffer to user's buffer
   1.257 +         */
   1.258 +        for(cdc_rx_len = 0; cdc_rx_len < len; cdc_rx_len++)
   1.259 +            buffer[cdc_rx_len] = cdc_data_rx[cdc_rx_len];
   1.260 +
   1.261 +        /*
   1.262 +         * Prepare dual-ram buffer for next OUT transaction
   1.263 +         */
   1.264 +        CDC_BULK_BD_OUT.Cnt = sizeof(cdc_data_rx);
   1.265 +        mUSBBufferReady(CDC_BULK_BD_OUT);
   1.266 +    }//end if
   1.267 +    
   1.268 +    return cdc_rx_len;
   1.269 +    
   1.270 +}//end getsUSBUSART
   1.271 +
   1.272 +/******************************************************************************
   1.273 + * Function:        void putsUSBUSART(char *data)
   1.274 + *
   1.275 + * PreCondition:    cdc_trf_state must be in the CDC_TX_READY state.
   1.276 + *                  
   1.277 + *                  The string of characters pointed to by 'data' must equal
   1.278 + *                  to or smaller than 255 bytes.
   1.279 + *
   1.280 + * Input:           data    : Pointer to a null-terminated string of data.
   1.281 + *                            If a null character is not found, 255 bytes
   1.282 + *                            of data will be transferred to the host.
   1.283 + *
   1.284 + * Output:          None
   1.285 + *
   1.286 + * Side Effects:    None
   1.287 + *
   1.288 + * Overview:        putsUSBUSART writes a string of data to the USB including
   1.289 + *                  the null character. Use this version, 'puts', to transfer
   1.290 + *                  data located in data memory.
   1.291 + *
   1.292 + * Note:            The transfer mechanism for device-to-host(put) is more
   1.293 + *                  flexible than host-to-device(get). It can handle
   1.294 + *                  a string of data larger than the maximum size of bulk IN
   1.295 + *                  endpoint. A state machine is used to transfer a long
   1.296 + *                  string of data over multiple USB transactions.
   1.297 + *                  See CDCTxService() for more details.
   1.298 + *****************************************************************************/
   1.299 +void putsUSBUSART(char *data)
   1.300 +{
   1.301 +    byte len;
   1.302 +
   1.303 +    /*
   1.304 +     * User should have checked that cdc_trf_state is in CDC_TX_READY state
   1.305 +     * before calling this function.
   1.306 +     * As a safety precaution, this fuction checks the state one more time
   1.307 +     * to make sure it does not override any pending transactions.
   1.308 +     *
   1.309 +     * Currently it just quits the routine without reporting any errors back
   1.310 +     * to the user.
   1.311 +     *
   1.312 +     * Bottomline: User MUST make sure that mUSBUSARTIsTxTrfReady()==1
   1.313 +     *             before calling this function!
   1.314 +     * Example:
   1.315 +     * if(mUSBUSARTIsTxTrfReady())
   1.316 +     *     putsUSBUSART(pData);
   1.317 +     *
   1.318 +     * IMPORTANT: Never use the following blocking while loop to wait:
   1.319 +     * while(!mUSBUSARTIsTxTrfReady())
   1.320 +     *     putsUSBUSART(pData);
   1.321 +     *
   1.322 +     * The whole firmware framework is written based on cooperative
   1.323 +     * multi-tasking and a blocking code is not acceptable.
   1.324 +     * Use a state machine instead.
   1.325 +     */
   1.326 +    if(cdc_trf_state != CDC_TX_READY) return;
   1.327 +    
   1.328 +    /*
   1.329 +     * While loop counts the number of bytes to send including the
   1.330 +     * null character.
   1.331 +     */
   1.332 +    len = 0;
   1.333 +    do
   1.334 +    {
   1.335 +        len++;
   1.336 +        if(len == 255) break;       // Break loop once max len is reached.
   1.337 +    }while(*data++);
   1.338 +    
   1.339 +    /*
   1.340 +     * Re-adjust pointer to its initial location
   1.341 +     */
   1.342 +    data-=len;
   1.343 +    
   1.344 +    /*
   1.345 +     * Second piece of information (length of data to send) is ready.
   1.346 +     * Call mUSBUSARTTxRam to setup the transfer.
   1.347 +     * The actual transfer process will be handled by CDCTxService(),
   1.348 +     * which should be called once per Main Program loop.
   1.349 +     */
   1.350 +    mUSBUSARTTxRam((byte*)data,len);     // See cdc.h
   1.351 +}//end putsUSBUSART
   1.352 +
   1.353 +/******************************************************************************
   1.354 + * Function:        void putrsUSBUSART(const rom char *data)
   1.355 + *
   1.356 + * PreCondition:    cdc_trf_state must be in the CDC_TX_READY state.
   1.357 + *                  
   1.358 + *                  The string of characters pointed to by 'data' must equal
   1.359 + *                  to or smaller than 255 bytes.
   1.360 + *
   1.361 + * Input:           data    : Pointer to a null-terminated string of data.
   1.362 + *                            If a null character is not found, 255 bytes
   1.363 + *                            of data will be transferred to the host.
   1.364 + *
   1.365 + * Output:          None
   1.366 + *
   1.367 + * Side Effects:    None
   1.368 + *
   1.369 + * Overview:        putrsUSBUSART writes a string of data to the USB including
   1.370 + *                  the null character. Use this version, 'putrs', to transfer
   1.371 + *                  data literals and data located in program memory.
   1.372 + *
   1.373 + * Note:            The transfer mechanism for device-to-host(put) is more
   1.374 + *                  flexible than host-to-device(get). It can handle
   1.375 + *                  a string of data larger than the maximum size of bulk IN
   1.376 + *                  endpoint. A state machine is used to transfer a long
   1.377 + *                  string of data over multiple USB transactions.
   1.378 + *                  See CDCTxService() for more details.
   1.379 + *****************************************************************************/
   1.380 +void putrsUSBUSART(const rom char *data)
   1.381 +{
   1.382 +    byte len;
   1.383 +
   1.384 +    /*
   1.385 +     * User should have checked that cdc_trf_state is in CDC_TX_READY state
   1.386 +     * before calling this function.
   1.387 +     * As a safety precaution, this fuction checks the state one more time
   1.388 +     * to make sure it does not override any pending transactions.
   1.389 +     *
   1.390 +     * Currently it just quits the routine without reporting any errors back
   1.391 +     * to the user.
   1.392 +     *
   1.393 +     * Bottomline: User MUST make sure that mUSBUSARTIsTxTrfReady()
   1.394 +     *             before calling this function!
   1.395 +     * Example:
   1.396 +     * if(mUSBUSARTIsTxTrfReady())
   1.397 +     *     putsUSBUSART(pData);
   1.398 +     *
   1.399 +     * IMPORTANT: Never use the following blocking while loop to wait:
   1.400 +     * while(cdc_trf_state != CDC_TX_READY)
   1.401 +     *     putsUSBUSART(pData);
   1.402 +     *
   1.403 +     * The whole firmware framework is written based on cooperative
   1.404 +     * multi-tasking and a blocking code is not acceptable.
   1.405 +     * Use a state machine instead.
   1.406 +     */
   1.407 +    if(cdc_trf_state != CDC_TX_READY) return;
   1.408 +    
   1.409 +    /*
   1.410 +     * While loop counts the number of bytes to send including the
   1.411 +     * null character.
   1.412 +     */
   1.413 +    len = 0;
   1.414 +    do
   1.415 +    {
   1.416 +        len++;
   1.417 +        if(len == 255) break;       // Break loop once max len is reached.
   1.418 +    }while(*data++);
   1.419 +    
   1.420 +    /*
   1.421 +     * Re-adjust pointer to its initial location
   1.422 +     */
   1.423 +    data-=len;
   1.424 +    
   1.425 +    /*
   1.426 +     * Second piece of information (length of data to send) is ready.
   1.427 +     * Call mUSBUSARTTxRom to setup the transfer.
   1.428 +     * The actual transfer process will be handled by CDCTxService(),
   1.429 +     * which should be called once per Main Program loop.
   1.430 +     */
   1.431 +    mUSBUSARTTxRom((rom byte*)data,len); // See cdc.h
   1.432 +
   1.433 +}//end putrsUSBUSART
   1.434 +
   1.435 +/******************************************************************************
   1.436 + * Function:        void CDCTxService(void)
   1.437 + *
   1.438 + * PreCondition:    None
   1.439 + *
   1.440 + * Input:           None
   1.441 + *
   1.442 + * Output:          None
   1.443 + *
   1.444 + * Side Effects:    None
   1.445 + *
   1.446 + * Overview:        CDCTxService handles device-to-host transaction(s).
   1.447 + *                  This function should be called once per Main Program loop.
   1.448 + *
   1.449 + * Note:            None
   1.450 + *****************************************************************************/
   1.451 +void CDCTxService(void)
   1.452 +{
   1.453 +    byte byte_to_send;
   1.454 +    
   1.455 +    if(mCDCUsartTxIsBusy()) return;
   1.456 +    /*
   1.457 +     * Completing stage is necessary while [ mCDCUSartTxIsBusy()==1 ].
   1.458 +     * By having this stage, user can always check cdc_trf_state,
   1.459 +     * and not having to call mCDCUsartTxIsBusy() directly.
   1.460 +     */
   1.461 +    if(cdc_trf_state == CDC_TX_COMPLETING)
   1.462 +        cdc_trf_state = CDC_TX_READY;
   1.463 +    
   1.464 +    /*
   1.465 +     * If CDC_TX_READY state, nothing to do, just return.
   1.466 +     */
   1.467 +    if(cdc_trf_state == CDC_TX_READY) return;
   1.468 +    
   1.469 +    /*
   1.470 +     * If CDC_TX_BUSY_ZLP state, send zero length packet
   1.471 +     */
   1.472 +    if(cdc_trf_state == CDC_TX_BUSY_ZLP)
   1.473 +    {
   1.474 +        CDC_BULK_BD_IN.Cnt = 0;
   1.475 +        cdc_trf_state = CDC_TX_COMPLETING;
   1.476 +    }
   1.477 +    else if(cdc_trf_state == CDC_TX_BUSY)
   1.478 +    {
   1.479 +        /*
   1.480 +         * First, have to figure out how many byte of data to send.
   1.481 +         */
   1.482 +    	if(cdc_tx_len > sizeof(cdc_data_tx))
   1.483 +    	    byte_to_send = sizeof(cdc_data_tx);
   1.484 +    	else
   1.485 +    	    byte_to_send = cdc_tx_len;
   1.486 +
   1.487 +        /*
   1.488 +         * Next, load the number of bytes to send to Cnt in buffer descriptor
   1.489 +         */
   1.490 +        CDC_BULK_BD_IN.Cnt = byte_to_send;
   1.491 +
   1.492 +        /*
   1.493 +         * Subtract the number of bytes just about to be sent from the total.
   1.494 +         */
   1.495 +    	cdc_tx_len = cdc_tx_len - byte_to_send;
   1.496 +    	        
   1.497 +        pCDCDst.bRam = (byte*)&cdc_data_tx; // Set destination pointer
   1.498 +        
   1.499 +        if(cdc_mem_type == _ROM)            // Determine type of memory source
   1.500 +        {
   1.501 +            while(byte_to_send)
   1.502 +            {
   1.503 +                *pCDCDst.bRam = *pCDCSrc.bRom;
   1.504 +                pCDCDst.bRam++;
   1.505 +                pCDCSrc.bRom++;
   1.506 +                byte_to_send--;
   1.507 +            }//end while(byte_to_send)
   1.508 +        }
   1.509 +        else // _RAM
   1.510 +        {
   1.511 +            while(byte_to_send)
   1.512 +            {
   1.513 +                *pCDCDst.bRam = *pCDCSrc.bRam;
   1.514 +                pCDCDst.bRam++;
   1.515 +                pCDCSrc.bRam++;
   1.516 +                byte_to_send--;
   1.517 +            }//end while(byte_to_send._word)
   1.518 +        }//end if(cdc_mem_type...)
   1.519 +        
   1.520 +        /*
   1.521 +         * Lastly, determine if a zero length packet state is necessary.
   1.522 +         * See explanation in USB Specification 2.0: Section 5.8.3
   1.523 +         */
   1.524 +        if(cdc_tx_len == 0)
   1.525 +        {
   1.526 +            if(CDC_BULK_BD_IN.Cnt == sizeof(cdc_data_tx))
   1.527 +                cdc_trf_state = CDC_TX_BUSY_ZLP;
   1.528 +            else
   1.529 +                cdc_trf_state = CDC_TX_COMPLETING;
   1.530 +        }//end if(cdc_tx_len...)
   1.531 +            
   1.532 +    }//end if(cdc_tx_sate == CDC_TX_BUSY)
   1.533 +    
   1.534 +    /*
   1.535 +     * Both CDC_TX_BUSY and CDC_TX_BUSY_ZLP states use the following macro
   1.536 +     */
   1.537 +    mUSBBufferReady(CDC_BULK_BD_IN);
   1.538 +
   1.539 +}//end CDCTxService
   1.540 +
   1.541 +#endif //USB_USE_CDC
   1.542 +
   1.543 +/** EOF cdc.c ****************************************************************/