package main import ( "fmt" "io" "log" "strings" "time" "github.com/tarm/serial" ) type TBM struct { Commands chan *Command Results chan *Result Port *serial.Port } type Command struct { command string args []string payload []byte } type Result struct { output []byte errcode []byte } func (t *TBM) Connect(device string, baud int) error { t.Commands = make(chan *Command) t.Results = make(chan *Result) serialconfig := &serial.Config{Name: device, Baud: baud} port, err := serial.OpenPort(serialconfig) if err != nil { return err } t.Port = port return nil } func (t *TBM) Handle() error { go handleResults(t.Port, t.Results) go handleCommands(t.Port, t.Commands) return nil } func (t *TBM) Close() { t.Port.Close() } func deserialise(in io.Reader, init []byte) (*Result, []byte, error) { var ( output, errorcode []byte data, rest []byte ) want_output := true _ = copy(data, init) for { buf := make([]byte, 4096) n, err := in.Read(buf) if err != nil { return nil, nil, err } n2 := n + len(data) data = append(data, buf[:n]...) for i := 0; i < n2; i++ { // '\r' is really '\n' if data[i] == '\r' { data = append(data[:i], data[i+1:]...) n2-- continue } if data[i] == 0x4 { if want_output { want_output = false output = data[:i] data = data[i+1:] // The TBM gives us our own commands back for j := 0; j < len(output); j++ { if output[j] == '\n' { output = output[j+1:] break } } break } else { errorcode = data[:i] rest = data[i+1:] return &Result{output, errorcode}, rest, nil } } } } } func handleResults(in io.Reader, c chan *Result) { var ( res *Result rest []byte err error ) for { res, rest, err = deserialise(in, rest) if err != nil { log.Fatal(err) } c <- res } } func serialise(out io.Writer, command string, args []string, payload []byte) error { var quoted_args []string var err error quoted_args = append(quoted_args, command) for _, arg := range args { quoted_args = append(quoted_args, fmt.Sprintf("\"%s\"", arg)) } out_string := strings.Join(quoted_args, " ") output := []byte(out_string) output = append(output, '\r') _, err = out.Write(output) // err is non nil if n != len(output) if err != nil { return err } if payload == nil { return nil } // FIXME: wait for command to finish time.Sleep(time.Second) output = append(payload, 0x4) _, err = out.Write(output) return err } func handleCommands(out io.Writer, c chan *Command) { for command := range c { err := serialise(out, command.command, command.args, command.payload) if err != nil { log.Fatal(err) } } }