How are datagrams received?

This is most likely directed to @bigjosh (or, at least, I know you know the answer, for some reason :wink: ).

In the context of guaranteed datagram delivery, I am experimenting with direct datagram sending/receiving in a way that hopefully would allow several packets to be exchanged in a single loop pass.

Looking ta the blinklib code, sending a datagram is trivial and it LOOKS like it would be sent right away (modulo a collision happening). I can not be sure as the actual code that does that is in BlinkBIOS, which is closed source, but I am assuming this is true (please correct me if I am wrong).

For the receiving end, it does not look like things are that straight forward and I am guessing it either involves some kind of background thread doing the receive (that would set the ir_rx_state stuff) or it is not a thread (or interrupt-based code) but is something done by BlinkBIOS synchronously which would mean it most likely woudl only happen between loop iterations.

So, my question is:

1 - Without changes to BlinkBIOS, is this doable?
2 - What would be the implications? Possible higher battery usage? I assume IR transfers are almost instantaneous in any case, correct?
3 - Do I need to call something to explicitly get the ir_rx_state stuff updated?

Note I do not want to generally bypass the normal datagram stuff but guaranteed delivery requires a 3 -way handshake and if I could do that in a single loop iteration (send/receive/send from the seding side and receive/send/receive from the receiving side), it would both simplify my code a lot (currently it is over 400 lines of code just to do that) and also make guaranteed delivery datagrams performance be on-par with the existing datagram delivery system (actually, maybe even faster due to not having the need to wait for the data sending/receiving timers).

Thanks in advance.

Just to put it in more practical terms, would this work?

Sending:

bool Send(byte f, const byte* data, byte len) {
  return BLINKBIOS_IRDATA_SEND_PACKET_VECTOR(f, data, len) != 0;
}

Receiving:

volatile ir_rx_state_t* ir_rx_state = blinkbios_irdata_block.ir_rx_states;

bool Receive(byte f, byte* data, byte* len) {
  volatile ir_rx_state_t& face_ir_rx_state = ir_rx_state[f];

  if (!face_ir_rx_state.packetBufferReady) return false;

  byte data_len = ir_rx_state->packetBufferLen;

  *len = data_len < *len ? data_len : *len;

  memcpy(data, (const byte*)face_ir_rx_state.packetBuffer, *len);

  face_ir_rx_state.packetBufferReady = 0;

  return true;
}

More specifically, would it work if I called these 2 functions multiple times in a single loop iteration? For now I am completely ignoring the fact that I would need to make sure the send and receive would happen in a single loop iteration.

Short answers:

Yes. In fact theblinkBIOS deals with asynchronous IR packets and the blinklib stuff is built on top of that to create the illusion of continuous value sharing and neighbor presence detection.

The IR LEDs communicate using very brief flashes that are spaced relatively far apart so use trivial amounts of power. The blinklib framework is constantly ping-ponging over the IR links so at any given moment one side is always transmitting.

instantaneous is all relative. :slight_smile:

A blinklib IR packet takes on the order of 10ms to transmit and includes a header, the setValueOnFace() value, info that keeps a group of blinks from going to sleep when the button on any one of them has been recently pressed, and error detection.

A datagram sent though the blinklib framework uses all the above time (there is a special “datagram data to follow” value) plus the time for the actual extra data and a checksum byte.

Remember that the whole point of the blinklib framework is specifically to hide the whole idea of packets from you and instead present you with a simplified “share this value continuously” inside a “stop the world” synchronous view. This view is very opinionated and it is not meant to be flexible.

While it is possible for you to build an asynchronous packet delivery system on top of this abstraction, it will always be frustrating and inefficient. It is like building a C interpreter inside a logo runtime.

If you have a problem that does not fit well with the shared value model, then much better to dump blinklib and talk directly to the blinkBIOS which naively uses asynchronous packets. You will be so much happier!