/
WebController.go
147 lines (132 loc) · 3.03 KB
/
WebController.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//Package controller contains the web server for the controller
package controller
import (
"flag"
"log"
"net/http"
"strconv"
"sync"
"github.com/AscendTech4H/AscendTechROV/go/debug"
"github.com/AscendTech4H/AscendTechROV/go/startup"
"github.com/AscendTech4H/AscendTechROV/go/util"
"github.com/gorilla/websocket"
)
func init() {
//HTTP startup
startup.NewTask(200, func() error {
http.HandleFunc("/websock", websockhandler)
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
return nil
})
//web server port as argument
var web string
startup.NewTask(1, func() error {
flag.StringVar(&web, "http", ":8080", "HTTP server host")
return nil
})
//Web server startup last
startup.NewTask(254, func() error {
log.Println("Starting web controller. . .")
go http.ListenAndServe(web, nil)
return nil
})
lck = new(sync.RWMutex)
}
//conn is a connection used internally
type conn struct {
sock *websocket.Conn
}
func (c *conn) read() ([]byte, error) {
_, msg, err := c.sock.ReadMessage()
if err != nil {
return nil, err
}
return msg, err
}
func (c *conn) write(msg []byte) error {
return c.sock.WriteMessage(websocket.BinaryMessage, msg)
}
func loadConn(w http.ResponseWriter, r *http.Request) (*conn, error) {
upgrader := websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024}
connection, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return nil, err
}
c := new(conn)
c.sock = connection
return c, nil
}
var currentConn *websocket.Conn
//Direction constants
const (
CCW = iota
STOP
CW
)
//Robot contains the controller data
type Robot struct {
Claw, Laser bool
Forward, Up, Turn, ClawTurn int
}
var r Robot
var lck *sync.RWMutex //Lock on robot object
//SendData sends data through websocket
func SendData(data []byte) {
lck.Lock()
if currentConn != nil {
currentConn.WriteMessage(websocket.BinaryMessage, data)
}
lck.Unlock()
}
func websockhandler(writer http.ResponseWriter, requ *http.Request) {
connection, err := loadConn(writer, requ)
util.UhOh(err)
debug.VLog("Websocket connected")
defer func() { //If we crash, don't break the robot
lck.Unlock()
debug.VLog("Websocket disconnected")
}()
for {
m, e := connection.read() //Read a message
lck.Lock()
util.UhOh(e)
str := string(m)
if debug.Verbose {
log.Printf("Websocket Command: %s", str)
}
var err error
switch str[0] {
case 'C':
r.Claw = true
case 'c':
r.Claw = false
case 'L':
r.Laser = true
case 'l':
r.Laser = false
case 'X':
r.Turn, err = strconv.Atoi(str[1:])
case 'Y':
r.Forward, err = strconv.Atoi(str[1:])
case 'S':
r.Up, err = strconv.Atoi(str[1:])
case '{':
r.ClawTurn = CCW
case '^':
r.ClawTurn = STOP
case '}':
r.ClawTurn = CW
default:
log.Printf("Ignored unrecognized WebSocket command %s\n", str)
}
debug.VLog(str)
util.UhOh(err)
lck.Unlock()
}
}
//RobotState gets robot control state
func RobotState() Robot {
lck.RLock() //Set a read lock
defer lck.RUnlock() //Unlock on exit
return r
}