From ba4a9b22f0b355ef0c515587c4918d793bc9962c Mon Sep 17 00:00:00 2001 From: "S.J.R. van Schaik" Date: Thu, 19 Oct 2017 13:26:42 +0200 Subject: [PATCH] admin: add admin tool --- admin/main.go | 109 ++++++++++++++++++++++++++++++++++++++++ admin/tbm.go | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 admin/main.go create mode 100644 admin/tbm.go diff --git a/admin/main.go b/admin/main.go new file mode 100644 index 0000000..8b02042 --- /dev/null +++ b/admin/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "flag" + "fmt" + "log" +) + +type CommandFunc func(tbm *TBM, args []string) error + +var ( + serial_device = flag.String("serial-device", "/dev/ttyUSB0", "Serial device to use") + serial_baudrate = flag.Int("serial-baud", 9600, "Serial baud rate") + + commands = map[string]CommandFunc{ + "ls": cmd_ls, + "cat": cmd_cat, + "stat": cmd_stat, + "cp": cmd_cp, + "rm": cmd_rm, + "mkdir": cmd_mkdir, + "rmdir": cmd_rmdir, + "date": cmd_date, + "set-date": cmd_set_date, + "time": cmd_time, + } +) + +func cmd_generic(tbm *TBM, command string, args []string) error { + cmd := &Command{command, args} + tbm.Commands <- cmd + res := <-tbm.Results + + if res.errcode[0] != '0' { + return fmt.Errorf("Error: %s", res.errcode) + } + fmt.Printf("%s", res.output) + + return nil +} + +func cmd_ls(tbm *TBM, args []string) error { + return cmd_generic(tbm, "mufs ls", args) +} + +func cmd_cat(tbm *TBM, args []string) error { + return cmd_generic(tbm, "mufs cat", args) +} + +func cmd_stat(tbm *TBM, args []string) error { + return cmd_generic(tbm, "mufs stat", args) +} + +func cmd_cp(tbm *TBM, args []string) error { + return cmd_generic(tbm, "mufs cp", args) +} + +func cmd_rm(tbm *TBM, args []string) error { + return cmd_generic(tbm, "mufs rm", args) +} + +func cmd_mkdir(tbm *TBM, args []string) error { + return cmd_generic(tbm, "mufs mkdir", args) +} + +func cmd_rmdir(tbm *TBM, args []string) error { + return cmd_generic(tbm, "mufs rmdir", args) +} + +func cmd_date(tbm *TBM, args []string) error { + return cmd_generic(tbm, "date", args) +} + +func cmd_set_date(tbm *TBM, args []string) error { + return cmd_generic(tbm, "set-date", args) +} + +func cmd_time(tbm *TBM, args []string) error { + return cmd_generic(tbm, "time", args) +} + +func main() { + flag.Parse() + + args := flag.Args() + if len(args) == 0 { + log.Fatalf("Please specify at least one command") + } + command := args[0] + + command_function, ok := commands[command] + + if !ok { + log.Fatalf("Unknown command: %s", command) + } + + t := &TBM{} + err := t.Connect(*serial_device, *serial_baudrate) + if err != nil { + log.Fatal(err) + } + t.Handle() + defer t.Close() + + err = command_function(t, args[1:]) + if err != nil { + log.Fatal(err) + } +} diff --git a/admin/tbm.go b/admin/tbm.go new file mode 100644 index 0000000..2b58b0f --- /dev/null +++ b/admin/tbm.go @@ -0,0 +1,158 @@ +package main + +import ( + "fmt" + "io" + "log" + "strings" + + "github.com/tarm/serial" +) + +type TBM struct { + Commands chan *Command + Results chan *Result + Port *serial.Port +} + +type Command struct { + command string + args []string +} + +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) error { + var quoted_args []string + + 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') + //output = append(output, 0x4) + + _, err := out.Write(output) + // err is non nil if n != len(output) + if err != nil { + return err + } + + return nil +} + +func handleCommands(out io.Writer, c chan *Command) { + for command := range c { + err := serialise(out, command.command, command.args) + if err != nil { + log.Fatal(err) + } + } +}