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.
170 lines
2.7 KiB
170 lines
2.7 KiB
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)
|
|
}
|
|
}
|
|
}
|
|
|