⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 d_usb.c

📁 乐高机器人的源码,开发平台是IAR_for_AVR.
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Programmer
//
// Date init       14.12.2004
//
// Reviser         $Author:: Dkpechri                                        $
//
// Revision date   $Date:: 19-07-06 10:02                                    $
//
// Filename        $Workfile:: d_usb.c                                       $
//
// Version         $Revision:: 32                                            $
//
// Archive         $Archive:: /LMS2006/Sys01/Main/Firmware/Source/d_usb.c    $
//
// Platform        C
//

#include  "stdconst.h"
#include  "m_sched.h"
#include  "d_usb.h"
#include  "d_usb.r"

#define ENDPOINT_OUT 1          // HOST write
#define ENDPOINT_OUT_SIZE 64
#define ENDPOINT_IN 2           // HOST read
#define ENDPOINT_IN_SIZE 64

#define AT91C_UDP_ISR         ((AT91_REG *)   0xFFFB001C) // (UDP) Interrupt Status Register
#define AT91C_RSTC_URSTEN     ((unsigned int) 0x1 <<  0)  // (RSTC) User Reset Enable

                // Endpoint Control and Status Registers
#define AT91C_UDP_CSR0  ((AT91_REG *)   0xFFFB0030) // Endpoint 0 Control and Status Register
#define AT91C_UDP_CSR1  ((AT91_REG *)   0xFFFB0034) // Endpoint 1 Control and Status Register
#define AT91C_UDP_CSR2  ((AT91_REG *)   0xFFFB0038) // Endpoint 2 Control and Status Register
#define AT91C_UDP_CSR3  ((AT91_REG *)   0xFFFB003C) // Endpoint 3 Control and Status Register

                          // Endpoint FIFO Data Registers
#define AT91C_UDP_FDR0  ((AT91_REG *)   0xFFFB0050) // Endpoint 0 FIFO Data Register
#define AT91C_UDP_FDR1  ((AT91_REG *)   0xFFFB0054) // Endpoint 1 FIFO Data Register
#define AT91C_UDP_FDR2  ((AT91_REG *)   0xFFFB0058) // Endpoint 2 FIFO Data Register
#define AT91C_UDP_FDR3  ((AT91_REG *)   0xFFFB005C) // Endpoint 3 FIFO Data Register

const UBYTE DeviceDescriptor[] = {
  /* Device descriptor */
  0x12,   // bLength, size of this descriptor = 18 entries
  0x01,   // bDescriptorType = 1 = DEVICE
  0x00,   // bcdUSBL, USB spec. vers. 2.0
  0x02,   // bcdUSBH, -
  0x00,   // bDeviceClass
  0x00,   // bDeviceSubclass
  0x00,   // bDeviceProtocol
  0x08,   // bMaxPacketSize0, EndPointZero packet size = 8
  0x94,   // idVendorL, LEGO Group
  0x06,   // idVendorH, -
  0x02,   // idProductL, LEGO USB IR Tower = 0x01
  0x00,   // idProductH, -
  0x00,   // bcdDeviceL, device is version (zero)
  0x00,   // bcdDeviceH, -
  0x00,   // iManufacturer, index of string descriptor describing manufacturer
  0x00,   // iProduct, index of string descriptor describing product
  0x01,   // iSerialNumber,  index of string descriptor describing the device's
          // serial no.
  0x01    // bNumConfigs, number of possible configurations (only one)
};

/* USB standard request codes */

#define STD_GET_STATUS_ZERO           0x0080
#define STD_GET_STATUS_INTERFACE      0x0081
#define STD_GET_STATUS_ENDPOINT       0x0082

#define STD_CLEAR_FEATURE_ZERO        0x0100
#define STD_CLEAR_FEATURE_INTERFACE   0x0101
#define STD_CLEAR_FEATURE_ENDPOINT    0x0102

#define STD_SET_FEATURE_ZERO          0x0300
#define STD_SET_FEATURE_INTERFACE     0x0301
#define STD_SET_FEATURE_ENDPOINT      0x0302

#define STD_SET_ADDRESS               0x0500
#define STD_GET_DESCRIPTOR            0x0680
#define STD_SET_DESCRIPTOR            0x0700
#define STD_GET_CONFIGURATION         0x0880
#define STD_SET_CONFIGURATION         0x0900
#define STD_GET_INTERFACE             0x0A81
#define STD_SET_INTERFACE             0x0B01
#define STD_SYNCH_FRAME               0x0C82

/* USB constants, masks etc. */

#define END_OF_BUS_RESET        ((unsigned int) 0x1 << 12)
#define SUSPEND_INT                   ((unsigned int) 0x1 << 8)
#define SUSPEND_RESUME                ((unsigned int) 0x1 << 9)
#define WAKEUP                        ((unsigned int) 0x1 << 13)

//USB spec allows 500ms for control transfers
#define USB_MAX_TIMEOUT                500

static    UBYTE UsbHandleList[MAX_HANDLES];
static    UBYTE UsbHandleCnt;
static    UWORD RequestedData;
static    UBYTE BrickNameKnown;
enum
{
  USB_NOT_CONFIGURED,
  USB_CONFIGURED,
  USB_CONFIGURED_BUT_SUSPENDED
};
static    UBYTE UsbConnectionStates;


const UBYTE ConfigurationDescriptor[] = {
  /* ============== CONFIGURATION 1 =========== */
  /* Configuration 1 descriptor */
  0x09,   // bLength, descriptor size in bytes
  0x02,   // bDescriptorType, The constant Configuration
  0x20,   // wTotalLengthL for 2 EP + Control
  0x00,   // wTotalLengthH -
  0x01,   // bNumInterfaces, Number of interfaces in the configuration
  0x01,   // bConfigurationValue, Identifier for
          // Set_Configuration and Get_Configuration requests
  0x00,   // iConfiguration, Index of string descriptor for the configuration
  0xC0,   // bmAttributes, Bit 7 shall always be set. See e.g. page 108 in the book:
          // "USB Complete" by Jan Axelson. June 2001
          // Self powered only bit 6 = 1 (zero = buspowered USB 1.1 and up)
  0x00,   // MaxPower, power required (mA./2) We're SELF-POWERED, so ZERO

  /* Interface Descriptor */
  0x09,   // bLength, descriptor size in bytes
  0x04,   // bDescriptorType, the constant 0x04 = "INTERFACE"
  0x00,   // bInterfaceNumber, No. identifying this interface
  0x00,   // bAlternateSetting, value used to get an alternative interface
  0x02,   // bNumEndpoints, No. of supported endpoints in addition to endpoint 0
  0xFF,   // bInterfaceClass, Specifies the class code = VENDOR Specific
  0xFF,   // bInterfaceSubclass, Specifies the subclass code = VENDOR Specific
  0xFF,   // bInterfaceProtocol, protocol code = VENDOR Specific
  0x00,   // iInterface, index of string descriptor for the interface

  /* Endpoint 1 descriptor */
  0x07,               // bLength, descriptor length incl. this = 7
  0x05,               // bDescriptorType
  0x01,               // bEndpointAddress, Endpoint 01 - OUT
  0x02,               // bmAttributes      BULK
  ENDPOINT_OUT_SIZE,  // wMaxPacketSize
  0x00,               // -
  0x00,               // bInterval

  /* Endpoint 2 descriptor */
  0x07,               // bLength, descriptor length incl. this = 7
  0x05,               // bDescriptorType
  0x82,               // bEndpointAddress, Endpoint 02 - IN
  0x02,               // bmAttributes      BULK
  ENDPOINT_IN_SIZE,   // wMaxPacketSize
  0x00,               // -
  0x00                // bInterval
};

UBYTE SerialNumberDescriptor[] =
{
      0x1A,           // bLength, descriptor length incl. this = 16 bytes
      0x03,           // bDescriptorType

      0x31, 0x00,     // MSD of Lap (Lap[2,3]) in UNICode
      0x32, 0x00,     // Lap[4,5]
      0x33, 0x00,     // Lap[6,7]
      0x34, 0x00,     // Lap[8,9]
      0x35, 0x00,     // Lap[10,11]
      0x36, 0x00,     // Lap[12,13]
      0x37, 0x00,     // Lap[14,15]
      0x38, 0x00,     // LSD of Lap (Lap[16,17]) in UNICode

      0x30, 0x00,     // MSD of Nap (Nap[18,19]) in UNICode
      0x30, 0x00,     // LSD of Nap (Nap[20,21]) in UNICode

      0x39, 0x00,     // MSD of Uap in UNICode
      0x30, 0x00      // LSD of Uap in UNICode
};

const UBYTE LangIdDescriptor[] =
{
      0x04,           // Length
      0x03,           // Type, 3 = CONSTANT String
      0x09,           // English
      0x04            // subcode = U.S. English
};

static UCHAR CurrentConfiguration;  // Configured or not. We've only 1 conf. so... Boolean
static ULONG CurrentReceiveBank;    // Used for keep track of the PING-PONG buffers

ULONG g_UsbTimeoutCounter;

#define MIN(a, b) (((a) < (b)) ? (a) : (b))

void   dUsbDisconnect(void)
{
  USBDisconnect;
}

void   dUsbConnect(void)
{
  USBConnect;
}

void  dUsbStartTimeoutTimer(void)
{
   g_UsbTimeoutCounter = 0;

  USBGetActualTime;
}

// A longer version of the USB timer.
// Table 7-14 of the USB 2.0 spec allows up to 500ms for standard request completion.
UBYTE dUsbTimedOut(void)
{
   if(USBTimedOut)
   {
      g_UsbTimeoutCounter++;

      USBGetActualTime;
   }

   return (g_UsbTimeoutCounter >= USB_MAX_TIMEOUT) ? TRUE : FALSE;
}


UBYTE ConvertHighToHex(UBYTE TempChar)
{
  TempChar = (TempChar >> 4) & 0x0F;
  if (TempChar > 0x09)
    TempChar += 0x37;
  else
    TempChar += 0x30;
  return TempChar;
}

UBYTE ConvertLowToHex(UBYTE TempChar)
{
  TempChar &= 0x0F;
  if (TempChar > 0x09)
    TempChar += 0x37;
  else
    TempChar += 0x30;
  return TempChar;
}

void dUsbStoreBtAddress(UBYTE *pBtAddress)
{
  UBYTE NoToConvert;

  // make the Lap human readable (hmmm Hexadecimal)
  NoToConvert = *pBtAddress++;
  SerialNumberDescriptor[2] = ConvertHighToHex(NoToConvert);
  SerialNumberDescriptor[4] = ConvertLowToHex(NoToConvert);

  NoToConvert = *pBtAddress++;
  SerialNumberDescriptor[6] = ConvertHighToHex(NoToConvert);
  SerialNumberDescriptor[8] = ConvertLowToHex(NoToConvert);

  NoToConvert = *pBtAddress++;
  SerialNumberDescriptor[10] = ConvertHighToHex(NoToConvert);
  SerialNumberDescriptor[12] = ConvertLowToHex(NoToConvert);

  NoToConvert = *pBtAddress++;
  SerialNumberDescriptor[14] = ConvertHighToHex(NoToConvert);
  SerialNumberDescriptor[16] = ConvertLowToHex(NoToConvert);

  // make the Uap human readable (hmmm Hexadecimal)
  NoToConvert = *pBtAddress++;
  SerialNumberDescriptor[18] = ConvertHighToHex(NoToConvert);
  SerialNumberDescriptor[20] = ConvertLowToHex(NoToConvert);

  // make the Nap human readable (hmmm Hexadecimal)
  NoToConvert = *pBtAddress++;
  SerialNumberDescriptor[22] = ConvertHighToHex(NoToConvert);
  SerialNumberDescriptor[24] = ConvertLowToHex(NoToConvert);

  USBConnect;             // We're ready to participate in the real world
  BrickNameKnown = TRUE;  // OK for referencing :-)
}


ULONG dUsbRead(UBYTE *pData, ULONG Length)
{
  ULONG PacketSize, NumberOfBytesReceived;

  NumberOfBytesReceived = 0;

  while (Length)                  // Wished read size from user (Max length)
  {
    if ( !(BrickNameKnown))       // Right Brick???
      break;

    if ( !(dUsbIsConfigured()) )
      break;                      // Not configured - no time to waste

    if ( (*AT91C_UDP_CSR1) & CurrentReceiveBank )			// Data packet rx'ed in Current bank?
    {

    PacketSize = MIN((*AT91C_UDP_CSR1) >> 16, Length);		// Normalize number of bytes available in FIFO
    Length -= PacketSize;									// Rest of data to receive

    if (PacketSize < ENDPOINT_OUT_SIZE)						// If data less, we only have one loop
      Length = 0;

    while(PacketSize--)										// While more data in this very packet...
      pData[NumberOfBytesReceived++] = *AT91C_UDP_FDR1;		// Fill in buffer

    *AT91C_UDP_CSR1 &= ~(CurrentReceiveBank);				// Reset current bank pointer

    if (CurrentReceiveBank == AT91C_UDP_RX_DATA_BK0)		// Current Receive Bank 0?
      CurrentReceiveBank = AT91C_UDP_RX_DATA_BK1;			// We better use Bank 1
    else
      CurrentReceiveBank = AT91C_UDP_RX_DATA_BK0;			// Okay, go for Bank 0 :-)

    }

    else Length = 0;                                        // Leave and let's use the CPU cycles in a better way

  }

  return NumberOfBytesReceived;                 // Size of actually received stuff

}

ULONG dUsbWrite( const UBYTE *pData, ULONG Length)
{
  ULONG CharsEachTx = 0;

                                                      // Send the very first (or only) packet
  CharsEachTx = MIN(Length, ENDPOINT_IN_SIZE);        // First transmission size
  Length -= CharsEachTx;                              // Adjust the rest of transmission size

  while (CharsEachTx--)                               // While more chars in this chunk
    *AT91C_UDP_FDR2 = *pData++;                       // Get rid off it one by one
                                                      // Pushing the data into the UDP TX-fifo
  *AT91C_UDP_CSR2 |= AT91C_UDP_TXPKTRDY;              // Signal "DO THE TX" the stuff is delivered...

  while (Length)                                      // While more bytes (I.e. packets) 韓 total transmission
  {                                                   // Start filling the second bank

    CharsEachTx = MIN(Length, ENDPOINT_IN_SIZE);
    Length -= CharsEachTx;                            // Adjust total length

    while (CharsEachTx--)                             // While more chars in this chunk
      *AT91C_UDP_FDR2 = *pData++;

          dUsbStartTimeoutTimer();
    while ( !((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP) )			// Wait for the the first bank to be sent
          if (dUsbTimedOut() || !(dUsbIsConfigured()) )			// Communication down..... Bail out
            return Length;										// Invalid function - return job length not done

          (*AT91C_UDP_CSR2) &= ~(AT91C_UDP_TXCOMP);				// Reset transmit interrupt flag

    while ((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP);				// Wait until flag (H/W) is reset

    (*AT91C_UDP_CSR2) |= AT91C_UDP_TXPKTRDY;					// We're ready to send next bank

  }																// Loop while bytes to tx

        dUsbStartTimeoutTimer();								// Arm the timeout timing
        while ( !((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP) )		// Wait for transmission to complete
          if ( !(dUsbIsConfigured()) || dUsbTimedOut())         // Communication down..... Bail out
            return Length;										// Invalid function - return job length not done

  (*AT91C_UDP_CSR2) &= ~(AT91C_UDP_TXCOMP);           // Reset Interrupt flag

  while ((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP);       // Wait for H/W to settle.....

  return Length;                                      // Return byte count NOT x-ferred

}

static void dUsbSendStall(void)
{
  (*AT91C_UDP_CSR0) |= AT91C_UDP_FORCESTALL;                                // Set STALL condition
  while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_ISOERROR) );                      // Wait until stall ack'ed

  (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);        // Reset again
  while ((*AT91C_UDP_CSR0) & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));  // Wait until H/W really reset
}

static void dUsbSendZeroLengthPackage(void)
{
   // Signal that buffer is ready to send
   (*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;

   dUsbStartTimeoutTimer();

   // Wait for ACK handshake from host
   while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP) && !dUsbTimedOut());
   // Clear handshake flag
   (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXCOMP);
   while ((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP);
}

static void dUsbSendViaControl(const UBYTE *pData, ULONG Length)
{
  ULONG BytesToTx = 0;
  AT91_REG Temp_Csr;
  UBYTE HaveToTxZeroLength = FALSE;
  UBYTE ZeroCouldBeNeeded = FALSE;

   // If the amount of data requested is more than what can be sent, a 0-length
   // packet may be required
   if (RequestedData > Length)
   {
      ZeroCouldBeNeeded = TRUE;  // Exact same size would be interpreted as EOP @ host
   }

  do
  {
		// The endpoint size is 8 bytes.  Limit each data phase to 8 bytes.
		
		BytesToTx = MIN(Length, 8);
		Length -= BytesToTx;

		// If this is the last data phase containing data, but the host requested
		// more, a 0-byte packet will be needed to terminate the data phase.
		if(ZeroCouldBeNeeded && (Length == 0) && (BytesToTx == 8))
		{
			HaveToTxZeroLength = TRUE;
		}

		// Copy data to endpoint buffer
		while (BytesToTx--)
		{
			(*AT91C_UDP_FDR0) = *pData++;
		}

		// Signal that buffer is ready to send
		(*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;

				dUsbStartTimeoutTimer();

		// Wait for ACK handshake from host
		do
		{
			Temp_Csr = (*AT91C_UDP_CSR0);

			// Return if the status phase occurs before the packet is accepted
			if (Temp_Csr & AT91C_UDP_RX_DATA_BK0)
			{
				// Clear the PKTRDY flag
				(*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXPKTRDY);
				// Clear the status phase flag
				(*AT91C_UDP_CSR0) &= ~(AT91C_UDP_RX_DATA_BK0);
				return;
			}
		}
		while (!(Temp_Csr & AT91C_UDP_TXCOMP) && !dUsbTimedOut());

		// Clear handshake flag
		(*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXCOMP);
	 
		while ((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP);

  } while (Length);

   if(HaveToTxZeroLength)
   {
      dUsbSendZeroLengthPackage();
   }

   dUsbStartTimeoutTimer();

   // Wait for Status Phase
   while(!((*AT91C_UDP_CSR0) & AT91C_UDP_RX_DATA_BK0) && !dUsbTimedOut());
   // Clear flag
   (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_RX_DATA_BK0);
}

static void dUsbEnumerate(void)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -