Tidy up interfaces and pretty printing

This commit is contained in:
Kyle Lemons
2012-03-26 22:37:25 -07:00
parent ba2dd5404f
commit 0f572675c9
7 changed files with 222 additions and 71 deletions

48
usbid/describe.go Normal file
View File

@@ -0,0 +1,48 @@
package usbid
import (
"fmt"
"github.com/kylelemons/gousb/usb"
)
// Describe one of the following:
// - *usb.Descriptor Product (Vendor)
func Describe(val interface{}) string {
switch val := val.(type) {
case *usb.Descriptor:
if v, ok := Vendors[val.Vendor]; ok {
if d, ok := v.Product[val.Product]; ok {
return fmt.Sprintf("%s (%s)", d, v)
}
return fmt.Sprintf("Unknown (%s)", v)
}
return fmt.Sprintf("Unknown %s:%s", val.Vendor, val.Product)
}
return fmt.Sprintf("Unknown (%T)", val)
}
// Classify one of the following:
// - *usb.Descriptor Class SubClass Protocol
func Classify(val interface{}) string {
var class, sub, proto uint8
switch val := val.(type) {
case *usb.Descriptor:
class, sub, proto = val.Class, val.SubClass, val.Protocol
case *usb.Interface:
class, sub, proto = val.IfClass, val.IfSubClass, val.IfProtocol
default:
return fmt.Sprintf("Unknown (%T)", val)
}
if c, ok := Classes[class]; ok {
if s, ok := c.SubClass[sub]; ok {
if p, ok := s.Protocol[proto]; ok {
return fmt.Sprintf("%s (%s) %s", c, s, p)
}
return fmt.Sprintf("%s (%s)", c, s)
}
return fmt.Sprintf("%s", c)
}
return fmt.Sprintf("Unknown %s.%s.%s", class, sub, proto)
}

View File

@@ -13,6 +13,7 @@ const (
)
var Vendors map[usb.ID]*Vendor
var Classes map[uint8]*Class
func LoadFromURL(url string) error {
resp, err := http.Get(url)
@@ -21,21 +22,23 @@ func LoadFromURL(url string) error {
}
defer resp.Body.Close()
ids, err := ParseIDs(resp.Body)
ids, cls, err := ParseIDs(resp.Body)
if err != nil {
return err
}
Vendors = ids
Classes = cls
return nil
}
func init() {
ids, err := ParseIDs(strings.NewReader(usbIdListData))
ids, cls, err := ParseIDs(strings.NewReader(usbIdListData))
if err != nil {
log.Printf("usbid: failed to parse: %s", err)
return
}
Vendors = ids
Classes = cls
}

View File

@@ -12,39 +12,45 @@ import (
type Vendor struct {
Name string
Devices map[usb.ID]*Device
Product map[usb.ID]*Product
}
func (v Vendor) String() string {
return v.Name
}
// TODO(kevlar) s/device/
type Device struct {
type Product struct {
Name string
Interfaces map[usb.ID]string
Interface map[usb.ID]string
}
func (d Device) String() string {
return d.Name
func (p Product) String() string {
return p.Name
}
/*
type Class struct {
Name string
SubClass map[usb.ID]*SubClass
SubClass map[uint8]*SubClass
}
func (c Class) String() string {
return c.Name
}
type SubClass struct {
Name string
Protocol map[usb.ID]string
Protocol map[uint8]string
}
*/
func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
func (s SubClass) String() string {
return s.Name
}
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 usb.ID, name string, err error) {
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)
@@ -71,16 +77,18 @@ func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
err = fmt.Errorf("malformatted id %q: %s", pieces[0], err)
return
}
id = usb.ID(i)
id = i
return
}
// Hold the interim values
var vendor *Vendor
var device *Device
var device *Product
parseVendor := func(level int, raw uint64, name string) error {
id := usb.ID(raw)
parseVendor := func(level int, id usb.ID, name string) error {
switch level {
case 0:
vendor = &Vendor{
@@ -93,23 +101,23 @@ func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
return fmt.Errorf("product line without vendor line")
}
device = &Device{
device = &Product{
Name: name,
}
if vendor.Devices == nil {
vendor.Devices = make(map[usb.ID]*Device)
if vendor.Product == nil {
vendor.Product = make(map[usb.ID]*Product)
}
vendor.Devices[id] = device
vendor.Product[id] = device
case 2:
if device == nil {
return fmt.Errorf("interface line without device line")
}
if device.Interfaces == nil {
device.Interfaces = make(map[usb.ID]string)
if device.Interface == nil {
device.Interface = make(map[usb.ID]string)
}
device.Interfaces[id] = name
device.Interface[id] = name
default:
return fmt.Errorf("too many levels of nesting for vendor block")
@@ -118,6 +126,50 @@ func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
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
@@ -132,9 +184,9 @@ parseLines:
case err == io.EOF:
break parseLines
case err != nil:
return nil, err
return nil, nil, err
case isPrefix:
return nil, fmt.Errorf("line %d: line too long", lineno)
return nil, nil, fmt.Errorf("line %d: line too long", lineno)
}
line := string(b)
@@ -144,7 +196,7 @@ parseLines:
k, level, id, name, err := split(line)
if err != nil {
return nil, fmt.Errorf("line %d: %s", lineno, err)
return nil, nil, fmt.Errorf("line %d: %s", lineno, err)
}
if k != "" {
kind = k
@@ -153,11 +205,13 @@ parseLines:
switch kind {
case "":
err = parseVendor(level, id, name)
case "C":
err = parseClass(level, id, name)
}
if err != nil {
return nil, fmt.Errorf("line %d: %s", lineno, err)
return nil, nil, fmt.Errorf("line %d: %s", lineno, err)
}
}
return vendors, nil
return vendors, classes, nil
}