
#include "a3load.h"

BOOL	GotSUD;			// Received setup data flag
BOOL  IsFX2;

BOOL CheckForFX2()
{
   BYTE temp;

   // make a backup copy of the test register
   temp = INTSETUP_FX2;
   
   // see if we are running on an FX2 by writing to a register that
   // only exists on FX2 and reading back the value that should stick
   INTSETUP_FX2 = 0xFF;
   if (INTSETUP_FX2 == 0x0B)
   {
      INTSETUP_FX2 = temp;
      return TRUE;
   }
   else
   {
      INTSETUP_FX2 = temp;
      return FALSE;
   }
}

void SetupCommand_EZUSB()
{
   WORD addr, len, bc, i;

   if (SETUPDAT_EZUSB[1] == VR_RAM)
   {
      addr = SETUPDAT_EZUSB[2];		// Get address and length
      addr |= SETUPDAT_EZUSB[3] << 8;
      len = SETUPDAT_EZUSB[6];
      len |= SETUPDAT_EZUSB[7] << 8;

      if(SETUPDAT_EZUSB[0] == VR_DOWNLOAD)
		{
         while(len)					// Move new data through EP0OUT 
         {							// one packet at a time.
            // Arm endpoint - do it here to clear (after sud avail)
            OUT0BC_EZUSB = 0;

            while(EP0CS_EZUSB & bmOUTBSY_EZUSB);

            bc = OUT0BC_EZUSB; // Get the new bytecount
         
	         for(i=0; i<bc; i++)
               *((BYTE xdata *)addr+i) = *(OUT0BUF_EZUSB+i);

            addr += bc;
            len -= bc;
         }
      }
      else if(SETUPDAT_EZUSB[0] == VR_UPLOAD)
      {
         while(len)					// Move requested data through EP0IN 
         {							// one packet at a time.

            if(len < EP0BUFF_SIZE)
               bc = len;
            else
	            bc = EP0BUFF_SIZE;

            for(i=0; i<bc; i++)
               *(IN0BUF_EZUSB+i) = *((BYTE xdata *)addr+i);

            IN0BC_EZUSB = (BYTE)bc; // Arm endpoint with # bytes to transfer

            addr += bc;
            len -= bc;

            while(EP0CS_EZUSB & bmINBSY_EZUSB);
			}
      }  // if VR_UPLOAD
   }  // if VR_RAM
   else if (SETUPDAT_EZUSB[1] == VR_ISFX2)
   {
      IN0BUF_EZUSB[0] = 0;    // not FX2
      IN0BC_EZUSB = 1;
   }

   // finish off the transfer by setting the handshake bit
   EP0CS_EZUSB |= bmHSNAK_EZUSB;

}

void SetupCommand_FX2()
{
   WORD addr, len, bc, i;

   if (SETUPDAT_FX2[1] == VR_RAM)
   {
      addr = SETUPDAT_FX2[2];		// Get address and length
      addr |= SETUPDAT_FX2[3] << 8;
      len = SETUPDAT_FX2[6];
      len |= SETUPDAT_FX2[7] << 8;

      if(SETUPDAT_FX2[0] == VR_DOWNLOAD)
		{
         while(len)					// Move new data through EP0OUT 
         {							// one packet at a time.
            // Arm endpoint - do it here to clear (after sud avail)
            EP0BCH_FX2 = 0;
            EP0BCL_FX2 = 0; // Clear bytecount to allow new data in; also stops NAKing

            while(EP0CS_FX2 & bmEPBUSY);

            bc = EP0BCL_FX2; // Get the new bytecount
         
	         for(i=0; i<bc; i++)
               *((BYTE xdata *)addr+i) = *(EP0BUF_FX2+i);

            addr += bc;
            len -= bc;
         }
      }
      else if(SETUPDAT_FX2[0] == VR_UPLOAD)
      {
         while(len)					// Move requested data through EP0IN 
         {							// one packet at a time.

            if(len < EP0BUFF_SIZE)
               bc = len;
            else
	            bc = EP0BUFF_SIZE;

            for(i=0; i<bc; i++)
               *(EP0BUF_FX2+i) = *((BYTE xdata *)addr+i);

            EP0BCH_FX2 = 0;
            EP0BCL_FX2 = (BYTE)bc; // Arm endpoint with # bytes to transfer

            addr += bc;
            len -= bc;

            while(EP0CS_FX2 & bmEPBUSY);
			}
      }  // if VR_UPLOAD
   }  // if VR_RAM
   else if (SETUPDAT_FX2[1] == VR_ISFX2)
   {
      EP0BUF_FX2[0] = 1;    // is FX2
      EP0BCH_FX2 = 0;
      EP0BCL_FX2 = 1;
   }

   // finish off the transfer by setting the handshake bit
   EP0CS_FX2 |= bmHSNAK_FX2;

}

void main()
{
   GotSUD = FALSE;

   IsFX2 = CheckForFX2();

   // Turn on r/w lines for external memory 
   PORTCCFG_EZUSB |= 0xc0;


   // enable USB interrupts
   EZUSB_IRQ_ENABLE();

   // enable autovector
   if (IsFX2)
   {
      INTSETUP_FX2 = bmAV2EN;
   }
   else
   {
      USBBAV_EZUSB |= 1;	// enable autovectoring
   }
   
   // we only care about SETUP Data Available
   if (IsFX2)
   {
      USBIE_FX2 = bmSUDAV;
   }
   else
   {
      USBIEN_EZUSB = bmSUDAV;
   }

   // enable 8051 interrupts
   EA = 1;

   while (1)
   {
      if(GotSUD)            // Wait for SUDAV
      {
         if (IsFX2)
         {
            SetupCommand_FX2();          // Implement setup command
         }
         else
         {
            SetupCommand_EZUSB();        // Implement setup command
         }
         
         GotSUD = FALSE;            // Clear SUDAV flag
      }
   }


}

void ISR_Sudav(void) interrupt 0
{
   GotSUD = TRUE;            // Set flag
   EZUSB_IRQ_CLEAR();
   if (IsFX2)
   {
      USBIRQ_FX2 = bmSUDAV;
   }
   else
   {
      USBIRQ_EZUSB = bmSUDAV;
   }
}
