Skip to content

Commit c799d3d

Browse files
bootstrap
1 parent 0913760 commit c799d3d

File tree

5 files changed

+215
-1
lines changed

5 files changed

+215
-1
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
# uno-r4-wifi-fwuploader-plugin
1+
# uno-r4-wifi-fwuploader-plugin
2+
3+
Be sure to have `libudev-dev` installed
4+
5+
### Ubuntu:
6+
`sudo apt install libudev-dev`

go.mod

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module github.com/arduino/uno-r4-wifi-fwuploader-plugin
2+
3+
go 1.20
4+
5+
require (
6+
github.com/arduino/fwuploader-plugin-helper v0.0.0-20230626132535-2effbfcc7853
7+
github.com/arduino/go-paths-helper v1.9.1
8+
github.com/sstallion/go-hid v0.14.0
9+
go.bug.st/relaxed-semver v0.10.2
10+
)
11+
12+
require (
13+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
14+
github.com/pkg/errors v0.9.1 // indirect
15+
github.com/spf13/cobra v1.7.0 // indirect
16+
github.com/spf13/pflag v1.0.5 // indirect
17+
golang.org/x/sys v0.9.0 // indirect
18+
)

go.sum

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
github.com/arduino/fwuploader-plugin-helper v0.0.0-20230626132535-2effbfcc7853 h1:SEWDw4xcN+qNReANPPlnlGn/R4uP2QHdZyYI4DEYwNs=
2+
github.com/arduino/fwuploader-plugin-helper v0.0.0-20230626132535-2effbfcc7853/go.mod h1:y7Vo30dco4xAb39pQ2CRaCvayADjhOBAMrlfji4AYuM=
3+
github.com/arduino/go-paths-helper v1.9.1 h1:qpK+zMMjsklSBQa09/P5FZ/uf3LyjVmJK3DLeyiGjCc=
4+
github.com/arduino/go-paths-helper v1.9.1/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU=
5+
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
6+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
8+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
9+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
10+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
11+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
12+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
13+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
14+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
15+
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
16+
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
17+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
18+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
19+
github.com/sstallion/go-hid v0.14.0 h1:bSCzyw5E9lGrdQb1NXgRYfmf/z+B+DfSftDlmjOMbfk=
20+
github.com/sstallion/go-hid v0.14.0/go.mod h1:UaqSxWjbdX9mId5JiqsMAnVtZymx/GSvQMgnzHMks2M=
21+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
22+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
23+
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
24+
go.bug.st/relaxed-semver v0.10.2 h1:d/ATAG3MByySZgg7rFj+Wj0fhvP4zfx9Z8Dn/NSCoFg=
25+
go.bug.st/relaxed-semver v0.10.2/go.mod h1:lPVGdtzbQ9/2fv6iXqIXWHOj6cMTUJ/l/Lu1w+sgdio=
26+
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
27+
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
28+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
29+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
30+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

hid.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package main
2+
3+
import "github.com/sstallion/go-hid"
4+
5+
const (
6+
vid uint16 = 0x2341
7+
pid uint16 = 0x1002
8+
)
9+
10+
func openFirstHID() (*hid.Device, error) {
11+
return openHID("")
12+
}
13+
14+
func openHID(port string) (*hid.Device, error) {
15+
if err := hid.Init(); err != nil {
16+
return nil, err
17+
}
18+
if port == "" {
19+
return hid.OpenFirst(vid, pid)
20+
}
21+
return hid.OpenPath(port)
22+
}
23+
24+
func reboot(d *hid.Device) error {
25+
b := make([]byte, 65)
26+
b[0] = 0
27+
b[1] = 0xAA
28+
if _, err := d.SendFeatureReport(b); err != nil {
29+
return err
30+
}
31+
return nil
32+
}

main.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
"time"
8+
9+
helper "github.com/arduino/fwuploader-plugin-helper"
10+
"github.com/arduino/go-paths-helper"
11+
"github.com/sstallion/go-hid"
12+
semver "go.bug.st/relaxed-semver"
13+
)
14+
15+
const (
16+
pluginName = "uno-r4-wifi-fwuploader"
17+
pluginVersion = "1.0.0"
18+
)
19+
20+
func main() {
21+
helper.RunPlugin(&unoR4WifiPlugin{})
22+
}
23+
24+
type unoR4WifiPlugin struct{}
25+
26+
var _ helper.Plugin = (*unoR4WifiPlugin)(nil)
27+
28+
// GetPluginInfo returns information about the plugin
29+
func (p *unoR4WifiPlugin) GetPluginInfo() *helper.PluginInfo {
30+
return &helper.PluginInfo{
31+
Name: pluginName,
32+
Version: semver.MustParse(pluginVersion),
33+
}
34+
}
35+
36+
// UploadFirmware performs a firmware upload on the board
37+
func (p *unoR4WifiPlugin) UploadFirmware(portAddress string, firmwarePath *paths.Path, feedback *helper.PluginFeedback) error {
38+
if portAddress == "" {
39+
fmt.Fprintln(feedback.Err(), "Port address not specified")
40+
return fmt.Errorf("invalid port address")
41+
}
42+
if firmwarePath == nil || firmwarePath.IsDir() {
43+
fmt.Fprintln(feedback.Err(), "Invalid firmware path")
44+
return fmt.Errorf("invalid firmware path")
45+
}
46+
47+
d, err := openFirstHID()
48+
if err != nil {
49+
return err
50+
}
51+
52+
if err := reboot(d); err != nil {
53+
return err
54+
}
55+
56+
if err := hid.Exit(); err != nil {
57+
return err
58+
}
59+
60+
// Wait a bit before flashing the firmware to allow the board to become available again.
61+
time.Sleep(3 * time.Second)
62+
63+
cmd := exec.Command("espflash", "flash", firmwarePath.String(), "-p", portAddress)
64+
cmd.Stdout = feedback.Out()
65+
cmd.Stderr = feedback.Err()
66+
cmd.Env = append(cmd.Env, os.Environ()...)
67+
if err := cmd.Run(); err != nil {
68+
return err
69+
}
70+
71+
fmt.Fprintf(feedback.Out(), "\nUpload completed! You can now detach the board.\n")
72+
return nil
73+
}
74+
75+
// UploadCertificate performs a certificate upload on the board. The certificate must be in crt format
76+
// and be multiple of 4, otherwise `espflash` won't work!
77+
func (p *unoR4WifiPlugin) UploadCertificate(portAddress string, certificatePath *paths.Path, feedback *helper.PluginFeedback) error {
78+
if portAddress == "" {
79+
fmt.Fprintln(feedback.Err(), "Port address not specified")
80+
return fmt.Errorf("invalid port address")
81+
}
82+
if certificatePath == nil || certificatePath.IsDir() {
83+
fmt.Fprintln(feedback.Err(), "Invalid certificate path")
84+
return fmt.Errorf("invalid certificate path")
85+
}
86+
fmt.Fprintf(feedback.Out(), "Uploading certificates to %s...\n", portAddress)
87+
88+
d, err := openFirstHID()
89+
if err != nil {
90+
return err
91+
}
92+
93+
if err := reboot(d); err != nil {
94+
return err
95+
}
96+
97+
if err := hid.Exit(); err != nil {
98+
return err
99+
}
100+
101+
// Wait a bit before flashing the certificate to allow the board to become available again.
102+
time.Sleep(3 * time.Second)
103+
104+
cmd := exec.Command("espflash", "write-bin", "-p", portAddress, "-b", "921600", "0x3C0000", certificatePath.String())
105+
cmd.Stdout = feedback.Out()
106+
cmd.Stderr = feedback.Err()
107+
cmd.Env = append(cmd.Env, os.Environ()...)
108+
if err := cmd.Run(); err != nil {
109+
return err
110+
}
111+
112+
fmt.Fprintf(feedback.Out(), "\nUpload completed! You can now detach the board.\n")
113+
return nil
114+
}
115+
116+
// GetFirmwareVersion retrieve the firmware version installed on the board
117+
func (p *unoR4WifiPlugin) GetFirmwareVersion(portAddress string, feedback *helper.PluginFeedback) (*semver.RelaxedVersion, error) {
118+
d, err := openFirstHID()
119+
if err != nil {
120+
return nil, err
121+
}
122+
defer hid.Exit()
123+
124+
buf := make([]byte, 65)
125+
if _, err := d.GetFeatureReport(buf); err != nil {
126+
return nil, err
127+
}
128+
return semver.ParseRelaxed(fmt.Sprintf("%d.%d.%d", buf[1], buf[2], buf[3])), nil
129+
}

0 commit comments

Comments
 (0)