ser.rxtime Discovery
I like to read data by setting the first read as an .rx so the loop just sits there till something arrives. Then any reads after that are rxtime. In the past I have rarely used speeds of 115200, but needed to on this project. After a number of hours I finally figured out the problem of why rx would would but rxtime would not on the same data stream. Even at 57600, the rxtime was taking too much time doing it's math.
repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
So I tried a different method shown below that still allows the rx to time out, but it works perfectly so far.
repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
So I tried a different method shown below that still allows the rx to time out, but it works perfectly so far.
Repeat
ser.rxflush
ms := 1
i :=0 ' Start loop here for Data in
SerialReadBuffer[i++] := ser.rx ' waits here for first PACKET HEADER byte (1F) from USB
SerialReadBuffer[i++] := ser.rxtime(ms) ' waits here for second byte OPCODE
SerialReadBuffer[i++] := ser.rxtime(ms) ' waits here for second byte LENGTH
Repeat 199 'SerialReadBuffer[2] + 10
SerialReadBuffer[i++] := ser.rxtime(ms)
PUB rxtime(ms) : rxbyte | t
'' Wait ms milliseconds for a byte to be received
'' returns -1 if no byte received, $00..$FF if byte
' added these next 5
repeat while (rxbyte := rxcheck) < 0
rxtimeout++
if rxtimeout++ > 10000 'prevent getting stuck in a rx
rxtimeout~
return -1
't := cnt
'repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms ' original

Comments
Right now I have code with .rxtime(ms) instead of .rx, but I am using "PBnJ_serial" library.
Tested with short data packets (20 bytes) ad 115_200. No problems.
Current FIFO buffer length 32 bytes.
Tomorrow I will test with 400- 24_000 byte packets.
var long parser PUB event if (something==true) parsermode:=true else parsermode:=false PUB parser | inchar,inlong,incount,outlong, 'run in new cog repeat dataport.rxflush inlong:=0 outlong:=-1 incount:=0 repeat while parsermode==true inchar:=dataport.rxtime(10) 'wait 10 mSec if (inchar==-1) inlong:=0 incount:=0 outlong:=-1 else inlong <<= 8 inlong += inchar incount++ if incount>3 outlong:=inlong inlong:=0 incount-=4 case outlong & $FF_00_00_00 $00_00_00_00: 'parse data 'do something $01_00_00_00: 'command 1 'do something $02_00_00_00: 'command 2 'do something other: 'garbage 'do anything outlong:=-1 ' !!!reset after parse!!!In the new method ms does nothing. The main idea is that you send data and it cannot lock up ever. It is not required to specify the length of data as long as you have enough repeats to capture the max data stream. If the data is less it doesn't matter
One possibility is that your incoming data at 115k is overrunning the serial data buffer. The Spin code is slow and isn't removing characters from the serial data buffer as fast as they appear there. The solution to that is to either increase the size of the buffer, or (as you have done) increase the speed of de-buffering the data.
Note that computations within a repeat loop are recalculated every time around the loop, and this applies to the costly division of clkfreq/1000. That could be precomputed and taken out of the loop. pre-compute clk1000 := clkfreq/1000, then That takes the the division out of the repeat loop, but still a long expression with a multiply to evaluate before returning a value. The following is more like your approach, so it can respond quickly if a character is already in the buffer.
t := cnt repeat while (rxbyte := rxcheck) < 0 if cnt - t > clk1000 * ms quitI'm uncomfortable with your approach in that its timeout is not based on clkfreq. Just a number of spin loops, good enough for escape but hard to figure the definite time allowed.
Below is the actual code. This allows any length of data to be sent and can never hang up.
Repeat ser.rxflush ms := 5 i :=0 ' Start loop here for Data in SerialReadBuffer[i++] := ser.rx ' 0 waits here for first PACKET HEADER byte (1F) from USB SerialReadBuffer[i++] := ser.rxtime(ms) ' 1 second byte OPCODE SerialReadBuffer[i++] := ser.rxtime(ms) ' 2 third byte LENGTH of Data to receive SerialReadBuffer[i++] := ser.rxtime(ms) ' 3 Chksum SerialReadBuffer[i++] := ser.rxtime(ms) ' 4 Target Single number to Update SerialReadBuffer[i++] := ser.rxtime(ms) ' 5 Transfer Range Start number SerialReadBuffer[i++] := ser.rxtime(ms) ' 6 Transfer Range END number SerialReadBuffer[i++] := ser.rxtime(ms) ' 7 Future SerialReadBuffer[i++] := ser.rxtime(ms) ' 8 Future SerialReadBuffer[i++] := ser.rxtime(ms) ' 9 Future Repeat SerialReadBuffer[2] SerialReadBuffer[i++] := ser.rxtime(ms)As a bug this bit me in a situation using RS485 (or SPI), where occasionally and unpredictably the device on the other end did not echo, and that caused the Prop to lock up waiting for an Rx that never came. There'd be other workarounds, but NOECHO is the most convenient way to separate commands from returned data.