diff --git a/usb/device.go b/usb/device.go index f0d2f4f..11332d4 100644 --- a/usb/device.go +++ b/usb/device.go @@ -15,7 +15,7 @@ import ( var DefaultReadTimeout = 1 * time.Second var DefaultWriteTimeout = 1 * time.Second -var DefaultControlTimeout = 5 * time.Second +var DefaultControlTimeout = 250 * time.Millisecond //5 * time.Second type Device struct { handle *C.libusb_device_handle diff --git a/usb/endpoint.go b/usb/endpoint.go index 4791597..7db2822 100644 --- a/usb/endpoint.go +++ b/usb/endpoint.go @@ -25,7 +25,7 @@ type endpoint struct { } func (e *endpoint) Read(buf []byte) (int, error) { - if EndpointDirection(e.Address)&ENDPOINT_DIR_MASK != ENDPOINT_DIR_OUT { + if EndpointDirection(e.Address)&ENDPOINT_DIR_MASK != ENDPOINT_DIR_IN { return 0, fmt.Errorf("usb: read: not an IN endpoint") } @@ -40,8 +40,8 @@ func (e *endpoint) Write(buf []byte) (int, error) { return e.xfer(e, buf, e.WriteTimeout) } -func (e *endpoint) Interface() InterfaceSetup { return InterfaceSetup{} } -func (e *endpoint) Info() EndpointInfo { return EndpointInfo{} } +func (e *endpoint) Interface() InterfaceSetup { return e.InterfaceSetup } +func (e *endpoint) Info() EndpointInfo { return e.EndpointInfo } // TODO(kevlar): (*Endpoint).Close diff --git a/usb/iso.c b/usb/iso.c index 1041641..25913c8 100644 --- a/usb/iso.c +++ b/usb/iso.c @@ -1,9 +1,49 @@ #include +#include +#include -void _callback(struct libusb_transfer *xfer) { +void print_xfer(struct libusb_transfer *xfer); + +void callback(struct libusb_transfer *xfer) { + printf("Callback!\n"); + print_xfer(xfer); iso_callback(xfer->user_data); } -libusb_transfer_cb_fn callback() { - return &_callback; +int submit(struct libusb_transfer *xfer) { + xfer->callback = &callback; + xfer->status = -1; + //print_xfer(xfer); + printf("Transfer submitted\n"); + + /* fake + strcpy(xfer->buffer, "hello"); + xfer->actual_length = 5; + callback(xfer); + return 0; */ + return libusb_submit_transfer(xfer); +} + +void print_xfer(struct libusb_transfer *xfer) { + int i; + + printf("Transfer:\n"); + //printf(" dev_handle: %p\n", xfer->dev_handle); + //printf(" flags: %08x\n", xfer->flags); + printf(" endpoint: %x\n", xfer->endpoint); + //printf(" type: %x\n", xfer->type); + printf(" timeout: %dms\n", xfer->timeout); + printf(" status: %x\n", xfer->status); + printf(" length: %d (%d)\n", xfer->length, xfer->actual_length); + //printf(" callback: %p\n", xfer->callback); + //printf(" user_data: %p\n", xfer->user_data); + //printf(" buffer: %p\n", xfer->buffer); + printf(" num_iso_pkts: %d\n", xfer->num_iso_packets); + printf(" packets:\n"); + for (i = 0; i < xfer->num_iso_packets; i++) { + printf(" [%04d] %d (%d) %x\n", i, + xfer->iso_packet_desc[i].length, + xfer->iso_packet_desc[i].actual_length, + xfer->iso_packet_desc[i].status); + } } diff --git a/usb/iso.go b/usb/iso.go index 0e7de4a..639872c 100644 --- a/usb/iso.go +++ b/usb/iso.go @@ -3,12 +3,13 @@ package usb /* #include -libusb_transfer_cb_fn callback(); +int submit(struct libusb_transfer *xfer); */ import "C" import ( "log" + "fmt" "reflect" "runtime" "time" @@ -24,8 +25,8 @@ func iso_callback(cptr unsafe.Pointer) { func (end *endpoint) allocTransfer() *Transfer { // Use libusb_get_max_iso_packet_size ? const ( - iso_packets = 242 - packet_size = 1760 + iso_packets = 8 // 128 // 242 + packet_size = 2048 // 1760 ) xfer := C.libusb_alloc_transfer(C.int(iso_packets)) @@ -34,27 +35,26 @@ func (end *endpoint) allocTransfer() *Transfer { return nil } + buf := make([]byte, iso_packets*packet_size) + done := make(chan struct{}, 1) + xfer.dev_handle = end.Device.handle xfer.endpoint = C.uchar(end.Address) xfer._type = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS - xfer.callback = C.callback() - xfer.timeout = C.uint(5 * time.Second / time.Millisecond) - - buf := make([]byte, iso_packets*packet_size) - xfer.num_iso_packets = iso_packets xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0])) xfer.length = C.int(len(buf)) - C.libusb_set_iso_packet_lengths(xfer, C.uint(len(buf))) + xfer.num_iso_packets = iso_packets + + xfer.user_data = (unsafe.Pointer)(&done) + + C.libusb_set_iso_packet_lengths(xfer, packet_size) pkts := *(*[]C.struct_libusb_packet_descriptor)(unsafe.Pointer(&reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(&xfer.iso_packet_desc)), Len: iso_packets, Cap: iso_packets, })) - done := make(chan struct{}) - xfer.user_data = (unsafe.Pointer)(&done) - t := &Transfer{ xfer: xfer, pkts: pkts, @@ -74,34 +74,48 @@ type Transfer struct { buf []byte } -func (xfer *Transfer) Submit() error { - if errno := C.libusb_submit_transfer(xfer.xfer); errno < 0 { +func (t *Transfer) Submit(timeout time.Duration) error { + log.Printf("iso: submitting %#v", t.xfer) + t.xfer.timeout = C.uint(timeout / time.Millisecond) + if errno := C.submit(t.xfer); errno < 0 { return usbError(errno) } return nil } -func (xfer *Transfer) Wait() (n int, err error) { - <-xfer.done - n = int(xfer.xfer.actual_length) - for _, pkt := range xfer.pkts { - log.Printf("PACKET[%4d] - %#v", pkt) +func (t *Transfer) Wait(b []byte) (n int, err error) { + select { + case <-time.After(10*time.Second): + return 0, fmt.Errorf("wait timed out after 10s") + case <-t.done: } + n = int(t.xfer.actual_length) + copy(b, ((*[1<<16]byte)(unsafe.Pointer(t.xfer.buffer)))[:n]) + /* + for i, pkt := range t.pkts { + log.Printf("PACKET[%4d] - %#v", i, pkt) + }*/ return n, err } -func (xfer *Transfer) Close() error { - C.libusb_free_transfer(xfer.xfer) +func (t *Transfer) Close() error { + C.libusb_free_transfer(t.xfer) return nil } func isochronous_xfer(e *endpoint, buf []byte, timeout time.Duration) (int, error) { - xfer := e.allocTransfer() - defer xfer.Close() + t := e.allocTransfer() + defer t.Close() - if err := xfer.Submit(); err != nil { + if err := t.Submit(timeout); err != nil { + log.Printf("iso: xfer failed to submit: %s", err) return 0, err } - return xfer.Wait() + n, err := t.Wait(buf) + if err != nil { + log.Printf("iso: xfer failed: %s", err) + return 0, err + } + return n, err }