/********************************************************************************** Function: BYTE getsUSBUSART(char *buffer, BYTE len) Summary: getsUSBUSART copies a string of BYTEs received through USB CDC Bulk OUT endpoint to a user's specified location. It is a non-blocking function. It does not wait for data if there is no data available. Instead it returns '0' to notify the caller that there is no data available. Description: getsUSBUSART copies a string of BYTEs received through USB CDC Bulk OUT endpoint to a user's specified location. It is a non-blocking function. It does not wait for data if there is no data available. Instead it returns '0' to notify the caller that there is no data available. Typical Usage: <code> BYTE numBytes; BYTE buffer[64] numBytes = getsUSBUSART(buffer,sizeof(buffer)); //until the buffer is free. if(numBytes \> 0) { //we received numBytes bytes of data and they are copied into // the "buffer" variable. We can do something with the data // here. } </code> Conditions: Value of input argument 'len' should be smaller than the maximum endpoint size responsible for receiving bulk data from USB host for CDC class. Input argument 'buffer' should point to a buffer area that is bigger or equal to the size specified by 'len'. Input: buffer - Pointer to where received BYTEs are to be stored len - The number of BYTEs expected. **********************************************************************************/ BYTE getsUSBUSART(char *buffer, BYTE len) { cdc_rx_len = 0; if(!USBHandleBusy(CDCDataOutHandle)) { /* * Adjust the expected number of BYTEs to equal * the actual number of BYTEs received. */ if(len > USBHandleGetLength(CDCDataOutHandle)) len = USBHandleGetLength(CDCDataOutHandle); /* * Copy data from dual-ram buffer to user's buffer */ for(cdc_rx_len = 0; cdc_rx_len < len; cdc_rx_len++) buffer[cdc_rx_len] = cdc_data_rx[cdc_rx_len]; /* * Prepare dual-ram buffer for next OUT transaction */ CDCDataOutHandle = USBRxOnePacket(CDC_DATA_EP,(BYTE*)&cdc_data_rx,sizeof(cdc_data_rx)); }//end if return cdc_rx_len; }//end getsUSBUSART
void FlashDataWrite() { BYTE *pData = (BYTE *) &FlashRxBuffer; BYTE len; if (gCommandProgress==0) { gGlobalStatus = XNANDErase(gCmdArgA << 5); gNextBlock = gCmdArgA << 5; gWordsLeft = 0x84; gBytesWritten = 0; XNANDWriteStart(); gCommandProgress = 1; } if (USBHandleBusy(FlashDataOutHandle)) return; len = USBHandleGetLength(FlashDataOutHandle); len/= 4; while (len) { BYTE writeNow = len > gWordsLeft?gWordsLeft:len; XNANDWriteProcess(pData, writeNow); pData += writeNow*4; len -= writeNow; gWordsLeft -= writeNow; if (gWordsLeft == 0) { gGlobalStatus |= XNANDWriteExecute(gNextBlock); gNextBlock++; gWordsLeft = 0x84; XNANDWriteStart(); gBytesWritten += 0x210; } } FlashDataOutHandle = USBRxOnePacket(NAND_RX_EP,(BYTE*)&FlashRxBuffer,sizeof(FlashRxBuffer)); if (gBytesWritten == gCmdArgB) gCurrentCommand = 0xFF; }
/****************************************************************************** Function: BYTE MSDWriteHandler(void) Description: This funtion processes a write command received through the MSD class driver PreCondition: None Parameters: None Return Values: BYTE - the current state of the MSDWriteHandler state machine. The valid values are defined in MSD.h under the MSDWriteHandler state machine declaration section Remarks: None *****************************************************************************/ BYTE MSDWriteHandler(void) { static BYTE MSDWriteState = MSD_WRITE10_WAIT; switch(MSDWriteState) { case MSD_WRITE10_WAIT: /* Read the LBA, TransferLength fields from Command Block NOTE: CB is Big-Endian */ LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; msd_csw.bCSWStatus=0x0; MSD_State = MSD_WRITE10_BLOCK; //Fall through to MSD_WRITE10_BLOCK case MSD_WRITE10_BLOCK: if(TransferLength.Val == 0) { MSDWriteState = MSD_WRITE10_WAIT; break; } MSDWriteState = MSD_WRITE10_RX_SECTOR; ptrNextData=(BYTE *)&msd_buffer[0]; msd_csw.dCSWDataResidue=BLOCKLEN_512; //Fall through to MSD_WRITE10_RX_SECTOR case MSD_WRITE10_RX_SECTOR: { /* Read 512B into msd_buffer*/ if(msd_csw.dCSWDataResidue>0) { if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,ptrNextData,MSD_OUT_EP_SIZE); MSDWriteState = MSD_WRITE10_RX_PACKET; //Fall through to MSD_WRITE10_RX_PACKET } else { if(LUNWriteProtectState()) { gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_WRITE_PROTECTED; gblSenseData[LUN_INDEX].ASCQ=ASCQ_WRITE_PROTECTED; msd_csw.bCSWStatus=0x01; //TODO: (DF) - what state should I return to? } else { MSDWriteState = MSD_WRITE10_SECTOR; } break; } } //Fall through to MSD_WRITE10_RX_PACKET case MSD_WRITE10_RX_PACKET: if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } gblCBW.dCBWDataTransferLength-=USBHandleGetLength(USBMSDOutHandle); // 64B read msd_csw.dCSWDataResidue-=USBHandleGetLength(USBMSDOutHandle); ptrNextData += MSD_OUT_EP_SIZE; MSDWriteState = MSD_WRITE10_RX_SECTOR; break; case MSD_WRITE10_SECTOR: { if(LUNSectorWrite(LBA.Val, (BYTE*)&msd_buffer[0], (LBA.Val==0)?TRUE:FALSE) != TRUE) { break; } // if (status) { // msd_csw.bCSWStatus=0x01; // /* add some sense keys here*/ // } LBA.Val++; // One LBA is written. Write the next LBA TransferLength.Val--; MSDWriteState = MSD_WRITE10_BLOCK; break; } } return MSDWriteState; }
/********************************************************************************* Function: BYTE MSDTasks(void) Summary: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Description: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Typical Usage: <code> void main(void) { USBDeviceInit(); while(1) { USBDeviceTasks(); if((USBGetDeviceState() \< CONFIGURED_STATE) || (USBIsDeviceSuspended() == TRUE)) { //Either the device is not configured or we are suspended // so we don't want to do execute any application code continue; //go back to the top of the while loop } else { //Keep the MSD state machine going MSDTasks(); //Run application code. UserApplication(); } } } </code> Conditions: None Return Values: BYTE - the current state of the MSD state machine the valid values are defined in MSD.h under the MSDTasks state machine declaration section. The possible values are the following\: * MSD_WAIT * MSD_DATA_IN * MSD_DATA_OUT * MSD_SEND_CSW Remarks: None *********************************************************************************/ BYTE MSDTasks(void) { BYTE i; switch(MSD_State) { case MSD_WAIT: { //If the MSD state machine is waiting for something to happen if(!USBHandleBusy(USBMSDOutHandle)) { //If we received an OUT packet from the host // then copy the data from the buffer to a global // buffer so that we can keep the information but // reuse the buffer gblCBW.dCBWSignature=msd_cbw.dCBWSignature; gblCBW.dCBWTag=msd_cbw.dCBWTag; gblCBW.dCBWDataTransferLength=msd_cbw.dCBWDataTransferLength; gblCBW.bCBWFlags=msd_cbw.bCBWFlags; gblCBW.bCBWLUN=msd_cbw.bCBWLUN; gblCBW.bCBWCBLength=msd_cbw.bCBWCBLength; // 3 MSB are zero for (i=0;i<msd_cbw.bCBWCBLength;i++) { gblCBW.CBWCB[i]=msd_cbw.CBWCB[i]; } gblCBWLength=USBHandleGetLength(USBMSDOutHandle); //If this CBW is valid? if ((gblCBWLength==MSD_CBW_SIZE)&&(gblCBW.dCBWSignature==0x43425355)) { //Is this CBW meaningful? if((gblCBW.bCBWLUN<=0x0f) &&(gblCBW.bCBWCBLength<=0x10) &&(gblCBW.bCBWCBLength>=0x01) &&(gblCBW.bCBWFlags==0x00||gblCBW.bCBWFlags==0x80)) { //Prepare the CSW to be sent msd_csw.dCSWTag=gblCBW.dCBWTag; msd_csw.dCSWSignature=0x53425355; /* If direction is device to host*/ if (gblCBW.bCBWFlags==0x80) { MSD_State=MSD_DATA_IN; } else if (gblCBW.bCBWFlags==0x00) { /* If direction is host to device*/ /* prepare to read data in msd_buffer */ MSD_State=MSD_DATA_OUT; } } } } break; } case MSD_DATA_IN: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { // Done processing the command, send the status MSD_State = MSD_SEND_CSW; } break; case MSD_DATA_OUT: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { /* Finished receiving the data prepare and send the status */ if ((msd_csw.bCSWStatus==0x00)&&(msd_csw.dCSWDataResidue!=0)) { msd_csw.bCSWStatus=0x02; } MSD_State = MSD_SEND_CSW; } break; case MSD_SEND_CSW: if(USBHandleBusy(USBMSDInHandle)) { //The TX buffer is not ready to send the status yet. break; } USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,(BYTE*)&msd_csw,MSD_CSW_SIZE); //Get ready for next command to come in if(!USBHandleBusy(USBMSDOutHandle)) { USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,(BYTE*)&msd_cbw,sizeof(msd_cbw)); } MSD_State=MSD_WAIT; break; } return MSD_State; }
WORD ChipKITUSBHandleGetLength(USB_HANDLE handle) { return(USBHandleGetLength(handle)); }
static void processUsbCommands(void) { #if defined(USB_POLLING) // Check bus status and service USB interrupts. USBDeviceTasks(); // Interrupt or polling method. If using polling, must call // this function periodically. This function will take care // of processing and responding to SETUP transactions // (such as during the enumeration process when you first // plug in). USB hosts require that USB devices should accept // and process SETUP packets in a timely fashion. Therefore, // when using polling, this function should be called // regularly (such as once every 1.8ms or faster** [see // inline code comments in usb_device.c for explanation when // "or faster" applies]) In most cases, the USBDeviceTasks() // function does not take very long to execute (ex: <100 // instruction cycles) before it returns. #endif // Note: The user application should not begin attempting to read/write over the USB // until after the device has been fully enumerated. After the device is fully // enumerated, the USBDeviceState will be set to "CONFIGURED_STATE". if ((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; // As the device completes the enumeration process, the UsbCbInitEP() function will // get called. In this function, we initialize the user application endpoints (in this // example code, the user application makes use of endpoint 1 IN and endpoint 1 OUT). // The USBGenRead() function call in the UsbCbInitEP() function initializes endpoint 1 OUT // and "arms" it so that it can receive a packet of data from the host. Once the endpoint // has been armed, the host can then send data to it (assuming some kind of application software // is running on the host, and the application software tries to send data to the USB device). // If the host sends a packet of data to the endpoint 1 OUT buffer, the hardware of the SIE will // automatically receive it and store the data at the memory location pointed to when we called // USBGenRead(). Additionally, the endpoint handle (in this case UsbOutCmdHandle) will indicate // that the endpoint is no longer busy. At this point, it is safe for this firmware to begin reading // from the endpoint buffer, and processing the data. In this example, we have implemented a few very // simple commands. For example, if the host sends a packet of data to the endpoint 1 OUT buffer, with the // first byte = 0x80, this is being used as a command to indicate that the firmware should "Toggle LED(s)". if (!USBHandleBusy(UsbOutCmdHandle)) { // Check if the endpoint has received any data from the host. #if DEBUG unsigned char l = USBHandleGetLength(UsbOutCmdHandle); if (usbfifo_debug_operation.dump_usb_out == 1) { unsigned char b[16]; unsigned char i; putrsUSART("USB OUT: '"); for (i=0;i<l;++i) { if (i != 0) { while (BusyUSART()); putcUSART(' '); } sprintf(b, "%02x", OutCmdPacket[i]); putsUSART(b); } sprintf(b, "' len=%3d\r\n", l); putsUSART(b); } if (usbfifo_debug_operation.usb_loopback == 1) { unsigned char i; // Now check to make sure no previous attempts to send data to the host are still pending. If any attemps are still // pending, we do not want to write to the endpoint 1 IN buffer again, until the previous transaction is complete. // Otherwise the unsent data waiting in the buffer will get overwritten and will result in unexpected behavior. while (USBHandleBusy(UsbInCmdHandle)); for (i=0;i<l;++i) InCmdPacket[i] = OutCmdPacket[i]; // The endpoint was not "busy", therefore it is safe to write to the buffer and arm the endpoint. // The USBGenWrite() function call "arms" the endpoint (and makes the handle indicate the endpoint is busy). // Once armed, the data will be automatically sent to the host (in hardware by the SIE) the next time the // host polls the endpoint. Once the data is successfully sent, the handle (in this case UsbInCmdHandle) // will indicate the the endpoint is no longer busy. UsbInCmdHandle = USBGenWrite(USBGEN_CMD_EP_NUM, (BYTE*)&InCmdPacket, l); } #endif switch (OutCmdPacket[0]) { #if DEBUG case USBFIFO_CMD_DUMP_USB_OUT: usbfifo_debug_operation.dump_usb_out ^= 1; break; case USBFIFO_CMD_DUMP_FIFO_OUT: usbfifo_debug_operation.dump_fifo_out ^= 1; break; case USBFIFO_CMD_FIFO_LOOPBACK: usbfifo_debug_operation.fifo_loopback ^= 1; break; case USBFIFO_CMD_USB_LOOPBACK: usbfifo_debug_operation.usb_loopback ^= 1; break; #endif default: { unsigned char b[8]; putrsUSART("Unexpected cmd="); sprintf(b, "0x%2X\r\n", OutCmdPacket[0]); putsUSART(b); } break; } // Re-arm the OUT endpoint for the next packet: // The USBGenRead() function call "arms" the endpoint (and makes it "busy"). If the endpoint is armed, the SIE will // automatically accept data from the host, if the host tries to send a packet of data to the endpoint. Once a data // packet addressed to this endpoint is received from the host, the endpoint will no longer be busy, and the application // can read the data which will be sitting in the buffer. UsbOutCmdHandle = USBGenRead(USBGEN_CMD_EP_NUM, (BYTE*)&OutCmdPacket, USBGEN_EP_SIZE); } if (!USBHandleBusy(UsbOutDataHandle)) { #if USBGEN_EP_SIZE > FIFO_9403A_MAX_MSG_LEN #error "Transfer of more than FIFO_9403A_MAX_MSG_LEN not implemented" #endif unsigned char l = USBHandleGetLength(UsbOutDataHandle); unsigned char i; #if DEBUG if (usbfifo_debug_operation.dump_usb_out == 1) { unsigned char b[16]; putrsUSART("USB OUT: '"); for (i=0;i<l;++i) { if (i != 0) { while (BusyUSART()); putcUSART(' '); } sprintf(b, "%02x", OutDataPacket[i]); } sprintf(b, "' len=%3d\r\n", l); putsUSART(b); } if (usbfifo_debug_operation.usb_loopback == 1) { while (USBHandleBusy(UsbInDataHandle)); // ensure that FIFO data left the device for (i=0;i<l;++i) InDataPacket[i] = OutDataPacket[i]; /* FIXME: use real ping-pong */ UsbInDataHandle = USBGenWrite(USBGEN_DATA_EP_NUM, (BYTE*)&InDataPacket, l); while (USBHandleBusy(UsbInDataHandle)); // have to wait here as full ping-pong is not implemented // and thus we don't want data from FIFO override the data being sent here } #endif fifo9403aPush(l, 1); for (i=0;i<l;++i) fifo9403aPush(OutDataPacket[i], 1); UsbOutDataHandle = USBGenRead(USBGEN_DATA_EP_NUM, (BYTE*)&OutDataPacket, USBGEN_EP_SIZE); } }
/****************************************************************************** Function: BYTE MSDWriteHandler(void) Description: This funtion processes a write command received through the MSD class driver PreCondition: None Parameters: None Return Values: BYTE - the current state of the MSDWriteHandler state machine. The valid values are defined in MSD.h under the MSDWriteHandler state machine declaration section Remarks: None *****************************************************************************/ BYTE MSDWriteHandler(void) { switch(MSDWriteState) { case MSD_WRITE10_WAIT: /* Read the LBA, TransferLength fields from Command Block NOTE: CB is Big-Endian */ LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; //Initially assume success, unless handler code later encounters an //error condition and sets the status to 0x01 or 0x02. msd_csw.bCSWStatus=0x0; MSD_State = MSD_WRITE10_BLOCK; //Fall through to MSD_WRITE10_BLOCK case MSD_WRITE10_BLOCK: if(TransferLength.Val == 0) { MSDWriteState = MSD_WRITE10_WAIT; break; } MSDWriteState = MSD_WRITE10_RX_SECTOR; ptrNextData=(BYTE *)&msd_buffer[0]; msd_csw.dCSWDataResidue=BLOCKLEN_512; //Fall through to MSD_WRITE10_RX_SECTOR case MSD_WRITE10_RX_SECTOR: { /* Read 512B into msd_buffer*/ if(msd_csw.dCSWDataResidue>0) { if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,ptrNextData,MSD_OUT_EP_SIZE); MSDWriteState = MSD_WRITE10_RX_PACKET; //Fall through to MSD_WRITE10_RX_PACKET } else { //We finished receiving a sector worth of data from the host. //Check if the media is write protected before deciding what //to do with the data. if(LUNWriteProtectState()) { //The device appears to be write protected. //Let host know error occurred. The bCSWStatus flag is also used by //the write handler, to know not to even attempt the write sequence. msd_csw.bCSWStatus=0x01; //Set sense keys so the host knows what caused the error. gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_WRITE_PROTECTED; gblSenseData[LUN_INDEX].ASCQ=ASCQ_WRITE_PROTECTED; } MSDWriteState = MSD_WRITE10_SECTOR; break; } } //Fall through to MSD_WRITE10_RX_PACKET case MSD_WRITE10_RX_PACKET: if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } gblCBW.dCBWDataTransferLength-=USBHandleGetLength(USBMSDOutHandle); // 64B read msd_csw.dCSWDataResidue-=USBHandleGetLength(USBMSDOutHandle); ptrNextData += MSD_OUT_EP_SIZE; MSDWriteState = MSD_WRITE10_RX_SECTOR; break; case MSD_WRITE10_SECTOR: { //Make sure that no error has been detected, before performing the write //operation. If there was an error, skip the write operation, but allow //the TransferLength to continue decrementing, so that we can eventually //receive all OUT bytes that the host is planning on sending us. Only //after that is complete will the host send the IN token for the CSW packet, //which will contain the bCSWStatus letting it know an error occurred. if(msd_csw.bCSWStatus == 0x00) { if(LUNSectorWrite(LBA.Val, (BYTE*)&msd_buffer[0], (LBA.Val==0)?TRUE:FALSE) != TRUE) { //The write operation failed for some reason. Keep track of retry //attempts and abort if repeated write attempts also fail. if(MSDRetryAttempt < MSD_FAILED_WRITE_MAX_ATTEMPTS) { MSDRetryAttempt++; break; } else { //Too many consecutive failed write attempts have occurred. //Need to give up and abandon the write attempt. msd_csw.bCSWStatus=0x01; // Error 0x01 Refer page#18 // of BOT specifications //Set error status sense keys, so the host can check them later //to determine how to proceed. gblSenseData[LUN_INDEX].SenseKey=S_MEDIUM_ERROR; gblSenseData[LUN_INDEX].ASC=ASC_NO_ADDITIONAL_SENSE_INFORMATION; gblSenseData[LUN_INDEX].ASCQ=ASCQ_NO_ADDITIONAL_SENSE_INFORMATION; } } } //One LBA is written (unless an error occurred). Advance state //variables so we can eventually finish handling the CBW request. LBA.Val++; TransferLength.Val--; MSDWriteState = MSD_WRITE10_BLOCK; break; } default: //Illegal condition which should not occur. If for some reason it //does, try to let the host know know an error has occurred. msd_csw.bCSWStatus=0x02; //Phase Error MSDWriteState = MSD_WRITE10_WAIT; } return MSDWriteState; }
/********************************************************************************* Function: BYTE MSDTasks(void) Summary: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Description: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Typical Usage: <code> void main(void) { USBDeviceInit(); while(1) { USBDeviceTasks(); if((USBGetDeviceState() \< CONFIGURED_STATE) || (USBIsDeviceSuspended() == TRUE)) { //Either the device is not configured or we are suspended // so we don't want to do execute any application code continue; //go back to the top of the while loop } else { //Keep the MSD state machine going MSDTasks(); //Run application code. UserApplication(); } } } </code> Conditions: None Return Values: BYTE - the current state of the MSD state machine the valid values are defined in MSD.h under the MSDTasks state machine declaration section. The possible values are the following\: * MSD_WAIT * MSD_DATA_IN * MSD_DATA_OUT * MSD_SEND_CSW Remarks: None *********************************************************************************/ BYTE MSDTasks(void) { BYTE i; switch(MSD_State) { case MSD_WAIT: { //If the MSD state machine is waiting for something to happen if(!USBHandleBusy(USBMSDOutHandle)) { //If we received an OUT packet from the host // then copy the data from the buffer to a global // buffer so that we can keep the information but // reuse the buffer gblCBW.dCBWSignature=msd_cbw.dCBWSignature; gblCBW.dCBWTag=msd_cbw.dCBWTag; gblCBW.dCBWDataTransferLength=msd_cbw.dCBWDataTransferLength; gblCBW.bCBWFlags=msd_cbw.bCBWFlags; gblCBW.bCBWLUN=msd_cbw.bCBWLUN; gblCBW.bCBWCBLength=msd_cbw.bCBWCBLength; // 3 MSB are zero for (i=0;i<msd_cbw.bCBWCBLength;i++) { gblCBW.CBWCB[i]=msd_cbw.CBWCB[i]; } gblCBWLength=USBHandleGetLength(USBMSDOutHandle); //If this CBW is valid? if ((gblCBWLength==MSD_CBW_SIZE)&&(gblCBW.dCBWSignature==0x43425355)) { //Is this CBW meaningful? if((gblCBW.bCBWLUN<=0x0f) &&(gblCBW.bCBWCBLength<=0x10) &&(gblCBW.bCBWCBLength>=0x01) &&(gblCBW.bCBWFlags==0x00||gblCBW.bCBWFlags==0x80)) { //Prepare the CSW to be sent msd_csw.dCSWTag=gblCBW.dCBWTag; msd_csw.dCSWSignature=0x53425355; //Keep track of retry attempts, in case of temporary failures //during processing of a command. MSDRetryAttempt = 0; //Check the command. With the exception of the REQUEST_SENSE //command, we should reset the sense key info for each new command block. //Assume the command will get processed successfully (and hence "NO SENSE" //response, which is used for success cases), unless handler code //later on detects some kind of error. If it does, it should //update the sense keys to reflect the type of error detected, //prior to sending the CSW. if(gblCBW.CBWCB[0] != MSD_REQUEST_SENSE) { gblSenseData[LUN_INDEX].SenseKey=S_NO_SENSE; gblSenseData[LUN_INDEX].ASC=ASC_NO_ADDITIONAL_SENSE_INFORMATION; gblSenseData[LUN_INDEX].ASCQ=ASCQ_NO_ADDITIONAL_SENSE_INFORMATION; } /* If direction is device to host*/ if (gblCBW.bCBWFlags==0x80) { MSD_State=MSD_DATA_IN; } else if (gblCBW.bCBWFlags==0x00) { /* If direction is host to device*/ /* prepare to read data in msd_buffer */ MSD_State=MSD_DATA_OUT; } } } } break; } case MSD_DATA_IN: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { // Done processing the command, send the status MSD_State = MSD_SEND_CSW; } break; case MSD_DATA_OUT: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { /* Finished receiving the data prepare and send the status */ if ((msd_csw.bCSWStatus==0x00)&&(msd_csw.dCSWDataResidue!=0)) { msd_csw.bCSWStatus=0x02; } MSD_State = MSD_SEND_CSW; } break; case MSD_SEND_CSW: if(USBHandleBusy(USBMSDInHandle)) { //The TX buffer is not ready to send the status yet. break; } USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,(BYTE*)&msd_csw,MSD_CSW_SIZE); //Get ready for next command to come in if(!USBHandleBusy(USBMSDOutHandle)) { USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,(BYTE*)&msd_cbw,sizeof(msd_cbw)); } MSD_State=MSD_WAIT; break; default: //Illegal condition that should not happen, but might occur if the //device firmware incorrectly calls MSDTasks() prior to calling //USBMSDInit() during the set-configuration portion of enumeration. MSD_State=MSD_WAIT; } return MSD_State; }
void ServiceRequests( void ) { BYTE num_return_bytes; // Number of bytes to return in response to received command. BYTE cmd; // Store the command in the received packet. // Process packets received through the primary endpoint. if ( !USBHandleBusy( OutHandle[OutIndex] ) ) { num_return_bytes = 0; // Initially, assume nothing needs to be returned. // Got a packet, so start getting another packet while we process this one. OutPacket = &OutBuffer[OutIndex]; // Store pointer to just-received packet. OutPacketLength = USBHandleGetLength( OutHandle[OutIndex] ); // Store length of received packet. cmd = OutPacket->cmd; blink_counter = NUM_ACTIVITY_BLINKS; // Blink the LED whenever a USB transaction occurs. switch ( cmd ) // Process the contents of the packet based on the command byte. { case ID_BOARD_CMD: // Blink the LED in order to identify the board. blink_counter = 50; InPacket->cmd = cmd; num_return_bytes = 1; break; case INFO_CMD: // memcpy( ( void * )( (BYTE *)InPacket ), (void *)&sdBuf, sizeof( sdBuf ) ); InPacket->_dword[0] = numBlocks; InPacket->_word[2] = rdBlockSize; InPacket->_word[3] = wrBlockSize; InPacket->_word[4] = eraseSize; num_return_bytes = 16; break; // Return a packet with information about this USB interface device. InPacket->cmd = cmd; memcpypgm2ram( ( void * )( (BYTE *)InPacket + 1 ), (const rom void *)&device_info, sizeof( DEVICE_INFO ) ); // InPacket->device_info.checksum = calc_checksum( (CHAR8 *)InPacket, sizeof( DEVICE_INFO ) ); num_return_bytes = sizeof( DEVICE_INFO ) + 1; // Return information stored in packet. break; case READ_EEDATA_CMD: InPacket->cmd = OutPacket->cmd; for(buffer_cntr=0; buffer_cntr < OutPacket->len; buffer_cntr++) { InPacket->data[buffer_cntr] = ReadEeprom((BYTE)OutPacket->ADR.pAdr + buffer_cntr); } num_return_bytes = buffer_cntr + 5; break; case WRITE_EEDATA_CMD: InPacket->cmd = OutPacket->cmd; for(buffer_cntr=0; buffer_cntr < OutPacket->len; buffer_cntr++) { WriteEeprom((BYTE)OutPacket->ADR.pAdr + buffer_cntr, OutPacket->data[buffer_cntr]); } num_return_bytes = 1; break; case RESET_CMD: // When resetting, make sure to drop the device off the bus // for a period of time. Helps when the device is suspended. UCONbits.USBEN = 0; lcntr = 0xFFFF; for(lcntr = 0xFFFF; lcntr; lcntr--) ; Reset(); break; default: num_return_bytes = 0; break; } /* switch */ // This command packet has been handled, so get another. OutHandle[OutIndex] = USBGenRead( USBGEN_EP_NUM, (BYTE *)&OutBuffer[OutIndex], USBGEN_EP_SIZE ); OutIndex ^= 1; // Point to next ping-pong buffer. // Packets of data are returned to the PC here. // The counter indicates the number of data bytes in the outgoing packet. if ( num_return_bytes != 0U ) { InHandle[InIndex] = USBGenWrite( USBGEN_EP_NUM, (BYTE *)InPacket, num_return_bytes ); // Now send the packet. InIndex ^= 1; while ( USBHandleBusy( InHandle[InIndex] ) ) { ; // Wait until transmitter is not busy. } InPacket = &InBuffer[InIndex]; } } } /* ServiceRequests */