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

📄 main.c

📁 HID类程序
💻 C
📖 第 1 页 / 共 3 页
字号:
void USBCtrlTrfSetupHandler()
{
   ctrl_trf_state = WAIT_SETUP;  // USB控制传输状态为等待
   ctrl_trf_session_owner = MUID_NULL; //此时USB EP0端点数据不归任何类所有
   wCount._word = 0;  //字节计数器清0,用于记录传送数据的大小
 
   USBCheckStdRequest();  //检测USB的标准请求

   if(ctrl_trf_session_owner == MUID_NULL)  // 如果上边没有请求,或请求不存在,检测HID请求
   {
     USBCheckHIDRequest();  // USB HID请求检测 
   }//end if
   
   USBCtrlEPServiceComplete();  // 控制传输完成
}//end USBCtrlTrfSetupHandler()

/*******************************
* USB控制数据输出处理函数
* 数据从主机-设备
********************************/
void USBCtrlTrfOutHandler()
{
//说明:此程序是控制传输的数主机请求数据阶段

  if(ctrl_trf_state == CTRL_TRF_RX)  // 如果控制状态是,数据读取(数据主机到设备)
   {
     USBCtrlTrfRxService();          // USB控制数据输出
     if (ctrl_trf_session_owner == MUID_HID)  // 如果此时的传输属于HID所有
      {
        HandleControlOutReport();    // HID控制输出报表(主机输出报表到设备)
      }

    if(ep0Bo.Stat.DTS == 0)          // DATA0与DATA1 交替
      ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN;
    else
      ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN;
   }//end if
   else  // 否则这是控制读的状态阶段
    USBPrepareForNextSetupTrf();  // 准备下一次的控制传输
}//end USBCtrlTrfOutHandler()

/********************************
* USB控制数据输入处理函数
* 数据从设备到主机
*********************************/
void USBCtrlTrfInHandler()
{

  mUSBCheckAdrPendingState();  // 因为这个是控制写(假设是设定地址)传输的最后一步,可以算是状态,在这里要检测地址状态
  if(ctrl_trf_state == CTRL_TRF_TX)   // 数据发送
  {
   USBCtrlTrfTxService(); // 数据加载到到发送缓冲区
    if(ep0Bi.Stat.DTS == 0)
      ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
     else
      ep0Bi.Stat._byte = _USIE|_DAT0|_DTSEN;
   }
    else // 否则这是控制写的状态阶段 	
      USBPrepareForNextSetupTrf();
}//end USBCtrlTrfInHandler()
/*****************************
* 控制传输完成函数
******************************/
void USBCtrlEPServiceComplete()
{
 //说明:令牌和包处理位在收到一个设置传输后将置位(禁止),要在改变ep0Bi.Stat or ep0Bo.Stat前清0(使能)
 //控制传输第一步:设置阶段 
   UCONbits.PKTDIS = 0;    //使能令牌和包接收
   
   if(ctrl_trf_session_owner == MUID_NULL)  // 请求不被支持,则直接发出端点停止信号
    { 
      /*
      如果主机的请求不被支持,或不知道怎么回应,则停止端点发出信号,同时准备好EP0
      接收下一次的请求
      */
      ep0Bo.Cnt = EP0_BUFF_SIZE;      // 设置缓冲器大小,这样可以准备接收下一次的令牌
      ep0Bo.ADR = (byte*)&SetupPkt;   // 设置缓冲器地址

      ep0Bo.Stat._byte = _USIE|_BSTALL; // 端点归SIE,禁止端点发出禁止端点信令
      ep0Bi.Stat._byte = _USIE|_BSTALL;
    }
   else                                  // 否则的话请求是能被执行的
    {
       if(SetupPkt.DataDir == 1)         // 如果请求数据设备到主机
        {
          if(SetupPkt.wLength < wCount._word)  // wLength是主机请求长度
             wCount._word = SetupPkt.wLength;  // 按照主机请求字节发送数据
           USBCtrlTrfTxService();              // USB控制传输数据从设备到主机服务程序
           ctrl_trf_state = CTRL_TRF_TX;       // 现在处于CTRL_TRF_TX设备传送数据状态

           ep0Bo.Cnt = EP0_BUFF_SIZE;
           ep0Bo.ADR = (byte*)&SetupPkt;   
           ep0Bo.Stat._byte = _USIE;               // DTSEN = 0,即不使能同步,准备接收主机发送来的信号

           ep0Bi.ADR = (byte*)&CtrlTrfData;
           ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;  // 启动发送,启动数据发送
        }
       else                                        // 否则数据从主机到设备
        {
           ctrl_trf_state = CTRL_TRF_RX;           // 控制传输接收状态
          /*
          1.IN 端点准备回应上一次的终止
          */
            ep0Bi.Cnt = 0;  //准备状态阶段的设备回应,设备在状态阶段回应0长度的数据包
            ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN; //发送DATA1数据包 

          /*
          2.准备OUT端点接收数据,这样已经设置了数据大小以及数据区
          */
          ep0Bo.Cnt = EP0_BUFF_SIZE;
          ep0Bo.ADR = (byte*)&CtrlTrfData;
          ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN;
        }
    }//end if
}//end USBCtrlEPServiceComplete()

/******************************
* USB控制传输(数据设备到主机)
******************************/
//此程序只完成数据的准备工作
void USBCtrlTrfTxService()
{
  WORD byte_to_send;                    // 定义计数字节
  if(wCount._word < EP0_BUFF_SIZE)      // 判断发送的字节数是否小于EP0_BUFF_SIZE
    byte_to_send._word = wCount._word;  // 如果小于则发送实际值
  else
    byte_to_send._word = EP0_BUFF_SIZE; // 否则发送EP0_BUFF_SIZE大小的字节
    
     /*
      接下来,加载发送字节数目,最多8个字节,数据区就8个字节
     */
    ep0Bi.Stat.BC9 = 0;    // 计数字节高两位清0
    ep0Bi.Stat.BC8 = 0;
    ep0Bi.Stat._byte |= MSB(byte_to_send);  // 设置传输字节数目
    ep0Bi.Cnt = LSB(byte_to_send);
// 从总发送字节中减掉本次发送的字节数
    wCount._word = wCount._word - byte_to_send._word;

    pDst.bRam = (byte*)&CtrlTrfData;   // 设定数据区指针,发送数据区(在400区内)
    
    if(usb_stat.ctrl_trf_mem == _ROM)  // 如果数据存放在ROM区,取出数据
     {
       while(byte_to_send._word)
        {
          *pDst.bRam = *pSrc.bRom;
           pDst.bRam++;
           pSrc.bRom++;
           byte_to_send._word--;
        }
     }  
    else
     {
       while(byte_to_send._word)
        {
          *pDst.bRam = *pSrc.bRam;
           pDst.bRam++;
           pSrc.bRam++;
           byte_to_send._word--;
        }//end while(byte_to_send._word)
     }//end if
}//end  USBCtrlTrfTxService() 

/********************************
* USB控制数据输出数据主机到设备
********************************/
void USBCtrlTrfRxService()
{
   WORD byte_to_read;    // 接收数据字节数计数

   MSB(byte_to_read) = 0x03 & ep0Bo.Stat._byte;  // 保留低两位,取出接收字节数,是主机给定的
   LSB(byte_to_read) = ep0Bo.Cnt;


   wCount._word = wCount._word + byte_to_read._word; // 接收字节数加操作
   pSrc.bRam = (byte*)&CtrlTrfData;  
   
    while(byte_to_read._word)  // 数据取出
    {
        *pDst.bRam = *pSrc.bRam;
        pDst.bRam++;
        pSrc.bRam++;
        byte_to_read._word--;
    }//end while(byte_to_read._word) 
   
}//end USBCtrlTrfRxService()

//---------------------------------------------------------end 控制传输函数区


//---------------------------------------------------------USB 传输协议(请求)函数定义

/*******************************
* 检测USB的标准请求
*********************************/
void USBCheckStdRequest()
{
  if(SetupPkt.RequestType != STANDARD) return;   // 如果不是USB标准请求返回
   
  switch(SetupPkt.bRequest)  //选择请求类型
   {
     case SET_ADR:   //=5  主机请求地址配置
      //说明: 设备不会执行此请求,除非它已经设置一个0长度数据信息包,来完成请求的状态阶段.
      //      主机传送状态阶段的令牌信息包给默认地址0,所以设备必须在改变它的地址前检测并响应此信息包
      //  wVAlue字段内容:新设备地址
      //  wIndex字段内容: 0    
       ctrl_trf_session_owner = MUID_USB9;     // MUID_USB9=1 USB9是USB驱动所有
       usb_device_state = ADR_PENDING_STATE;   // 只更新状态,进入到地址未定状态
     break;

     case  GET_DSC:  //6   获得描述符表
      //说明:描述符有7种类型,每一设备至少有一个设备描述符,
      //      以及至少一个配置描述符和一个接口描述符
      // 数据来源:设备
      // 数据长度:传回字节的数目主机给定
      // wValue:   高字节是描述符类型,低字节是描述符数值
      // wIndex:   如果是字符串描述符此字段是语言ID,其他是0
       USBStdGetDscHandler();                  //USB标准获得描述符表处理
     break;  

     case  SET_CFG:   //9   指示设备使用所选择的配置
      //说明:在完成这个请求来指定一个支持的设置配置后,设备会进入配置状态。
      //      许多标准请求需要设备在设置状态
      //数据长度:0
      //wValue字段:低字节指示一个设置配置。如果此字段的数值符合设备所支持的一个配置,设备会选择
      //            该请求的配置。如果是0表示尚未设置配置,进入地址状态。需要新的请求来设置配置
      //wIndex字段:0
      //支持状态:  地址、配置
       USBStdSetCfgHandler();   //USB标准设置设备配置处理
     break;  

     case  GET_CFG:    //8   主机请求目前设备配置的数值
      //说明:如果设备没有设置配置,则传回0
      //数据长度:1
      //wValue字段:0
      //wIndex字段:0   
      ctrl_trf_session_owner = MUID_USB9;  // USB9是USB驱动所有
      pSrc.bRam = (byte*)&usb_active_cfg;  // 数据首地址
      usb_stat.ctrl_trf_mem = _RAM;        // 数据定义在RAM区
      wCount._word = 1;                    // 数据字节计数=1
     break;   

     case   GET_STATUS: // 0  主机请求一个设备、接口或端点的特征状态
      //说明:如果是设备请求只有两个位。位0是自身电源字段。主机不能改变此数值。
      //      位1是远程唤醒字段,在重置事0。如果是接口的请求。所有位保留。如果是
      //      端点请求,只有位0有意义,位0=1是一个暂停态(Halt).
      //数据字节:2
      //wValue字段:0
      //wIndex字段:设备=0。如果是接口为接口号,如果是端点=端点号
      USBStdGetStatusHandler();  // 主机获得状态处理函数
     break;      

     case  CLR_FEATURE:  //1 主机请求禁用一个在设备,接口或端点上的特征
                         //  将继续往下执行
     case SET_FEATURE:   //3 主机请求启用一个在设备,接口或端点上的特征
      //说明:USB规范定义两个特性:即DEVICE_REMOTE_WAKEUP(数值为1,应用在设备)
      //      以及ENDPOINT_HALT(数值为0,应用在端点)
      //数据:无
      //wValue字段:要启用的特性 DEVICE_REMOTE_WAKEUP  1 设备
      //                         ENDPOINT_HALT         0 端点
      //                         TEST_MODE             2 设备
      //wIndex字段:如果是设备的特性此字段为0,如果是接口此字段为接口号码
      //            如果是端点特性,此字段是端点号码
      USBStdFeatureReqHandler();  //主机请求启用特征值处理函数
     break;
  
     case GET_INTF:     //10  如果设备的配置支持多个互不相关设置的接口,主机请求目前的状态        
      //说明:wIndex字段的几口号码,是指接口描述符中的bInterface字段。每一个接口的号码不同
      //      数据字段的内容,是指接口描述符中的bAlternateInterface字段内容。数据字段表示目前
      //      使用的接口中两个或多个互不相关的设置。
      //wValue字段:0
      //wIndex字段:接口号码  
      ctrl_trf_session_owner = MUID_USB9;
      pSrc.bRam = (byte*)&usb_alt_intf+SetupPkt.bIntfID;  // 取出数据,也就是接口号码,一般就一个接口0
      usb_stat.ctrl_trf_mem = _RAM;
      wCount._word = 1;   // 计数字节     
     break;

     case  SET_INTF:   //11  如果设备的配置支持多个互不相关设置的接口,主机请求设备使用一个指定的设置
      ctrl_trf_session_owner = MUID_USB9;
      usb_alt_intf[SetupPkt.bIntfID] = SetupPkt.bAltID;  // 选择替代的接口号替代以前的
     break;
 
     case SET_DSC:     //7   主机新增一个描述符,或是更新一个存在的描述符
     case SYNCH_FRAME: //12  设备设置与报告一个端点的同步帧
     default:
     break;
   }// end switch
}//end USBCheckStdRequest()

/********************************
*  USB标准描述符获得处理函数
*********************************/
void USBStdGetDscHandler()
{
  if(SetupPkt.bmRequestType == 0x80) // 检测是否是GET_DSC
   {
     switch(SetupPkt.bDscType)       // 选择描述符类型
      {
        case DSC_DEV:                // 设备描述符
          ctrl_trf_session_owner = MUID_USB9;  // 控制传输归SETUP所有
          pSrc.bRom = (rom byte*)&device_dsc;  // 取设备描述符区的首地址,bRom两字节指针1字节数据
          wCount._word = sizeof(device_dsc);   // 取出设备描述符大小
        break;
 
        case DSC_CFG:                   // 配置描述符
          ctrl_trf_session_owner = MUID_USB9;  // 控制传输归SETUP所有
          pSrc.bRom = *(USB_CD_Ptr+SetupPkt.bDscIndex); //USB_CD_Ptr是地址指针数组,存放CFG0地址,加上偏移后取*把地址内容也就是把CFG0地址给到指针brom
          wCount._word = *(pSrc.wRom+1); //pSrc.wRom是指针,他的地址与pSrc.bRom相同但是指向2个字节数据
                                         //加1就越过两字节数据到CFG01的sizeof(cfg01),字节这样把配置的总字节数给出
        break;

        case DSC_STR:                       // 字符串描述符   
          ctrl_trf_session_owner = MUID_USB9;
          pSrc.bRom = *(USB_SD_Ptr+SetupPkt.bDscIndex);
          wCount._word = *pSrc.bRom;         // Set data count
        break;
      } //end switch
   }//end if
  usb_stat.ctrl_trf_mem = _ROM;
}//end USBStdGetDscHandler()  

/********************************
*USB指示设备使用所选择的配置处理
*********************************/
void USBStdSetCfgHandler()
{
   ctrl_trf_session_owner = MUID_USB9;           // 控制传输归USB9,设置这个以后可以返回状态
   mDisableEP1to15();                            // 复位端点1——15
   ClearArray((byte*)&usb_alt_intf,MAX_NUM_INT); // 清交替数组(中断端点)本例使用一个其实可以不用
   usb_active_cfg = SetupPkt.bCfgValue;          // 取出主机给定的设置配置
   if(SetupPkt.bCfgValue == 0)                   // 表示尚未设置配置,进入地址状态
    {
      usb_device_state = ADDRESS_STATE;          // 设备进入地址状态
    }//end if
   else
    {
      usb_device_state = CONFIGURED_STATE;       // 否则进入配置状态
      HIDInitEP();                               // HID端点设置
                                                 // 一旦进入配置状态后主机已确认设备将进入数据传输阶段
    } //enf if
}// end USBStdSetCfgHandler()

/******************************
* USB获得状态处理函数
******************************/
void USBStdGetStatusHandler()
{
  CtrlTrfData._byte0 = 0;      // 准备两个字节的数据区
  CtrlTrfData._byte1 = 0;

  switch(SetupPkt.Recipient)   // 选择是设备接口还是端点
   {
     case  RCPT_DEV:           // =0 获取设备状态
      ctrl_trf_session_owner = MUID_USB9;   //归传输协议(请求)所有

⌨️ 快捷键说明

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