Skip to content

Commit 27e577d

Browse files
authored
feat(pkg/board): expose board name and name (#452)
1 parent 0bfd4bb commit 27e577d

File tree

5 files changed

+121
-19
lines changed

5 files changed

+121
-19
lines changed
Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fs
1+
package board
22

33
import (
44
"context"
@@ -19,12 +19,13 @@ const boardHomePath = "/home/arduino"
1919
type contextKey string
2020

2121
const remoteConnKey contextKey = "remoteConn"
22+
const boardsListKey contextKey = "boardsList"
2223

23-
func NewFSCmd() *cobra.Command {
24+
func NewBoardCmd() *cobra.Command {
2425
var fqbn, host string
2526
fsCmd := &cobra.Command{
26-
Use: "fs",
27-
Short: "Manage board fs",
27+
Use: "board",
28+
Short: "Manage boards",
2829
Long: "",
2930
PersistentPreRun: func(cmd *cobra.Command, args []string) {
3031
if host != "" {
@@ -43,13 +44,13 @@ func NewFSCmd() *cobra.Command {
4344
if len(boards) == 0 {
4445
panic(fmt.Errorf("no boards found for FQBN %s", fqbn))
4546
}
46-
conn, err := boards[0].Connect()
47+
conn, err := boards[0].GetConnection()
4748
if err != nil {
4849
panic(fmt.Errorf("failed to connect to board: %w", err))
4950
}
5051

5152
cmd.SetContext(context.WithValue(cmd.Context(), remoteConnKey, conn))
52-
53+
cmd.SetContext(context.WithValue(cmd.Context(), boardsListKey, boards))
5354
},
5455
}
5556
fsCmd.PersistentFlags().StringVarP(&fqbn, "fqbn", "b", "arduino:zephyr:unoq", "fqbn of the board")
@@ -58,6 +59,8 @@ func NewFSCmd() *cobra.Command {
5859
fsCmd.AddCommand(newPushCmd())
5960
fsCmd.AddCommand(newPullCmd())
6061
fsCmd.AddCommand(newSyncAppCmd())
62+
fsCmd.AddCommand(newBoardListCmd())
63+
fsCmd.AddCommand(newBoardSetName())
6164

6265
return fsCmd
6366
}
@@ -99,3 +102,48 @@ func newSyncAppCmd() *cobra.Command {
99102

100103
return syncAppCmd
101104
}
105+
106+
func newBoardListCmd() *cobra.Command {
107+
listCmd := &cobra.Command{
108+
Use: "list",
109+
Short: "List available boards",
110+
RunE: func(cmd *cobra.Command, args []string) error {
111+
boards := cmd.Context().Value(boardsListKey).([]board.Board)
112+
for _, b := range boards {
113+
var address string
114+
switch b.Protocol {
115+
case board.SerialProtocol:
116+
address = b.Serial
117+
case board.NetworkProtocol:
118+
address = b.Address
119+
default:
120+
panic("unreachable")
121+
}
122+
feedback.Printf("%s (%s) - Connection: %s [%s]\n", b.BoardName, b.CustomName, b.Protocol, address)
123+
}
124+
return nil
125+
},
126+
}
127+
128+
return listCmd
129+
}
130+
131+
func newBoardSetName() *cobra.Command {
132+
setNameCmd := &cobra.Command{
133+
Use: "set-name <name>",
134+
Short: "Set the custom name of the board",
135+
Args: cobra.ExactArgs(1),
136+
RunE: func(cmd *cobra.Command, args []string) error {
137+
conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn)
138+
name := args[0]
139+
140+
if err := board.SetCustomName(cmd.Context(), conn, name); err != nil {
141+
return fmt.Errorf("failed to set custom name: %w", err)
142+
}
143+
feedback.Printf("Custom name set to %q\n", name)
144+
return nil
145+
},
146+
}
147+
148+
return setNameCmd
149+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fs
1+
package board
22

33
import (
44
"fmt"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fs
1+
package board
22

33
import (
44
"fmt"

cmd/arduino-app-cli/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import (
1111
"go.bug.st/cleanup"
1212

1313
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/app"
14+
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/board"
1415
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/brick"
1516
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/completion"
1617
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/config"
1718
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/daemon"
18-
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/fs"
1919
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/internal/servicelocator"
2020
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/properties"
2121
"github.com/bcmi-labs/orchestrator/cmd/arduino-app-cli/system"
@@ -58,7 +58,7 @@ func main() {
5858
properties.NewPropertiesCmd(),
5959
config.NewConfigCmd(),
6060
system.NewSystemCmd(),
61-
fs.NewFSCmd(),
61+
board.NewBoardCmd(),
6262
version.NewVersionCmd(Version),
6363
)
6464

pkg/board/board.go

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package board
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
7+
"io"
68
"log/slog"
9+
"regexp"
710
"slices"
811
"strings"
912

@@ -18,10 +21,11 @@ import (
1821
)
1922

2023
type Board struct {
21-
// TODO: add fields for allowing identification
22-
Protocol string
23-
Serial string
24-
Address string
24+
Protocol string
25+
Serial string
26+
Address string
27+
CustomName string
28+
BoardName string
2529
}
2630

2731
const (
@@ -70,17 +74,25 @@ func FromFQBN(ctx context.Context, fqbn string) ([]Board, error) {
7074
if port.GetPort() == nil {
7175
continue
7276
}
77+
78+
var boardName string
79+
if len(port.GetMatchingBoards()) > 0 {
80+
boardName = port.GetMatchingBoards()[0].GetName()
81+
}
82+
7383
switch port.GetPort().GetProtocol() {
7484
case SerialProtocol:
7585
serial := strings.ToLower(port.GetPort().GetHardwareId()) // in windows this is uppercase.
7686
boards = append(boards, Board{
77-
Protocol: SerialProtocol,
78-
Serial: serial,
87+
Protocol: SerialProtocol,
88+
Serial: serial,
89+
BoardName: boardName,
7990
})
8091
case NetworkProtocol:
8192
boards = append(boards, Board{
82-
Protocol: NetworkProtocol,
83-
Address: port.GetPort().GetAddress(),
93+
Protocol: NetworkProtocol,
94+
Address: port.GetPort().GetAddress(),
95+
BoardName: boardName,
8496
})
8597
default:
8698
slog.Warn("unknown protocol", "protocol", port.GetPort().GetProtocol())
@@ -96,13 +108,29 @@ func FromFQBN(ctx context.Context, fqbn string) ([]Board, error) {
96108
}
97109
})
98110

111+
// Get board names
112+
for i := range boards {
113+
switch boards[i].Protocol {
114+
case SerialProtocol:
115+
// TODO: we should store the board custom name in the product id so we can get it from the discovery service.
116+
var name string
117+
if conn, err := adb.FromSerial(boards[i].Serial, ""); err == nil {
118+
if name, err = GetCustomName(ctx, conn); err == nil {
119+
boards[i].CustomName = name
120+
}
121+
}
122+
case NetworkProtocol:
123+
// TODO: get from mDNS
124+
}
125+
}
126+
99127
return boards, nil
100128
}
101129

102130
return nil, fmt.Errorf("no hardware ID found for FQBN %s", fqbn)
103131
}
104132

105-
func (b *Board) Connect() (remote.RemoteConn, error) {
133+
func (b *Board) GetConnection() (remote.RemoteConn, error) {
106134
switch b.Protocol {
107135
case SerialProtocol:
108136
return adb.FromSerial(b.Serial, "")
@@ -114,6 +142,32 @@ func (b *Board) Connect() (remote.RemoteConn, error) {
114142
}
115143
}
116144

145+
var customNameRegex = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]{0,63}$`)
146+
147+
func SetCustomName(ctx context.Context, conn remote.RemoteConn, name string) error {
148+
if !customNameRegex.MatchString(name) {
149+
return fmt.Errorf("invalid custom name: %s, must match regex %s", name, customNameRegex.String())
150+
}
151+
152+
if err := conn.WriteFile(strings.NewReader(name), "/etc/hostname"); err != nil {
153+
return fmt.Errorf("failed to set board name: %w", err)
154+
}
155+
return nil
156+
}
157+
158+
func GetCustomName(ctx context.Context, conn remote.RemoteConn) (string, error) {
159+
r, err := conn.ReadFile("/etc/hostname")
160+
if err != nil {
161+
return "", fmt.Errorf("failed to get board name: %w", err)
162+
}
163+
defer r.Close()
164+
out, err := io.ReadAll(r)
165+
if err != nil {
166+
return "", fmt.Errorf("failed to read board name: %w", err)
167+
}
168+
return string(bytes.TrimSpace(out)), nil
169+
}
170+
117171
func EnsurePlatformInstalled(ctx context.Context, rawFQBN string) error {
118172
parsedFQBN, err := fqbn.Parse(rawFQBN)
119173
if err != nil {

0 commit comments

Comments
 (0)