Skip to content

Commit 39f4000

Browse files
committed
Implement basic websocket connection
1 parent e7e5a2b commit 39f4000

File tree

4 files changed

+172
-16
lines changed

4 files changed

+172
-16
lines changed

connect/connect.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Package connect allows to open connections to devices connected to a serial port to
2+
// read and write from them
3+
//
4+
// Usage
5+
// ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
6+
// input, output, err := connect.Open(ctx, "/dev/ttyACM0", 9600)
7+
// if err != nil {
8+
// panic(err)
9+
// }
10+
// go func() {
11+
// for msg := range output {
12+
// fmt.Print(string(msg))
13+
// }
14+
// }()
15+
// input <- []byte("some message")
16+
package connect
17+
18+
import (
19+
"bytes"
20+
"log"
21+
22+
"github.com/pkg/errors"
23+
24+
serial "go.bug.st/serial.v1"
25+
"golang.org/x/net/context"
26+
)
27+
28+
// Open will establish a connection to a device connected to a serial port
29+
// Will return two channels that will be used to communicate. Use input to send data,
30+
// read from output to retrieve data.
31+
// It accepts a cancelable context, so you can close the connection when you're finished
32+
// Errors during read or write will result in a the error being sent to the output channel
33+
// and the connection being closed
34+
func Open(ctx context.Context, name string, baud int) (input, output chan []byte, err error) {
35+
mode := &serial.Mode{
36+
BaudRate: baud,
37+
}
38+
39+
p, err := serial.Open(name, mode)
40+
if err != nil {
41+
return nil, nil, errors.Wrapf(err, "open %s", name)
42+
}
43+
44+
input = make(chan []byte)
45+
output = make(chan []byte)
46+
47+
// reader
48+
go func() {
49+
for {
50+
ch := make([]byte, 1024)
51+
n, err := p.Read(ch)
52+
if err != nil {
53+
output <- []byte(err.Error())
54+
break
55+
}
56+
if n > 0 {
57+
log.Println(len(bytes.Trim(ch, "\x00")))
58+
output <- bytes.Trim(ch, "\x00")
59+
}
60+
}
61+
62+
close(output)
63+
}()
64+
65+
go func() {
66+
L:
67+
for {
68+
select {
69+
case <-ctx.Done():
70+
break L
71+
case msg := <-input:
72+
_, err := p.Write(msg)
73+
if err != nil {
74+
output <- []byte(err.Error())
75+
break L
76+
}
77+
}
78+
}
79+
80+
p.Close()
81+
close(input)
82+
}()
83+
84+
return input, output, nil
85+
}

connect/connect_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package connect_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
"time"
7+
8+
"github.com/arduino/arduino-create-agent/connect"
9+
"golang.org/x/net/context"
10+
)
11+
12+
func TestUsage(t *testing.T) {
13+
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
14+
15+
input, output, err := connect.Open(ctx, "/dev/ttyACM0", 9600)
16+
if err != nil {
17+
t.Fatalf(err.Error())
18+
}
19+
20+
go func() {
21+
for msg := range output {
22+
fmt.Print(string(msg))
23+
}
24+
}()
25+
26+
input <- []byte("some message")
27+
28+
time.Sleep(11 * time.Second)
29+
}

connect_v1.go

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,72 @@
11
package main
22

33
import (
4+
"log"
5+
46
"github.com/arduino/arduino-create-agent/app"
7+
"github.com/arduino/arduino-create-agent/connect"
58
"github.com/goadesign/goa"
6-
"golang.org/x/net/websocket"
7-
"io"
9+
"github.com/gorilla/websocket"
10+
"golang.org/x/net/context"
811
)
912

13+
type device struct {
14+
input chan []byte
15+
output chan []byte
16+
cancel func()
17+
}
18+
1019
// ConnectV1Controller implements the connect_v1 resource.
1120
type ConnectV1Controller struct {
1221
*goa.Controller
22+
devices map[string]device
1323
}
1424

1525
// NewConnectV1Controller creates a connect_v1 controller.
1626
func NewConnectV1Controller(service *goa.Service) *ConnectV1Controller {
17-
return &ConnectV1Controller{Controller: service.NewController("ConnectV1Controller")}
27+
return &ConnectV1Controller{
28+
Controller: service.NewController("ConnectV1Controller"),
29+
devices: make(map[string]device),
30+
}
1831
}
1932

2033
// Websocket runs the websocket action.
2134
func (c *ConnectV1Controller) Websocket(ctx *app.WebsocketConnectV1Context) error {
22-
c.WebsocketWSHandler(ctx).ServeHTTP(ctx.ResponseWriter, ctx.Request)
23-
return nil
24-
}
35+
cont, cancel := context.WithCancel(context.Background())
36+
input, output, err := connect.Open(cont, ctx.Port, ctx.Baud)
37+
if err != nil {
38+
return ctx.BadRequest()
39+
}
2540

26-
// WebsocketWSHandler establishes a websocket connection to run the websocket action.
27-
func (c *ConnectV1Controller) WebsocketWSHandler(ctx *app.WebsocketConnectV1Context) websocket.Handler {
28-
return func(ws *websocket.Conn) {
29-
// ConnectV1Controller_Websocket: start_implement
41+
var upgrader = websocket.Upgrader{
42+
ReadBufferSize: 1024,
43+
WriteBufferSize: 1024,
44+
}
3045

31-
// Put your logic here
46+
conn, err := upgrader.Upgrade(ctx.ResponseWriter, ctx.Request, nil)
47+
if err != nil {
48+
return ctx.BadRequest()
49+
}
50+
51+
go func() {
52+
for msg := range output {
53+
log.Println(len(msg))
54+
55+
conn.WriteMessage(websocket.TextMessage, msg)
56+
}
57+
conn.Close()
58+
}()
59+
60+
for {
61+
_, msg, err := conn.ReadMessage()
62+
if err != nil {
63+
break
64+
}
3265

33-
// ConnectV1Controller_Websocket: end_implement
34-
ws.Write([]byte("websocket connect_v1"))
35-
// Dummy echo websocket server
36-
io.Copy(ws, ws)
66+
input <- msg
3767
}
68+
69+
cancel()
70+
71+
return nil
3872
}

templates/debug.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ <h1>Arduino Create Agent - Debug</h1>
8585
});
8686
}
8787

88+
var ws;
89+
8890
function connect() {
8991
var port = document.getElementById('connect-port').value;
9092
var baud = document.getElementById('connect-baud').value;
@@ -93,7 +95,7 @@ <h1>Arduino Create Agent - Debug</h1>
9395
var codeEl = document.getElementById('connect-code');
9496

9597
codeEl.textContent = '';
96-
var ws = new WebSocket("ws://localhost:9000/v1/connect?port=" + port + "&baud=" + baud);
98+
ws = new WebSocket("ws://localhost:9000/v1/connect?port=" + port + "&baud=" + baud);
9799
ws.onopen = function () {
98100
formEl.removeAttribute('hidden')
99101
}
@@ -102,6 +104,7 @@ <h1>Arduino Create Agent - Debug</h1>
102104
codeEl.textContent = codeEl.textContent + 'DISCONNECTED\n';
103105
}
104106
ws.onmessage = function (event) {
107+
console.debug(event.data)
105108
codeEl.textContent = codeEl.textContent + event.data + '\n';
106109
}
107110

@@ -116,5 +119,10 @@ <h1>Arduino Create Agent - Debug</h1>
116119
console.debug(port, baud)
117120
}
118121

122+
function send() {
123+
var msg = document.getElementById('connect-msg').value;
124+
ws.send(msg)
125+
}
126+
119127
</script>
120128
</body>

0 commit comments

Comments
 (0)