16
16
package monitor
17
17
18
18
import (
19
+ "bytes"
19
20
"context"
20
21
"errors"
21
22
"fmt"
@@ -35,29 +36,34 @@ import (
35
36
"github.com/fatih/color"
36
37
"github.com/sirupsen/logrus"
37
38
"github.com/spf13/cobra"
39
+ "go.bug.st/cleanup"
38
40
)
39
41
40
- var (
41
- portArgs arguments.Port
42
- describe bool
43
- configs []string
44
- quiet bool
45
- fqbn arguments.Fqbn
46
- tr = i18n .Tr
47
- )
42
+ var tr = i18n .Tr
48
43
49
44
// NewCommand created a new `monitor` command
50
45
func NewCommand () * cobra.Command {
46
+ var (
47
+ raw bool
48
+ portArgs arguments.Port
49
+ describe bool
50
+ configs []string
51
+ quiet bool
52
+ fqbn arguments.Fqbn
53
+ )
51
54
monitorCommand := & cobra.Command {
52
55
Use : "monitor" ,
53
56
Short : tr ("Open a communication port with a board." ),
54
57
Long : tr ("Open a communication port with a board." ),
55
58
Example : "" +
56
59
" " + os .Args [0 ] + " monitor -p /dev/ttyACM0\n " +
57
60
" " + os .Args [0 ] + " monitor -p /dev/ttyACM0 --describe" ,
58
- Run : runMonitorCmd ,
61
+ Run : func (cmd * cobra.Command , args []string ) {
62
+ runMonitorCmd (& portArgs , & fqbn , configs , describe , quiet , raw )
63
+ },
59
64
}
60
65
portArgs .AddToCommand (monitorCommand )
66
+ monitorCommand .Flags ().BoolVar (& raw , "raw" , false , tr ("Set terminal in raw mode (unbuffered)." ))
61
67
monitorCommand .Flags ().BoolVar (& describe , "describe" , false , tr ("Show all the settings of the communication port." ))
62
68
monitorCommand .Flags ().StringSliceVarP (& configs , "config" , "c" , []string {}, tr ("Configure communication port settings. The format is <ID>=<value>[,<ID>=<value>]..." ))
63
69
monitorCommand .Flags ().BoolVarP (& quiet , "quiet" , "q" , false , tr ("Run in silent mode, show only monitor input and output." ))
@@ -66,7 +72,7 @@ func NewCommand() *cobra.Command {
66
72
return monitorCommand
67
73
}
68
74
69
- func runMonitorCmd (cmd * cobra. Command , args []string ) {
75
+ func runMonitorCmd (portArgs * arguments. Port , fqbn * arguments. Fqbn , configs []string , describe , quiet , raw bool ) {
70
76
instance := instance .CreateAndInit ()
71
77
logrus .Info ("Executing `arduino-cli monitor`" )
72
78
@@ -93,12 +99,6 @@ func runMonitorCmd(cmd *cobra.Command, args []string) {
93
99
return
94
100
}
95
101
96
- tty , err := newStdInOutTerminal ()
97
- if err != nil {
98
- feedback .FatalError (err , feedback .ErrGeneric )
99
- }
100
- defer tty .Close ()
101
-
102
102
configuration := & rpc.MonitorPortConfiguration {}
103
103
if len (configs ) > 0 {
104
104
for _ , config := range configs {
@@ -151,9 +151,33 @@ func runMonitorCmd(cmd *cobra.Command, args []string) {
151
151
}
152
152
defer portProxy .Close ()
153
153
154
- ctx , cancel := context .WithCancel (context .Background ())
154
+ if ! quiet {
155
+ feedback .Print (tr ("Connected to %s! Press CTRL-C to exit." , portAddress ))
156
+ }
157
+
158
+ ttyIn , ttyOut , err := feedback .InteractiveStreams ()
159
+ if err != nil {
160
+ feedback .FatalError (err , feedback .ErrGeneric )
161
+ }
162
+
163
+ ctx , cancel := cleanup .InterruptableContext (context .Background ())
164
+ if raw {
165
+ feedback .SetRawModeStdin ()
166
+ defer func () {
167
+ feedback .RestoreModeStdin ()
168
+ }()
169
+
170
+ // In RAW mode CTRL-C is not converted into an Interrupt by
171
+ // the terminal, we must intercept ASCII 3 (CTRL-C) on our own...
172
+ ctrlCDetector := & charDetectorWriter {
173
+ callback : cancel ,
174
+ detectedChar : 3 , // CTRL-C
175
+ }
176
+ ttyIn = io .TeeReader (ttyIn , ctrlCDetector )
177
+ }
178
+
155
179
go func () {
156
- _ , err := io .Copy (tty , portProxy )
180
+ _ , err := io .Copy (ttyOut , portProxy )
157
181
if err != nil && ! errors .Is (err , io .EOF ) {
158
182
if ! quiet {
159
183
feedback .Print (tr ("Port closed: %v" , err ))
@@ -162,7 +186,7 @@ func runMonitorCmd(cmd *cobra.Command, args []string) {
162
186
cancel ()
163
187
}()
164
188
go func () {
165
- _ , err := io .Copy (portProxy , tty )
189
+ _ , err := io .Copy (portProxy , ttyIn )
166
190
if err != nil && ! errors .Is (err , io .EOF ) {
167
191
if ! quiet {
168
192
feedback .Print (tr ("Port closed: %v" , err ))
@@ -171,14 +195,22 @@ func runMonitorCmd(cmd *cobra.Command, args []string) {
171
195
cancel ()
172
196
}()
173
197
174
- if ! quiet {
175
- feedback .Print (tr ("Connected to %s! Press CTRL-C to exit." , portAddress ))
176
- }
177
-
178
198
// Wait for port closed
179
199
<- ctx .Done ()
180
200
}
181
201
202
+ type charDetectorWriter struct {
203
+ callback func ()
204
+ detectedChar byte
205
+ }
206
+
207
+ func (cd * charDetectorWriter ) Write (buf []byte ) (int , error ) {
208
+ if bytes .IndexByte (buf , cd .detectedChar ) != - 1 {
209
+ cd .callback ()
210
+ }
211
+ return len (buf ), nil
212
+ }
213
+
182
214
type detailsResult struct {
183
215
Settings []* rpc.MonitorPortSettingDescriptor `json:"settings"`
184
216
}
0 commit comments