int16_t MeUSBHost::initHIDDevice() { int16_t irq, len, address; if(usbtype==USB1_0) set_freq(); //work on a lower freq, necessary for ch375 irq = get_desr(1); #ifdef CH375_DBG Serial.printf("get des irq:%x\n",irq); #endif if(irq==USB_INT_SUCCESS){ len = rd_usb_data( RECV_BUFFER ); #ifdef CH375_DBG Serial.printf("descr1 len %d type %x\r\n",len,p_dev_descr->bDescriptorType); #endif irq = set_addr(2); if(irq==USB_INT_SUCCESS){ irq = get_desr(2); // max buf 64byte, todo:config descr overflow if(irq==USB_INT_SUCCESS){ len = rd_usb_data( RECV_BUFFER ); #ifdef CH375_DBG Serial.printf("descr2 len %d class %x subclass %x\r\n",len,p_cfg_descr->itf_descr.bInterfaceClass, p_cfg_descr->itf_descr.bInterfaceSubClass); // interface class should be 0x03 for HID Serial.printf("num of ep %d\r\n",p_cfg_descr->itf_descr.bNumEndpoints); Serial.printf("ep0 %x %x\r\n",p_cfg_descr->endp_descr[0].bLength, p_cfg_descr->endp_descr[0].bDescriptorType); #endif if(p_cfg_descr->endp_descr[0].bDescriptorType==0x21){ // skip hid des tmpEp = (PUSB_ENDP_DESCR)((int8_t*)(&(p_cfg_descr->endp_descr[0]))+p_cfg_descr->endp_descr[0].bLength); // get the real ep position } #ifdef CH375_DBG Serial.printf("endpoint %x %x\r\n",tmpEp->bEndpointAddress,tmpEp->bDescriptorType); #endif endp_out_addr=endp_in_addr=0; address =tmpEp->bEndpointAddress; /* Address of First EndPoint */ // actually we only care about the input end points if( address&0x80 ){ endp_in_addr = address&0x0f; /* Address of IN EndPoint */ }else{ /* OUT EndPoint */ endp_out_addr = address&0x0f; endp_out_size = p_cfg_descr->endp_descr[0].wMaxPacketSize; /* Length of Package for Received Data EndPoint */ if( endp_out_size == 0 || endp_out_size > 64 ) endp_out_size = 64; } // todo: some joystick with more than 2 node // just assume every thing is fine, bring the device up irq = set_config(p_cfg_descr->cfg_descr.bConfigurationvalue); if(irq==USB_INT_SUCCESS){ CH375_WR( CMD_SET_RETRY ); // set the retry times CH375_WR( 0x25 ); CH375_WR( 0x85 ); device_ready = true; return 1; } } } } return 0; }
unsigned char init_print() { /* 初始化USB打印机,完成打印机枚举 */ #define p_dev_descr ((PUSB_DEV_DESCR)buffer) #define p_cfg_descr ((PUSB_CFG_DESCR_LONG)buffer) unsigned char status, len, c; status=get_descr(1); /* 获取设备描述符 */ if ( status==USB_INT_SUCCESS ) { len=rd_usb_data( buffer ); /* 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度 */ if ( len<18 || p_dev_descr->bDescriptorType!=1 ) return( UNKNOWN_USB_DEVICE ); /* 意外错误:描述符长度错误或者类型错误 */ if ( p_dev_descr->bDeviceClass!=0 ) return( UNKNOWN_USB_DEVICE ); /* 连接的USB设备不是USB打印机,或者不符合USB规范 */ status=set_addr(3); /* 设置打印机的USB地址 */ if ( status==USB_INT_SUCCESS ) { status=get_descr(2); /* 获取配置描述符 */ if ( status==USB_INT_SUCCESS ) { /* 操作成功则读出描述符并分析 */ len=rd_usb_data( buffer ); /* 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度 */ if ( p_cfg_descr->itf_descr.bInterfaceClass!=7 || p_cfg_descr->itf_descr.bInterfaceSubClass!=1 ) return( UNKNOWN_USB_PRINT ); /* 不是USB打印机或者不符合USB规范 */ endp_out_addr=endp_in_addr=0; c=p_cfg_descr->endp_descr[0].bEndpointAddress; /* 第一个端点的地址 */ if ( c&0x80 ) endp_in_addr=c&0x0f; /* IN端点的地址 */ else { /* OUT端点 */ endp_out_addr=c&0x0f; endp_out_size=p_cfg_descr->endp_descr[0].wMaxPacketSize; /* 数据接收端点的最大包长度 */ } if ( p_cfg_descr->itf_descr.bNumEndpoints>=2 ) { /* 接口有两个以上的端点 */ if ( p_cfg_descr->endp_descr[1].bDescriptorType==5 ) { /* 端点描述符 */ c=p_cfg_descr->endp_descr[1].bEndpointAddress; /* 第二个端点的地址 */ if ( c&0x80 ) endp_in_addr=c&0x0f; /* IN端点 */ else { /* OUT端点 */ endp_out_addr=c&0x0f; endp_out_size=p_cfg_descr->endp_descr[1].wMaxPacketSize; } } } if ( p_cfg_descr->itf_descr.bInterfaceProtocol<=1 ) endp_in_addr=0; /* 单向接口不需要IN端点 */ if ( endp_out_addr==0 ) return( UNKNOWN_USB_PRINT ); /* 不是USB打印机或者不符合USB规范 */ status=set_config( p_cfg_descr->cfg_descr.bConfigurationValue ); /* 加载USB配置值 */ if ( status==USB_INT_SUCCESS ) { CH375_WR_CMD_PORT( CMD_SET_RETRY ); /* 设置USB事务操作的重试次数 */ CH375_WR_DAT_PORT( 0x25 ); CH375_WR_DAT_PORT( 0x89 ); /* 位7为1则收到NAK时无限重试, 位3~位0为超时后的重试次数 */ /* 如果单片机在打印机忙时并无事可做,建议设置位7为1,使CH375在收到NAK时自动重试直到操作成功或者失败 */ /* 如果希望单片机在打印机忙时能够做其它事,那么应该设置位7为0,使CH375在收到NAK时不重试, 所以在下面的USB通讯过程中,如果USB打印机正忙,issue_token等子程序将得到状态码USB_INT_RET_NAK */ } } } } return(status); }
unsigned char get_port_status_X( ) { /* 查询打印机端口状态,返回状态码,如果为0FFH则说明操作失败,适用于CH375A */ /* 返回状态码中: 位5(Paper Empty)为1说明无纸, 位4(Select)为1说明打印机联机, 位3(Not Error)为0说明打印机出错 */ buffer[0]=0xA1; buffer[1]=1; buffer[2]=buffer[3]=buffer[4]=buffer[5]=0; buffer[6]=1; buffer[7]=0; /* 控制传输获取打印机状态,SETUP数据 */ wr_usb_data( 8, buffer ); /* SETUP数据总是8字节 */ if ( issue_token_X( ( 0 << 4 ) | DEF_USB_PID_SETUP, 0x00 )==USB_INT_SUCCESS ) { /* SETUP阶段DATA0操作成功 */ if ( issue_token_X( ( 0 << 4 ) | DEF_USB_PID_IN, 0x80 )==USB_INT_SUCCESS ) { /* DATA阶段DATA1接收操作成功 */ rd_usb_data( buffer ); /* 读出接收到的数据,通常只有1个字节 */ wr_usb_data( 0, buffer ); /* 发送0长度的数据DATA1说明控制传输成功 */ if ( issue_token_X( ( 0 << 4 ) | DEF_USB_PID_OUT, 0x40 )==USB_INT_SUCCESS ) return( buffer[0] ); /* STATUS阶段操作成功,返回状态码 */ } } return( 0xFF ); /* 返回操作失败 */ }
unsigned char get_port_status( ) { /* 查询打印机端口状态,返回状态码,如果为0FFH则说明操作失败 */ /* 返回状态码中: 位5(Paper Empty)为1说明无纸, 位4(Select)为1说明打印机联机, 位3(Not Error)为0说明打印机出错 */ toggle_send( 0 ); /* 下面通过控制传输获取打印机的状态, SETUP阶段为DATA0 */ buffer[0]=0xA1; buffer[1]=1; buffer[2]=buffer[3]=buffer[4]=buffer[5]=0; buffer[6]=1; buffer[7]=0; /* SETUP数据,GET_PORT_STATUS */ wr_usb_data( 8, buffer ); /* SETUP数据总是8字节 */ if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_SETUP )==USB_INT_SUCCESS ) { /* SETUP阶段操作成功 */ toggle_recv( 1 ); /* DATA阶段,准备接收DATA1 */ if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_IN )==USB_INT_SUCCESS ) { /* DATA阶段操作成功 */ rd_usb_data( buffer ); /* 读出接收到的数据,通常只有1个字节 */ toggle_send( 1 ); /* STATUS阶段为DATA1 */ wr_usb_data( 0, buffer ); /* 发送0长度的数据说明控制传输成功 */ if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_OUT )==USB_INT_SUCCESS ) return( buffer[0] ); /* 返回状态码 */ } } return( 0xFF ); /* 返回操作失败 */ }
unsigned char MeUsb::host_recv() { unsigned char irq; toggle_recv(); irq = issue_token( ( endp_in_addr << 4 ) | DEF_USB_PID_IN ); if(irq==USB_INT_SUCCESS){ int len = rd_usb_data(RECV_BUFFER); #ifdef USB_DBG for(int i=0;i<len;i++){ // point hid device Serial.print("0x"); Serial.println((int)RECV_BUFFER[i],HEX); } Serial.println(); #endif stallCount = 0; return len; }else if(irq==USB_INT_DISCONNECT){ device_online = false; device_ready = false; #ifdef USB_DBG Serial.println("##### disconn #####"); #endif return 0; }else{ clr_stall6(); #ifdef USB_DBG Serial.println("##### stall #####"); #endif delay(10); /* stallCount++; if(stallCount>10){ device_online = false; device_ready = false; resetBus(); } */ return 0; } }