feat: gate video and terminal logs on AUX2 state
Build Ground Station / build (push) Successful in 19s
Build Ground Station / build (push) Successful in 19s
This commit is contained in:
+27
-17
@@ -7,7 +7,6 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
@@ -18,23 +17,21 @@ import (
|
||||
func main() {
|
||||
serialPath := flag.String("serial", "/dev/ttyS0", "GX12 AUX1 UART device")
|
||||
stdin := flag.Bool("stdin", false, "read framed data from standard input")
|
||||
startVideo := flag.Bool("start-video", false, "start fpv-video with Ground Station")
|
||||
videoByAux2 := flag.Bool("video-by-aux2", true, "start fpv-video when AUX2 is above -512")
|
||||
videoCommand := flag.String("video-command", "fpv-video", "video launcher command")
|
||||
flag.Parse()
|
||||
|
||||
if *stdin && *startVideo {
|
||||
log.Fatal("-stdin is intended for protocol tests; omit -start-video")
|
||||
if *stdin {
|
||||
*videoByAux2 = false
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
if *startVideo {
|
||||
cmd := exec.CommandContext(ctx, "fpv-video")
|
||||
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Fatalf("start fpv-video: %v", err)
|
||||
}
|
||||
defer func() { _ = cmd.Wait() }()
|
||||
var video *videoController
|
||||
if *videoByAux2 {
|
||||
video = newVideoController(*videoCommand)
|
||||
defer func() { _ = video.Stop() }()
|
||||
}
|
||||
|
||||
var input io.Reader = os.Stdin
|
||||
@@ -49,13 +46,14 @@ func main() {
|
||||
input = port
|
||||
}
|
||||
|
||||
if err := run(ctx, input, os.Stdout); err != nil && err != context.Canceled {
|
||||
if err := run(ctx, input, os.Stdout, video); err != nil && err != context.Canceled {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run(ctx context.Context, input io.Reader, output io.Writer) error {
|
||||
func run(ctx context.Context, input io.Reader, output io.Writer, video *videoController) error {
|
||||
buf := make([]byte, protocol.RCSize)
|
||||
var previous *protocol.RCFrame
|
||||
for {
|
||||
if err := readRCFrame(ctx, input, buf); err != nil {
|
||||
return err
|
||||
@@ -65,10 +63,22 @@ func run(ctx context.Context, input io.Reader, output io.Writer) error {
|
||||
log.Printf("discard frame: %v", err)
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(output, "seq=%d t=%d ch1=%d ch2=%d ch3=%d ch4=%d aux1=%d aux2=%d\n",
|
||||
frame.Sequence, frame.Timestamp,
|
||||
frame.Channels[0], frame.Channels[1], frame.Channels[2], frame.Channels[3],
|
||||
frame.Channels[4], frame.Channels[5])
|
||||
// AUX2 is the dedicated GS video switch: -1024 means management/off,
|
||||
// while its middle position (0) means preflight/WFB/on.
|
||||
if video != nil {
|
||||
if err := video.Set(frame.Channels[5] > -512); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if previous == nil || previous.Channels != frame.Channels {
|
||||
fmt.Fprintf(output, "seq=%d t=%d ch1=%d ch2=%d ch3=%d ch4=%d aux1=%d aux2=%d\n",
|
||||
frame.Sequence, frame.Timestamp,
|
||||
frame.Channels[0], frame.Channels[1], frame.Channels[2], frame.Channels[3],
|
||||
frame.Channels[4], frame.Channels[5])
|
||||
copy := frame
|
||||
previous = ©
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// videoController owns the optional fpv-video launcher. It never touches WFB
|
||||
// directly; fpv-video remains the sole owner of the video receiver lifecycle.
|
||||
type videoController struct {
|
||||
command string
|
||||
mu sync.Mutex
|
||||
cmd *exec.Cmd
|
||||
done chan error
|
||||
}
|
||||
|
||||
func newVideoController(command string) *videoController {
|
||||
return &videoController{command: command}
|
||||
}
|
||||
|
||||
func (v *videoController) Set(active bool) error {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
|
||||
if active {
|
||||
if v.cmd != nil {
|
||||
return nil
|
||||
}
|
||||
v.cmd = exec.Command(v.command)
|
||||
v.cmd.Stdout, v.cmd.Stderr = os.Stdout, os.Stderr
|
||||
if err := v.cmd.Start(); err != nil {
|
||||
v.cmd = nil
|
||||
return fmt.Errorf("start %s: %w", v.command, err)
|
||||
}
|
||||
v.done = make(chan error, 1)
|
||||
cmd := v.cmd
|
||||
go func() { v.done <- cmd.Wait() }()
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.cmd == nil {
|
||||
return nil
|
||||
}
|
||||
if err := v.cmd.Process.Signal(os.Interrupt); err != nil {
|
||||
return fmt.Errorf("stop %s: %w", v.command, err)
|
||||
}
|
||||
<-v.done
|
||||
v.cmd, v.done = nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *videoController) Stop() error {
|
||||
return v.Set(false)
|
||||
}
|
||||
Reference in New Issue
Block a user