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 ****************************************************************/