Skip to content

Commit 7e0269d

Browse files
committed
Buffer flow plugins added. TinyG has a plugin.
Added ability for buffer flow plugins. There is a new buffer flow plugin for TinyG that watches the {"qr":NN} response. When it sees the qr value go below 12 it pauses its own sending and queues up whatever is still coming in on the Websocket. This is fine because we've got plenty of RAM on the websocket server. The {"qr":NN} value is still sent back on the websocket as soon as it was before, so the host application should see no real difference as to how it worked before. The difference now though is that the serial sending knows to check if sending is paused to the serial port and queue. This makes sure no buffer overflows ever occur. The reason this was becoming important is that the lag time between the qr response and the sending of Gcode was too distant and this buffer flow needs resolution around 5ms. Normal latency on the Internet is like 20ms to 200ms, so it just wasn't fast enough. If the Javascript hosting the websocket was busy processing other events, then this lag time became even worse. So, now the Serial Port JSON Server simply helps out by lots of extra buffering. Go ahead and pound it even harder with more serial commands and see it fly. Former-commit-id: bcb0129da3d37ac644a82217c2b6ddaf107e65e0 [formerly e3b08b3f77cf660f60438b87291016341e63386b] Former-commit-id: c0f43b80d13f2acfc8a9ff145bc60f89779272df
1 parent f0b29e4 commit 7e0269d

12 files changed

+228
-65
lines changed

README.md

Lines changed: 0 additions & 48 deletions
This file was deleted.

README.md.REMOVED.git-id

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c853ea9ac9a7a8a3e6ead8da3c207e28a9303a2a

bufferflow.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import (
4+
//"log"
5+
//"time"
6+
)
7+
8+
type Bufferflow interface {
9+
BlockUntilReady() // implement this method
10+
OnIncomingData(data string) // implement this method
11+
//Name string
12+
//Port string
13+
//myvar mytype string
14+
//pause bool // keep track if we're paused from sending
15+
//buffertype string // is it tinyg, grbl, or other?
16+
}
17+
18+
/*
19+
// this method is a method of the struct above
20+
func (b *bufferflow) blockUntilReady() {
21+
log.Printf("Blocking until ready. Buffertype is:%v\n", b.buffertype)
22+
//time.Sleep(3000 * time.Millisecond)
23+
if b.buffertype == "dummypause" {
24+
buf := bufferflow_dummypause{Name: "blah"}
25+
buf.blockUntilReady()
26+
}
27+
log.Printf("Done blocking. Buffertype is:%v\n", b.buffertype)
28+
}
29+
30+
func (b *bufferflow) onIncomingData(data) {
31+
log.Printf("onIncomingData. data:%v", data)
32+
if b.buffertype == "dummypause" {
33+
buf := bufferflow_dummypause{Name: "blah"}
34+
buf.waitUntilReady()
35+
}
36+
}
37+
*/

bufferflow_dummypause.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"time"
6+
)
7+
8+
type BufferflowDummypause struct {
9+
Name string
10+
Port string
11+
NumLines int
12+
Paused bool
13+
}
14+
15+
func (b *BufferflowDummypause) Init() {
16+
}
17+
18+
func (b *BufferflowDummypause) BlockUntilReady() {
19+
log.Printf("BlockUntilReady() start. numLines:%v\n", b.NumLines)
20+
log.Printf("buffer:%v\n", b)
21+
//for b.Paused {
22+
log.Println("We are paused. Yeilding send.")
23+
time.Sleep(3000 * time.Millisecond)
24+
//}
25+
log.Printf("BlockUntilReady() end\n")
26+
}
27+
28+
func (b *BufferflowDummypause) OnIncomingData(data string) {
29+
log.Printf("OnIncomingData() start. data:%v\n", data)
30+
b.NumLines++
31+
//time.Sleep(3000 * time.Millisecond)
32+
log.Printf("OnIncomingData() end. numLines:%v\n", b.NumLines)
33+
}

bufferflow_grbl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package main

bufferflow_tinyg.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"regexp"
6+
"strconv"
7+
"time"
8+
)
9+
10+
type BufferflowTinyg struct {
11+
Name string
12+
Port string
13+
Paused bool
14+
StopSending int
15+
StartSending int
16+
sem chan int
17+
}
18+
19+
var (
20+
// the regular expression to find the qr value
21+
re, _ = regexp.Compile("\"qr\":(\\d+)")
22+
)
23+
24+
func (b *BufferflowTinyg) Init() {
25+
b.StartSending = 16
26+
b.StopSending = 14
27+
b.sem = make(chan int)
28+
}
29+
30+
func (b *BufferflowTinyg) BlockUntilReady() {
31+
log.Printf("BlockUntilReady() start\n")
32+
//log.Printf("buffer:%v\n", b)
33+
if b.Paused {
34+
//<-b.sem // will block until told from OnIncomingData to go
35+
36+
for b.Paused {
37+
//log.Println("We are paused. Yeilding send.")
38+
time.Sleep(5 * time.Millisecond)
39+
}
40+
41+
} else {
42+
// still yeild a bit cuz seeing we need to let tinyg
43+
// have a chance to respond
44+
time.Sleep(15 * time.Millisecond)
45+
}
46+
log.Printf("BlockUntilReady() end\n")
47+
}
48+
49+
func (b *BufferflowTinyg) OnIncomingData(data string) {
50+
//log.Printf("OnIncomingData() start. data:%v\n", data)
51+
if re.Match([]byte(data)) {
52+
// we have a qr value
53+
//log.Printf("Found a qr value:%v", re)
54+
res := re.FindStringSubmatch(data)
55+
qr, err := strconv.Atoi(res[1])
56+
if err != nil {
57+
log.Printf("Got error converting qr value. huh? err:%v\n", err)
58+
} else {
59+
log.Printf("The qr val is:\"%v\"", qr)
60+
if qr <= b.StopSending {
61+
b.Paused = true
62+
63+
log.Println("Paused sending gcode")
64+
} else if qr >= b.StartSending {
65+
b.Paused = false
66+
//b.sem <- 1 // send channel a val to trigger the unblocking in BlockUntilReady()
67+
log.Println("Started sending gcode again")
68+
} else {
69+
log.Println("In a middle state where we're paused sending gcode but watching for the buffer to get high enough to start sending again")
70+
}
71+
}
72+
}
73+
// Look for {"qr":28}
74+
// Actually, if we hit qr:10, stop sending
75+
// when hit qr:16 start again
76+
//time.Sleep(3000 * time.Millisecond)
77+
//log.Printf("OnIncomingData() end.\n")
78+
}

dummy.go

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"fmt"
45
"log"
56
"time"
67
)
@@ -17,7 +18,59 @@ func (d *dummy) run() {
1718
for {
1819
//h.broadcast <- message
1920
log.Print("dummy data")
20-
h.broadcast <- []byte("dummy data")
21-
time.Sleep(15000 * time.Millisecond)
21+
//h.broadcast <- []byte("dummy data")
22+
time.Sleep(8000 * time.Millisecond)
23+
h.broadcast <- []byte("list")
24+
25+
// open com4 (tinyg)
26+
h.broadcast <- []byte("open com4 115200 tinyg")
27+
time.Sleep(1000 * time.Millisecond)
28+
29+
// send some commands
30+
//h.broadcast <- []byte("send com4 ?\n")
31+
//time.Sleep(3000 * time.Millisecond)
32+
h.broadcast <- []byte("send com4 {\"qr\":\"\"}\n")
33+
h.broadcast <- []byte("send com4 g21 g90\n") // mm
34+
//h.broadcast <- []byte("send com4 {\"qr\":\"\"}\n")
35+
//h.broadcast <- []byte("send com4 {\"sv\":0}\n")
36+
//time.Sleep(3000 * time.Millisecond)
37+
for i := 0.0; i < 10.0; i = i + 0.001 {
38+
h.broadcast <- []byte("send com4 G1 X" + fmt.Sprintf("%.3f", i) + " F100\n")
39+
time.Sleep(10 * time.Millisecond)
40+
}
41+
/*
42+
h.broadcast <- []byte("send com4 G1 X1\n")
43+
h.broadcast <- []byte("send com4 G1 X2\n")
44+
h.broadcast <- []byte("send com4 G1 X3\n")
45+
h.broadcast <- []byte("send com4 G1 X4\n")
46+
h.broadcast <- []byte("send com4 G1 X5\n")
47+
h.broadcast <- []byte("send com4 G1 X6\n")
48+
h.broadcast <- []byte("send com4 G1 X7\n")
49+
h.broadcast <- []byte("send com4 G1 X8\n")
50+
h.broadcast <- []byte("send com4 G1 X9\n")
51+
h.broadcast <- []byte("send com4 G1 X10\n")
52+
h.broadcast <- []byte("send com4 G1 X1\n")
53+
h.broadcast <- []byte("send com4 G1 X2\n")
54+
h.broadcast <- []byte("send com4 G1 X3\n")
55+
h.broadcast <- []byte("send com4 G1 X4\n")
56+
h.broadcast <- []byte("send com4 G1 X5\n")
57+
h.broadcast <- []byte("send com4 G1 X6\n")
58+
h.broadcast <- []byte("send com4 G1 X7\n")
59+
h.broadcast <- []byte("send com4 G1 X8\n")
60+
h.broadcast <- []byte("send com4 G1 X9\n")
61+
h.broadcast <- []byte("send com4 G1 X10\n")
62+
h.broadcast <- []byte("send com4 G1 X1\n")
63+
h.broadcast <- []byte("send com4 G1 X2\n")
64+
h.broadcast <- []byte("send com4 G1 X3\n")
65+
h.broadcast <- []byte("send com4 G1 X4\n")
66+
h.broadcast <- []byte("send com4 G1 X5\n")
67+
h.broadcast <- []byte("send com4 G1 X6\n")
68+
h.broadcast <- []byte("send com4 G1 X7\n")
69+
h.broadcast <- []byte("send com4 G1 X8\n")
70+
h.broadcast <- []byte("send com4 G1 X9\n")
71+
h.broadcast <- []byte("send com4 G1 X10\n")
72+
*/
73+
break
2274
}
75+
log.Println("dummy process exited")
2376
}

hub.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,20 @@ func (h *hub) run() {
4343
delete(h.connections, c)
4444
close(c.send)
4545
case m := <-h.broadcast:
46-
log.Print("Got a broadcast")
46+
//log.Print("Got a broadcast")
4747
//log.Print(m)
4848
//log.Print(len(m))
4949
if len(m) > 0 {
5050
//log.Print(string(m))
5151
//log.Print(h.broadcast)
5252
checkCmd(m)
53-
log.Print("-----")
53+
//log.Print("-----")
5454

5555
for c := range h.connections {
5656
select {
5757
case c.send <- m:
58-
log.Print("did broadcast to ")
59-
log.Print(c.ws.RemoteAddr())
58+
//log.Print("did broadcast to ")
59+
//log.Print(c.ws.RemoteAddr())
6060
//c.send <- []byte("hello world")
6161
default:
6262
delete(h.connections, c)
@@ -66,15 +66,15 @@ func (h *hub) run() {
6666
}
6767
}
6868
case m := <-h.broadcastSys:
69-
log.Print("Got a system broadcast")
70-
log.Print(string(m))
71-
log.Print("-----")
69+
//log.Print("Got a system broadcast")
70+
//log.Print(string(m))
71+
//log.Print("-----")
7272

7373
for c := range h.connections {
7474
select {
7575
case c.send <- m:
76-
log.Print("did broadcast to ")
77-
log.Print(c.ws.RemoteAddr())
76+
//log.Print("did broadcast to ")
77+
//log.Print(c.ws.RemoteAddr())
7878
//c.send <- []byte("hello world")
7979
default:
8080
delete(h.connections, c)
@@ -111,7 +111,15 @@ func checkCmd(m []byte) {
111111
go spErr("Problem converting baud rate " + args[2])
112112
return
113113
}
114-
go spHandlerOpen(args[1], baud)
114+
// pass in buffer type now as string. if user does not
115+
// ask for a buffer type pass in empty string
116+
bufferAlgorithm := ""
117+
if len(args) > 3 {
118+
// cool. we got a buffer type request
119+
buftype := strings.Replace(args[3], "\n", "", -1)
120+
bufferAlgorithm = buftype
121+
}
122+
go spHandlerOpen(args[1], baud, bufferAlgorithm)
115123

116124
} else if strings.HasPrefix(sl, "close") {
117125

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Version 1.2
1+
// Version 1.3
22
// Supports Windows, Linux, Mac, and Raspberry Pi, Beagle Bone Black
33

44
package main
@@ -13,7 +13,7 @@ import (
1313
)
1414

1515
var (
16-
version = "1.2"
16+
version = "1.3"
1717
addr = flag.String("addr", ":8989", "http service address")
1818
assets = flag.String("assets", defaultAssetPath(), "path to assets")
1919
//homeTempl *template.Template

serial.go.REMOVED.git-id

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4b4a2756e40ce076283ed745ce36528a896c1058
1+
f7c160746bc7a68236eca7dc217c4f9935ae9fb9

seriallist_windows.go.REMOVED.git-id

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
d2e28b7f7e3a4048570b0aabe104acb8ef4105e1
1+
4d6f104a295068e38405dfd6ac558824f9461079

serialport.go.REMOVED.git-id

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
06dd8da3d283650c785c0e949f4acbae22be3974
1+
88815166941a7461c676ab1d1a7c0d6fa5e92692

0 commit comments

Comments
 (0)