package main import ( "bufio" "flag" "fmt" "github.com/trzsz/trzsz-go/trzsz" "github.com/zimolab/charsetconv" "go.bug.st/serial" "golang.org/x/term" "io" "log" "net" "os" "os/signal" "runtime" "strings" "time" ) var ( serialPort serial.Port err error args []string ) var ( in io.Reader = os.Stdin out io.Writer = os.Stdout ins = []io.Reader{os.Stdin} outs = []io.Writer{os.Stdout} trzszFilter *trzsz.TrzszFilter clientIn *io.PipeReader stdoutPipe *io.PipeReader stdinPipe *io.PipeWriter clientOut *io.PipeWriter ) func checkPortAvailability(name string) ([]string, error) { ports, err := serial.GetPortsList() if err != nil { log.Fatal(err) } if len(ports) == 0 { return nil, fmt.Errorf("无串口") } if name == "" { return ports, fmt.Errorf("串口未指定") } for _, port := range ports { if strings.Compare(port, name) == 0 { return ports, nil } } return ports, fmt.Errorf("串口 " + name + " 未在线") } func init() { log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile | log.Lmsgprefix) for _, f := range flags { flagInit(&f) } cmdinit() } func input(in io.Reader) { input := bufio.NewScanner(in) var ok = false for { input.Scan() ok = false args = strings.Split(input.Text(), " ") for _, cmd := range commands { if strings.Compare(strings.TrimSpace(args[0]), cmd.name) == 0 { cmd.function() ok = true } } if !ok { _, err := io.WriteString(stdinPipe, input.Text()) if err != nil { log.Fatal(err) } _, err = io.WriteString(stdinPipe, config.endStr) if err != nil { log.Fatal(err) } } err = serialPort.Drain() if err != nil { log.Fatal(err) } } } func strout(out io.Writer, cs, str string) { err = charsetconv.EncodeWith(strings.NewReader(str), out, charsetconv.Charset(cs), false) if err != nil { log.Fatal(err) } } func output() { if strings.Compare(config.inputCode, "hex") == 0 { b := make([]byte, config.frameSize) r, _ := io.LimitReader(stdoutPipe, int64(config.frameSize)).Read(b) if r != 0 { if config.timesTamp { strout(out, config.outputCode, fmt.Sprintf("%v % X %q \n", time.Now().Format(config.timesFmt), b, b)) } else { strout(out, config.outputCode, fmt.Sprintf("% X %q \n", b, b)) } } } else { if config.timesTamp { line, _, _ := bufio.NewReader(stdoutPipe).ReadLine() if line != nil { strout(out, config.outputCode, fmt.Sprintf("%v %s\n", time.Now().Format(config.timesFmt), line)) } } else { err = charsetconv.ConvertWith(stdoutPipe, charsetconv.Charset(config.inputCode), out, charsetconv.Charset(config.outputCode), false) } } if err != nil { log.Fatal(err) } } func main() { flag.Parse() if config.portName == "" { getCliFlag() } ports, err := checkPortAvailability(config.portName) if err != nil { fmt.Println(err) printUsage(ports) os.Exit(0) } mode := &serial.Mode{ BaudRate: config.baudRate, StopBits: serial.StopBits(config.stopBits), DataBits: config.dataBits, Parity: serial.Parity(config.parityBit), } serialPort, err = serial.Open(config.portName, mode) if err != nil { log.Fatal(err) } defer func(port serial.Port) { err := port.Close() if err != nil { log.Fatal(err) } }(serialPort) fd := int(os.Stdin.Fd()) width, _, err := term.GetSize(fd) if err != nil { if runtime.GOOS != "windows" { fmt.Printf("term get size failed: %s\n", err) return } width = 80 } clientIn, stdinPipe = io.Pipe() stdoutPipe, clientOut = io.Pipe() trzszFilter = trzsz.NewTrzszFilter(clientIn, clientOut, serialPort, serialPort, trzsz.TrzszOptions{TerminalColumns: int32(width), EnableZmodem: true}) trzsz.SetAffectedByWindows(false) ch := make(chan os.Signal, 1) go func() { for range ch { width, _, err := term.GetSize(fd) if err != nil { fmt.Printf("term get size failed: %s\n", err) continue } trzszFilter.SetTerminalColumns(int32(width)) } }() defer func() { signal.Stop(ch); close(ch) }() if FoeWardMode(config.forWard) != NOT { conn := setForWardClient() ins = append(ins, conn) outs = append(outs, conn) defer func(conn net.Conn) { err := conn.Close() if err != nil { log.Fatal(err) } }(conn) } checkLogOpen() if len(ins) != 0 { for _, reader := range ins { go input(reader) } } if len(outs) != 1 { out = io.MultiWriter(outs...) } for { output() } }