// GetScales scan all usb devices and return all scales func GetScales(ctx *usb.Context, config UsbConfig) ([]*UsbScale, error) { var scales []*UsbScale devices, err := ctx.ListDevices(func(desc *usb.Descriptor) bool { var selected = desc.Vendor == config.Vendor if config.Product != usb.ID(0) { selected = selected && desc.Product == config.Product } return selected }) if err != nil { return scales, err } if len(devices) == 0 { return scales, ErrorDeviceNotFound } getDevice: for _, dev := range devices { if runtime.GOOS == "linux" { dev.DetachKernelDriver(0) } // get devices with IN direction on endpoint for _, cfg := range dev.Descriptor.Configs { for _, alt := range cfg.Interfaces { for _, iface := range alt.Setups { for _, end := range iface.Endpoints { if end.Direction() == usb.ENDPOINT_DIR_IN { config.Config = cfg.Config config.Iface = alt.Number config.Setup = iface.Number config.Endpoint = uint8(end.Number()) scale := &UsbScale{ dev, config, } // don't timeout reading scale.ReadTimeout = 0 scales = append(scales, scale) continue getDevice } } } } } } return scales, nil }
// ParseIDs parses and returns mappings from the given reader. In general, this // should not be necessary, as a set of mappings is already embedded in the library. // If a new or specialized file is obtained, this can be used to retrieve the mappings, // which can be stored in the global Vendors and Classes map. func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, map[uint8]*Class, error) { vendors := make(map[usb.ID]*Vendor, 2800) classes := make(map[uint8]*Class) // TODO(kevlar): count split := func(s string) (kind string, level int, id uint64, name string, err error) { pieces := strings.SplitN(s, " ", 2) if len(pieces) != 2 { err = fmt.Errorf("malformatted line %q", s) return } // Save the name name = pieces[1] // Parse out the level for len(pieces[0]) > 0 && pieces[0][0] == '\t' { level, pieces[0] = level+1, pieces[0][1:] } // Parse the first piece to see if it has a kind first := strings.SplitN(pieces[0], " ", 2) if len(first) == 2 { kind, pieces[0] = first[0], first[1] } // Parse the ID i, err := strconv.ParseUint(pieces[0], 16, 16) if err != nil { err = fmt.Errorf("malformatted id %q: %s", pieces[0], err) return } id = i return } // Hold the interim values var vendor *Vendor var device *Product parseVendor := func(level int, raw uint64, name string) error { id := usb.ID(raw) switch level { case 0: vendor = &Vendor{ Name: name, } vendors[id] = vendor case 1: if vendor == nil { return fmt.Errorf("product line without vendor line") } device = &Product{ Name: name, } if vendor.Product == nil { vendor.Product = make(map[usb.ID]*Product) } vendor.Product[id] = device case 2: if device == nil { return fmt.Errorf("interface line without device line") } if device.Interface == nil { device.Interface = make(map[usb.ID]string) } device.Interface[id] = name default: return fmt.Errorf("too many levels of nesting for vendor block") } return nil } // Hold the interim values var class *Class var subclass *SubClass parseClass := func(level int, raw uint64, name string) error { id := uint8(raw) switch level { case 0: class = &Class{ Name: name, } classes[id] = class case 1: if class == nil { return fmt.Errorf("subclass line without class line") } subclass = &SubClass{ Name: name, } if class.SubClass == nil { class.SubClass = make(map[uint8]*SubClass) } class.SubClass[id] = subclass case 2: if subclass == nil { return fmt.Errorf("protocol line without subclass line") } if subclass.Protocol == nil { subclass.Protocol = make(map[uint8]string) } subclass.Protocol[id] = name default: return fmt.Errorf("too many levels of nesting for class") } return nil } // TODO(kevlar): Parse class information, etc //var class *Class //var subclass *SubClass var kind string lines := bufio.NewReaderSize(r, 512) parseLines: for lineno := 0; ; lineno++ { b, isPrefix, err := lines.ReadLine() switch { case err == io.EOF: break parseLines case err != nil: return nil, nil, err case isPrefix: return nil, nil, fmt.Errorf("line %d: line too long", lineno) } line := string(b) if len(line) == 0 || line[0] == '#' { continue } k, level, id, name, err := split(line) if err != nil { return nil, nil, fmt.Errorf("line %d: %s", lineno, err) } if k != "" { kind = k } switch kind { case "": err = parseVendor(level, id, name) case "C": err = parseClass(level, id, name) } if err != nil { return nil, nil, fmt.Errorf("line %d: %s", lineno, err) } } return vendors, classes, nil }