Skip to content

Commit

Permalink
initial webusb support
Browse files Browse the repository at this point in the history
  • Loading branch information
solipsis committed Dec 11, 2018
1 parent 1f2c759 commit 784fdcd
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 129 deletions.
1 change: 0 additions & 1 deletion pkg/keepkey/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"unicode/utf8"

"github.com/fatih/color"
"github.com/karalabe/hid"
"github.com/pkg/term"
"github.com/solipsis/go-keepkey/pkg/kkProto"
)
Expand Down
193 changes: 68 additions & 125 deletions pkg/keepkey/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package keepkey

import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
Expand All @@ -13,15 +12,14 @@ import (
"strings"

"github.com/golang/protobuf/proto"
"github.com/google/gousb"
"github.com/karalabe/hid"
"github.com/solipsis/go-keepkey/pkg/kkProto"
)

const (
vendorID uint16 = 0x2B24
//vendorID uint16 = 0x534c
productID uint16 = 0x0001
productID uint16 = 0x0002 // TODO: support old and new product ID
)

// Keepkey represents an open HID connection to a keepkey and possibly a
Expand Down Expand Up @@ -79,10 +77,12 @@ func (kk *Keepkey) log(str string, args ...interface{}) {
}
}

// Serial returns the serial id of the device
func (kk *Keepkey) Serial() string {
return kk.serial
}

// Label returns the user set lable identifying the device
func (kk *Keepkey) Label() string {
return kk.label
}
Expand All @@ -99,14 +99,15 @@ type hidInterfaces struct {

// HID INTERFACE DESCRIPTORS
const (
HID_DEVICE = "0"
HID_DEBUG = "1"
HIDInterfaceStandard = "0"
HIDInterfaceDebug = "1"
//HID_INFO = "2"
)

// Transport Types
// TransportType defines the interface to interact with the device
type TransportType int

// Transport Types for interfacing with the device
const (
TransportHID TransportType = iota
TransportWebUSB
Expand All @@ -121,7 +122,6 @@ func discoverKeepkeys() map[string]*hidInterfaces {
// corresponding debug link if enabled
deviceMap := make(map[string]*hidInterfaces)
for _, info := range hid.Enumerate(vendorID, 0) {
fmt.Println("INFO:", info)

// TODO: revisit this when keepkey adds additional product id's
if info.ProductID == productID {
Expand All @@ -133,14 +133,11 @@ func discoverKeepkeys() map[string]*hidInterfaces {
}

// seperate connection to debug/info HID interface if debug link is enabled
if strings.HasSuffix(info.Path, HID_DEBUG) {
if strings.HasSuffix(info.Path, HIDInterfaceDebug) {
deviceMap[pathKey].debug = info
} else if strings.HasSuffix(info.Path, HID_DEVICE) {
} else if strings.HasSuffix(info.Path, HIDInterfaceStandard) {
deviceMap[pathKey].device = info
}
/* else if strings.HasSuffix(info.Path, HID_INFO) {*/
//deviceMap[pathKey].info = info
/* }*/
}
}

Expand All @@ -154,138 +151,92 @@ func GetDevices() ([]*Keepkey, error) {
return GetDevicesWithConfig(&Config{Logger: log.New(ioutil.Discard, "", 0), AutoButton: true})
}

// TODO; DELETE. Endpoint struct to satisfy io.ReadWriter
type eps struct {
r *gousb.InEndpoint
w *gousb.OutEndpoint
}

func (e *eps) Read(p []byte) (n int, err error) {
fmt.Println("Reading USB")
return e.r.Read(p)
}
func (e *eps) Write(p []byte) (n int, err error) {
fmt.Println("Writing USB")
return e.w.Write(p)
}

// GetDevices establishes connections to all available KeepKey devices and
// GetDevicesWithConfig establishes connections to all available KeepKey devices and
// their enabled HID interfaces (primary/debug/info)
// the provided config is applied to all found keepkeys
func GetDevicesWithConfig(cfg *Config) ([]*Keepkey, error) {
//enumerateWebUSB()

// Open HID connections to all devices found in the previous step
//var deviceIFace, debugIFace, infoIFace hid.DeviceInfo
var deviceIFace, debugIFace, infoIFace hid.DeviceInfo
devices := make([]*Keepkey, 0)

webUSBDevices, err := enumerateWebUSB()
if err != nil {
return nil, err
fmt.Println("Unable to connect to device of webusb, ", err) // TODO: Can't find good way to tell if device is webusb or hid because it is advertised on both?
//return nil, err
}
for _, dev := range webUSBDevices {
fmt.Println(dev)
/*
config, err := dev.Config(1)
if err != nil {
log.Fatal("canofofig", err)
}
fmt.Println("config: ", config)
intf, _, err := dev.DefaultInterface()
if err != nil {
log.Fatalf("%s.DefaultInterface(): %v", dev, err)
}
in, err := intf.InEndpoint(1)
if err != nil {
log.Fatalf("%s.inEndpoint(0x81): %v", intf, err)
}
out, err := intf.OutEndpoint(1)
if err != nil {
log.Fatalf("%s.OutEndpoint(0x1): %v", intf, err)
}
/*
kk := newKeepkeyFromConfig(&Config{Logger: log.New(os.Stdout, "Log: ", 0), AutoButton: true})
kk.device = dev.conn
if dev.debug != nil {
kk.debug = dev.debug
go listenForMessages(kk.debug, kk.debugQueue)
fmt.Println("DebugLink established over WebUSB")
}
devices = append(devices, kk)
go listenForMessages(kk.device, kk.deviceQueue)
kk.Initialize(kk.device)

ctx := gousb.NewContext()
dev, err := ctx.OpenDeviceWithVIDPID(0x2b24, 0x0001)
if err != nil {
log.Fatalf("Could not open device: %v", err)
}
*/
}

kk := newKeepkeyFromConfig(&Config{Logger: log.New(os.Stdout, "Log: ", 0), AutoButton: true})
//endpoints := &eps{in, out}
kk.device = webUSBDevices[0].conn
if webUSBDevices[0].debug != nil {
kk.debug = webUSBDevices[0].debug
fmt.Println("DEBUG", kk.debug)
go listenForMessages(kk.debug, kk.debugQueue)
}
devices = append(devices, kk)
go listenForMessages(kk.device, kk.deviceQueue)
kk.Initialize(kk.device)
// HID TODO: move to seperate implementation file
for _, IFaces := range discoverKeepkeys() {
kk := newKeepkeyFromConfig(cfg)
deviceIFace = IFaces.device
debugIFace = IFaces.debug
infoIFace = IFaces.info

/*
for _, IFaces := range discoverKeepkeys() {
kk := newKeepkeyFromConfig(cfg)
deviceIFace = IFaces.device
debugIFace = IFaces.debug
infoIFace = IFaces.info
if deviceIFace.Path == "" {
continue
}

if deviceIFace.Path == "" {
continue
}
// Open connection to device on primary HID interface
device, err := deviceIFace.Open()
if err != nil {
fmt.Printf("Unable to connect to HID: %v dropping..., %s\n", deviceIFace, err)
continue
}
kk.device = device
go listenForMessages(device, kk.deviceQueue)

// Open connection to device on primary HID interface
device, err := deviceIFace.Open()
// debug HID interface
if debugIFace.Path != "" {
debug, err := debugIFace.Open()
if err != nil {
fmt.Printf("Unable to connect to HID: %v dropping..., %s\n", deviceIFace, err)
fmt.Println("unable to initiate debug link, skipping...")
continue
}
kk.device = device
go listenForMessages(device, kk.deviceQueue)
// debug HID interface
if debugIFace.Path != "" {
debug, err := debugIFace.Open()
if err != nil {
fmt.Println("unable to initiate debug link, skipping...")
continue
}
fmt.Println("Debug link established")
kk.debug = debug
go listenForMessages(debug, kk.debugQueue)
}
// info HID interface
if infoIFace.Path != "" {
info, err := infoIFace.Open()
if err != nil {
fmt.Println("unable to connect to Info HID interface, skipping...")
continue
}
fmt.Println("Connected to Info HID interface")
kk.infoOut = info
go listenForMessages(info, kk.infoQueue)
}
fmt.Println("Debug link established")
kk.debug = debug
go listenForMessages(debug, kk.debugQueue)
}

// Ping the device and ask for its features
features, err := kk.Initialize(device)
// info HID interface
if infoIFace.Path != "" {
info, err := infoIFace.Open()
if err != nil {
fmt.Println("Device failed to respond to initial request, dropping: ", err)
fmt.Println("unable to connect to Info HID interface, skipping...")
continue
}
fmt.Println("Connected to Info HID interface")
kk.infoOut = info
go listenForMessages(info, kk.infoQueue)
}

// store information to identify this particular device later
kk.serial = deviceIFace.Serial
kk.label = features.GetLabel()
devices = append(devices, kk)
// Ping the device and ask for its features
features, err := kk.Initialize(device)
if err != nil {
fmt.Println("Device failed to respond to initial request, dropping: ", err)
continue
}
*/

// store information to identify this particular device later
kk.serial = deviceIFace.Serial
kk.label = features.GetLabel()

devices = append(devices, kk)
}
if len(devices) < 1 {
return devices, errors.New("No keepkeys detected")
}
Expand All @@ -301,7 +252,6 @@ func listenForMessages(in io.Reader, out chan *deviceResponse) {
var reply []byte
var kind uint16
for {
fmt.Println("Waiting to read chunk")
// Read next chunk
if _, err := io.ReadFull(in, chunk); err != nil {
fmt.Println("Unable to read chunk from device:", err) // TODO: move to device specific log
Expand Down Expand Up @@ -339,7 +289,6 @@ func listenForMessages(in io.Reader, out chan *deviceResponse) {
fmt.Println("INFO: ", info.GetMsg())
}

fmt.Println("Device Message Received")
out <- &deviceResponse{reply, kind}
}
}
Expand Down Expand Up @@ -394,22 +343,17 @@ func (kk *Keepkey) keepkeyExchange(req proto.Message, results ...proto.Message)
payload = nil
}
// send over to the device
fmt.Println("Chunk", hex.EncodeToString(chunk))
if _, err := device.Write(chunk); err != nil {
fmt.Println("err", err)
return 0, err
}
fmt.Println("Post write")
}

// don't wait for response if sending debug buttonPress
if debug && kkProto.Name(kkProto.Type(req)) == "MessageType_DebugLinkDecision" {
return 0, nil
}

fmt.Println("Waiting to read")
fmt.Println("Debug: ", debug)
fmt.Println("queue: ", kk.deviceQueue)
// Read from the proper message queue
var response *deviceResponse
if debug {
Expand All @@ -419,7 +363,6 @@ func (kk *Keepkey) keepkeyExchange(req proto.Message, results ...proto.Message)
}
kind := response.kind
reply := response.reply
fmt.Println("Read successful")

// Try to parse the reply into the requested reply message
if kind == uint16(kkProto.MessageType_MessageType_Failure) {
Expand Down
3 changes: 0 additions & 3 deletions pkg/keepkey/webusb.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package keepkey

import (
"fmt"
"io"

"github.com/google/gousb"
Expand Down Expand Up @@ -40,14 +39,12 @@ func (w *webUSBEndpoints) Write(p []byte) (n int, err error) {
func enumerateWebUSB() ([]*transport, error) {
ctx := gousb.NewContext()
devices, err := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
fmt.Println(*desc)
if uint16(desc.Vendor) == uint16(vendorID) && uint16(desc.Product) == uint16(productID) {
return true
}
return false
})
if err != nil {
fmt.Println("OPEN ERROR")
return nil, err
}

Expand Down

0 comments on commit 784fdcd

Please sign in to comment.