firmware/cdc.c
author root@rika
Thu, 23 Apr 2009 20:55:41 +0200
changeset 33 7a0c4b0354ba
parent 2 2f55e5dd591d
permissions -rw-r--r--
updated documentation
     1 /*********************************************************************
     2  *
     3  *             Microchip USB C18 Firmware -  CDC Version 1.0
     4  *
     5  *********************************************************************
     6  * FileName:        cdc.c
     7  * Dependencies:    See INCLUDES section below
     8  * Processor:       PIC18
     9  * Compiler:        C18 2.30.01+
    10  * Company:         Microchip Technology, Inc.
    11  *
    12  * Software License Agreement
    13  *
    14  * The software supplied herewith by Microchip Technology Incorporated
    15  * (the “Company”) for its PICmicro® Microcontroller is intended and
    16  * supplied to you, the Company’s customer, for use solely and
    17  * exclusively on Microchip PICmicro Microcontroller products. The
    18  * software is owned by the Company and/or its supplier, and is
    19  * protected under applicable copyright laws. All rights are reserved.
    20  * Any use in violation of the foregoing restrictions may subject the
    21  * user to criminal sanctions under applicable laws, as well as to
    22  * civil liability for the breach of the terms and conditions of this
    23  * license.
    24  *
    25  * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
    26  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
    27  * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    28  * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
    29  * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
    30  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
    31  *
    32  * Author               Date        Comment
    33  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    34  * Rawin Rojvanit       11/19/04    Original. RS-232 Emulation Subset
    35  ********************************************************************/
    36 
    37 /** I N C L U D E S **********************************************************/
    38 #include <p18cxxx.h>
    39 #include "typedefs.h"
    40 #include "usb.h"
    41 
    42 #ifdef USB_USE_CDC
    43 
    44 /** V A R I A B L E S ********************************************************/
    45 #pragma udata
    46 byte cdc_rx_len;            // total rx length
    47 
    48 byte cdc_trf_state;         // States are defined cdc.h
    49 POINTER pCDCSrc;            // Dedicated source pointer
    50 POINTER pCDCDst;            // Dedicated destination pointer
    51 byte cdc_tx_len;            // total tx length
    52 byte cdc_mem_type;          // _ROM, _RAM
    53 
    54 LINE_CODING line_coding;    // Buffer to store line coding information
    55 CONTROL_SIGNAL_BITMAP control_signal_bitmap;
    56 
    57 /*
    58  * SEND_ENCAPSULATED_COMMAND and GET_ENCAPSULATED_RESPONSE are required
    59  * requests according to the CDC specification.
    60  * However, it is not really being used here, therefore a dummy buffer is
    61  * used for conformance.
    62  */
    63 #define dummy_length    0x08
    64 byte dummy_encapsulated_cmd_response[dummy_length];
    65 
    66 /** P R I V A T E  P R O T O T Y P E S ***************************************/
    67 
    68 /** D E C L A R A T I O N S **************************************************/
    69 #pragma code
    70 
    71 /** C L A S S  S P E C I F I C  R E Q ****************************************/
    72 /******************************************************************************
    73  * Function:        void USBCheckCDCRequest(void)
    74  *
    75  * PreCondition:    None
    76  *
    77  * Input:           None
    78  *
    79  * Output:          None
    80  *
    81  * Side Effects:    None
    82  *
    83  * Overview:        This routine checks the setup data packet to see if it
    84  *                  knows how to handle it
    85  *
    86  * Note:            None
    87  *****************************************************************************/
    88 void USBCheckCDCRequest(void)
    89 {
    90     /*
    91      * If request recipient is not an interface then return
    92      */
    93     if(SetupPkt.Recipient != RCPT_INTF) return;
    94 
    95     /*
    96      * If request type is not class-specific then return
    97      */
    98     if(SetupPkt.RequestType != CLASS) return;
    99 
   100     /*
   101      * Interface ID must match interface numbers associated with
   102      * CDC class, else return
   103      */
   104     if((SetupPkt.bIntfID != CDC_COMM_INTF_ID)&&
   105        (SetupPkt.bIntfID != CDC_DATA_INTF_ID)) return;
   106     
   107     switch(SetupPkt.bRequest)
   108     {
   109         case SEND_ENCAPSULATED_COMMAND:
   110             ctrl_trf_session_owner = MUID_CDC;
   111             pSrc.bRam = (byte*)&dummy_encapsulated_cmd_response;
   112             usb_stat.ctrl_trf_mem = _RAM;
   113             LSB(wCount) = dummy_length;
   114             break;
   115         case GET_ENCAPSULATED_RESPONSE:
   116             ctrl_trf_session_owner = MUID_CDC;
   117             // Populate dummy_encapsulated_cmd_response first.
   118             pDst.bRam = (byte*)&dummy_encapsulated_cmd_response;
   119             break;
   120         case SET_COMM_FEATURE:                  // Optional
   121             break;
   122         case GET_COMM_FEATURE:                  // Optional
   123             break;
   124         case CLEAR_COMM_FEATURE:                // Optional
   125             break;
   126         case SET_LINE_CODING:
   127             ctrl_trf_session_owner = MUID_CDC;
   128             pDst.bRam = (byte*)&line_coding;    // Set destination
   129             break;
   130         case GET_LINE_CODING:
   131             ctrl_trf_session_owner = MUID_CDC;
   132             pSrc.bRam = (byte*)&line_coding;    // Set source
   133             usb_stat.ctrl_trf_mem = _RAM;       // Set memory type
   134             LSB(wCount) = LINE_CODING_LENGTH;   // Set data count
   135             break;
   136         case SET_CONTROL_LINE_STATE:
   137             ctrl_trf_session_owner = MUID_CDC;
   138             control_signal_bitmap._byte = LSB(SetupPkt.W_Value);
   139             break;
   140         case SEND_BREAK:                        // Optional
   141             break;
   142         default:
   143             break;
   144     }//end switch(SetupPkt.bRequest)
   145 
   146 }//end USBCheckCDCRequest
   147 
   148 /** U S E R  A P I ***********************************************************/
   149 
   150 /******************************************************************************
   151  * Function:        void CDCInitEP(void)
   152  *
   153  * PreCondition:    None
   154  *
   155  * Input:           None
   156  *
   157  * Output:          None
   158  *
   159  * Side Effects:    None
   160  *
   161  * Overview:        CDCInitEP initializes CDC endpoints, buffer descriptors,
   162  *                  internal state-machine, and variables.
   163  *                  It should be called after the USB host has sent out a
   164  *                  SET_CONFIGURATION request.
   165  *                  See USBStdSetCfgHandler() in usb9.c for examples.
   166  *
   167  * Note:            None
   168  *****************************************************************************/
   169 void CDCInitEP(void)
   170 {
   171     //Abstract line coding information
   172     line_coding.dwDTERate._dword = 115200;      // baud rate
   173     line_coding.bCharFormat = 0x00;             // 1 stop bit
   174     line_coding.bParityType = 0x00;             // None
   175     line_coding.bDataBits = 0x08;               // 5,6,7,8, or 16
   176 
   177     cdc_trf_state = CDC_TX_READY;
   178     cdc_rx_len = 0;
   179     
   180     CDC_COMM_UEP = EP_IN|HSHK_EN;               // Enable 1 Comm pipe
   181     CDC_DATA_UEP = EP_OUT_IN|HSHK_EN;           // Enable 2 data pipes
   182 
   183     /*
   184      * Do not have to init Cnt of IN pipes here.
   185      * Reason:  Number of bytes to send to the host
   186      *          varies from one transaction to
   187      *          another. Cnt should equal the exact
   188      *          number of bytes to transmit for
   189      *          a given IN transaction.
   190      *          This number of bytes will only
   191      *          be known right before the data is
   192      *          sent.
   193      */
   194     CDC_INT_BD_IN.ADR = (byte*)&cdc_notice;     // Set buffer address
   195     CDC_INT_BD_IN.Stat._byte = _UCPU|_DAT1;     // Set status
   196 
   197     CDC_BULK_BD_OUT.Cnt = sizeof(cdc_data_rx);  // Set buffer size
   198     CDC_BULK_BD_OUT.ADR = (byte*)&cdc_data_rx;  // Set buffer address
   199     CDC_BULK_BD_OUT.Stat._byte = _USIE|_DAT0|_DTSEN;// Set status
   200 
   201     CDC_BULK_BD_IN.ADR = (byte*)&cdc_data_tx;   // Set buffer size
   202     CDC_BULK_BD_IN.Stat._byte = _UCPU|_DAT1;    // Set buffer address
   203 
   204 }//end CDCInitEP
   205 
   206 /******************************************************************************
   207  * Function:        byte getsUSBUSART(char *buffer,
   208  *                                    byte len)
   209  *
   210  * PreCondition:    Value of input argument 'len' should be smaller than the
   211  *                  maximum endpoint size responsible for receiving bulk
   212  *                  data from USB host for CDC class.
   213  *                  Input argument 'buffer' should point to a buffer area that
   214  *                  is bigger or equal to the size specified by 'len'.
   215  *
   216  * Input:           buffer  : Pointer to where received bytes are to be stored
   217  *                  len     : The number of bytes expected.
   218  *
   219  * Output:          The number of bytes copied to buffer.
   220  *
   221  * Side Effects:    Publicly accessible variable cdc_rx_len is updated with
   222  *                  the number of bytes copied to buffer.
   223  *                  Once getsUSBUSART is called, subsequent retrieval of
   224  *                  cdc_rx_len can be done by calling macro mCDCGetRxLength().
   225  *
   226  * Overview:        getsUSBUSART copies a string of bytes received through
   227  *                  USB CDC Bulk OUT endpoint to a user's specified location. 
   228  *                  It is a non-blocking function. It does not wait
   229  *                  for data if there is no data available. Instead it returns
   230  *                  '0' to notify the caller that there is no data available.
   231  *
   232  * Note:            If the actual number of bytes received is larger than the
   233  *                  number of bytes expected (len), only the expected number
   234  *                  of bytes specified will be copied to buffer.
   235  *                  If the actual number of bytes received is smaller than the
   236  *                  number of bytes expected (len), only the actual number
   237  *                  of bytes received will be copied to buffer.
   238  *****************************************************************************/
   239 byte getsUSBUSART(char *buffer, byte len)
   240 {
   241     cdc_rx_len = 0;
   242     
   243     if(!mCDCUsartRxIsBusy())
   244     {
   245         /*
   246          * Adjust the expected number of bytes to equal
   247          * the actual number of bytes received.
   248          */
   249         if(len > CDC_BULK_BD_OUT.Cnt)
   250             len = CDC_BULK_BD_OUT.Cnt;
   251         
   252         /*
   253          * Copy data from dual-ram buffer to user's buffer
   254          */
   255         for(cdc_rx_len = 0; cdc_rx_len < len; cdc_rx_len++)
   256             buffer[cdc_rx_len] = cdc_data_rx[cdc_rx_len];
   257 
   258         /*
   259          * Prepare dual-ram buffer for next OUT transaction
   260          */
   261         CDC_BULK_BD_OUT.Cnt = sizeof(cdc_data_rx);
   262         mUSBBufferReady(CDC_BULK_BD_OUT);
   263     }//end if
   264     
   265     return cdc_rx_len;
   266     
   267 }//end getsUSBUSART
   268 
   269 /******************************************************************************
   270  * Function:        void putsUSBUSART(char *data)
   271  *
   272  * PreCondition:    cdc_trf_state must be in the CDC_TX_READY state.
   273  *                  
   274  *                  The string of characters pointed to by 'data' must equal
   275  *                  to or smaller than 255 bytes.
   276  *
   277  * Input:           data    : Pointer to a null-terminated string of data.
   278  *                            If a null character is not found, 255 bytes
   279  *                            of data will be transferred to the host.
   280  *
   281  * Output:          None
   282  *
   283  * Side Effects:    None
   284  *
   285  * Overview:        putsUSBUSART writes a string of data to the USB including
   286  *                  the null character. Use this version, 'puts', to transfer
   287  *                  data located in data memory.
   288  *
   289  * Note:            The transfer mechanism for device-to-host(put) is more
   290  *                  flexible than host-to-device(get). It can handle
   291  *                  a string of data larger than the maximum size of bulk IN
   292  *                  endpoint. A state machine is used to transfer a long
   293  *                  string of data over multiple USB transactions.
   294  *                  See CDCTxService() for more details.
   295  *****************************************************************************/
   296 void putsUSBUSART(char *data)
   297 {
   298     byte len;
   299 
   300     /*
   301      * User should have checked that cdc_trf_state is in CDC_TX_READY state
   302      * before calling this function.
   303      * As a safety precaution, this fuction checks the state one more time
   304      * to make sure it does not override any pending transactions.
   305      *
   306      * Currently it just quits the routine without reporting any errors back
   307      * to the user.
   308      *
   309      * Bottomline: User MUST make sure that mUSBUSARTIsTxTrfReady()==1
   310      *             before calling this function!
   311      * Example:
   312      * if(mUSBUSARTIsTxTrfReady())
   313      *     putsUSBUSART(pData);
   314      *
   315      * IMPORTANT: Never use the following blocking while loop to wait:
   316      * while(!mUSBUSARTIsTxTrfReady())
   317      *     putsUSBUSART(pData);
   318      *
   319      * The whole firmware framework is written based on cooperative
   320      * multi-tasking and a blocking code is not acceptable.
   321      * Use a state machine instead.
   322      */
   323     if(cdc_trf_state != CDC_TX_READY) return;
   324     
   325     /*
   326      * While loop counts the number of bytes to send including the
   327      * null character.
   328      */
   329     len = 0;
   330     do
   331     {
   332         len++;
   333         if(len == 255) break;       // Break loop once max len is reached.
   334     }while(*data++);
   335     
   336     /*
   337      * Re-adjust pointer to its initial location
   338      */
   339     data-=len;
   340     
   341     /*
   342      * Second piece of information (length of data to send) is ready.
   343      * Call mUSBUSARTTxRam to setup the transfer.
   344      * The actual transfer process will be handled by CDCTxService(),
   345      * which should be called once per Main Program loop.
   346      */
   347     mUSBUSARTTxRam((byte*)data,len);     // See cdc.h
   348 }//end putsUSBUSART
   349 
   350 /******************************************************************************
   351  * Function:        void putrsUSBUSART(const rom char *data)
   352  *
   353  * PreCondition:    cdc_trf_state must be in the CDC_TX_READY state.
   354  *                  
   355  *                  The string of characters pointed to by 'data' must equal
   356  *                  to or smaller than 255 bytes.
   357  *
   358  * Input:           data    : Pointer to a null-terminated string of data.
   359  *                            If a null character is not found, 255 bytes
   360  *                            of data will be transferred to the host.
   361  *
   362  * Output:          None
   363  *
   364  * Side Effects:    None
   365  *
   366  * Overview:        putrsUSBUSART writes a string of data to the USB including
   367  *                  the null character. Use this version, 'putrs', to transfer
   368  *                  data literals and data located in program memory.
   369  *
   370  * Note:            The transfer mechanism for device-to-host(put) is more
   371  *                  flexible than host-to-device(get). It can handle
   372  *                  a string of data larger than the maximum size of bulk IN
   373  *                  endpoint. A state machine is used to transfer a long
   374  *                  string of data over multiple USB transactions.
   375  *                  See CDCTxService() for more details.
   376  *****************************************************************************/
   377 void putrsUSBUSART(const rom char *data)
   378 {
   379     byte len;
   380 
   381     /*
   382      * User should have checked that cdc_trf_state is in CDC_TX_READY state
   383      * before calling this function.
   384      * As a safety precaution, this fuction checks the state one more time
   385      * to make sure it does not override any pending transactions.
   386      *
   387      * Currently it just quits the routine without reporting any errors back
   388      * to the user.
   389      *
   390      * Bottomline: User MUST make sure that mUSBUSARTIsTxTrfReady()
   391      *             before calling this function!
   392      * Example:
   393      * if(mUSBUSARTIsTxTrfReady())
   394      *     putsUSBUSART(pData);
   395      *
   396      * IMPORTANT: Never use the following blocking while loop to wait:
   397      * while(cdc_trf_state != CDC_TX_READY)
   398      *     putsUSBUSART(pData);
   399      *
   400      * The whole firmware framework is written based on cooperative
   401      * multi-tasking and a blocking code is not acceptable.
   402      * Use a state machine instead.
   403      */
   404     if(cdc_trf_state != CDC_TX_READY) return;
   405     
   406     /*
   407      * While loop counts the number of bytes to send including the
   408      * null character.
   409      */
   410     len = 0;
   411     do
   412     {
   413         len++;
   414         if(len == 255) break;       // Break loop once max len is reached.
   415     }while(*data++);
   416     
   417     /*
   418      * Re-adjust pointer to its initial location
   419      */
   420     data-=len;
   421     
   422     /*
   423      * Second piece of information (length of data to send) is ready.
   424      * Call mUSBUSARTTxRom to setup the transfer.
   425      * The actual transfer process will be handled by CDCTxService(),
   426      * which should be called once per Main Program loop.
   427      */
   428     mUSBUSARTTxRom((rom byte*)data,len); // See cdc.h
   429 
   430 }//end putrsUSBUSART
   431 
   432 /******************************************************************************
   433  * Function:        void CDCTxService(void)
   434  *
   435  * PreCondition:    None
   436  *
   437  * Input:           None
   438  *
   439  * Output:          None
   440  *
   441  * Side Effects:    None
   442  *
   443  * Overview:        CDCTxService handles device-to-host transaction(s).
   444  *                  This function should be called once per Main Program loop.
   445  *
   446  * Note:            None
   447  *****************************************************************************/
   448 void CDCTxService(void)
   449 {
   450     byte byte_to_send;
   451     
   452     if(mCDCUsartTxIsBusy()) return;
   453     /*
   454      * Completing stage is necessary while [ mCDCUSartTxIsBusy()==1 ].
   455      * By having this stage, user can always check cdc_trf_state,
   456      * and not having to call mCDCUsartTxIsBusy() directly.
   457      */
   458     if(cdc_trf_state == CDC_TX_COMPLETING)
   459         cdc_trf_state = CDC_TX_READY;
   460     
   461     /*
   462      * If CDC_TX_READY state, nothing to do, just return.
   463      */
   464     if(cdc_trf_state == CDC_TX_READY) return;
   465     
   466     /*
   467      * If CDC_TX_BUSY_ZLP state, send zero length packet
   468      */
   469     if(cdc_trf_state == CDC_TX_BUSY_ZLP)
   470     {
   471         CDC_BULK_BD_IN.Cnt = 0;
   472         cdc_trf_state = CDC_TX_COMPLETING;
   473     }
   474     else if(cdc_trf_state == CDC_TX_BUSY)
   475     {
   476         /*
   477          * First, have to figure out how many byte of data to send.
   478          */
   479     	if(cdc_tx_len > sizeof(cdc_data_tx))
   480     	    byte_to_send = sizeof(cdc_data_tx);
   481     	else
   482     	    byte_to_send = cdc_tx_len;
   483 
   484         /*
   485          * Next, load the number of bytes to send to Cnt in buffer descriptor
   486          */
   487         CDC_BULK_BD_IN.Cnt = byte_to_send;
   488 
   489         /*
   490          * Subtract the number of bytes just about to be sent from the total.
   491          */
   492     	cdc_tx_len = cdc_tx_len - byte_to_send;
   493     	        
   494         pCDCDst.bRam = (byte*)&cdc_data_tx; // Set destination pointer
   495         
   496         if(cdc_mem_type == _ROM)            // Determine type of memory source
   497         {
   498             while(byte_to_send)
   499             {
   500                 *pCDCDst.bRam = *pCDCSrc.bRom;
   501                 pCDCDst.bRam++;
   502                 pCDCSrc.bRom++;
   503                 byte_to_send--;
   504             }//end while(byte_to_send)
   505         }
   506         else // _RAM
   507         {
   508             while(byte_to_send)
   509             {
   510                 *pCDCDst.bRam = *pCDCSrc.bRam;
   511                 pCDCDst.bRam++;
   512                 pCDCSrc.bRam++;
   513                 byte_to_send--;
   514             }//end while(byte_to_send._word)
   515         }//end if(cdc_mem_type...)
   516         
   517         /*
   518          * Lastly, determine if a zero length packet state is necessary.
   519          * See explanation in USB Specification 2.0: Section 5.8.3
   520          */
   521         if(cdc_tx_len == 0)
   522         {
   523             if(CDC_BULK_BD_IN.Cnt == sizeof(cdc_data_tx))
   524                 cdc_trf_state = CDC_TX_BUSY_ZLP;
   525             else
   526                 cdc_trf_state = CDC_TX_COMPLETING;
   527         }//end if(cdc_tx_len...)
   528             
   529     }//end if(cdc_tx_sate == CDC_TX_BUSY)
   530     
   531     /*
   532      * Both CDC_TX_BUSY and CDC_TX_BUSY_ZLP states use the following macro
   533      */
   534     mUSBBufferReady(CDC_BULK_BD_IN);
   535 
   536 }//end CDCTxService
   537 
   538 #endif //USB_USE_CDC
   539 
   540 /** EOF cdc.c ****************************************************************/