The RFM12B wireless module is a transceiver, i.e. able to send and receive packets over wireless. This is an important advantage over simple sensor units which just send out what they measure, and things like RF-controlled power switches which only listen to incoming data but are not able to report their current state.
The only thing is… it’s a bit more work.
This is reflected in how the RF12 library works:
- simple reception is a matter of regularly polling with rf12_recvDone()
- simple transmission means you also have to call rf12_canSend() and rf12_sendStart()
- the above are both essentially uni-directional, so packets can get lost
The second mechanism added to RF12 was a set of “easy transmission” functions, i.e. rf12_easyPoll() and rf12_easySend(). These look similar, but they send out data packets asking for an ACK (acknowledge) packet from the receiver to confirm that the packet was correctly received. If nothing comes in, they will re-send the packet (and repeat a few times, if needed). This mechanism greatly improves the chance of a message arriving properly at the destination. Losing an occasional packet is one thing, losing all retries is a lot less likely!
Note that packets can be damaged or get lost at any time. It may well be that the original packet arrived just fine, but the ACK got lost instead. The sender will resend, and then (probably) get the ACK which stops this retry cycle.
So with the easy transmission functions, note that very occasionally a packet might be received twice. If it is crucial to weed these out, you can include a counter in your data packets to help detect and ignore duplicates.
With RF12demo as receiver, ACK handling is automatic. It knows when the originating node wants to get an ACK, and will send it out as soon as possible. This is reported in the output as the text “-> ack”.
The code for this in RF12demo is horrendous:
This is silly, and overkill for simple cases. So let’s improve on it.
I’ve added two utility definitions to the RF12.h header, which can simplify the above code to:
That’s better, eh?
The rest is just there to deal with a special configuration setting in RF12demo.
So if all you want is to add logic in your own sketch to send back an empty ACK packet when requested, the above can be simplified even further to:
For completeness, here’s a complete processing loop for a receiving sketch which supports nodes using the easy transmission mechanism:
You have to send out the ACK after processing the packet, because the rf12_sendStart() call will re-use the same packet buffer and overwrite the incoming packet.
Also, RF12_WANTS_ACK and RF12_ACK_REPLY are defined as macros which access the global rf12_hdr variable, as set by rf12_recvDone(). IOW, the convenience comes for free, but it does depend on some fixed assumptions. I can’t think of a situation where this would lead to problems, given that RF12-based sketches are probably all structured in the same way, and that globals are part of the RF12 driver.
For another example, see the blink_recv.pde sketch, which has also been simplified with these two macros.