Serial API: NOACK when sending with ACK failed
-
I assume, sending messages with ack are re-sent multiple times. Anyways I don't see how long this is being retried (which IS built in nicely in the RF24NETWORK library, if known).
But something I really think is important is the fact that we only know whether the radio message worked is, when we receive the answer. And the answer unfortunately is exactly what we have sent.
Wouldn't it be nice if we could have the sending node would print the message that was not acknowledged back to the serial console, but with a "2" in the ACK field? This way we could react to problems asynchronously, instead of waiting a couple of seconds for receiving what we have sent. Also it would make it easier for repeating nodes to tell the GW what happened.
Any thoughts about this?
-
@SiLeX said:
I assume, sending messages with ack are re-sent multiple times
Currently, no.
You have to resend them yourself if you get no ack back in due time. We've been reluctant implementing resend-functionality in the library just because it would require buffering of outgoing non acked messages in a queue taking up lots of precious space.
Might be easier to implement as a per-sketch selectable feature now... But not top on my prio list.
-
From my perspective it is an absolute must to have this handled by the library, because it is a core feature of nRF24L01+'s and would be relatively easy to implement.
My home automation system should not need to care about the transport layer stuff, but just make use of a reliable transport layer and be notified if sending and retransmission fail consecutively. Even TCP/IP Stack connections just notify the application layer if the timed out.
Can you put this higher on the list and help if possible?
Edit: This is the library where i got this from and it automagically just works https://github.com/TMRh20/RF24Network/tree/Development
Other libraries like the common RadioHead are doing this as well.
-
MySensors has a build in network ack feature similar to RF24Network's.
I can't find any automatic network resend functionality in RF24Network. Both MySensors and RF24Network utilises the automatic hardware ack functionality in the NRF24L01 radio though. But this only works between two nodes, not when messages needs several hops to reach their destination.
Implementing what you say is not hard but it has unwanted drawbacks. Here is a few I've considered.
We would either need to have a ...
Blocking send which waits and resends until ack arrives...
- What should we do with other incoming messages while blocking/resending? Throw away? If we start processing these in-the-middle we could get some interesting scenarios.
- Howto handle battery operated devices when radio link fails. They would stay awake/resending until battery is flat.
- Should we have a timeout? If so, the send could still fail.
...or queue outgoing messages with resending in the background:
- Takes space which we don't have.
- Increases complexity; Especially when you start thinking of message signing etc.
- How long should they be queued? We will have to drop them eventually.. Then we're back at square 1. Message never was sent. How do we notify sender/programmer about this?
- How do we handle timestamping of message (which we don't have to care about today)
I've also considered a blocking version of the request().. but it has the same drawbacks as the blocking send.
-
I could not find it in the code either, but I assume it is described as a feature on http://tmrh20.github.io/RF24Network/
New (2014): Network ACKs: Efficient acknowledgement of network-wide transmissions, via dynamic radio acks and network protocol acks.
The thoughts about the resend drawbacks are interesting. Especially while hopping over multiple nodes we seem to have no easy way to determine if the send was OK or FAILED. At least with hardware, because the neighbor node was okay and this is all the nrf provides.
Regarding the "lost or queued" messages while resending (and thus blocking completely and not running
loop()
: Messages will be kept in serial buffer. But with 64 bytes we don't have space for many messages anyway. So we should time out after max 500ms of retries (which is a lot in radio world, as you know).I saw that there acually is a arduino-driven solution for at leat retrying it a couple of times: http://forum.mysensors.org/topic/1424/resend-if-st-fail/9
Do you think it would make sense to provide a new
bool send(MyMessage &msg, bool ack, uint8_t retries)
for this case? ( I hope I am not overloading any existing function).At least I will try this this tonight and give feedback about the increased reliability of my PCB-antenna nRF24L01+ modules.
-
Here is a patch of what I have done to the original
GatewayUtil.h
:SiLeX@SiLeX-PC /c/c/U/S/D/Arduino> diff libraries/MySensors/examples/SerialGateway/GatewayUtil.h SerialGateway/GatewayUtil.h -pbBc4 1 *** libraries/MySensors/examples/SerialGateway/GatewayUtil.h 2015-09-04 16:19:18.000000000 +0200 --- SerialGateway/GatewayUtil.h 2015-10-25 00:37:06.482032200 +0200 *************** void parseAndSend(MySensor &gw, char *co *** 114,129 **** --- 114,135 ---- } else { #ifdef WITH_LEDS_BLINKING gw.txBlink(1); #endif + + uint8_t resends = 0; + while (!ok && resends < 10) { ok = gw.sendRoute(msg); + resends++; + delay(random(5, 50)); if (!ok) { #ifdef WITH_LEDS_BLINKING gw.errBlink(1); #endif } } } + } } void setInclusionMode(boolean newMode) { if (newMode != inclusionMode) {
It is very aggressive for now and may be considered as a proof-of-conept only. This is running on the Gateway. The sensors would need another change. For me this fit's better as I am remote-controlling way more than I receive data from sensors.
Improvements are very welcome.
-
Nice start.. But this mod only resend if the first hop fails. You have to take the whole radio network into the picture with relay and final ack from destination node.
-
@hek If I understand correctly: This is what you try to achive by sending back a requested ACK. So this means, to take the whole network into picture, I would have to remember the message I sent (including the request for an ACK from the reciepient) and see if I receive the same message back from the node.
Unfortunately I don't have the recources to build a bigger network with relays. But I think this would be the same like I did here. But with checking the String and much more time. And much less buffering...
Hope someone want's to try this or something similar
-
In the BACnet protocol, the messages are not sent directly, but pushed into an internal state machine that remembers (some) of the previously messages sent (i.e.
memorize(_msg); send(_msg);
).The state machine also peeks incoming messages and can trigger a message re-send in case of a missed ACK.
the difference with MySensors is that all the messages are numbered, otherwise you would not know which message of the last N sent previously was ACKed,
but well.. ACKing the last similar message might be good enough.Anyway @SiLeX : if you want to try, this is not that complicated, (if you don't take into account the STREAMs) it will just costs about (1 status byte + 1 timestamp + 1 frame size) x N ; for N frames memorized.