/* probe bus to determine device presense and speed and switch host to this speed */
void MAX3421E::busprobe( void )
{
    byte bus_sample;
    bus_sample = regRd( rHRSL );            //Get J,K status
    bus_sample &= ( bmJSTATUS|bmKSTATUS );      //zero the rest of the byte
    switch( bus_sample ) {                          //start full-speed or low-speed host 
        case( bmJSTATUS ):
            if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
                regWr( rMODE, MODE_FS_HOST );       //start full-speed host
                vbusState = FSHOST;
            }
            else {
                regWr( rMODE, MODE_LS_HOST);        //start low-speed host
                vbusState = LSHOST;
            }
            break;
        case( bmKSTATUS ):
            if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
                regWr( rMODE, MODE_LS_HOST );       //start low-speed host
                vbusState = LSHOST;
            }
            else {
                regWr( rMODE, MODE_FS_HOST );       //start full-speed host
                vbusState = FSHOST;
            }
            break;
        case( bmSE1 ):              //illegal state
            vbusState = MAXSE1;
            break;
        case( bmSE0 ):              //disconnected state
		regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ);
            vbusState = MAXSE0;
            break;
        }//end switch( bus_sample )
}
Beispiel #2
0
/* 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 )
}
Beispiel #3
0
/* major part of this function borrowed from code shared by Richard Ibbotson    */
byte USB::outTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
{
    byte rcode, retry_count;
    char* data_p = data;   //local copy of the data pointer
    unsigned int bytes_tosend, nak_count;
    unsigned int bytes_left = nbytes;
    byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
    unsigned long timeout = millis() + USB_XFER_TIMEOUT;

    if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64
        return 0xFE;
    }

    regWr( rHCTL, devtable[ addr ].epinfo[ ep ].sndToggle );    //set toggle value
    while( bytes_left ) {
        retry_count = 0;
        nak_count = 0;
        bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
        bytesWr( rSNDFIFO, bytes_tosend, data_p );      //filling output FIFO
        regWr( rSNDBC, bytes_tosend );                  //set number of bytes
        regWr( rHXFR, ( tokOUT | ep ));                 //dispatch packet
        while(!(regRd( rHIRQ ) & bmHXFRDNIRQ ));        //wait for the completion IRQ
        regWr( rHIRQ, bmHXFRDNIRQ );                    //clear IRQ
        rcode = ( regRd( rHRSL ) & 0x0f );
        while( rcode && ( timeout > millis())) {
            switch( rcode ) {
            case hrNAK:
                nak_count++;
                if( nak_limit && ( nak_count == USB_NAK_LIMIT )) {
                    return( rcode);                                   //return NAK
                }
                break;
            case hrTIMEOUT:
                retry_count++;
                if( retry_count == USB_RETRY_LIMIT ) {
                    return( rcode );    //return TIMEOUT
                }
                break;
            default:
                return( rcode );
            }//switch( rcode...
            /* process NAK according to Host out NAK bug */
            regWr( rSNDBC, 0 );
            regWr( rSNDFIFO, *data_p );
            regWr( rSNDBC, bytes_tosend );
            regWr( rHXFR, ( tokOUT | ep ));                 //dispatch packet
            while(!(regRd( rHIRQ ) & bmHXFRDNIRQ ));        //wait for the completion IRQ
            regWr( rHIRQ, bmHXFRDNIRQ );                    //clear IRQ
            rcode = ( regRd( rHRSL ) & 0x0f );
        }//while( rcode && ....
        bytes_left -= bytes_tosend;
        data_p += bytes_tosend;
    }//while( bytes_left...
    devtable[ addr ].epinfo[ ep ].sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? bmSNDTOG1 : bmSNDTOG0;  //update toggle
    return( rcode );    //should be 0 in all cases
}
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 )
}
Beispiel #5
0
/* return codes 0x00-0x0F are HRSLT( 0x00 being success ), 0xFF means timeout                       */
uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
  uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
  uint8_t tmpdata;
  uint8_t rcode = hrSUCCESS;
  uint8_t retry_count = 0;
  uint16_t nak_count = 0;

  while ((int32_t)((uint32_t)millis() - timeout) < 0L) {
    #if defined(ESP8266) || defined(ESP32)
      yield(); // needed in order to reset the watchdog timer on the ESP8266
    #endif
    regWr(rHXFR, (token | ep)); //launch the transfer
    rcode = USB_ERROR_TRANSFER_TIMEOUT;

    while ((int32_t)((uint32_t)millis() - timeout) < 0L) { //wait for transfer completion
      #if defined(ESP8266) || defined(ESP32)
        yield(); // needed to reset the watchdog timer on the ESP8266
      #endif
      tmpdata = regRd(rHIRQ);

      if (tmpdata & bmHXFRDNIRQ) {
        regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
        rcode = 0x00;
        break;
      }

    } // while millis() < timeout

    //if (rcode != 0x00) //exit if timeout
    //        return ( rcode);

    rcode = (regRd(rHRSL) & 0x0F); //analyze transfer result

    switch (rcode) {
      case hrNAK:
        nak_count++;
        if (nak_limit && (nak_count == nak_limit))
          return (rcode);
        break;
      case hrTIMEOUT:
        retry_count++;
        if (retry_count == USB_RETRY_LIMIT)
          return (rcode);
        break;
      default:
        return (rcode);
    }

  } // while timeout > millis()
  return rcode;
}
/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout                       */
uint8_t UsbHost_::dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit )
{
	unsigned long timeout = millis() + USB_XFER_TIMEOUT;
	uint8_t		tmpdata;   
	uint8_t		rcode;
	uint8_t		retry_count = 0;
	uint16_t	nak_count = 0;

	while( timeout > millis() ) 
	{
		regWr( rHXFR, ( token|ep ));            //launch the transfer
		rcode = USB_ERROR_TRANSFER_TIMEOUT;   

		while( millis() < timeout )				//wait for transfer completion
		{           
			tmpdata = regRd( rHIRQ );

			if( tmpdata & bmHXFRDNIRQ ) 
			{
				regWr( rHIRQ, bmHXFRDNIRQ );    //clear the interrupt
				rcode = 0x00;
				break;
			}//if( tmpdata & bmHXFRDNIRQ

		}//while ( millis() < timeout

		if( rcode != 0x00 )                 //exit if timeout
			return( rcode );

		rcode = ( regRd( rHRSL ) & 0x0f );  //analyze transfer result

		switch( rcode ) 
		{
		case hrNAK:
			nak_count ++;
			if( nak_limit && ( nak_count == nak_limit )) 
				return( rcode );
			break;
		case hrTIMEOUT:
			retry_count ++;
			if( retry_count == USB_RETRY_LIMIT )
				return( rcode );
			break;
		default:
			return( rcode );
		}//switch( rcode

	}//while( timeout > millis() 
	return( rcode );
}
uint8_t UsbHost_::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit)
{
	UsbDevice *p = addrPool.GetUsbDevicePtr(addr);

	if (!p)
		return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

 	if (!p->epinfo)
		return USB_ERROR_EPINFO_IS_NULL;

	*ppep = getEpInfoEntry(addr, ep);

	if (!*ppep)
		return USB_ERROR_EP_NOT_FOUND_IN_TBL;

	nak_limit = (0x0001UL << ( ( (*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower) );
	nak_limit--;
	  
/*
  USBTRACE2("\r\nAddress: ", addr);
  USBTRACE2(" EP: ", ep);
  USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
  USBTRACE2(" NAK Limit: ", nak_limit);
  USBTRACE("\r\n");
*/  
	regWr( rPERADDR, addr );                    //set peripheral address

	uint8_t	mode = regRd( rMODE );

	// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
	regWr( rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED)); 

	return 0;
}
/* GPIN pins are in high nibbles of IOPINS1, IOPINS2    */
byte MAX3421E::gpioRd( void )
{
    byte tmpbyte = 0;
    tmpbyte = regRd( rIOPINS2 );            //pins 4-7
    tmpbyte &= 0xf0;                        //clean lower nibble
    tmpbyte |= ( regRd( rIOPINS1 ) >>4 ) ;  //shift low bits and OR with upper from previous operation. Upper nibble zeroes during shift, at least with this compiler
    return( tmpbyte );
}
Beispiel #9
0
/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout                       */
byte USB::dispatchPkt( byte token, byte ep, unsigned int nak_limit )
{
    unsigned long timeout = millis() + USB_XFER_TIMEOUT;
    byte tmpdata;
    byte rcode;
    unsigned int nak_count = 0;
    char retry_count = 0;

    while( timeout > millis() ) {
        regWr( rHXFR, ( token|ep ));            //launch the transfer
        rcode = 0xff;
        while( millis() < timeout ) {           //wait for transfer completion
            tmpdata = regRd( rHIRQ );
            if( tmpdata & bmHXFRDNIRQ ) {
                regWr( rHIRQ, bmHXFRDNIRQ );    //clear the interrupt
                rcode = 0x00;
                break;
            }//if( tmpdata & bmHXFRDNIRQ
        }//while ( millis() < timeout
        if( rcode != 0x00 ) {                //exit if timeout
            return( rcode );
        }
        rcode = ( regRd( rHRSL ) & 0x0f );  //analyze transfer result
        switch( rcode ) {
        case hrNAK:
            nak_count ++;
            if( nak_limit && ( nak_count == nak_limit )) {
                return( rcode );
            }
            break;
        case hrTIMEOUT:
            retry_count ++;
            if( retry_count == USB_RETRY_LIMIT ) {
                return( rcode );
            }
            break;
        default:
            return( rcode );
        }//switch( rcode
    }//while( timeout > millis()
    return( rcode );
}
byte MAX3421E::GpxHandler()
{
    byte GPINIRQ = regRd( rGPINIRQ );          //read GPIN IRQ register
//    if( GPINIRQ & bmGPINIRQ7 ) {            //vbus overload
//        vbusPwr( OFF );                     //attempt powercycle
//        delay( 1000 );
//        vbusPwr( ON );
//        regWr( rGPINIRQ, bmGPINIRQ7 );
//    }       
    return( GPINIRQ );
}
/* reset MAX3421E using chip reset bit. SPI configuration is not affected   */
boolean MAX3421E::reset()
{
    unsigned short tmp = 0;
    regWr( rUSBCTL, bmCHIPRES );                        //Chip reset. This stops the oscillator
    regWr( rUSBCTL, 0x00 );                             //Remove the reset
    while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) {          //wait until the PLL is stable
        tmp++;                                          //timeout after 256 attempts
        if( tmp == 0 ) {
            return( false );
        }
    }
    return( true );
}
byte MAX3421E::IntHandler()
{
    byte HIRQ;
    byte HIRQ_sendback = 0x00;
    HIRQ = regRd( rHIRQ );                  //determine interrupt source
    //if( HIRQ & bmFRAMEIRQ ) {               //->1ms SOF interrupt handler
    //    HIRQ_sendback |= bmFRAMEIRQ;
    //}//end FRAMEIRQ handling
    if( HIRQ & bmCONDETIRQ ) {
        busprobe();
        HIRQ_sendback |= bmCONDETIRQ;
    }
    /* End HIRQ interrupts handling, clear serviced IRQs    */
    regWr( rHIRQ, HIRQ_sendback );
    return( HIRQ_sendback );
}
/* MAX3421E initialization after power-on   */
void MAX3421E::powerOn()
{
    /* Configure full-duplex SPI, interrupt pulse   */
    regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL + bmGPXB ));    //Full-duplex SPI, level interrupt, GPX
    if( reset() == false ) {                                //stop/start the oscillator
        Serial.println("Error: OSCOKIRQ failed to assert");
    }

    /* configure host operation */
    regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ );      // set pull-downs, Host, Separate GPIN IRQ on GPX
    regWr( rHIEN, bmCONDETIE|bmFRAMEIE );                                             //connection detection
    /* check if device is connected */
    regWr( rHCTL,bmSAMPLEBUS );                                             // sample USB bus
    while(!(regRd( rHCTL ) & bmSAMPLEBUS ));                                //wait for sample operation to finish
    busprobe();                                                             //check if anything is connected
    regWr( rHIRQ, bmCONDETIRQ );                                            //clear connection detect interrupt                 
    regWr( rCPUCTL, 0x01 );                                                 //enable interrupt pin
}
Beispiel #14
0
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);
}
Beispiel #15
0
/* USB main task. Performs enumeration/cleanup */
void USB::Task( void )      //USB state machine
{
    byte i;
    byte rcode;
    static byte tmpaddr;
    byte tmpdata;
    static unsigned long delay = 0;
    USB_DEVICE_DESCRIPTOR buf;
    tmpdata = getVbusState();
    /* modify USB task state if Vbus changed */

    switch( tmpdata ) {
    case SE1:   //illegal state
        usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
        break;
    case SE0:   //disconnected
        if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) {
            usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
        }
        break;
    case FSHOST:    //attached
    case LSHOST:
        if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
            delay = millis() + USB_SETTLE_DELAY;
            usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
        }
        break;
    }// switch( tmpdata
    //Serial.print("USB task state: ");
    //Serial.println( usb_task_state, HEX );
    switch( usb_task_state ) {
    case USB_DETACHED_SUBSTATE_INITIALIZE:
        init();
        usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
        break;
    case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE:     //just sit here
        break;
    case USB_DETACHED_SUBSTATE_ILLEGAL:             //just sit here
        break;
    case USB_ATTACHED_SUBSTATE_SETTLE:              //setlle time for just attached device
        if( delay < millis() ) {
            usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
        }
        break;
    case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
        regWr( rHCTL, bmBUSRST );                   //issue bus reset
        usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
        break;
    case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
        if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) {
            tmpdata = regRd( rMODE ) | bmSOFKAENAB;                 //start SOF generation
            regWr( rMODE, tmpdata );
//                  regWr( rMODE, bmSOFKAENAB );
            usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
            delay = millis() + 20; //20ms wait after reset per USB spec
        }
        break;
    case USB_ATTACHED_SUBSTATE_WAIT_SOF:  //todo: change check order
        if( regRd( rHIRQ ) & bmFRAMEIRQ ) {                         //when first SOF received we can continue
            if( delay < millis() ) {                                    //20ms passed
                usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
            }
        }
        break;
    case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE:
        // toggle( BPNT_0 );
        devtable[ 0 ].epinfo->MaxPktSize = 8;   //set max.packet size to min.allowed
        rcode = getDevDescr( 0, 0, 8, ( char* )&buf );
        if( rcode == 0 ) {
            devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0;
            usb_task_state = USB_STATE_ADDRESSING;
        }
        else {
            usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
            usb_task_state = USB_STATE_ERROR;
        }
        break;
    case USB_STATE_ADDRESSING:
        for( i = 1; i < USB_NUMDEVICES; i++ ) {
            if( devtable[ i ].epinfo == NULL ) {
                devtable[ i ].epinfo = devtable[ 0 ].epinfo;        //set correct MaxPktSize
                //temporary record
                //until plugged with real device endpoint structure
                rcode = setAddr( 0, 0, i );
                if( rcode == 0 ) {
                    tmpaddr = i;
                    usb_task_state = USB_STATE_CONFIGURING;
                }
                else {
                    usb_error = USB_STATE_ADDRESSING;          //set address error
                    usb_task_state = USB_STATE_ERROR;
                }
                break;  //break if address assigned or error occured during address assignment attempt
            }
        }//for( i = 1; i < USB_NUMDEVICES; i++
        if( usb_task_state == USB_STATE_ADDRESSING ) {     //no vacant place in devtable
            usb_error = 0xfe;
            usb_task_state = USB_STATE_ERROR;
        }
        break;
    case USB_STATE_CONFIGURING:
        break;
    case USB_STATE_RUNNING:
        break;
    case USB_STATE_ERROR:
        break;
    }// switch( usb_task_state
}
Beispiel #16
0
/* 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
}
Beispiel #17
0
/* USB main task. Performs enumeration/cleanup */
void USB::Task(void) //USB state machine
{
        uint8_t rcode;
        uint8_t tmpdata;
        static unsigned long delay = 0;
        //USB_DEVICE_DESCRIPTOR buf;
        bool lowspeed = false;

        MAX3421E::Task();

        tmpdata = getVbusState();

        /* modify USB task state if Vbus changed */
        switch(tmpdata) {
                case SE1: //illegal state
                        usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
                        lowspeed = false;
                        break;
                case SE0: //disconnected
                        if((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
                                usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
                        lowspeed = false;
                        break;
                case LSHOST:

                        lowspeed = true;
                        //intentional fallthrough
                case FSHOST: //attached
                        if((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
                                delay = millis() + USB_SETTLE_DELAY;
                                usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
                        }
                        break;
        }// switch( tmpdata

        for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
                if(devConfig[i])
                        rcode = devConfig[i]->Poll();

        switch(usb_task_state) {
                case USB_DETACHED_SUBSTATE_INITIALIZE:
                        init();

                        for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
                                if(devConfig[i])
                                        rcode = devConfig[i]->Release();

                        usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
                        break;
                case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
                        break;
                case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
                        break;
                case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
                        if(delay < millis())
                                usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
                        else break; // don't fall through
                case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
                        regWr(rHCTL, bmBUSRST); //issue bus reset
                        usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
                        break;
                case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
                        if((regRd(rHCTL) & bmBUSRST) == 0) {
                                tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
                                regWr(rMODE, tmpdata);
                                usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
                                //delay = millis() + 20; //20ms wait after reset per USB spec
                        }
                        break;
                case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
                        if(regRd(rHIRQ) & bmFRAMEIRQ) {
                                //when first SOF received _and_ 20ms has passed we can continue
                                /*
                                if (delay < millis()) //20ms passed
                                        usb_task_state = USB_STATE_CONFIGURING;
                                 */
                                usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
                                delay = millis() + 20;
                        }
                        break;
                case USB_ATTACHED_SUBSTATE_WAIT_RESET:
                        if(delay < millis()) usb_task_state = USB_STATE_CONFIGURING;
                        else break; // don't fall through
                case USB_STATE_CONFIGURING:

                        //Serial.print("\r\nConf.LS: ");
                        //Serial.println(lowspeed, HEX);

                        rcode = Configuring(0, 0, lowspeed);

                        if(rcode) {
                                if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
                                        usb_error = rcode;
                                        usb_task_state = USB_STATE_ERROR;
                                }
                        } else
                                usb_task_state = USB_STATE_RUNNING;
                        break;
                case USB_STATE_RUNNING:
                        break;
                case USB_STATE_ERROR:
                        //MAX3421E::Init();
                        break;
        } // switch( usb_task_state )
}
Beispiel #18
0
uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
        uint8_t rcode = hrSUCCESS, retry_count;
        uint8_t *data_p = data; //local copy of the data pointer
        uint16_t bytes_tosend, nak_count;
        uint16_t bytes_left = nbytes;

        uint8_t maxpktsize = pep->maxPktSize;

        if(maxpktsize < 1 || maxpktsize > 64)
                return USB_ERROR_INVALID_MAX_PKT_SIZE;

        unsigned long timeout = millis() + USB_XFER_TIMEOUT;

        regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value

        while(bytes_left) {
                retry_count = 0;
                nak_count = 0;
                bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
                bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
                regWr(rSNDBC, bytes_tosend); //set number of bytes
                regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
                while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
                regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
                rcode = (regRd(rHRSL) & 0x0f);

                while(rcode && (timeout > millis())) {
                        switch(rcode) {
                                case hrNAK:
                                        nak_count++;
                                        if(nak_limit && (nak_count == nak_limit))
                                                goto breakout;
                                        //return ( rcode);
                                        break;
                                case hrTIMEOUT:
                                        retry_count++;
                                        if(retry_count == USB_RETRY_LIMIT)
                                                goto breakout;
                                        //return ( rcode);
                                        break;
                                case hrTOGERR:
                                        // yes, we flip it wrong here so that next time it is actually correct!
                                        pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
                                        regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
                                        break;
                                default:
                                        goto breakout;
                        }//switch( rcode

                        /* process NAK according to Host out NAK bug */
                        regWr(rSNDBC, 0);
                        regWr(rSNDFIFO, *data_p);
                        regWr(rSNDBC, bytes_tosend);
                        regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
                        while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
                        regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
                        rcode = (regRd(rHRSL) & 0x0f);
                }//while( rcode && ....
                bytes_left -= bytes_tosend;
                data_p += bytes_tosend;
        }//while( bytes_left...
breakout:

        pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0;  //update toggle
        return ( rcode); //should be 0 in all cases
}