gdsports / USB_Host_Library_SAMD

USB host library 2.0 for Zero/M0/SAMD
126 stars 39 forks source link

OutTransfer not handling >64bytes #1

Open mjunior-fitec opened 5 years ago

mjunior-fitec commented 5 years ago

I am running some tests here with a FTDI device and I just can't send more than 64 bytes. Checking the Ftdi.SndData, I saw it calls the OutTransfer which is suppose to deal with the maxpktsize (64 byte) limit. I didn't test a solution yet, but looks like this is wrong:

uint8_t buf[64];

for( i=0; i<nbytes; i++) {
    buf[i] = data[i];
}

nbytes is the number of bytes (total) to be sent, a uint32. But this implementation takes only the fist 64bytes, since buf is 64 bytes long.

This for loop, copying the data to the buffer that will be writen should be done insisde the while (bytes_left) loop. This while loop seems to be OK, treating the message in chunks of 64 bytes and updating bytes_left every iteration.

I will test the solution tomorrow.

mjunior-fitec commented 5 years ago

I just test a simple solution, but unfortunately doesn't seem to work. Yet...

uint32_t USBHost::OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, uint8_t *data) {
    uint32_t rcode = 0, retry_count;
    uint8_t *data_p = data; //local copy of the data pointer
    uint32_t bytes_tosend, nak_count;
    uint32_t bytes_left = nbytes;
    uint8_t buf[64];
    uint8_t i;

    uint32_t maxpktsize = pep->maxPktSize;

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

    /*mjunior - removing to fix the >64b bug
    for( i=0; i<nbytes; i++) {
        buf[i] = data[i];
    }
    */
    //unsigned long timeout = millis() + USB_XFER_TIMEOUT;

    //set toggle value
    if(pep->bmSndToggle)
        USB->HOST.HostPipe[pep->epAddr].PSTATUSSET.reg = USB_HOST_PSTATUSSET_DTGL;
    else
        USB->HOST.HostPipe[pep->epAddr].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_DTGL;

    while(bytes_left) {     
        retry_count = 0;
        nak_count = 0;
        bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
        for (i = 0; i < bytes_tosend; i++){
            buf[i] = data_p[i]; //mjunior - set the buf data to be sent in this iteration (** must use data_p **)
        }
        UHD_Pipe_Write(pep->epAddr, bytes_tosend, buf); //filling output FIFO

        //set number of bytes
        //dispatch packet
        //wait for the completion IRQ
        //clear IRQ

        rcode = dispatchPkt(tokOUT, pep->epAddr, nak_limit);
        if (rcode)
        {
            switch(rcode) {
                            // --- NO CHANGES HERE --- //
            }//switch( rcode
        }

        bytes_left -= bytes_tosend;
        data_p += bytes_tosend;
    }//while( bytes_left...
breakout:
    pep->bmSndToggle = USB_HOST_DTGL(pep->epAddr);
    return (rcode); //should be 0 in all cases
}

I basically moved the for loop to inside the while(bytes_left) and adjusted the assignment to data_p and indexing with bytes_tosend. My testing conditions here are very poor, and by now I just can't check what's going wrong. As a workarround I am treating the 64b limitations outside the Ftdi.SndData call.

gdsports commented 5 years ago

I think this commit fixes the problem. https://github.com/gdsports/USB_Host_Library_SAMD/commit/ac8c3233381280f68560b36ad7224b546fcec04d