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