/* Assumed peripheral address is already set */ byte USB::ctrlStatus( byte ep, boolean direction, unsigned int nak_limit ) { byte rcode; if( direction ) { //GET rcode = dispatchPkt( tokOUTHS, ep, nak_limit ); } else { rcode = dispatchPkt( tokINHS, ep, nak_limit ); } return( rcode ); }
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, fe USB xfer timeout */ byte USB::inTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit ) { byte rcode; byte pktsize; byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize; unsigned int xfrlen = 0; regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value while( 1 ) { // use a 'return' to exit this loop rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS. if( rcode ) { return( rcode ); //should be 0, indicating ACK. Else return error code. } /* check for RCVDAVIRQ and generate error if not present */ /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */ if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) { return ( 0xf0 ); //receive error } pktsize = regRd( rRCVBC ); //number of received bytes data = bytesRd( rRCVFIFO, pktsize, data ); regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer xfrlen += pktsize; // add this packet's byte count to total transfer length /* The transfer is complete under two conditions: */ /* 1. The device sent a short packet (L.T. maxPacketSize) */ /* 2. 'nbytes' have been transferred. */ if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes? if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; } else { devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0; } return( 0 ); } }//while( 1 ) }
uint8_t UsbHost_::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) { uint8_t rcode = 0; uint8_t pktsize; uint16_t nbytes = *nbytesptr; uint8_t maxpktsize = pep->maxPktSize; *nbytesptr = 0; regWr( rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0 ); //set toggle value while( 1 ) // use a 'return' to exit this loop { rcode = dispatchPkt( tokIN, pep->epAddr, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS. if( rcode ) { #if 0 if ((rcode != 0x04) && (rcode != 0x0d)) { USBTRACE2("\ndispatchPkt error: ", rcode); } #endif return( rcode ); //should be 0, indicating ACK. Else return error code. } /* check for RCVDAVIRQ and generate error if not present */ /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */ if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) return ( 0xf0 ); //receive error pktsize = regRd( rRCVBC ); //number of received bytes assert(pktsize <= nbytes); int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); if (mem_left < 0) mem_left = 0; data = bytesRd( rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data ); regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer *nbytesptr += pktsize; // add this packet's byte count to total transfer length /* The transfer is complete under two conditions: */ /* 1. The device sent a short packet (L.T. maxPacketSize) */ /* 2. 'nbytes' have been transferred. */ if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) // have we transferred 'nbytes' bytes? { // Save toggle value pep->bmRcvToggle = (( regRd( rHRSL ) & bmRCVTOGRD )) ? 1 : 0; return( 0 ); } // if } //while( 1 ) }
/* 01-0f = non-zero HRSLT */ byte USB::ctrlReq( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, unsigned int nbytes, char* dataptr, unsigned int nak_limit ) { boolean direction = false; //request direction, IN or OUT byte rcode; SETUP_PKT setup_pkt; regWr( rPERADDR, addr ); //set peripheral address if( bmReqType & 0x80 ) { direction = true; //determine request direction } /* fill in setup packet */ setup_pkt.ReqType_u.bmRequestType = bmReqType; setup_pkt.bRequest = bRequest; setup_pkt.wVal_u.wValueLo = wValLo; setup_pkt.wVal_u.wValueHi = wValHi; setup_pkt.wIndex = wInd; setup_pkt.wLength = nbytes; bytesWr( rSUDFIFO, 8, ( char *)&setup_pkt ); //transfer to setup packet FIFO rcode = dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet //Serial.println("Setup packet"); //DEBUG if( rcode ) { //return HRSLT if not zero Serial.print("Setup packet error: "); Serial.print( rcode, HEX ); return( rcode ); } //Serial.println( direction, HEX ); if( dataptr != NULL ) { //data stage, if present rcode = ctrlData( addr, ep, nbytes, dataptr, direction ); } if( rcode ) { //return error Serial.print("Data packet error: "); Serial.print( rcode, HEX ); return( rcode ); } rcode = ctrlStatus( ep, direction ); //status stage return( rcode ); }
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) { uint8_t rcode = 0; uint8_t pktsize; uint16_t nbytes = *nbytesptr; //printf("Requesting %i bytes ", nbytes); uint8_t maxpktsize = pep->maxPktSize; *nbytesptr = 0; regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value // use a 'break' to exit this loop while(1) { rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS. if(rcode == hrTOGERR) { // yes, we flip it wrong here so that next time it is actually correct! pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value continue; } if(rcode) { //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode); break; //should be 0, indicating ACK. Else return error code. } /* check for RCVDAVIRQ and generate error if not present */ /* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */ if((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) { //printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n"); rcode = 0xf0; //receive error break; } pktsize = regRd(rRCVBC); //number of received bytes //printf("Got %i bytes \r\n", pktsize); // This would be OK, but... //assert(pktsize <= nbytes); if(pktsize > nbytes) { // This can happen. Use of assert on Arduino locks up the Arduino. // So I will trim the value, and hope for the best. //printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize); pktsize = nbytes; } int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); if(mem_left < 0) mem_left = 0; data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data); regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer *nbytesptr += pktsize; // add this packet's byte count to total transfer length /* The transfer is complete under two conditions: */ /* 1. The device sent a short packet (L.T. maxPacketSize) */ /* 2. 'nbytes' have been transferred. */ if((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes? { // Save toggle value pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0; //printf("\r\n"); rcode = 0; break; } // if } //while( 1 ) return ( rcode); }
/* 01-0f = non-zero HRSLT */ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) { bool direction = false; //request direction, IN or OUT uint8_t rcode; SETUP_PKT setup_pkt; EpInfo *pep = NULL; uint16_t nak_limit = 0; rcode = SetAddress(addr, ep, &pep, nak_limit); if(rcode) return rcode; direction = ((bmReqType & 0x80) > 0); /* fill in setup packet */ setup_pkt.ReqType_u.bmRequestType = bmReqType; setup_pkt.bRequest = bRequest; setup_pkt.wVal_u.wValueLo = wValLo; setup_pkt.wVal_u.wValueHi = wValHi; setup_pkt.wIndex = wInd; setup_pkt.wLength = total; bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet if(rcode) //return HRSLT if not zero return ( rcode); if(dataptr != NULL) //data stage, if present { if(direction) //IN transfer { uint16_t left = total; pep->bmRcvToggle = 1; //bmRCVTOG1; while(left) { // Bytes read into buffer uint16_t read = nbytes; //uint16_t read = (left<nbytes) ? left : nbytes; rcode = InTransfer(pep, nak_limit, &read, dataptr); if(rcode == hrTOGERR) { // yes, we flip it wrong here so that next time it is actually correct! pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; continue; } if(rcode) return rcode; // Invoke callback function if inTransfer completed successfully and callback function pointer is specified if(!rcode && p) ((USBReadParser*)p)->Parse(read, dataptr, total - left); left -= read; if(read < nbytes) break; } } else //OUT transfer { pep->bmSndToggle = 1; //bmSNDTOG1; rcode = OutTransfer(pep, nak_limit, nbytes, dataptr); } if(rcode) //return error return ( rcode); } // Status stage return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction }
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) { uint8_t rcode = 0; uint8_t pktsize; uint16_t nbytes = *nbytesptr; //printf("Requesting %i bytes ", nbytes); uint16_t maxpktsize = pep->maxPktSize; USB_OTG_CORE_HANDLE *pdev = coreConfig; uint32_t hcnum = pep->hcNumIn; //pdev->host.hc_num_in; #if 0 // get all packets via rx fifo pdev->host.hc[hcnum].data_pid = (pdev->host.hc[hcnum].toggle_in) ? HC_PID_DATA1 : HC_PID_DATA0; pdev->host.hc[hcnum].ep_is_in = 1; pdev->host.hc[hcnum].xfer_buff = data; pdev->host.hc[hcnum].xfer_len = nbytes; HCD_SubmitRequest(pdev, hcnum); #else // get one packet per transfer. //*nbytesptr = 0; // 1. means how many bytes was received. // 2. on stm32, we receive all data at once, so we don't need to count this var. if(maxpktsize != pdev->host.hc[hcnum].max_packet) pdev->host.hc[hcnum].max_packet = maxpktsize; uint8_t ep_addr = pep->epAddr & 0x7F; // todo: dont like this, will remove "&0x7f" if(ep_addr != pdev->host.hc[hcnum].ep_num) pdev->host.hc[hcnum].ep_num = ep_addr; //USBH_Modify_Channel(pdev, hcnum, 0, ep_addr, 0, 0, 0); if(pep->bmRcvToggle != pdev->host.hc[hcnum].toggle_in) // for hid composite pdev->host.hc[hcnum].toggle_in = pep->bmRcvToggle; while (1) // use a 'return' to exit this loop { rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit, data, nbytes, hcnum); //IN packet to EP-'endpoint'. Function takes care of NAKS. if (rcode == hrTOGERR) { // yes, we flip it wrong here so that next time it is actually correct! // pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; // regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value STM_EVAL_LEDToggle(LED3); //pdev->host.hc[hcnum].toggle_in ^= 0x1; //btd hci case printf("\nInXfer - toggle err, hc num=%d", hcnum); // will meet toggle error here? todo: sometimes once unplugged device, there is small chance that Poll still works here. //continue; } if (rcode) { //printf("\r\n>>>>>>>> Problem! dispatchPkt %d", rcode); break; //should be 0, indicating ACK. Else return error code. } /* check for RCVDAVIRQ and generate error if not present */ /* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */ // if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) { //printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n"); // rcode = 0xf0; //receive error // break; // } // pktsize = regRd(rRCVBC); //number of received bytes //printf("Got %i bytes \r\n", pktsize); // This would be OK, but... //assert(pktsize <= nbytes); // if (pktsize > nbytes) { // This can happen. Use of assert on Arduino locks up the Arduino. // So I will trim the value, and hope for the best. //printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize); // pktsize = nbytes; // } // int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); // if (mem_left < 0) // mem_left = 0; // data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data); // regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer // *nbytesptr += pktsize; // add this packet's byte count to total transfer length /* The transfer is complete under two conditions: */ /* 1. The device sent a short packet (L.T. maxPacketSize) */ /* 2. 'nbytes' have been transferred. */ //if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes? { // thanks to large fifo on stm32, we don't need packet by packet handling. // Save toggle value // the toggle is flipped at interrupt handler. //pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0; pep->bmRcvToggle = pdev->host.hc[hcnum].toggle_in; //save last toggle //printf("\r\n"); rcode = 0; break; } // if } //while( 1 ) #endif return ( rcode); }
/* 01-0f = non-zero HRSLT */ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) { bool direction = false; //request direction, IN or OUT uint8_t rcode; SETUP_PKT setup_pkt; USB_OTG_CORE_HANDLE *pdev = coreConfig; URB_STATE URB_Status = URB_IDLE; EpInfo *pep = NULL; uint16_t nak_limit = 0; /* the address are set by HC functions as 0*/ rcode = SetAddress(addr, ep, &pep, nak_limit); if (rcode) return rcode; direction = ((bmReqType & 0x80) > 0); /* fill in setup packet */ setup_pkt.ReqType_u.bmRequestType = bmReqType; setup_pkt.bRequest = bRequest; setup_pkt.wVal_u.wValueLo = wValLo; setup_pkt.wVal_u.wValueHi = wValHi; setup_pkt.wIndex = wInd; setup_pkt.wLength = total; // bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO // *pep points to EP0 (HC0-out, HC1-in) if(addr != 0) { // in case hid->setAddr() called, we should reset or reuse hid's addr. suck.. if(pdev->host.hc[pep->hcNumOut].dev_addr != addr) pdev->host.hc[pep->hcNumOut].dev_addr = addr; //USBH_Modify_Channel (pdev, pep->hcNumOut, addr, 0, 0, 0, 0); if(pdev->host.hc[pep->hcNumIn].dev_addr != addr) pdev->host.hc[pep->hcNumIn].dev_addr = addr; //USBH_Modify_Channel (pdev, pep->hcNumIn, addr, 0, 0, 0, 0); } rcode = dispatchPkt(tokSETUP, ep, nak_limit, (uint8_t *)&setup_pkt, sizeof(setup_pkt), pep->hcNumOut); //dispatch packet if (rcode) //return HRSLT if not zero return ( rcode); if (dataptr != NULL) //data stage, if present { if (direction) //IN transfer { uint16_t left = total; #if 1 //pep->bmRcvToggle = 1; //bmRCVTOG1; pdev->host.hc[pep->hcNumIn].toggle_in = 0x1; pep->bmRcvToggle = pdev->host.hc[pep->hcNumIn].toggle_in; uint16_t read = total; //nbytes; rcode = InTransfer(pep, nak_limit, &read, dataptr); // Invoke callback function if inTransfer completed successfully and callback function pointer is specified if (!rcode && p) ((USBReadParser*)p)->Parse(read, dataptr, total - left); #else while (left) { // Bytes read into buffer uint16_t read = nbytes; //uint16_t read = (left<nbytes) ? left : nbytes; pdev->host.hc[pep->hcNumIn].toggle_in = 0x1; rcode = InTransfer(pep, nak_limit, &read, dataptr); /* if (rcode == hrTOGERR) { // yes, we flip it wrong here so that next time it is actually correct! pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; continue; } */ if (rcode) return rcode; // Invoke callback function if inTransfer completed successfully and callback function pointer is specified if (!rcode && p) ((USBReadParser*)p)->Parse(read, dataptr, total - left); left -= read; if (read < nbytes) break; } #endif } else //OUT transfer { //pep->bmSndToggle = 1; //bmSNDTOG1; pdev->host.hc[pep->hcNumOut].toggle_out = 0x1; pep->bmSndToggle = pdev->host.hc[pep->hcNumOut].toggle_out; rcode = OutTransfer(pep, nak_limit, nbytes, dataptr); } if (rcode) //return error return ( rcode); } // Status stage return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit, NULL, 0, (direction) ? pep->hcNumOut : pep->hcNumIn); //GET if direction }