Skip to content

Commit dbc3032

Browse files
committed
Line Mode using r:{} counting
1 parent 01b63ac commit dbc3032

File tree

1 file changed

+133
-12
lines changed

1 file changed

+133
-12
lines changed

bufferflow_tinygpktmode.go

Lines changed: 133 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"encoding/json"
55
"log"
66
"regexp"
7-
//"strconv"
7+
"strconv"
88
"strings"
99
"sync"
1010
//"time"
@@ -56,9 +56,13 @@ type BufferflowTinygPktMode struct {
5656
//BufferMax int
5757
rePacketCtr *regexp.Regexp
5858

59-
PacketCtrMin int
60-
PacketCtrMax int
61-
PacketCtrAvail int
59+
PacketCtrMin int
60+
PacketCtrMax int
61+
PacketCtrAvail int
62+
isInReSyncMode bool
63+
reSyncCtr int
64+
reSyncCtrTriggerAt int
65+
6266
//BufferSize int
6367
//BufferSizeArray []int
6468
//BufferCmdArray []string
@@ -119,11 +123,13 @@ func (b *BufferflowTinygPktMode) Init() {
119123

120124
// Packet Mode Counters
121125
b.rePacketCtr, _ = regexp.Compile("\"f\":\\[\\d+,\\d+,(\\d+)")
122-
b.PacketCtrMin = 12 // 3 // if you are at this many packet mode slots left, stop, don't go below it
123-
b.PacketCtrAvail = 30 //6 // this is the default number that TinyG starts with
124-
b.PacketCtrMax = 30 // how many Line Mode packet counters there are
125-
126+
b.PacketCtrMin = 10 // 3 // if you are at this many packet mode slots left, stop, don't go below it
127+
b.PacketCtrAvail = 24 //6 // main variable keeping track of how many Line Mode slots are avaialable in TinyG, this is the default number that TinyG starts with
128+
b.PacketCtrMax = 24 // how many Line Mode packet counters there are max on the TinyG firmware
129+
b.isInReSyncMode = false
126130
b.testDropCtr = 0
131+
b.reSyncCtr = 0
132+
b.reSyncCtrTriggerAt = 41 // the number of processed Gcode lines that have us a trigger a resync
127133

128134
//b.StartSending = 20
129135
//b.StopSending = 18
@@ -281,7 +287,30 @@ func (b *BufferflowTinygPktMode) BlockUntilReady(cmd string, id string) (bool, b
281287

282288
isNeedToUnlock := true
283289

284-
if b.PacketCtrAvail <= b.PacketCtrMin {
290+
// count the amount of outbound lines that will get back an r:{} response
291+
// and then re-sync after a set amount to reset our Line Mode counter
292+
/*b.reSyncCtr++
293+
if b.reSyncCtr >= b.reSyncCtrTriggerAt {
294+
295+
// we need to do a re-sync
296+
b.reSyncStart()
297+
298+
// clear all b.sem signals so when we block below, we truly block
299+
b.ClearOutSemaphore()
300+
301+
log.Println("\tBlocking on b.sem for re-sync until told from OnIncomingData to go")
302+
303+
// since we need other code to run while we're blocking, we better release the packet ctr lock
304+
b.packetCtrLock.Unlock()
305+
306+
unblockType, ok := <-b.sem // will block until told from OnIncomingData to go
307+
308+
log.Printf("\tDone blocking for re-sync cuz got b.sem semaphore release. ok:%v, unblockType:%v\n", ok, unblockType)
309+
310+
// since we already unlocked this thread, note it so we don't doubly unlock
311+
isNeedToUnlock = false
312+
313+
} else */if b.PacketCtrAvail <= b.PacketCtrMin {
285314

286315
log.Printf("\tThe PacketCtrAvail (%v) is at PacketCtrMin (%v), so we are going to pause.\n", b.PacketCtrAvail, b.PacketCtrMin)
287316

@@ -389,16 +418,17 @@ func (b *BufferflowTinygPktMode) OnIncomingData(data string) {
389418
// is test out how this algorithm performs during a re-sync to ask TinyG what our
390419
// counters are at. So, randomly drop r:{}'s to mimic what takes hours to achieve
391420
// in a real world test.
392-
if b.reSlotDone.MatchString(element) {
421+
/*if b.reSlotDone.MatchString(element) {
393422
// should we drop or not? how about we drop every 10th
394423
b.testDropCtr++
395424
if b.testDropCtr == 10 {
396425
// drop the r:{}
397-
log.Println("Dropping this line for test purposes: %v", element)
426+
log.Println("\tDropping this line for test purposes: %v", element)
398427
element = ""
399428
b.testDropCtr = 0
400429
}
401-
}
430+
}*/
431+
// END COMMENT THIS SECTION OUT WHEN IN PRODUCTION
402432

403433
//check for r:{} response indicating a gcode line has been processed
404434
if b.reSlotDone.MatchString(element) {
@@ -416,7 +446,11 @@ func (b *BufferflowTinygPktMode) OnIncomingData(data string) {
416446
// accurate. We know an r:{} can occasionally get dropped on the floor and thus
417447
// this approach needs an occasional stop-the-world re-sync, but on a normal per
418448
// line basis we decrement on the r:{} to keep our local count up to date
449+
//if !b.isInReSyncMode {
419450
b.onGotLineModeCounterFromTinyG(b.PacketCtrAvail + 1)
451+
//} else {
452+
// log.Println("\tWe are in re-sync mode so this incoming r:{} will do nothing for us resetting Line Mode ctr until done with re-sync mode")
453+
//}
420454

421455
// Send cmd:"Complete" back
422456
m := DataCmdComplete{"Complete", id, b.Port, b.q.LenOfCmds(), doneCmd}
@@ -547,6 +581,21 @@ func (b *BufferflowTinygPktMode) OnIncomingData(data string) {
547581

548582
}
549583

584+
// see if we are in re-sync mode
585+
if b.isInReSyncMode {
586+
587+
// if regexp.MatchString("{\"r\":\{\"rx\":", element) {
588+
if b.reRxResponse.MatchString(element) {
589+
590+
log.Println("\tWe are in re-sync mode and looks like we just got our rx: response: %v", element)
591+
b.reSyncEnd(element)
592+
593+
} else {
594+
log.Println("\tIn re-sync mode, but this line was not an rx: val")
595+
}
596+
597+
}
598+
550599
// handle communication back to client
551600
// for base serial data (this is not the cmd:"Write" or cmd:"Complete")
552601
m := DataPerLine{b.Port, element + "\n"}
@@ -574,6 +623,78 @@ func (b *BufferflowTinygPktMode) OnIncomingData(data string) {
574623
log.Printf("OnIncomingData() End.\n")
575624
}
576625

626+
func (b *BufferflowTinygPktMode) reSyncStart() {
627+
628+
// Ok, this method is a stop-the-world approach to syncing our
629+
// Line Mode counter with what TinyG says it should be. What we do
630+
// is pause all outgoing traffic. Send a {rx:n} request and then
631+
// only when we get this counter back do we reset our b.PacketAvailCtr
632+
// to that count and we know it's authoritative again
633+
log.Println("Re-sync: Started")
634+
635+
b.Pause()
636+
b.isInReSyncMode = true
637+
638+
//b.Unpause()
639+
go func() {
640+
time.Sleep(1000 * time.Millisecond)
641+
spWriteJson("sendjson {\"P\":\"" + b.parent_serport.portConf.Name + "\",\"Data\":[{\"D\":\"" + "{\\\"rx\\\":null}\\n\", \"Buf\":\"NoBuf\", \"Id\":\"resync1\"}]}")
642+
643+
}()
644+
go func() {
645+
time.Sleep(1200 * time.Millisecond)
646+
spWriteJson("sendjson {\"P\":\"" + b.parent_serport.portConf.Name + "\",\"Data\":[{\"D\":\"" + "{\\\"rx\\\":null}\\n\", \"Buf\":\"NoBuf\", \"Id\":\"resync1\"}]}")
647+
648+
}()
649+
}
650+
651+
func (b *BufferflowTinygPktMode) reSyncEnd(gcodeLine string) {
652+
653+
// Ok, this method is a stop-the-world approach to syncing our
654+
// Line Mode counter with what TinyG says it should be. What we do
655+
// is pause all outgoing traffic. Send a {rx:n} request and then
656+
// only when we get this counter back do we reset our b.PacketAvailCtr
657+
// to that count and we know it's authoritative again
658+
//b.Pause()
659+
b.isInReSyncMode = false
660+
b.reSyncCtr = 0
661+
662+
// parse the incoming line so we can extract the counter
663+
// SEND > {"rx":null}
664+
// RECV < {"r":{"rx":30},"f":[3,0,30]}
665+
reLineModeRxVal := regexp.MustCompile("\"rx\":(\\d+)")
666+
lineRxCtrArr := reLineModeRxVal.FindStringSubmatch(gcodeLine)
667+
668+
// if we got back an index 1 val (i.e. the digit) and it's parseable as an integer
669+
// that means we got back the packet mode counter and can pivot off of it
670+
if len(lineRxCtrArr) > 0 {
671+
672+
// now make sure it really was an integer
673+
if lineCtr, err5 := strconv.Atoi(lineRxCtrArr[1]); err5 == nil {
674+
675+
// what to do when we actually get back a Line Mode counter from TinyG
676+
//b.onGotLineModeCounterFromTinyG(lineCtr)
677+
678+
// we just got back what we think is an authoritative answer
679+
// let's spit out debug to see how far off we are
680+
log.Printf("Re-sync got back authoritative answer. What we think we should have as available: %v, what TinyG just told us: %v\n", b.PacketCtrAvail, lineCtr)
681+
682+
// set our current packet ctr to this val cuz it's authoritative
683+
b.PacketCtrAvail = lineCtr
684+
685+
} else {
686+
log.Printf("\tERROR in Re-Sync: We could not parse an integer from the Line Mode ctr???\n")
687+
}
688+
689+
} else {
690+
log.Printf("\tERROR in Re-Sync: We got an r:{\"rx\":...} response but could not parse out the Line Mode counter.\n")
691+
}
692+
693+
//b.Unpause()
694+
log.Println("Re-sync: End")
695+
696+
}
697+
577698
func (b *BufferflowTinygPktMode) onGotLineModeCounterFromTinyG(pktCtr int) {
578699
// we got back a packet ctr
579700

0 commit comments

Comments
 (0)