You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

122 lines
4.2 KiB

// tera-serial-line-check temporarily applies and restores CH01 line settings.
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
"tera-clone/services/tera-api/internal/serial"
)
const (
representativeChannel = "CH01"
representativeDevice = "/dev/ttyWCH4"
representativePCPort = "COM3"
)
type probeClient interface {
Probe(context.Context, serial.ChannelConfig) (serial.ProbeResult, error)
}
type checkReport struct {
Kind string `json:"kind"`
Status string `json:"status"`
CheckedAt string `json:"checked_at"`
Channel string `json:"channel"`
Device string `json:"device"`
PCPort string `json:"pc_port"`
Requested serial.LineSettings `json:"requested"`
Probe *serial.ProbeResult `json:"probe,omitempty"`
Findings []string `json:"findings,omitempty"`
DataSent bool `json:"data_sent"`
}
func main() {
os.Exit(run(os.Args[1:], os.Stdout, os.Stderr, time.Now))
}
func run(args []string, stdout, stderr io.Writer, now func() time.Time) int {
flags := flag.NewFlagSet("tera-serial-line-check", flag.ContinueOnError)
flags.SetOutput(stderr)
socketPath := flags.String("socket", serial.DefaultSocketPath, "tera-seriald Unix socket")
baudRate := flags.Int("baud", 115200, "temporary baud rate")
dataBits := flags.Int("data-bits", 8, "temporary data bits")
parity := flags.String("parity", "none", "temporary parity")
stopBits := flags.Int("stop-bits", 1, "temporary stop bits")
flowControl := flags.String("flow-control", "none", "temporary flow control")
timeout := flags.Duration("timeout", 10*time.Second, "overall probe timeout")
if err := flags.Parse(args); err != nil {
return 2
}
if flags.NArg() != 0 || !filepath.IsAbs(*socketPath) || *timeout <= 0 {
fmt.Fprintln(stderr, "invalid arguments: require an absolute socket path and positive timeout")
return 2
}
requested := serial.ChannelConfig{
Channel: representativeChannel, BaudRate: *baudRate, DataBits: *dataBits,
Parity: strings.ToLower(strings.TrimSpace(*parity)), StopBits: *stopBits,
FlowControl: strings.ToLower(strings.TrimSpace(*flowControl)),
}
if _, err := serial.NormalizeLineConfig(serial.LineConfig{
Device: representativeDevice, BaudRate: requested.BaudRate, DataBits: requested.DataBits,
Parity: requested.Parity, StopBits: requested.StopBits, FlowControl: requested.FlowControl,
}); err != nil {
fmt.Fprintln(stderr, err)
return 2
}
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
defer cancel()
report := inspect(ctx, serial.NewSocketClient(*socketPath), requested, now().UTC())
encoder := json.NewEncoder(stdout)
encoder.SetIndent("", " ")
if err := encoder.Encode(report); err != nil {
fmt.Fprintln(stderr, "write serial line check report:", err)
return 1
}
if report.Status != "pass" {
return 1
}
return 0
}
func inspect(ctx context.Context, client probeClient, requested serial.ChannelConfig, checkedAt time.Time) checkReport {
wanted := serial.LineSettings{
BaudRate: requested.BaudRate, DataBits: requested.DataBits, Parity: requested.Parity,
StopBits: requested.StopBits, FlowControl: requested.FlowControl,
}
report := checkReport{
Kind: "tera-serial-line-check", Status: "fail", CheckedAt: checkedAt.UTC().Format(time.RFC3339Nano),
Channel: representativeChannel, Device: representativeDevice, PCPort: representativePCPort,
Requested: wanted, DataSent: false,
}
result, err := client.Probe(ctx, requested)
if err != nil {
report.Findings = append(report.Findings, err.Error())
return report
}
report.Probe = &result
if result.Channel != representativeChannel {
report.Findings = append(report.Findings, "probe returned a non-representative channel")
}
if result.Device != representativeDevice {
report.Findings = append(report.Findings, "probe returned an unexpected target device")
}
if result.Applied != wanted {
report.Findings = append(report.Findings, "applied readback does not match requested line settings")
}
if !result.Restored {
report.Findings = append(report.Findings, "prior line settings were not restored")
}
if len(report.Findings) == 0 {
report.Status = "pass"
}
return report
}