📄 main.c
字号:
CtrlTrfData._byte0|=0b000000001; // SetB byte0.0,表示使用自身电源
if(usb_stat.RemoteWakeup == 1) // usb_stat defined in usbmmap.c
CtrlTrfData._byte0|=0b00000010; // Set bit1,是否支持,远程唤醒
break;
case RCPT_INTF: // =1 获取接口状态
ctrl_trf_session_owner = MUID_USB9; // 两个数据字段=0;
break;
case RCPT_EP: // =2 如果是获取端点状态
ctrl_trf_session_owner = MUID_USB9;
pDst.bRam = (byte*)&ep0Bo+(SetupPkt.EPNum*8)+(SetupPkt.EPDir*4); // 取出状态寄存器地址
if(*pDst.bRam & _BSTALL) // 判断端点是否停止
CtrlTrfData._byte0=0x01;// 如果停止表示端点进入一个暂停态
break;
}// end switch
} // end USBStdGetStatusHandler()
/***********************************
*主机请求启用特征值处理函数
************************************/
void USBStdFeatureReqHandler()
{
if((SetupPkt.bFeature == DEVICE_REMOTE_WAKEUP)&&(SetupPkt.Recipient == RCPT_DEV)) //RCPT_DEV=0,设置设备的远程唤醒状态状态
{
ctrl_trf_session_owner = MUID_USB9;
if(SetupPkt.bRequest == SET_FEATURE) // 判断是否是这个请求
usb_stat.RemoteWakeup = 1; // 如果配置远程唤醒,状态位置1
else //否则是CLEAR_FEATURE
usb_stat.RemoteWakeup = 0;
}//end if
if((SetupPkt.bFeature == ENDPOINT_HALT)&&(SetupPkt.Recipient == RCPT_EP)&&(SetupPkt.EPNum != 0))// 加上请求的端点不是端点0条件
{
ctrl_trf_session_owner = MUID_USB9;
pDst.bRam = (byte*)&ep0Bo+(SetupPkt.EPNum*8)+(SetupPkt.EPDir*4); //确定端点状态地址
if(SetupPkt.bRequest == SET_FEATURE)//如果是端点特征配置
*pDst.bRam = _USIE|_BSTALL; //把端点状态寄存器设置为SIE所有并使能缓冲器停止
else //否则是CLEAR_FEATURE
{
if(SetupPkt.EPDir == 1) // 如果是IN
*pDst.bRam = _UCPU; // 端点归CPU
else
*pDst.bRam = _USIE|_DAT0|_DTSEN; //如果是输出的话,端点归SIE用DATA0使能数据同步位
}// end if
}//end if
}//end USBStdFeatureReqHandler()
/********************************
* USB检测地址状态
********************************/
void mUSBCheckAdrPendingState()
{
if(usb_device_state==ADR_PENDING_STATE)
{
UADDR = SetupPkt.bDevADR._byte;
if(UADDR > 0)
usb_device_state=ADDRESS_STATE;
else
usb_device_state=DEFAULT_STATE;
}//end if
}//end mUSBCheckAdrPendingState()
//--------------------------------------------------------- end USB 传输协议(请求)函数定义
//--------------------------------------------------------- HID 函数区
/*******************************
* HID 端点设置函数
*******************************/
void HIDInitEP()
{
hid_rpt_rx_len=0; // HID报表接收字节数清0
HID_UEP = EP_OUT_IN|HSHK_EN;
ClearArray((byte*)&usb_alt_intf,MAX_NUM_INT);// 清一个数组,为交替设置MAX_NUM_INT=1,中断端点个数=1
HID_UEP = EP_OUT_IN|HSHK_EN; // 初始化端点1
HID_BD_OUT.Cnt = sizeof(hid_report_out); // 设置缓冲区大小
HID_BD_OUT.ADR = (byte*)&hid_report_out; // 设置缓冲区首地址
HID_BD_OUT.Stat._byte = _USIE|_DAT0|_DTSEN; // 端点1的OUT设置
HID_BD_IN.ADR = (byte*)&hid_report_in; // 端点1的IN端点地址设置
HID_BD_IN.Stat._byte = _UCPU|_DAT1; // 端点1的IN状态设置
}// end HIDInitEP()
/***********************************
* HID检测请求
***********************************/
void USBCheckHIDRequest() //HID检测请求,如果USB状态不是空,不会检测,因为那是USB的标准请求时刻
{
if(SetupPkt.Recipient != RCPT_INTF) return; // 如果请求不是对接口则退出,对HID 都是对端口说话
if(SetupPkt.bIntfID != HID_INTF_ID) return; // 如果HID接口的号不与请求的接口ID相同退出
if(SetupPkt.bRequest == GET_DSC) // 如果是主机获得描述符
{
/*
#define DSC_HID 0x21 // HID
#define DSC_RPT 0x22 // 报表
#define DSC_PHY 0x23 // 实体
*/
switch(SetupPkt.bDscType)
{
case 0x21: // 获得HID描述符
ctrl_trf_session_owner = MUID_HID; // 传输归HID所有
if(usb_active_cfg == 1) // 即进入配置状态以后才做的事情
{
pSrc.bRom = (rom byte*)&cfg01.hid_i00a00; // 取出HID描述符的首地址
}
wCount._word = sizeof(USB_HID_DSC); //取得描述符大小
break;
case 0x22: //报表描述符
ctrl_trf_session_owner = MUID_HID; // 传输归HID所有
if(usb_active_cfg == 1)
{
pSrc.bRom = (rom byte*)&hid_rpt01; // 报表描述符在ROM内的首地址
wCount._word = sizeof(hid_rpt01); // 报表描述符大小
}
break;
case 0x23:
default:
break;
}//end switch
usb_stat.ctrl_trf_mem = _ROM; // 数据存储在ROM区
}//end if
if(SetupPkt.RequestType != CLASS) return; // 如果不是特定USB的类请求返回
switch(SetupPkt.bRequest) // 选择HID特定请求
{
case GET_REPORT: // 01 启用主机使用控制传输,来从设备读取数据
HIDGetReportHandler(); // 主机获得数据处理函数
break;
case SET_REPORT: // 09 启用设备控制传输,设备从主机获得数据
HIDSetReportHandler(); // 设备接收数据处理函数
break;
case GET_IDLE: // 02 启用主机从设备读取目前的闲置率
ctrl_trf_session_owner = MUID_HID; // 控制传输的系统归HID所有
pSrc.bRam = (byte*)&idle_rate; // 数据以4MS为单位,即一个数代表4MS
usb_stat.ctrl_trf_mem = _RAM; // Set memory type 数据存储在RAM区
wCount._word = 1;
break;
case SET_IDLE:
//说明:0x0a 当数据从上一个报表后再没有改变时,闲置中断输入端点的报表频率来节省带宽
// 如果HID支持此请求则只有在数据改变时才会发送报表
ctrl_trf_session_owner = MUID_HID;
idle_rate = MSB(SetupPkt.W_Value);
break;
case GET_PROTOCOL: // 0x03 启用主机了解设备目前作用是启动协议或是报表协议
ctrl_trf_session_owner = MUID_HID; // 控制传输的系统归HID所有
pSrc.bRam = (byte*)&active_protocol;// Set source
usb_stat.ctrl_trf_mem = _RAM;
wCount._word = 1; // 数据长度
break;
case SET_PROTOCOL: // 0x0b 主机指定使用启动协议或是报表协议
ctrl_trf_session_owner = MUID_HID;
active_protocol = LSB(SetupPkt.W_Value); //取出协议类型
break;
}//end switch
}//end USBCheckHIDRequest()
/**********************************
* 主机获得数据处理函数
**********************************/
void HIDGetReportHandler()
{
switch(MSB(SetupPkt.W_Value))
{
case 1: // 输入报表
switch(LSB(SetupPkt.W_Value))
{
case 0: // 选择报表ID
ctrl_trf_session_owner = MUID_HID; // 控制传输的系统归HID所有
GetInputReport0(); // 准备数据发送到主机
break;
case 1: // 本例只有一个报表
break;
}
break;
case 3: // 主机获得特征
switch(LSB(SetupPkt.W_Value))
{
case 0:
ctrl_trf_session_owner = MUID_HID;
GetFeatureReport0();
break;
case 1:
break;
}
break;
}//end switch
usb_stat.ctrl_trf_mem = _RAM; // Set memory type,数据都放在RAM区
}//end HIDGetReportHandler()
/***********************************
* 设备获得数据处理函数
***********************************/
void HIDSetReportHandler()
{
switch(MSB(SetupPkt.W_Value))
{
case 2: // 设备获得数据
switch(LSB(SetupPkt.W_Value)) //选择ID号
{
case 0: // 如果是0号报表
ctrl_trf_session_owner = MUID_HID;
pDst.bRam = (byte*)&hid_report_out; //设置数据存储区,当主机数据发送到以后会存储到缓冲区
break;
}
break;
case 3: // 主机设置特征值
switch(LSB(SetupPkt.W_Value))
{
case 0:
ctrl_trf_session_owner = MUID_HID;
pDst.bRam = (byte*)&hid_report_feature; //设置存储缓冲区
break;
}
break;
}//end switch
}//end HIDSetReportHandler()
/*******************************
* HID取接收字节长度
*******************************/
byte HIDRxReport(char *buffer, byte len)
{
hid_rpt_rx_len = 0;
if(!HID_BD_OUT.Stat.UOWN) // 接收主机数据任务结束后端点会归CPU所有
{
if(len > HID_BD_OUT.Cnt) // 调整期待接收数据字节数等于实际接收的字节数
len = HID_BD_OUT.Cnt; //
for(hid_rpt_rx_len = 0; hid_rpt_rx_len < len; hid_rpt_rx_len++) // 数据读取
{
buffer[hid_rpt_rx_len] = hid_report_out[hid_rpt_rx_len]; // 把数据读到缓冲区
}
HID_BD_OUT.Cnt = sizeof(hid_report_out); // 准备下一次的数据接收,初始化
HID_BD_OUT.ADR = (byte*)&hid_report_out;
mUSBBufferReady(HID_BD_OUT); // 准备好下一次的接收,交替DATA端点归SIE所有
}//end if
return hid_rpt_rx_len; // 返回接收字节的长度,如果事务没完成
}//end
/********************************
* HID 发送数据到主机
********************************/
void HIDTxReport(char *buffer, byte len)
{
byte i;
if(len > HID_INT_IN_EP_SIZE) //取出发送数据字节
len = HID_INT_IN_EP_SIZE;
for (i = 0; i < len; i++)
{
hid_report_in[i] = buffer[i]; //把数据写入发送缓冲区
}
HID_BD_IN.Cnt = len;
mUSBBufferReady(HID_BD_IN); //数据开始发送
}//end HIDTxRepor
//--------------------------------------------------------- end HID函数区
//--------------------------------------------------------- 用户函数数区
/********************************
* 准备数据发送到主机
********************************/
void GetInputReport0()
{
byte count;
pSrc.bRam = (byte*)&hid_report_in; // 数据指针指向IN REPORT区,即准备好数据
wCount._word = HID_INPUT_REPORT_BYTES; // 传输数据字节数,就2个字节
}//end GetInputReport0()
/********************************
*
********************************/
void GetFeatureReport0()
{
byte count;
pSrc.bRam = (byte*)&hid_report_feature; // 准备特征数据地址地址
wCount._word = HID_FEATURE_REPORT_BYTES; // 传送两个字节
}//end GetFeatureReport0()
/********************************
* HID输出报表(主机发送)
*********************************/
void HandleControlOutReport()
{
byte count; //字节计数器
switch (MSB(SetupPkt.W_Value))
{
case 0x02: // Output report
switch(LSB(SetupPkt.W_Value))
{
case 0: // Report ID 0
for (count = 1; count <= HID_OUTPUT_REPORT_BYTES; count = count + 1)
{
hid_report_in[count-1] = hid_report_out[count-1];
}
break;
} // end switch(LSB(SetupPkt.W_Value))
case 0x03:
switch(LSB(SetupPkt.W_Value))
{
case 0: // Report ID 0
break;
} // end switch(LSB(SetupPkt.W_Value))
} // end switch(MSB(SetupPkt.W_Value))
} // end HandleControlOutReport
/******************************
* 报表查询
******************************/
//检测是否有主机传来的报表
void ReportLoopback()
{
byte count; // 定义计数字节
//获取读缓冲区字节的数目
number_of_bytes_read = HIDRxReport(receive_buffer, HID_OUTPUT_REPORT_BYTES);
if (number_of_bytes_read > 0) // 如果接收字节不为0则有数据传入
{
//取出主机发送数据到发送缓冲区
for(count =0 ; count < HID_OUTPUT_REPORT_BYTES; count++)
{
transmit_buffer[count] = receive_buffer[count]; //2个字节的数据到发送缓冲区
}//end for
while(HID_BD_IN.Stat.UOWN) // 如果发送缓冲区此时处于发送数据阶段等待
{
USBDriverService();
}//end while
HIDTxReport(transmit_buffer, HID_INPUT_REPORT_BYTES); // 数据发送
} //end if
}//end ReportLoopback()
//--------------------------------------------------------- end用户函数数区
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -