From: Bernhard Tittelbach Date: Tue, 24 Sep 2013 02:44:52 +0000 (+0000) Subject: door_daemon_zmq X-Git-Url: https://git.realraum.at/?p=svn42.git;a=commitdiff_plain;h=88e758b4025ef2a84acafc7b832a41028280c296 door_daemon_zmq --- diff --git a/go/door_daemon_zmq/handle_commands.go b/go/door_daemon_zmq/handle_commands.go new file mode 100644 index 0000000..d33070a --- /dev/null +++ b/go/door_daemon_zmq/handle_commands.go @@ -0,0 +1,68 @@ +// (c) Bernhard Tittelbach, 2013 + +package main + +import ( + "errors" +) + +type DoorCmdHandler struct { + Checker func([][]byte)(error) + FirmwareChar string +} + +var cmdToDoorCmdHandler = map[string]DoorCmdHandler { + "open": DoorCmdHandler{ checkCmdDoorControl, "o"}, + "close": DoorCmdHandler{ checkCmdDoorControl, "c"}, + "toggle": DoorCmdHandler{ checkCmdDoorControl, "t"}, + "status": DoorCmdHandler{ checkCmdDoorControl, "s"}, +} + +// ---------- Command Handling Code ------------- + +func checkCmdDoorControl(tokens [][]byte) (error) { + doorctrl_usage := "syntax: " + if len(tokens) != 3 { + return errors.New(doorctrl_usage) + } + cmd := string(tokens[0]) + if ! (cmd == "open" || cmd == "close" || cmd == "toggle") { + return errors.New(doorctrl_usage) + } + method := string(tokens[1]) + if ! (method == "Button" || method == "ssh" || method == "SSH" || method == "Phone") { + return errors.New("method must be one either Button, SSH or Phone") + } + if len(tokens[2]) == 0 && method != "Button" { + return errors.New("Operator nickname must be given") + } + return nil +} + +func checkCmdStatus(tokens [][]byte) (error) { + if len(tokens) != 1 { + return errors.New("status command does not accept arguments") + } + return nil +} + +func HandleCommand(tokens [][]byte, topub chan <- [][]byte, serial_wr chan string, serial_rd chan [][]byte) ([][]byte, error){ + if len(tokens) < 1 { + return nil, errors.New("No Command to handle") + } + + dch, present := cmdToDoorCmdHandler[string(tokens[0])] + if ! present { + return nil, errors.New("Unknown Command") + } + + if err := dch.Checker(tokens); err != nil { + //return error to sender + return nil, err + } + + topub <- tokens + serial_wr <- dch.FirmwareChar + fw_reply := <- serial_rd + return fw_reply, nil +} diff --git a/go/door_daemon_zmq/main.go b/go/door_daemon_zmq/main.go new file mode 100644 index 0000000..28be188 --- /dev/null +++ b/go/door_daemon_zmq/main.go @@ -0,0 +1,59 @@ +// (c) Bernhard Tittelbach, 2013 + +package main + +import ( + "fmt" + "os" + "flag" + "log" +) + +//~ func StringArrayToByteArray(ss []string) [][]byte { + //~ bb := make([][]byte, len(ss)) + //~ for index, s := range(ss) { + //~ bb[index] = []byte(s) + //~ } + //~ return bb +//~ } + +// ---------- Main Code ------------- + +func usage() { + fmt.Fprintf(os.Stderr, "Usage: door_daemon_0mq \n") + flag.PrintDefaults() +} + +func main() { + flag.Usage = usage + flag.Parse() + + args := flag.Args() + if len(args) < 1 { + fmt.Fprintf(os.Stderr, "Input file is missing!\n"); + usage() + os.Exit(1); + } + + cmd_chans, pub_chans := ZmqsInit("tcp://localhost:5555", "gmp://*:6666") + + serial_wr, serial_rd, err := OpenAndHandleSerial(args[0], pub_chans.Out()) + if err != nil { + close(serial_wr) + panic(err) + } + + serial_wr <- "f" + firmware_version := <- serial_rd + log.Print("Firmware version:", firmware_version) + + for incoming_request := range cmd_chans.In() { + reply, err := HandleCommand(incoming_request, pub_chans.Out(), serial_wr, serial_rd) + if err != nil { + cmd_chans.Out() <- [][]byte{[]byte("ERROR"), []byte(err.Error())} + log.Print(err) + } else { + cmd_chans.Out() <- reply + } + } +} diff --git a/go/door_daemon_zmq/serial_tty.go b/go/door_daemon_zmq/serial_tty.go new file mode 100644 index 0000000..4ec786a --- /dev/null +++ b/go/door_daemon_zmq/serial_tty.go @@ -0,0 +1,60 @@ +// (c) Bernhard Tittelbach, 2013 + +package main + +import ( + "fmt" + "bufio" + "bytes" + "os" + "svn.spreadspace.org/realraum/go.svn/termios" + "log" +) + +// ---------- Serial TTY Code ------------- + +func openTTY(name string) (*os.File, error) { + file, err := os.OpenFile(name,os.O_RDWR, 0600) // For read access. + if err != nil { + log.Println(err.Error()) + return nil, err + } + termios.Ttyfd(file.Fd()) + termios.SetRaw() + return file, nil +} + +func SerialWriter(in <- chan string, serial * os.File) { + for totty := range(in) { + serial.WriteString(totty) + serial.Sync() + } +} + +func SerialReader(out chan <- [][]byte, topub chan <- [][]byte, serial * os.File) { + linescanner := bufio.NewScanner(serial) + linescanner.Split(bufio.ScanLines) + for linescanner.Scan() { + if err := linescanner.Err(); err != nil { + panic(fmt.Sprintf("Error in read from serial: %v\n",err.Error())) + } + text := bytes.Fields([]byte(linescanner.Text())) + if len(text) == 0 { + continue + } + out <- text + topub <- text + } +} + +func OpenAndHandleSerial(filename string, topub chan <- [][]byte) (chan string, chan [][]byte, error) { + serial, err :=openTTY(filename) + if err != nil { + return nil, nil, err + } + var wr chan string + var rd chan [][]byte + go SerialWriter(wr, serial) + go SerialReader(rd, topub, serial) + return wr, rd, nil +} diff --git a/go/door_daemon_zmq/zeromq.go b/go/door_daemon_zmq/zeromq.go new file mode 100644 index 0000000..70fe795 --- /dev/null +++ b/go/door_daemon_zmq/zeromq.go @@ -0,0 +1,65 @@ +// (c) Bernhard Tittelbach, 2013 + +package main + +import ( + zmq "github.com/vaughan0/go-zmq" + ) + +// ---------- ZeroMQ Code ------------- + +func ZmqsInit(cmd_port, pub_port string) (cmd_chans, pub_chans *zmq.Channels) { + + cmd_ctx, err := zmq.NewContext() + if err != nil { + panic(err) + } + //close only on panic, otherwise leave open: + defer func(){ if r:= recover(); r != nil { cmd_ctx.Close(); panic(r) } }() + + pub_ctx, err := zmq.NewContext() + if err != nil { + panic(err) + } + defer func() { if r:= recover(); r != nil { pub_ctx.Close(); panic(r) } }() + + cmd_sock, err := cmd_ctx.Socket(zmq.Rep) + if err != nil { + panic(err) + } + defer func() { if r:= recover(); r != nil { cmd_sock.Close(); panic(r) } }() + + pub_sock, err := pub_ctx.Socket(zmq.Pub) + if err != nil { + panic(err) + } + defer func() { if r:= recover(); r != nil { pub_sock.Close(); panic(r) } }() + + if err = cmd_sock.Bind(cmd_port); err != nil { // "tcp://*:5555" + panic(err) + } + + if err = pub_sock.Bind(pub_port); err != nil { // "tcp://*:5556" + panic(err) + } + + cmd_chans = cmd_sock.Channels() + pub_chans = cmd_sock.Channels() + go zmqsHandleError(cmd_chans, pub_chans) + return +} + +func zmqsHandleError(cmd_chans, pub_chans *zmq.Channels) { + for { + select { + case cmd_error := <- cmd_chans.Errors(): + cmd_chans.Close() + pub_chans.Close() + panic(cmd_error) + case pub_error := <- pub_chans.Errors(): + cmd_chans.Close() + pub_chans.Close() + panic(pub_error) + } + } +} \ No newline at end of file