Esempio n. 1
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 )
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/* 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 )
}
Esempio n. 4
0
/* upper 4 bits of IOPINS1, IOPINS2 are read-only, so no masking is necessary */
void MAX3421E::gpioWr( byte val )
{
    regWr( rIOPINS1, val );
    val = val >>4;
    regWr( rIOPINS2, val );
    
    return;     
}
Esempio n. 5
0
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 )
}
Esempio n. 6
0
/* 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 );
}
Esempio n. 7
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
}
Esempio n. 8
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;
}
Esempio n. 9
0
/* 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 );
}
Esempio n. 10
0
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
  //printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
  uint8_t retries = 0;

again:
  uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
  if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
    if (parent == 0) {
      // Send a bus reset on the root interface.
      regWr(rHCTL, bmBUSRST); //issue bus reset
      delay(102); // delay 102ms, compensate for clock inaccuracy.
    }
    else {
      // reset parent port
      devConfig[parent]->ResetHubPort(port);
    }
  }
  else if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
    delay(100);
    retries++;
    goto again;
  }
  else if (rcode)
    return rcode;

  rcode = devConfig[driver]->Init(parent, port, lowspeed);
  if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
    delay(100);
    retries++;
    goto again;
  }

  if (rcode) {
    // Issue a bus reset, because the device may be in a limbo state
    if (parent == 0) {
      // Send a bus reset on the root interface.
      regWr(rHCTL, bmBUSRST); //issue bus reset
      delay(102); // delay 102ms, compensate for clock inaccuracy.
    }
    else {
      // reset parent port
      devConfig[parent]->ResetHubPort(port);
    }
  }
  return rcode;
}
Esempio n. 11
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 );
}
Esempio n. 12
0
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 );
}
Esempio n. 13
0
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
        uint8_t rcode = 0;
        //printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);

        rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
        if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
                if (parent == 0) {
                        // Send a bus reset on the root interface.
                        regWr(rHCTL, bmBUSRST); //issue bus reset
                        delay(102); // delay 102ms, compensate for clock inaccuracy.
                } else {
                        // reset parent port
                        devConfig[parent]->ResetHubPort(port);
                }
        }
        rcode = devConfig[driver]->Init(parent, port, lowspeed);
        return rcode;
}
Esempio n. 14
0
/* 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
}
Esempio n. 15
0
/* 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 );
}
Esempio n. 16
0
/* 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 power switch   */
//    vbusPwr( OFF );                                         //turn Vbus power off
//    regWr( rGPINIEN, bmGPINIEN7 );                          //enable interrupt on GPIN7 (power switch overload flag)
//    if( vbusPwr( ON  ) == false ) {
//        Serial.println("Error: Vbus overload");
//    }
    /* configure host operation */
    regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ );      // set pull-downs, Host, Separate GPIN IRQ on GPX
    regWr( rHIEN, bmCONDETIE|bmFRAMEIE );                                             //connection detection
    regWr(rHCTL,bmSAMPLEBUS);                                               // update the JSTATUS and KSTATUS bits
    busprobe();                                                             //check if anything is connected
    regWr( rHIRQ, bmCONDETIRQ );                                            //clear connection detect interrupt                 
    regWr( rCPUCTL, 0x01 );                                                 //enable interrupt pin
}
Esempio n. 17
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
}
Esempio n. 18
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 )
}
Esempio n. 19
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
}
Esempio n. 20
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);
}