00001 /********************************************************************* 00002 * 00003 * Microchip USB C18 Firmware - CDC Version 1.0 00004 * 00005 ********************************************************************* 00006 * FileName: cdc.c 00007 * Dependencies: See INCLUDES section below 00008 * Processor: PIC18 00009 * Compiler: C18 2.30.01+ 00010 * Company: Microchip Technology, Inc. 00011 * 00012 * Software License Agreement 00013 * 00014 * The software supplied herewith by Microchip Technology Incorporated 00015 * (the “Company”) for its PICmicro® Microcontroller is intended and 00016 * supplied to you, the Company’s customer, for use solely and 00017 * exclusively on Microchip PICmicro Microcontroller products. The 00018 * software is owned by the Company and/or its supplier, and is 00019 * protected under applicable copyright laws. All rights are reserved. 00020 * Any use in violation of the foregoing restrictions may subject the 00021 * user to criminal sanctions under applicable laws, as well as to 00022 * civil liability for the breach of the terms and conditions of this 00023 * license. 00024 * 00025 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES, 00026 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED 00027 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00028 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, 00029 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR 00030 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. 00031 * 00032 * Author Date Comment 00033 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00034 * Rawin Rojvanit 11/19/04 Original. RS-232 Emulation Subset 00035 ********************************************************************/ 00036 00037 /** I N C L U D E S **********************************************************/ 00038 #include <p18cxxx.h> 00039 #include "system\typedefs.h" 00040 #include "system\usb\usb.h" 00041 00042 #ifdef USB_USE_CDC 00043 00044 /** V A R I A B L E S ********************************************************/ 00045 #pragma udata 00046 byte cdc_rx_len; // total rx length 00047 00048 byte cdc_trf_state; // States are defined cdc.h 00049 POINTER pCDCSrc; // Dedicated source pointer 00050 POINTER pCDCDst; // Dedicated destination pointer 00051 byte cdc_tx_len; // total tx length 00052 byte cdc_mem_type; // _ROM, _RAM 00053 00054 LINE_CODING line_coding; // Buffer to store line coding information 00055 CONTROL_SIGNAL_BITMAP control_signal_bitmap; 00056 00057 /* 00058 * SEND_ENCAPSULATED_COMMAND and GET_ENCAPSULATED_RESPONSE are required 00059 * requests according to the CDC specification. 00060 * However, it is not really being used here, therefore a dummy buffer is 00061 * used for conformance. 00062 */ 00063 #define dummy_length 0x08 00064 byte dummy_encapsulated_cmd_response[dummy_length]; 00065 00066 /** P R I V A T E P R O T O T Y P E S ***************************************/ 00067 00068 /** D E C L A R A T I O N S **************************************************/ 00069 #pragma code 00070 00071 /** C L A S S S P E C I F I C R E Q ****************************************/ 00072 /****************************************************************************** 00073 * Function: void USBCheckCDCRequest(void) 00074 * 00075 * PreCondition: None 00076 * 00077 * Input: None 00078 * 00079 * Output: None 00080 * 00081 * Side Effects: None 00082 * 00083 * Overview: This routine checks the setup data packet to see if it 00084 * knows how to handle it 00085 * 00086 * Note: None 00087 *****************************************************************************/ 00088 void USBCheckCDCRequest(void) 00089 { 00090 /* 00091 * If request recipient is not an interface then return 00092 */ 00093 if(SetupPkt.Recipient != RCPT_INTF) return; 00094 00095 /* 00096 * If request type is not class-specific then return 00097 */ 00098 if(SetupPkt.RequestType != CLASS) return; 00099 00100 /* 00101 * Interface ID must match interface numbers associated with 00102 * CDC class, else return 00103 */ 00104 if((SetupPkt.bIntfID != CDC_COMM_INTF_ID)&& 00105 (SetupPkt.bIntfID != CDC_DATA_INTF_ID)) return; 00106 00107 switch(SetupPkt.bRequest) 00108 { 00109 case SEND_ENCAPSULATED_COMMAND: 00110 ctrl_trf_session_owner = MUID_CDC; 00111 pSrc.bRam = (byte*)&dummy_encapsulated_cmd_response; 00112 usb_stat.ctrl_trf_mem = _RAM; 00113 LSB(wCount) = dummy_length; 00114 break; 00115 case GET_ENCAPSULATED_RESPONSE: 00116 ctrl_trf_session_owner = MUID_CDC; 00117 // Populate dummy_encapsulated_cmd_response first. 00118 pDst.bRam = (byte*)&dummy_encapsulated_cmd_response; 00119 break; 00120 case SET_COMM_FEATURE: // Optional 00121 break; 00122 case GET_COMM_FEATURE: // Optional 00123 break; 00124 case CLEAR_COMM_FEATURE: // Optional 00125 break; 00126 case SET_LINE_CODING: 00127 ctrl_trf_session_owner = MUID_CDC; 00128 pDst.bRam = (byte*)&line_coding; // Set destination 00129 break; 00130 case GET_LINE_CODING: 00131 ctrl_trf_session_owner = MUID_CDC; 00132 pSrc.bRam = (byte*)&line_coding; // Set source 00133 usb_stat.ctrl_trf_mem = _RAM; // Set memory type 00134 LSB(wCount) = LINE_CODING_LENGTH; // Set data count 00135 break; 00136 case SET_CONTROL_LINE_STATE: 00137 ctrl_trf_session_owner = MUID_CDC; 00138 control_signal_bitmap._byte = LSB(SetupPkt.W_Value); 00139 break; 00140 case SEND_BREAK: // Optional 00141 break; 00142 default: 00143 break; 00144 }//end switch(SetupPkt.bRequest) 00145 00146 }//end USBCheckCDCRequest 00147 00148 /** U S E R A P I ***********************************************************/ 00149 00150 /****************************************************************************** 00151 * Function: void CDCInitEP(void) 00152 * 00153 * PreCondition: None 00154 * 00155 * Input: None 00156 * 00157 * Output: None 00158 * 00159 * Side Effects: None 00160 * 00161 * Overview: CDCInitEP initializes CDC endpoints, buffer descriptors, 00162 * internal state-machine, and variables. 00163 * It should be called after the USB host has sent out a 00164 * SET_CONFIGURATION request. 00165 * See USBStdSetCfgHandler() in usb9.c for examples. 00166 * 00167 * Note: None 00168 *****************************************************************************/ 00169 void CDCInitEP(void) 00170 { 00171 //Abstract line coding information 00172 line_coding.dwDTERate._dword = 115200; // baud rate 00173 line_coding.bCharFormat = 0x00; // 1 stop bit 00174 line_coding.bParityType = 0x00; // None 00175 line_coding.bDataBits = 0x08; // 5,6,7,8, or 16 00176 00177 cdc_trf_state = CDC_TX_READY; 00178 cdc_rx_len = 0; 00179 00180 CDC_COMM_UEP = EP_IN|HSHK_EN; // Enable 1 Comm pipe 00181 CDC_DATA_UEP = EP_OUT_IN|HSHK_EN; // Enable 2 data pipes 00182 00183 /* 00184 * Do not have to init Cnt of IN pipes here. 00185 * Reason: Number of bytes to send to the host 00186 * varies from one transaction to 00187 * another. Cnt should equal the exact 00188 * number of bytes to transmit for 00189 * a given IN transaction. 00190 * This number of bytes will only 00191 * be known right before the data is 00192 * sent. 00193 */ 00194 CDC_INT_BD_IN.ADR = (byte*)&cdc_notice; // Set buffer address 00195 CDC_INT_BD_IN.Stat._byte = _UCPU|_DAT1; // Set status 00196 00197 CDC_BULK_BD_OUT.Cnt = sizeof(cdc_data_rx); // Set buffer size 00198 CDC_BULK_BD_OUT.ADR = (byte*)&cdc_data_rx; // Set buffer address 00199 CDC_BULK_BD_OUT.Stat._byte = _USIE|_DAT0|_DTSEN;// Set status 00200 00201 CDC_BULK_BD_IN.ADR = (byte*)&cdc_data_tx; // Set buffer size 00202 CDC_BULK_BD_IN.Stat._byte = _UCPU|_DAT1; // Set buffer address 00203 00204 }//end CDCInitEP 00205 00206 /****************************************************************************** 00207 * Function: byte getsUSBUSART(char *buffer, 00208 * byte len) 00209 * 00210 * PreCondition: Value of input argument 'len' should be smaller than the 00211 * maximum endpoint size responsible for receiving bulk 00212 * data from USB host for CDC class. 00213 * Input argument 'buffer' should point to a buffer area that 00214 * is bigger or equal to the size specified by 'len'. 00215 * 00216 * Input: buffer : Pointer to where received bytes are to be stored 00217 * len : The number of bytes expected. 00218 * 00219 * Output: The number of bytes copied to buffer. 00220 * 00221 * Side Effects: Publicly accessible variable cdc_rx_len is updated with 00222 * the number of bytes copied to buffer. 00223 * Once getsUSBUSART is called, subsequent retrieval of 00224 * cdc_rx_len can be done by calling macro mCDCGetRxLength(). 00225 * 00226 * Overview: getsUSBUSART copies a string of bytes received through 00227 * USB CDC Bulk OUT endpoint to a user's specified location. 00228 * It is a non-blocking function. It does not wait 00229 * for data if there is no data available. Instead it returns 00230 * '0' to notify the caller that there is no data available. 00231 * 00232 * Note: If the actual number of bytes received is larger than the 00233 * number of bytes expected (len), only the expected number 00234 * of bytes specified will be copied to buffer. 00235 * If the actual number of bytes received is smaller than the 00236 * number of bytes expected (len), only the actual number 00237 * of bytes received will be copied to buffer. 00238 *****************************************************************************/ 00239 byte getsUSBUSART(char *buffer, byte len) 00240 { 00241 cdc_rx_len = 0; 00242 00243 if(!mCDCUsartRxIsBusy()) 00244 { 00245 /* 00246 * Adjust the expected number of bytes to equal 00247 * the actual number of bytes received. 00248 */ 00249 if(len > CDC_BULK_BD_OUT.Cnt) 00250 len = CDC_BULK_BD_OUT.Cnt; 00251 00252 /* 00253 * Copy data from dual-ram buffer to user's buffer 00254 */ 00255 for(cdc_rx_len = 0; cdc_rx_len < len; cdc_rx_len++) 00256 buffer[cdc_rx_len] = cdc_data_rx[cdc_rx_len]; 00257 00258 /* 00259 * Prepare dual-ram buffer for next OUT transaction 00260 */ 00261 CDC_BULK_BD_OUT.Cnt = sizeof(cdc_data_rx); 00262 mUSBBufferReady(CDC_BULK_BD_OUT); 00263 }//end if 00264 00265 return cdc_rx_len; 00266 00267 }//end getsUSBUSART 00268 00269 /****************************************************************************** 00270 * Function: void putsUSBUSART(char *data) 00271 * 00272 * PreCondition: cdc_trf_state must be in the CDC_TX_READY state. 00273 * 00274 * The string of characters pointed to by 'data' must equal 00275 * to or smaller than 255 bytes. 00276 * 00277 * Input: data : Pointer to a null-terminated string of data. 00278 * If a null character is not found, 255 bytes 00279 * of data will be transferred to the host. 00280 * 00281 * Output: None 00282 * 00283 * Side Effects: None 00284 * 00285 * Overview: putsUSBUSART writes a string of data to the USB including 00286 * the null character. Use this version, 'puts', to transfer 00287 * data located in data memory. 00288 * 00289 * Note: The transfer mechanism for device-to-host(put) is more 00290 * flexible than host-to-device(get). It can handle 00291 * a string of data larger than the maximum size of bulk IN 00292 * endpoint. A state machine is used to transfer a long 00293 * string of data over multiple USB transactions. 00294 * See CDCTxService() for more details. 00295 *****************************************************************************/ 00296 void putsUSBUSART(char *data) 00297 { 00298 byte len; 00299 00300 /* 00301 * User should have checked that cdc_trf_state is in CDC_TX_READY state 00302 * before calling this function. 00303 * As a safety precaution, this fuction checks the state one more time 00304 * to make sure it does not override any pending transactions. 00305 * 00306 * Currently it just quits the routine without reporting any errors back 00307 * to the user. 00308 * 00309 * Bottomline: User MUST make sure that mUSBUSARTIsTxTrfReady()==1 00310 * before calling this function! 00311 * Example: 00312 * if(mUSBUSARTIsTxTrfReady()) 00313 * putsUSBUSART(pData); 00314 * 00315 * IMPORTANT: Never use the following blocking while loop to wait: 00316 * while(!mUSBUSARTIsTxTrfReady()) 00317 * putsUSBUSART(pData); 00318 * 00319 * The whole firmware framework is written based on cooperative 00320 * multi-tasking and a blocking code is not acceptable. 00321 * Use a state machine instead. 00322 */ 00323 if(cdc_trf_state != CDC_TX_READY) return; 00324 00325 /* 00326 * While loop counts the number of bytes to send including the 00327 * null character. 00328 */ 00329 len = 0; 00330 do 00331 { 00332 len++; 00333 if(len == 255) break; // Break loop once max len is reached. 00334 }while(*data++); 00335 00336 /* 00337 * Re-adjust pointer to its initial location 00338 */ 00339 data-=len; 00340 00341 /* 00342 * Second piece of information (length of data to send) is ready. 00343 * Call mUSBUSARTTxRam to setup the transfer. 00344 * The actual transfer process will be handled by CDCTxService(), 00345 * which should be called once per Main Program loop. 00346 */ 00347 mUSBUSARTTxRam((byte*)data,len); // See cdc.h 00348 }//end putsUSBUSART 00349 00350 /****************************************************************************** 00351 * Function: void putrsUSBUSART(const rom char *data) 00352 * 00353 * PreCondition: cdc_trf_state must be in the CDC_TX_READY state. 00354 * 00355 * The string of characters pointed to by 'data' must equal 00356 * to or smaller than 255 bytes. 00357 * 00358 * Input: data : Pointer to a null-terminated string of data. 00359 * If a null character is not found, 255 bytes 00360 * of data will be transferred to the host. 00361 * 00362 * Output: None 00363 * 00364 * Side Effects: None 00365 * 00366 * Overview: putrsUSBUSART writes a string of data to the USB including 00367 * the null character. Use this version, 'putrs', to transfer 00368 * data literals and data located in program memory. 00369 * 00370 * Note: The transfer mechanism for device-to-host(put) is more 00371 * flexible than host-to-device(get). It can handle 00372 * a string of data larger than the maximum size of bulk IN 00373 * endpoint. A state machine is used to transfer a long 00374 * string of data over multiple USB transactions. 00375 * See CDCTxService() for more details. 00376 *****************************************************************************/ 00377 void putrsUSBUSART(const rom char *data) 00378 { 00379 byte len; 00380 00381 /* 00382 * User should have checked that cdc_trf_state is in CDC_TX_READY state 00383 * before calling this function. 00384 * As a safety precaution, this fuction checks the state one more time 00385 * to make sure it does not override any pending transactions. 00386 * 00387 * Currently it just quits the routine without reporting any errors back 00388 * to the user. 00389 * 00390 * Bottomline: User MUST make sure that mUSBUSARTIsTxTrfReady() 00391 * before calling this function! 00392 * Example: 00393 * if(mUSBUSARTIsTxTrfReady()) 00394 * putsUSBUSART(pData); 00395 * 00396 * IMPORTANT: Never use the following blocking while loop to wait: 00397 * while(cdc_trf_state != CDC_TX_READY) 00398 * putsUSBUSART(pData); 00399 * 00400 * The whole firmware framework is written based on cooperative 00401 * multi-tasking and a blocking code is not acceptable. 00402 * Use a state machine instead. 00403 */ 00404 if(cdc_trf_state != CDC_TX_READY) return; 00405 00406 /* 00407 * While loop counts the number of bytes to send including the 00408 * null character. 00409 */ 00410 len = 0; 00411 do 00412 { 00413 len++; 00414 if(len == 255) break; // Break loop once max len is reached. 00415 }while(*data++); 00416 00417 /* 00418 * Re-adjust pointer to its initial location 00419 */ 00420 data-=len; 00421 00422 /* 00423 * Second piece of information (length of data to send) is ready. 00424 * Call mUSBUSARTTxRom to setup the transfer. 00425 * The actual transfer process will be handled by CDCTxService(), 00426 * which should be called once per Main Program loop. 00427 */ 00428 mUSBUSARTTxRom((rom byte*)data,len); // See cdc.h 00429 00430 }//end putrsUSBUSART 00431 00432 /****************************************************************************** 00433 * Function: void CDCTxService(void) 00434 * 00435 * PreCondition: None 00436 * 00437 * Input: None 00438 * 00439 * Output: None 00440 * 00441 * Side Effects: None 00442 * 00443 * Overview: CDCTxService handles device-to-host transaction(s). 00444 * This function should be called once per Main Program loop. 00445 * 00446 * Note: None 00447 *****************************************************************************/ 00448 void CDCTxService(void) 00449 { 00450 byte byte_to_send; 00451 00452 if(mCDCUsartTxIsBusy()) return; 00453 /* 00454 * Completing stage is necessary while [ mCDCUSartTxIsBusy()==1 ]. 00455 * By having this stage, user can always check cdc_trf_state, 00456 * and not having to call mCDCUsartTxIsBusy() directly. 00457 */ 00458 if(cdc_trf_state == CDC_TX_COMPLETING) 00459 cdc_trf_state = CDC_TX_READY; 00460 00461 /* 00462 * If CDC_TX_READY state, nothing to do, just return. 00463 */ 00464 if(cdc_trf_state == CDC_TX_READY) return; 00465 00466 /* 00467 * If CDC_TX_BUSY_ZLP state, send zero length packet 00468 */ 00469 if(cdc_trf_state == CDC_TX_BUSY_ZLP) 00470 { 00471 CDC_BULK_BD_IN.Cnt = 0; 00472 cdc_trf_state = CDC_TX_COMPLETING; 00473 } 00474 else if(cdc_trf_state == CDC_TX_BUSY) 00475 { 00476 /* 00477 * First, have to figure out how many byte of data to send. 00478 */ 00479 if(cdc_tx_len > sizeof(cdc_data_tx)) 00480 byte_to_send = sizeof(cdc_data_tx); 00481 else 00482 byte_to_send = cdc_tx_len; 00483 00484 /* 00485 * Next, load the number of bytes to send to Cnt in buffer descriptor 00486 */ 00487 CDC_BULK_BD_IN.Cnt = byte_to_send; 00488 00489 /* 00490 * Subtract the number of bytes just about to be sent from the total. 00491 */ 00492 cdc_tx_len = cdc_tx_len - byte_to_send; 00493 00494 pCDCDst.bRam = (byte*)&cdc_data_tx; // Set destination pointer 00495 00496 if(cdc_mem_type == _ROM) // Determine type of memory source 00497 { 00498 while(byte_to_send) 00499 { 00500 *pCDCDst.bRam = *pCDCSrc.bRom; 00501 pCDCDst.bRam++; 00502 pCDCSrc.bRom++; 00503 byte_to_send--; 00504 }//end while(byte_to_send) 00505 } 00506 else // _RAM 00507 { 00508 while(byte_to_send) 00509 { 00510 *pCDCDst.bRam = *pCDCSrc.bRam; 00511 pCDCDst.bRam++; 00512 pCDCSrc.bRam++; 00513 byte_to_send--; 00514 }//end while(byte_to_send._word) 00515 }//end if(cdc_mem_type...) 00516 00517 /* 00518 * Lastly, determine if a zero length packet state is necessary. 00519 * See explanation in USB Specification 2.0: Section 5.8.3 00520 */ 00521 if(cdc_tx_len == 0) 00522 { 00523 if(CDC_BULK_BD_IN.Cnt == sizeof(cdc_data_tx)) 00524 cdc_trf_state = CDC_TX_BUSY_ZLP; 00525 else 00526 cdc_trf_state = CDC_TX_COMPLETING; 00527 }//end if(cdc_tx_len...) 00528 00529 }//end if(cdc_tx_sate == CDC_TX_BUSY) 00530 00531 /* 00532 * Both CDC_TX_BUSY and CDC_TX_BUSY_ZLP states use the following macro 00533 */ 00534 mUSBBufferReady(CDC_BULK_BD_IN); 00535 00536 }//end CDCTxService 00537 00538 #endif //USB_USE_CDC 00539 00540 /** EOF cdc.c ****************************************************************/