teslaworksumn / domeshow-sercoms-ard

Library for communicating over serial with Arduino
MIT License
1 stars 0 forks source link

Inter-frame gap (IFG) #3

Open computergeek125 opened 7 years ago

computergeek125 commented 7 years ago

One of the things I've noticed while working with this protocol is that there is a high probability of encountering the start code in random binary data, which causes communication errors with devices reading invalid frames. Initially I mitidaged this by artificially decreasing the maximum packet size (the device would reject a packet > a set size)

I was thinking today about Ethernet, and how it really doesn't have that problem. So I looked it up. Ethernet has a 7 octet preamble (ours is 4), and a 12 octet inter-frame gap.

I propose here to create an IFG between the CRC and the preamble (0xde 0xad 0xbe 0xef). Like the preamble size, it will be able to be set with constructor parameters.

Behavior: The transmitter will wait for n=IFG octets in milliseconds before transmitting the next frame after sending the CRC. The receiver will wait for slightly shorter than this gap before accepting the next start code. So, like Ethernet, the channel would have to go quiet for a certain period of time, even though we're using a full-duplex protocol.

I believe this will solve some of our invalid frame problems. Additionally, the IFG-capable transmitter is capable of sending to an older receiver, since the old receivers just wait for a start code with a non-blocking read. However, the new receiver would not be compatible with an older transmitter.

bookdude13 commented 7 years ago

Makes sense to me. So the transmitter would essentially sleep for n milliseconds, and the receiver would sleep for <n milliseconds? Or would it send out null octets in between frames?

computergeek125 commented 7 years ago

The transmitter would sleep, since sending null octets would (pun completely intended) nullify the congestion control strategy on simplex connections. The receiver would not sleep, but it would "stopwatch" the connection and start seeking a new start sequence ONLY if the IFG time has elapsed. If packets end up getting dropped because of legitimate timing goofs on the transmitter side or radio congestion, we could put a buffer time period where the receiver starts listening before the full IFG has elapsed.

Code-wise, this would put an additional state before DSCOM_STATE_READY of DSCOM_STATE_WAITING, where the receiver loops keeping track of a timer, and if the timer >= IFG, the code swaps over to DSCOM_STATE_READY. It will scan for the start sequence as per normal, but (added functionality) if the start sequence fails, it will reset back to DSCOM_STATE_WAITING in addition to resetting the magic_status global.

This is what makes the new receiver incompatible with old transmitters. Old transmitters keep sending data no matter what, so the receiver would never enter DSCOM_STATE_READY and it would be stuck in DSCOM_STATE_WAITING.

Something like CSMA/CD would be super useful on these simplex links, but our hardware mostly black-boxes the physical interface, so we don't have access to the data we need. We might be able to pull something off by shorting the TX and RX pins and use the RX for CSMA/CD, but we would have to set the TX pin to float when we are receiving otherwise it would never work. Not sure if the latter option is possible in Arduino.

To be fair in terms of reference, I'm borrowing a ton of ideas from OG Ethernet (10Base-5/10Base-2)