forked from zsa/wally-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
teensy.go
117 lines (101 loc) · 3.04 KB
/
teensy.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
package main
import (
"fmt"
"github.com/google/gousb"
"github.com/marcinbor85/gohex"
"runtime"
"log"
"os"
"time"
)
// TeensyFlash: Flashes Teensy boards.
// It opens the firmware file at the provided path, checks it's integrity, wait for the keyboard to be in Flash mode, flashes it and reboots the board.
func teensyFlash(firmwarePath string, s *state) {
file, err := os.Open(firmwarePath)
if err != nil {
message := fmt.Sprintf("Error while opening firmware: %s", err)
log.Fatal(message)
return
}
defer file.Close()
s.total = ergodoxCodeSize
firmware := gohex.NewMemory()
err = firmware.ParseIntelHex(file)
if err != nil {
message := fmt.Sprintf("Error while parsing firmware: %s", err)
log.Fatal(message)
return
}
ctx := gousb.NewContext()
ctx.Debug(0)
defer ctx.Close()
var dev *gousb.Device
// Loop until a keyboard is ready to flash
for {
devs, _ := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
if desc.Vendor == gousb.ID(halfKayVendorID) && desc.Product == gousb.ID(halfKayProductID) {
return true
}
return false
})
defer func() {
for _, d := range devs {
d.Close()
}
}()
if len(devs) > 0 {
dev = devs[0]
break
}
time.Sleep(1 * time.Second)
}
if runtime.GOOS != "darwin" {
dev.SetAutoDetach(true)
}
// Claim usb device
cfg, err := dev.Config(1)
defer cfg.Close()
if err != nil {
message := fmt.Sprintf("Error while claiming the usb interface: %s", err)
log.Fatal(message)
return
}
s.step = 1
// Loop on the firmware data and program
var addr uint32
for addr = 0; addr < ergodoxCodeSize; addr += ergodoxBlockSize {
// set a longer timeout when writing the first block
if addr == 0 {
dev.ControlTimeout = 5 * time.Second
} else {
dev.ControlTimeout = 500 * time.Millisecond
}
// Prepare and write a firmware block
// https://www.pjrc.com/teensy/halfkay_protocol.html
buf := make([]byte, ergodoxBlockSize+2)
buf[0] = byte(addr & 255)
buf[1] = byte((addr >> 8) & 255)
block := firmware.ToBinary(addr, ergodoxBlockSize, 255)
for index := range block {
buf[index+2] = block[index]
}
bytes, err := dev.Control(0x21, 9, 0x0200, 0, buf)
if err != nil {
message := fmt.Sprintf("Error while sending firmware bytes: %s", err)
log.Fatal(message)
return
}
s.sent += bytes
}
buf := make([]byte, ergodoxBlockSize+2)
buf[0] = byte(0xFF)
buf[1] = byte(0xFF)
buf[2] = byte(0xFF)
_, err = dev.Control(0x21, 9, 0x0200, 0, buf)
if err != nil {
message := fmt.Sprintf("Error while rebooting device: %s", err)
log.Fatal(message)
return
}
s.step = 2
}