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

📄 lpc_hid.c

📁 IAR EWARM嵌入式系统编程与实践光盘源码
💻 C
字号:
#include "lpc_hid.h"

typedef union {
  unsigned int Data[2];
  unsigned short SetupRecuest;
  struct {
    unsigned char  RequestType;
    unsigned char  Request;
    unsigned short Value;
    unsigned short Index;
    unsigned short Length;
  } DataFields;
} USB_SETUP_PACKET_DEF;

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

unsigned char  currentConfiguration;
unsigned char  currentAddress;

const short mouseDescriptor[] = { // 鼠标描述符
  0x0105, // Usage Page (Generic Desktop)
  0x0209, // Usage (Mouse)
  0x01A1, // Collection (Application)
  0x0109, //  Usage (Pointer)
  0x00A1, //  Collection (Physical)
  0x0905, //    Usage Page (Buttons)
  0x0119, //    Usage Minimum?(01)
  0x0329, //    Usage Maximum (03)
  0x0015, //    Logical Minimum (0)
  0x0125, //    Logical Maximum (1)
  0x0395, //    Report Count (3)
  0x0175, //    Report Size (1)
  0x0281, //    3 Button bits
  0x0195, //    Report Count (1)
  0x0575, //    Report Size (6)
  0x0181, //    6 bit padding
  0x0105, //    Generic desktop
  0x3009, //    Usage(X)
  0x3109, //    Usage(Y)
  0x8115, //    Logical Minimum (-127)
  0x7F25, //    Logical Maximum (127)
  0x0875, //    Report Size (8)
  0x0295, //    Report Count (2)
  0x0681, //    2 position bytes
  0xC0C0  // End collection x2
};

const char devDescriptor[] = { // 设备描述符
  /* Device descriptor */
  0x12,                 // bLength
  0x01,                 // bDescriptorType
  0x10,                 // bcdUSBL
  0x01,                 //
  0x00,                 // bDeviceClass:
  0x00,                 // bDeviceSubclass:
  0x00,                 // bDeviceProtocol:
  MAX_CTRL_EP_PK_SIZE,  // bMaxPacketSize0
  0xFF,                 // idVendorL
  0xFF,                 //
  0x01,                 // idProductL
  0x00,                 //
  0x00,                 // bcdDeviceL
  0x00,                 //
  0x01,                 // iManufacturer
  0x02,                 // iProduct
  0x00,                 // SerialNumber
  0x01                  // bNumConfigs
};

const char cfgDescriptor[] = { // 配置描述符
  0x09,   // CbLength
  0x02,   // CbDescriptorType
  0x22,   // CwTotalLength 2 EP + Control
  0x00,
  0x01,   // CbNumInterfaces
  0x01,   // CbConfigurationValue
  0x00,   // CiConfiguration
  0xA0,   // CbmAttributes Bus powered + Remote Wakeup
  0x32,   // CMaxPower: 100mA

  /* 鼠标接口描述符 */
  0x09,   // bLength
  0x04,   // bDescriptorType
  0x00,   // bInterfaceNumber
  0x00,   // bAlternateSetting
  0x01,   // bNumEndpoints
  0x03,   // bInterfaceClass: HID code
  0x01,   // bInterfaceSubclass
  0x02,   // bInterfaceProtocol: Mouse
  0x00,   // iInterface

  /* HID 述符 */
  0x09,   // bLength
  0x21,   // bDescriptor type: HID Descriptor Type
  0x00,   // bcdHID
  0x01,
  0x00,   // bCountry Code
  0x01,   // bNumDescriptors
  0x22,   // bDescriptorType
  sizeof(mouseDescriptor), // wItemLength
  0x00,

  /* 端点1述符 */
  0x07,   // bLength
  0x05,   // bDescriptorType
  ((EP_REP&1)<<7) + (EP_REP>>1),// bEndpointAddress and direction, Endpoint Logic address!!
  0x03,   // bmAttributes      INT
  0x04,   // wMaxPacketSize: 3 bytes (button, x, y)
  0x00,
  0x0A,   // bInterval
};


const char LanguagesStr[] = { //语言字符串
  /* 字符串述符0 */
  0x04, // bLength
  0x03, // bDescriptorType
  0x09,0x04 // Language English
};

const char ManufacturerStr[] = { // 厂家字符串
  /* 字符串述符1 */
  60,   // bLength
  0x03, // bDescriptorType
  'P',0,'h',0,'i',0,'l',0,'i',0,
  'p',0,' ',0,'S',0,'e',0,'m',0,
  'i',0,'c',0,'o',0,'n',0,'d',0,
  'u',0,'c',0,'t',0,'o',0,'r',0,
  's',0,' ',0,'L',0,'P',0,'C',0,
  '2',0,'1',0,'4',0,'8',0,
};

const char ProductStr[] = // 产品字符串
{
  /* 字符串述符2 */
  98,   // bLength
  0x03, // bDescriptorType
  'I',0,'A',0,'R',0,' ',0,'E',0,
  'm',0,'b',0,'e',0,'d',0,'d',0,
  'e',0,'d',0,' ',0,'W',0,'o',0,
  'r',0,'k',0,'b',0,'e',0,'n',0,
  'c',0,'h',0,' ',0,'A',0,'R',0,
  'M',0,' ',0,'-',0,' ',0,'H',0,
  'I',0,'D',0,' ',0,'D',0,'e',0,
  'v',0,'i',0,'c',0,'e',0,' ',0,
  'e',0,'x',0,'a',0,'m',0,'p',0,
  'l',0,'e',0,'!',0
};

const char * const StrPoin [] = {
  LanguagesStr,ManufacturerStr,ProductStr
};

/*************************************************************************
 * 说明: HID_Intr函数
 * 参数:无
 * 返回值:无
 *************************************************************************/
void HID_Init (void) {
  currentConfiguration = 0;
  currentAddress = 0;
  // 实现 I/O 控制端点
  USB_RealizeEndPoint(CTRL_ENP_OUT,MAX_CTRL_EP_PK_SIZE,USB_LowPrior,1);
  USB_RealizeEndPoint(CTRL_ENP_IN ,MAX_CTRL_EP_PK_SIZE,USB_LowPrior,0);
  // 设置默认地址
  USB_SetAdd(currentAddress);
  // 设置设备状态,激活软连接
  USB_Cmd(CMD_USB_SET_DEV_STAT,1);
}

/*************************************************************************
 * 说明:HID_GetConfiguration函数
 * 参数:无
 * 返回值:unsigned char
 *************************************************************************/
unsigned char HID_GetConfiguration (void) {
  return(currentConfiguration);
}

/*************************************************************************
 * 说明:HID_CallBack函数
 * 参数:无
 * 返回值:无
 *************************************************************************/
void HID_CallBack (void) {
  if (DEVINTS & USB_ErrorInterrupt)   {
    // 出错中断
    USB_Cmd(CMD_USB_RD_ERROR_STAT,0);
    DEVINTCLR = USB_ErrorInterrupt;
  }

  if (DEVINTS & USB_DevStatusInterrupt) {
    // 设备状态中断
    int USB_DevIntrStaus = USB_Cmd(CMD_USB_GET_DEV_STAT,0);
    // 总线复位
    if (USB_DevIntrStaus & USB_BusReset) {
      HID_Init();
    }
    DEVINTCLR = USB_DevStatusInterrupt;
  }

  if (DEVINTS & USB_FastInterrupt) {
    DEVINTCLR = USB_FastInterrupt;
  }

  if (DEVINTS & USB_SlowInterrupt) {
    // 慢中断
    if (ENDPINTS & (1<<CTRL_ENP_OUT)) {
      // 选择并清除中断
      HID_ImplSetupPacket();
      ENDPINTCLR = 1<<CTRL_ENP_OUT;
    }
    DEVINTCLR = USB_SlowInterrupt;
  }
}

/*************************************************************************
 * 说明:HID_CtrlStall函数
 * 参数:无
 * 返回值:无
 *************************************************************************/
void HID_CtrlStall (void) {
  USB_Cmd(CMD_USB_SET_EP_STAT + CTRL_ENP_OUT,0x80);
}

/*************************************************************************
 * 说明:HID_SendDataByCtrlEP函数
 * 参数:无
 * 返回值:无
 *************************************************************************/
void HID_SendZeroLengthByCtrlEP (void) {
  USBCTRL_bit.LOG_ENDPOINT = 0;
  USBCTRL_bit.WR_EN = 1;
  TPKTLEN = 0;
  do {
    TDATA = 0;
  }
  while (USBCTRL_bit.WR_EN);

  // 有效缓冲区
  USB_ValidateBuffer(CTRL_ENP_IN);

  // 等待端点0输入中断
  while ((ENDPINTS & (1<<CTRL_ENP_IN)) == 0) {
    if ((USB_Cmd(CMD_USB_SET_EP_STAT + CTRL_ENP_IN,0) & 1) == 0) {
      if((ENDPINTS & (1<<CTRL_ENP_IN)) == 0) {
        break;
      }
    }
  }
  // 清除端点中断(在USB时钟范围之内)
  USB_Cmd(CMD_USB_SEL_CLR_INT_EP + CTRL_ENP_IN,0);
  // 清除中断
  ENDPINTCLR = (1<<CTRL_ENP_IN);
}

/*************************************************************************
 * 说明:HID_SendDataByCtrlEP函数
 * 参数:无
 * 返回值:无
 *************************************************************************/
void HID_SendDataByCtrlEP (unsigned char * Data, unsigned int DataSize) {
unsigned int * pData = (unsigned int *)Data;
unsigned int i;
int ZerroLength = 0;
  do {
    if (DataSize == MAX_CTRL_EP_PK_SIZE) {
      ++ZerroLength;
    }
    i = MIN(DataSize,MAX_CTRL_EP_PK_SIZE);
    DataSize -= i;
    // 选择端点
    USBCTRL_bit.LOG_ENDPOINT = 0;
    USBCTRL_bit.WR_EN = 1;
    TPKTLEN = i;
    do {
      TDATA = *pData++;
    }
    while (USBCTRL_bit.WR_EN);

    // 有效缓冲区
    USB_ValidateBuffer(CTRL_ENP_IN);
    // 等待数据传输或被设置包覆盖
    while ((ENDPINTS & (1<<CTRL_ENP_IN)) == 0) {
      if ((USB_Cmd(CMD_USB_SET_EP_STAT + CTRL_ENP_IN,0) & 1) == 0) {
        if((ENDPINTS & (1<<CTRL_ENP_IN)) == 0) {
          USB_Cmd(CMD_USB_SEL_CLR_INT_EP + CTRL_ENP_IN,0);
          return;
        }
      }
    }

    USB_Cmd(CMD_USB_SEL_CLR_INT_EP + CTRL_ENP_IN,0);
    ENDPINTCLR = (1<<CTRL_ENP_IN);
  }
  while (DataSize);
  if (ZerroLength) {
    HID_SendZeroLengthByCtrlEP();
  }
}

/*************************************************************************
 * 说明:HID_ImplSetupPacket函数
 * 参数:无
 * 返回值:无
 *************************************************************************/
void HID_ImplSetupPacket (void) {
USB_SETUP_PACKET_DEF Setup;
unsigned short Status,Length;
int i = 0;
  do {
    // 读控制端点(0 - 输出)
    USBCTRL_bit.LOG_ENDPOINT = 0;
    USBCTRL_bit.RD_EN = 1;
    // 等待数据包就绪标志
    while (RCVEPKTLEN_bit.PKT_RDY == 0);
    // 从 USB FIFO 读取数据,获得数据包大小
    Length = RCVEPKTLEN_bit.PKT_LNGTH;
    while (RCVEPKTLEN_bit.DV) {
      Setup.Data[i++] = RCVEDATA;
    }
    // 清除缓冲区满标志
    i = USB_ClearBuffer(CTRL_ENP_OUT);
    USB_Cmd(CMD_USB_SEL_CLR_INT_EP+CTRL_ENP_OUT,0);
  }
  while(i);

  if (Length == 0) return;

  switch (Setup.SetupRecuest) {
  case USB_GET_DESCRIPTOR:
    if (Setup.DataFields.Value == 0x100) {      // 返回设备描述符
      HID_SendDataByCtrlEP((unsigned char *)devDescriptor,MIN(sizeof(devDescriptor), Setup.DataFields.Length));
    }
    else if (Setup.DataFields.Value == 0x200) { // 返回配置描述符

      HID_SendDataByCtrlEP((unsigned char *)cfgDescriptor,MIN(sizeof(cfgDescriptor), Setup.DataFields.Length));
    }
    else if ((Setup.DataFields.Value & 0xFF00) == 0x300) { // 返回字符串
      if ((Setup.DataFields.Value & 0xF) < 3) {
        const char * Data = StrPoin[Setup.DataFields.Value & 0xF];
        HID_SendDataByCtrlEP((unsigned char *)Data,MIN(*Data, Setup.DataFields.Length));
      }
      else {
        HID_CtrlStall();
      }
    }
    else {
      HID_CtrlStall();
    }
    break;
  case USB_SET_ADD:
    HID_SendZeroLengthByCtrlEP();
    currentAddress = Setup.DataFields.Value;
    USB_SetAdd(currentAddress);
    break;
  case USB_SET_CONFIGURATION:
    if (Setup.DataFields.Value == 1) {
      currentConfiguration = Setup.DataFields.Value;
      USB_RealizeEndPoint(EP_REP,4,USB_LowPrior,0);
      USB_Cmd(CMD_USB_CFG_DEV,1);
      HID_SendZeroLengthByCtrlEP();
    }
    else {
      // 仅允许端点0
      USB_Cmd(CMD_USB_CFG_DEV,0);
      HID_SendZeroLengthByCtrlEP();
    }
    break;
  case USB_GET_CONFIGURATION:
    HID_SendDataByCtrlEP(&currentConfiguration,sizeof(currentConfiguration));
    break;
  case USB_GET_STATUS_DEV:
  case USB_GET_STATUS_INTERFACE:
    Status = 0;
    HID_SendDataByCtrlEP((unsigned char *)&Status,sizeof(Status));
    break;
  case USB_GET_STATUS_ENDPOINT:
    Status = 0;
    if (currentConfiguration && (Setup.DataFields.Index <= 1)) {
      HID_SendDataByCtrlEP((unsigned char *)&Status,sizeof(Status));
    }
    else if (currentAddress && (Setup.DataFields.Index == 0)) {
      HID_SendDataByCtrlEP((unsigned char *)&Status,sizeof(Status));
    }
    else {
      HID_CtrlStall();
    }
    break;
  case USB_SET_FEATURE_ENDPOINT:
    if (Setup.DataFields.Index <= 1) {
      HID_SendZeroLengthByCtrlEP();
    }
    else {
      HID_CtrlStall();
    }
    break;
  case USB_CLEAR_FEATURE_ENDPOINT:
    if ((Setup.DataFields.Value == 0) && (Setup.DataFields.Index == 1)) {
      HID_SendZeroLengthByCtrlEP();
    }
    else {
      HID_CtrlStall();
    }
    break;
  case USB_SET_FEATURE_INTERFACE:
  case USB_CLEAR_FEATURE_INTERFACE:
  case USB_HID_SET_IDLE:
    HID_SendZeroLengthByCtrlEP();
    break;
  case USB_GET_HID_DESCRIPTOR:
    HID_SendDataByCtrlEP((unsigned char*) mouseDescriptor,MIN(sizeof(mouseDescriptor), Setup.DataFields.Length));
    break;
  case USB_SET_FEATURE_DEV:
  case USB_CLEAR_FEATURE_DEV:
  case USB_SET_DESCRIPTOR:
  case USB_GET_INTERFACE:
  case USB_SET_INTERFACE:
  default:
    HID_CtrlStall();
    break;
  }
}

/*************************************************************************
 * 说明:HID_SendReport
 * 参数:char button, char x, char y
 * 返回值:无
 *************************************************************************/
void HID_SendReport(char button, char x, char y) {
unsigned int Data = button + (x<<8) + (y<<16);
  USBCTRL_bit.LOG_ENDPOINT = EP_REP >> 1;
  USBCTRL_bit.WR_EN = 1;
  TPKTLEN = 3;
  TDATA = Data;
  if (USBCTRL_bit.WR_EN) {
#ifndef NDEBUG
    printf("Error Send Data");
#endif
    return;
  }

  // 有效缓冲区
  USB_ValidateBuffer(EP_REP);

  // 等待传输完成
  while ((ENDPINTS & (1<<EP_REP)) == 0) {
    // 获得端点状态
    if ((USB_Cmd(CMD_USB_SET_EP_STAT + EP_REP,0) & 1) == 0) {
      if((ENDPINTS & (1<<EP_REP)) == 0) {
        break;
      }
    }
  }
  USB_Cmd(CMD_USB_SEL_CLR_INT_EP + EP_REP,0);
  ENDPINTCLR = (1<<EP_REP);
}

⌨️ 快捷键说明

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