-
Notifications
You must be signed in to change notification settings - Fork 1
/
gousb_adapter.go
130 lines (109 loc) · 3.17 KB
/
gousb_adapter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package skreader
import (
"errors"
"fmt"
"github.com/google/gousb"
)
const (
IDVendor = 0x0A41
IDProduct = 0x7003
EndpointNumOut = 0x02
EndpointNumIn = 0x81
)
var _ UsbAdapter = (*GousbAdapter)(nil) // assert it implements UsbAdapter interface
// GousbAdapter implements UsbAdapter interface using `gousb` library.
// The gousb package is a Google's Go-like wrapper around `libusb` library which is required to be
// installed on the target system. See more: https://github.com/libusb/libusb/wiki
type GousbAdapter struct {
ctx *gousb.Context
dev *gousb.Device
intf *gousb.Interface
intfDone func()
epIn *gousb.InEndpoint
epOut *gousb.OutEndpoint
}
// Expose all used gousb functions as variables to be able to mock them in tests.
var (
GousbNewContext = func() *gousb.Context { //nolint:all
return gousb.NewContext()
}
GousbOpenDeviceWithVIDPID = func(ctx *gousb.Context, vid gousb.ID, pid gousb.ID) (*gousb.Device, error) {
return ctx.OpenDeviceWithVIDPID(vid, pid)
}
GousbDefaultInterface = func(d *gousb.Device) (*gousb.Interface, func(), error) {
return d.DefaultInterface()
}
GousbInEndpoint = func(i *gousb.Interface, epNum int) (*gousb.InEndpoint, error) {
return i.InEndpoint(epNum)
}
GousbOutEndpoint = func(i *gousb.Interface, epNum int) (*gousb.OutEndpoint, error) {
return i.OutEndpoint(epNum)
}
GousbManufacturer = func(d *gousb.Device) (string, error) {
return d.Manufacturer()
}
GousbProduct = func(d *gousb.Device) (string, error) {
return d.Product()
}
GousbRead = func(ep *gousb.InEndpoint, buf []byte) (int, error) {
return ep.Read(buf)
}
GousbWrite = func(ep *gousb.OutEndpoint, buf []byte) (int, error) {
return ep.Write(buf)
}
)
func (u *GousbAdapter) Open() (err error) {
u.ctx = GousbNewContext()
u.dev, err = GousbOpenDeviceWithVIDPID(u.ctx, IDVendor, IDProduct)
if err != nil {
return fmt.Errorf("could not open a device: %v", err)
}
if u.dev == nil {
return errors.New("could not open a device, is it connected?")
}
u.intf, u.intfDone, err = GousbDefaultInterface(u.dev)
if err != nil {
return fmt.Errorf("could not get default interface: %v", err)
}
u.epIn, err = GousbInEndpoint(u.intf, EndpointNumIn)
if err != nil {
return fmt.Errorf("could not get IN endpoint: %v", err)
}
u.epOut, err = GousbOutEndpoint(u.intf, EndpointNumOut)
if err != nil {
return fmt.Errorf("could not get OUT endpoint: %v", err)
}
return nil
}
func (u *GousbAdapter) Close() (err error) {
if u.intfDone != nil {
u.intfDone()
}
if u.dev != nil {
err = u.dev.Close()
}
if u.ctx != nil {
err = u.ctx.Close()
}
return err
}
func (u *GousbAdapter) Read(buf []byte) (int, error) {
return GousbRead(u.epIn, buf)
}
func (u *GousbAdapter) Write(buf []byte) (int, error) {
return GousbWrite(u.epOut, buf)
}
func (u *GousbAdapter) Manufacturer() (string, error) {
manufacturer, err := GousbManufacturer(u.dev)
if err != nil {
return "", fmt.Errorf("could not read Manufacturer: %v", err)
}
return manufacturer, nil
}
func (u *GousbAdapter) Product() (string, error) {
product, err := GousbProduct(u.dev)
if err != nil {
return "", fmt.Errorf("could not read Product: %v", err)
}
return product, nil
}