--- /dev/null
+// (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: <open|close|toggle> <method> <nickname>"
+ 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
+}
--- /dev/null
+// (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 <door tty device>\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
+ }
+ }
+}
--- /dev/null
+// (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
+}
--- /dev/null
+// (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