では、gousbを使ってみよう。
exampleを使う。
https://github.com/google/gousb/blob/master/example_test.go
まあ、まずはデバイスを認識できるかどうかからだ。
libusb-1.0がいるから、事前にaptなりなんなりでインストールしておく。
01: // sudo apt install libusb-1.0
02:
03: package main
04:
05: import (
06: "fmt"
07: "log"
08:
09: "github.com/google/gousb"
10: )
11:
12: const (
13: VID = 0x054c
14: PID = 0x02e1
15: )
16:
17: // https://github.com/google/gousb/blob/master/example_test.go
18: func exampleSimple() {
19: // Initialize a new Context.
20: ctx := gousb.NewContext()
21: defer ctx.Close()
22:
23: // Open any device with a given VID/PID using a convenience function.
24: dev, err := ctx.OpenDeviceWithVIDPID(VID, PID)
25: if err != nil {
26: log.Fatalf("Could not open a device: %v", err)
27: }
28: defer dev.Close()
29:
30: // Claim the default interface using a convenience function.
31: // The default interface is always #0 alt #0 in the currently active
32: // config.
33: intf, done, err := dev.DefaultInterface()
34: if err != nil {
35: log.Fatalf("%s.DefaultInterface(): %v", dev, err)
36: }
37: defer done()
38:
39: // Open an OUT endpoint.
40: ep, err := intf.OutEndpoint(7)
41: if err != nil {
42: log.Fatalf("%s.OutEndpoint(7): %v", intf, err)
43: }
44:
45: // Generate some data to write.
46: data := make([]byte, 5)
47: for i := range data {
48: data[i] = byte(i)
49: }
50:
51: // Write data to the USB device.
52: numBytes, err := ep.Write(data)
53: if numBytes != 5 {
54: log.Fatalf("%s.Write([5]): only %d bytes written, returned error is %v", ep, numBytes, err)
55: }
56: fmt.Println("5 bytes successfully sent to the endpoint")
57: }
58:
59: func main() {
60: exampleSimple()
61: }
$ go run .
2020/03/07 11:04:01 Could not open a device: libusb: bad access [code -3]
exit status 1
まあ、いきなりは動かんか。
デバイスを使う場合、sudoとかしないといけなさそうな気がするのだが、lsusbなんかはsudoしなくても使える。
wiresharkなんかはグループを作っておけばsudoせずにいけたのだが、libusbはどうだったか。
L.24のctx.OpenDeviceWithVIDPID(VID, PID) で起きている。
C言語で書くとこんな感じだった。
https://github.com/hirokuma/libhknfcrw_c/blob/master/examples/cyg_devaccess_pasori.c#L109
sudoしてみる。
$ sudo ./go_pasori1
2020/03/07 11:11:44 vid=054c,pid=02e1,bus=2,addr=5.DefaultInterface(): failed to select interface #0 alternate setting 0 of config 1 of device vid=054c,pid=02e1,bus=2,addr=5: failed to claim interface 0 on vid=054c,pid=02e1,bus=2,addr=5,config=1: libusb: device or resource busy [code -6]
これはL.35のメッセージだから、権限の問題ということか。
udevで設定を書くことで回避できるようだが、しばらくはsudoでよかろう。
では、次はL.35のエラーについてだ。
Busyっぽいのだが、私はRC-S370をVirtualBoxのデバイス指定で使えるようにしただけだ。
dmesgを見てみる。
[15145.225082] usb 2-2: new full-speed USB device number 6 using ohci-pci
[15146.112505] usb 2-2: New USB device found, idVendor=054c, idProduct=02e1
[15146.112507] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[15146.112509] usb 2-2: Product: RC-S370/P
[15146.112511] usb 2-2: Manufacturer: Sony
[15146.124738] usb 2-2: NFC: NXP PN533 firmware ver 1.48 now attached
OSがRC-S370をデバイスとして認めてしまっている・・・?
そういえば、いつからかLinuxはNFCデバイス(たぶんReader/Writerだろう)を識別するようになったという記事を見かけた気がする。
RC-S380(Pasori)とLinux NFC Subsystem | 何かできる気がする
https://dekirukigasuru.com/blog/2019/01/05/linux-nfc-subsystem/
Linux NFC Subsystem、ね。
できれば、今回は新しいことは試さず、USBとして動かしたいのだ。
そういえばC言語で書いていたときも、default interfaceみたいなものは使えなかった気がする。
https://github.com/hirokuma/libhknfcrw_c/blob/master/examples/cyg_devaccess_pasori.c#L133-L156
おそらく、この辺りはend pointを探しているところだろう。
なので、便利関数を使うサンプルではなく、その下にある方のサンプルを使おう。
https://github.com/google/gousb/blob/master/example_test.go#L76
ここから下を貼り付けただけなので、コードは省略だ。
2020/03/07 11:47:56 vid=054c,pid=02e1,bus=2,addr=6.Config(2): device vid=054c,pid=02e1,bus=2,addr=6: configuration id 2 not found in the descriptor of the device. Available config ids: [1]
"Config(2)"なので、ここのエラーか。
https://github.com/google/gousb/blob/master/example_test.go#L105
そういえば、なんとなくコードを貼り付けて動かしているのだが・・・この2とか3とかってなんなのだ??
エラーログの一番最後に"[1]"となっているから、2じゃなくて1ならconfigがあるということか。
・・・1にすると進んだ。。。
まあいい、最後まで通してから考えよう。
次のエラーはこれ。
2020/03/07 11:53:06 vid=054c,pid=02e1,bus=2,addr=6,config=1.Interface(3, 0): descriptor of interface (3, 0) in vid=054c,pid=02e1,bus=2,addr=6,config=1: interface 3 not found, available interfaces 0..0
3じゃなくて0ってことか。
が、0にしたらしたで別のエラーになった。
2020/03/07 11:54:51 vid=054c,pid=02e1,bus=2,addr=6,config=1.Interface(3, 0): failed to claim interface 0 on vid=054c,pid=02e1,bus=2,addr=6,config=1: libusb: device or resource busy [code -6]
ダメだ、このやり方じゃダメだ。。。
C言語で書いていたときのやり方がいいだろう。
調べられるリストを作って、先頭から順に調べて使えるものを探す、と。
改めて、openする流れをおさらいしよう。
https://github.com/hirokuma/libhknfcrw_c/blob/master/examples/cyg_devaccess_pasori.c#L47
- libusb_open_device_with_vid_pid()でハンドル取得
- libusb_get_device()でデバイス取得
- libusb_get_config_descriptor()でコンフィグ取得
- コンフィグからinterfaceの数だけEnd Pointを探す?
- libusb_claim_interface()でclaim
自分で書いておきながら理解していないが、当時もlibusbのサンプルから持ってきたやり方を使っただけだろう。
コンフィグ中をぐるぐる探すところも、本当はbreakとかして抜けるべき何じゃなかろうかね。。。
01: // sudo apt install libusb-1.0
02:
03: package main
04:
05: import (
06: "fmt"
07: "log"
08:
09: "github.com/google/gousb"
10: )
11:
12: const (
13: VID = 0x054c
14: PID = 0x02e1
15: )
16:
17: // https://github.com/google/gousb/blob/master/example_test.go
18: func openUsb() {
19: // Initialize a new Context.
20: ctx := gousb.NewContext()
21: defer ctx.Close()
22:
23: // Open any device with a given VID/PID using a convenience function.
24: dev, err := ctx.OpenDeviceWithVIDPID(VID, PID)
25: if err != nil {
26: log.Fatalf("Could not open a device: %v", err)
27: }
28: defer dev.Close()
29:
30: for _, cfg := range dev.Desc.Configs {
31: for _, inf := range cfg.Interfaces {
32: for _, alt := range inf.AltSettings {
33: for _, endPnt := range alt.Endpoints {
34: fmt.Printf("endpoint=%v\n", endPnt)
35: }
36: }
37: }
38: }
39: }
40:
41: func main() {
42: openUsb()
43: }
$ sudo ./go_pasori1
endpoint=ep #4 OUT (address 0x04) bulk [64 bytes]
endpoint=ep #4 IN (address 0x84) bulk [64 bytes]
最初、for文でinterface数なんかをがんばって取得してぐるぐる回そうとしていたのだが、lsusbサンプルを見てrangeというものがあったことを思い出す。
おそらくこれでUSBデバイスはオープンできたと思う。
だが、C言語でlibusbを使ったときは最後にlibusb_claim_interface()を呼んでいた。
これは何をする関数なのだろうか?
http://libusb.sourceforge.net/api-1.0/group__dev.html#ga32fabedf5f13fdecf1cb33acdb19b57a
制御するデバイスを主張する、なのか?
C言語版では固定で0を使っていたのだが、果たしてうまくいっていたのだろうか・・・。
それはともかく、gousbだとConfig()がそれなのか。
しかし、libusb_bulk_transfer()は無く、代わりにReadStream, WriteStreamを取得してアクセスするようだ。
その辺はサンプルを見た方が早いだろう。
https://github.com/google/gousb/blob/master/example_test.go#L52
Closeするのはdevだけでよさそうな気配がする。
これはまだ確信を得られないので、後で考えよう。