google / gousb

gousb provides low-level interface for accessing USB devices
Apache License 2.0
838 stars 124 forks source link

gousb.Endpoint.Read(): libusb: invalid param [code -2] #55

Closed notnot closed 5 years ago

notnot commented 5 years ago

I am developing a UVC driver and i have two camera modules to test with. One module (ELP-SUSB1080P01) gives an error when i try to read from an endpoint:

libusb: error [submit_iso_transfer] isochronous transfer failed (dir: In): invalid argument --- FAIL: TestDeviceCaptureSettings (1.12s) uvc_test.go:208: Device.UseVideoSetting(): gousb.Endpoint.Read(): libusb: invalid param [code -2]

The other camera works fine. The camera with the error has an isochronous asynchronous IN endpoint, whereas the other has a bulk unsynchronised IN endpoint, maybe that is significant.

This is the function where it goes wrong at the end, in line n, err := d.vsEndp.Read(buf)

// UseVideoSetting sets up the device to use the requested video capture
// settings and starts streaming. If the requested settings were taken from
// the list of supported settings, then the request should be honoured as is.
func (d *Device) UseVideoSetting(setting *VideoSetting) error {
    var (
        formatIndex uint8
        frameIndex  uint8
    )
    switch desc := setting.fmt.(type) {
    case *formatDescUncompressed:
        formatIndex = desc.formatIndex
    case *formatDescMJPEG:
        formatIndex = desc.formatIndex
    }
    switch desc := setting.frame.(type) {
    case *frameDescUncompressed:
        frameIndex = desc.frameIndex
    case *frameDescMJPEG:
        frameIndex = desc.frameIndex
    }

    params := probeParams{
        hint:          0x0001,
        formatIndex:   formatIndex,
        frameIndex:    frameIndex,
        frameInterval: uint32(setting.Rate * 10000000),
    }
    fmt.Printf("desired params %#v\n", params)
    data := params.toBytes()

    // set desired state
    _, err := d.dev.Control(
        gousb.ControlOut|gousb.ControlClass|gousb.ControlInterface,
        _SET_CUR, vs_PROBE_CONTROL<<8, uint16(d.vsIfaceNum), data)
    if err != nil {
        return fmt.Errorf("gousb.Device.Control(): %s", err)
    }
    // get supported state
    _, err = d.dev.Control(
        gousb.ControlIn|gousb.ControlClass|gousb.ControlInterface,
        _GET_CUR, vs_PROBE_CONTROL<<8, uint16(d.vsIfaceNum), data)
    if err != nil {
        return fmt.Errorf("gousb.Device.Control(): %s", err)
    }
    paramsNew := probeParams{}
    paramsNew.fromBytes(data)
    fmt.Printf("supported params: %#v\n", paramsNew)

    // commit
    _, err = d.dev.Control(
        gousb.ControlOut|gousb.ControlClass|gousb.ControlInterface,
        _SET_CUR, vs_COMMIT_CONTROL<<8, uint16(d.vsIfaceNum), data)
    if err != nil {
        return fmt.Errorf("gousb.Device.Control(): %s", err)
    }

    // TODO: start a goroutine that reads the stream

    // read from the input endpoint
    bufSize := paramsNew.maxPayloadTransferSize //d.vsEndpD.maxPacketSize
    buf := make([]byte, bufSize)
    fmt.Fprintf(os.Stderr, "start streaming to %dB buffer\n", bufSize)

    for i := 0; i < 128; i++ {
        n, err := d.vsEndp.Read(buf)
        if err != nil {
            return fmt.Errorf("gousb.Endpoint.Read(): %s", err)
        }
        fmt.Printf("read %d bytes %v\n", n, buf[:32])
    }
    return nil
}

Anyone spot any error or flaw in my approach?

notnot commented 5 years ago

Never mind, it turned out that the camera with the error needs specific buffer sizes to work well. It doesn't have anything to do with libusb/gousb i think.