Merge pull request #27 from kylelemons/rawread_benchmark
Rawread improvements
This commit is contained in:
161
rawread/main.go
161
rawread/main.go
@@ -20,20 +20,58 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/kylelemons/gousb/usb"
|
"github.com/kylelemons/gousb/usb"
|
||||||
"github.com/kylelemons/gousb/usbid"
|
"github.com/kylelemons/gousb/usbid"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
device = flag.String("device", "vend:prod", "Device to which to connect")
|
vidPID = flag.String("vidpid", "", "VID:PID of the device to which to connect. Exclusive with busaddr flag.")
|
||||||
config = flag.Int("config", 1, "Endpoint to which to connect")
|
busAddr = flag.String("busaddr", "", "Bus:address of the device to which to connect. Exclusive with vidpid flag.")
|
||||||
iface = flag.Int("interface", 0, "Endpoint to which to connect")
|
config = flag.Uint("config", 1, "Endpoint to which to connect")
|
||||||
setup = flag.Int("setup", 0, "Endpoint to which to connect")
|
iface = flag.Uint("interface", 0, "Endpoint to which to connect")
|
||||||
endpoint = flag.Int("endpoint", 1, "Endpoint to which to connect")
|
setup = flag.Uint("setup", 0, "Endpoint to which to connect")
|
||||||
|
endpoint = flag.Uint("endpoint", 1, "Endpoint to which to connect")
|
||||||
debug = flag.Int("debug", 3, "Debug level for libusb")
|
debug = flag.Int("debug", 3, "Debug level for libusb")
|
||||||
|
size = flag.Uint("read_size", 1024, "Number of bytes of data to read in a single transaction.")
|
||||||
|
num = flag.Uint("read_num", 0, "Number of read transactions to perform. 0 means infinite.")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func parseVIDPID(vidPid string) (usb.ID, usb.ID, error) {
|
||||||
|
s := strings.Split(vidPid, ":")
|
||||||
|
if len(s) != 2 {
|
||||||
|
return 0, 0, fmt.Errorf("want VID:PID, two 32-bit hex numbers separated by colon, e.g. 1d6b:0002")
|
||||||
|
}
|
||||||
|
vid, err := strconv.ParseUint(s[0], 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("VID must be a hexadecimal 32-bit number, e.g. 1d6b")
|
||||||
|
}
|
||||||
|
pid, err := strconv.ParseUint(s[1], 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("PID must be a hexadecimal 32-bit number, e.g. 1d6b")
|
||||||
|
}
|
||||||
|
return usb.ID(vid), usb.ID(pid), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBusAddr(busAddr string) (uint8, uint8, error) {
|
||||||
|
s := strings.Split(busAddr, ":")
|
||||||
|
if len(s) != 2 {
|
||||||
|
return 0, 0, fmt.Errorf("want bus:addr, two 8-bit decimal unsigned integers separated by colon, e.g. 1:1")
|
||||||
|
}
|
||||||
|
bus, err := strconv.ParseUint(s[0], 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("bus number must be an 8-bit decimal unsigned integer")
|
||||||
|
}
|
||||||
|
addr, err := strconv.ParseUint(s[1], 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("device address must be an 8-bit decimal unsigned integer")
|
||||||
|
}
|
||||||
|
return uint8(bus), uint8(addr), nil
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -43,40 +81,41 @@ func main() {
|
|||||||
|
|
||||||
ctx.Debug(*debug)
|
ctx.Debug(*debug)
|
||||||
|
|
||||||
log.Printf("Scanning for device %q...", *device)
|
var devName string
|
||||||
|
var vid, pid usb.ID
|
||||||
|
var bus, addr uint8
|
||||||
|
switch {
|
||||||
|
case *vidPID == "" && *busAddr == "":
|
||||||
|
log.Fatal("You need to specify the device through a --vidpid flag or through a --busaddr flag.")
|
||||||
|
case *vidPID != "" && *busAddr != "":
|
||||||
|
log.Fatal("You can't use --vidpid flag together with --busaddr. Pick one.")
|
||||||
|
case *vidPID != "":
|
||||||
|
var err error
|
||||||
|
vid, pid, err = parseVIDPID(*vidPID)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Invalid value for --vidpid (%q): %v", *vidPID, err)
|
||||||
|
}
|
||||||
|
devName = fmt.Sprintf("VID:PID %s:%s", vid, pid)
|
||||||
|
default:
|
||||||
|
var err error
|
||||||
|
bus, addr, err = parseBusAddr(*busAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Invalid value for --busaddr (%q): %v", *busAddr, err)
|
||||||
|
}
|
||||||
|
devName = fmt.Sprintf("bus:addr %d:%d", bus, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Scanning for device %q...", devName)
|
||||||
// ListDevices is used to find the devices to open.
|
// ListDevices is used to find the devices to open.
|
||||||
devs, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
|
devs, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
|
||||||
if fmt.Sprintf("%s:%s", desc.Vendor, desc.Product) != *device {
|
switch {
|
||||||
return false
|
case vid == desc.Vendor && pid == desc.Product:
|
||||||
|
return true
|
||||||
|
case bus == desc.Bus && addr == desc.Address:
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
// The usbid package can be used to print out human readable information.
|
|
||||||
fmt.Printf(" Protocol: %s\n", usbid.Classify(desc))
|
|
||||||
|
|
||||||
// The configurations can be examined from the Descriptor, though they can only
|
|
||||||
// be set once the device is opened. All configuration references must be closed,
|
|
||||||
// to free up the memory in libusb.
|
|
||||||
for _, cfg := range desc.Configs {
|
|
||||||
// This loop just uses more of the built-in and usbid pretty printing to list
|
|
||||||
// the USB devices.
|
|
||||||
fmt.Printf(" %s:\n", cfg)
|
|
||||||
for _, alt := range cfg.Interfaces {
|
|
||||||
fmt.Printf(" --------------\n")
|
|
||||||
for _, iface := range alt.Setups {
|
|
||||||
fmt.Printf(" %s\n", iface)
|
|
||||||
fmt.Printf(" %s\n", usbid.Classify(iface))
|
|
||||||
for _, end := range iface.Endpoints {
|
|
||||||
fmt.Printf(" %s\n", end)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Printf(" --------------\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// All Devices returned from ListDevices must be closed.
|
// All Devices returned from ListDevices must be closed.
|
||||||
defer func() {
|
defer func() {
|
||||||
for _, d := range devs {
|
for _, d := range devs {
|
||||||
@@ -84,22 +123,58 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// ListDevices can occaionally fail, so be sure to check its return value.
|
// ListDevices can occasionally fail, so be sure to check its return value.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("list: %s", err)
|
log.Printf("Warning: ListDevices: %s.", err)
|
||||||
}
|
}
|
||||||
|
switch {
|
||||||
if len(devs) == 0 {
|
case len(devs) == 0:
|
||||||
log.Fatalf("no devices found")
|
log.Fatal("No matching devices found.")
|
||||||
|
case len(devs) > 1:
|
||||||
|
log.Printf("Warning: multiple devices found. Using bus %d, addr %d.", devs[0].Bus, devs[0].Address)
|
||||||
|
for _, d := range devs[1:] {
|
||||||
|
d.Close()
|
||||||
|
}
|
||||||
|
devs = devs[:1]
|
||||||
}
|
}
|
||||||
|
|
||||||
dev := devs[0]
|
dev := devs[0]
|
||||||
|
|
||||||
log.Printf("Connecting to endpoint...")
|
// The usbid package can be used to print out human readable information.
|
||||||
log.Printf("- %#v", dev.Descriptor)
|
log.Printf(" Protocol: %s\n", usbid.Classify(dev.Descriptor))
|
||||||
|
|
||||||
|
// The configurations can be examined from the Descriptor, though they can only
|
||||||
|
// be set once the device is opened. All configuration references must be closed,
|
||||||
|
// to free up the memory in libusb.
|
||||||
|
for _, cfg := range dev.Configs {
|
||||||
|
// This loop just uses more of the built-in and usbid pretty printing to list
|
||||||
|
// the USB devices.
|
||||||
|
log.Printf(" %s:\n", cfg)
|
||||||
|
for _, alt := range cfg.Interfaces {
|
||||||
|
log.Printf(" --------------\n")
|
||||||
|
for _, iface := range alt.Setups {
|
||||||
|
log.Printf(" %s\n", iface)
|
||||||
|
log.Printf(" %s\n", usbid.Classify(iface))
|
||||||
|
for _, end := range iface.Endpoints {
|
||||||
|
log.Printf(" %s\n", end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf(" --------------\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Connecting to endpoint %d...", *endpoint)
|
||||||
ep, err := dev.OpenEndpoint(uint8(*config), uint8(*iface), uint8(*setup), uint8(*endpoint)|uint8(usb.ENDPOINT_DIR_IN))
|
ep, err := dev.OpenEndpoint(uint8(*config), uint8(*iface), uint8(*setup), uint8(*endpoint)|uint8(usb.ENDPOINT_DIR_IN))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("open: %s", err)
|
log.Fatalf("open: %s", err)
|
||||||
}
|
}
|
||||||
_ = ep
|
log.Print("Reading...")
|
||||||
|
|
||||||
|
buf := make([]byte, *size)
|
||||||
|
for i := uint(0); *num == 0 || i < *num; i++ {
|
||||||
|
num, err := ep.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Reading from device failed: %v", err)
|
||||||
|
}
|
||||||
|
os.Stdout.Write(buf[:num])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -87,7 +87,7 @@ func (dt DescriptorType) String() string {
|
|||||||
type EndpointDirection uint8
|
type EndpointDirection uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ENDPOINT_NUM_MASK = 0x03
|
ENDPOINT_NUM_MASK = 0x0f
|
||||||
ENDPOINT_DIR_IN EndpointDirection = C.LIBUSB_ENDPOINT_IN
|
ENDPOINT_DIR_IN EndpointDirection = C.LIBUSB_ENDPOINT_IN
|
||||||
ENDPOINT_DIR_OUT EndpointDirection = C.LIBUSB_ENDPOINT_OUT
|
ENDPOINT_DIR_OUT EndpointDirection = C.LIBUSB_ENDPOINT_OUT
|
||||||
ENDPOINT_DIR_MASK EndpointDirection = 0x80
|
ENDPOINT_DIR_MASK EndpointDirection = 0x80
|
||||||
|
@@ -74,8 +74,8 @@ int extract_data(struct libusb_transfer *xfer, void *raw, int max, unsigned char
|
|||||||
|
|
||||||
// Copy the data
|
// Copy the data
|
||||||
int len = pkt.actual_length;
|
int len = pkt.actual_length;
|
||||||
if (len > max) {
|
if (copied + len > max) {
|
||||||
len = max;
|
len = max - copied;
|
||||||
}
|
}
|
||||||
memcpy(out, in, len);
|
memcpy(out, in, len);
|
||||||
copied += len;
|
copied += len;
|
||||||
@@ -84,6 +84,10 @@ int extract_data(struct libusb_transfer *xfer, void *raw, int max, unsigned char
|
|||||||
in += pkt.length;
|
in += pkt.length;
|
||||||
out += len;
|
out += len;
|
||||||
|
|
||||||
|
if (copied == max) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Extract first error
|
// Extract first error
|
||||||
if (pkt.status == 0 || *status != 0) {
|
if (pkt.status == 0 || *status != 0) {
|
||||||
continue;
|
continue;
|
||||||
|
21
usb/iso.go
21
usb/iso.go
@@ -37,18 +37,21 @@ func iso_callback(cptr unsafe.Pointer) {
|
|||||||
close(ch)
|
close(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (end *endpoint) allocTransfer() *Transfer {
|
func (end *endpoint) allocTransfer(maxLen int) *Transfer {
|
||||||
const (
|
isoPacketSize := end.EndpointInfo.MaxIsoPacket
|
||||||
iso_packets = 8 // 128 // 242
|
// the larget the input buffer, the more packets we use in a single
|
||||||
)
|
// transfer.
|
||||||
|
numIsoPackets := maxLen / int(isoPacketSize)
|
||||||
xfer := C.libusb_alloc_transfer(C.int(iso_packets))
|
if numIsoPackets*int(isoPacketSize) < maxLen {
|
||||||
|
numIsoPackets++
|
||||||
|
}
|
||||||
|
xfer := C.libusb_alloc_transfer(C.int(numIsoPackets))
|
||||||
if xfer == nil {
|
if xfer == nil {
|
||||||
log.Printf("usb: transfer allocation failed?!")
|
log.Printf("usb: transfer allocation failed?!")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, iso_packets*end.EndpointInfo.MaxIsoPacket)
|
buf := make([]byte, numIsoPackets*int(end.EndpointInfo.MaxIsoPacket))
|
||||||
done := make(chan struct{}, 1)
|
done := make(chan struct{}, 1)
|
||||||
|
|
||||||
xfer.dev_handle = end.Device.handle
|
xfer.dev_handle = end.Device.handle
|
||||||
@@ -57,7 +60,7 @@ func (end *endpoint) allocTransfer() *Transfer {
|
|||||||
|
|
||||||
xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0]))
|
xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0]))
|
||||||
xfer.length = C.int(len(buf))
|
xfer.length = C.int(len(buf))
|
||||||
xfer.num_iso_packets = iso_packets
|
xfer.num_iso_packets = C.int(numIsoPackets)
|
||||||
|
|
||||||
C.libusb_set_iso_packet_lengths(xfer, C.uint(end.EndpointInfo.MaxIsoPacket))
|
C.libusb_set_iso_packet_lengths(xfer, C.uint(end.EndpointInfo.MaxIsoPacket))
|
||||||
/*
|
/*
|
||||||
@@ -130,7 +133,7 @@ func (t *Transfer) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isochronous_xfer(e *endpoint, buf []byte, timeout time.Duration) (int, error) {
|
func isochronous_xfer(e *endpoint, buf []byte, timeout time.Duration) (int, error) {
|
||||||
t := e.allocTransfer()
|
t := e.allocTransfer(len(buf))
|
||||||
defer t.Close()
|
defer t.Close()
|
||||||
|
|
||||||
if err := t.Submit(timeout); err != nil {
|
if err := t.Submit(timeout); err != nil {
|
||||||
|
Reference in New Issue
Block a user