RadioHead
|
RHDatagram subclass for sending addressed, acknowledged, retransmitted datagrams. More...
#include <RHReliableDatagram.h>
Public Member Functions | |
RHReliableDatagram (RHGenericDriver &driver, uint8_t thisAddress=0) | |
void | setTimeout (uint16_t timeout) |
void | setRetries (uint8_t retries) |
uint8_t | retries () |
bool | sendtoWait (uint8_t *buf, uint8_t len, uint8_t address) |
bool | recvfromAck (uint8_t *buf, uint8_t *len, uint8_t *from=NULL, uint8_t *to=NULL, uint8_t *id=NULL, uint8_t *flags=NULL) |
bool | recvfromAckTimeout (uint8_t *buf, uint8_t *len, uint16_t timeout, uint8_t *from=NULL, uint8_t *to=NULL, uint8_t *id=NULL, uint8_t *flags=NULL) |
uint32_t | retransmissions () |
void | resetRetransmissions () |
Public Member Functions inherited from RHDatagram | |
RHDatagram (RHGenericDriver &driver, uint8_t thisAddress=0) | |
bool | init () |
void | setThisAddress (uint8_t thisAddress) |
bool | sendto (uint8_t *buf, uint8_t len, uint8_t address) |
bool | recvfrom (uint8_t *buf, uint8_t *len, uint8_t *from=NULL, uint8_t *to=NULL, uint8_t *id=NULL, uint8_t *flags=NULL) |
bool | available () |
void | waitAvailable (uint16_t polldelay=0) |
bool | waitPacketSent () |
bool | waitPacketSent (uint16_t timeout) |
bool | waitAvailableTimeout (uint16_t timeout, uint16_t polldelay=0) |
void | setHeaderTo (uint8_t to) |
void | setHeaderFrom (uint8_t from) |
void | setHeaderId (uint8_t id) |
void | setHeaderFlags (uint8_t set, uint8_t clear=RH_FLAGS_NONE) |
uint8_t | headerTo () |
uint8_t | headerFrom () |
uint8_t | headerId () |
uint8_t | headerFlags () |
uint8_t | thisAddress () |
Protected Member Functions | |
void | acknowledge (uint8_t id, uint8_t from) |
bool | haveNewMessage () |
Additional Inherited Members | |
Protected Attributes inherited from RHDatagram | |
RHGenericDriver & | _driver |
The Driver we are to use. | |
uint8_t | _thisAddress |
The address of this node. | |
RHDatagram subclass for sending addressed, acknowledged, retransmitted datagrams.
Manager class that extends RHDatagram to define addressed, reliable datagrams with acknowledgement and retransmission. Based on RHDatagram, adds flags and sequence numbers. RHReliableDatagram is reliable in the sense that messages are acknowledged by the recipient, and unacknowledged messages are retransmitted until acknowledged or the retries are exhausted. When addressed messages are sent (by sendtoWait()), it will wait for an ack, and retransmit after timeout until an ack is received or retries are exhausted. When addressed messages are collected by the application (by recvfromAck()), an acknowledgement is automatically sent to the sender.
You can use RHReliableDatagram to send broadcast messages, with a TO address of RH_BROADCAST_ADDRESS, however broadcasts are not acknowledged or retransmitted and are therefore NOT actually reliable.
The retransmit timeout is randomly varied between timeout and timeout*2 to prevent collisions on all retries when 2 nodes happen to start sending at the same time .
Each new message sent by sendtoWait() has its ID incremented.
An ack consists of a message with:
RHReliableDatagram and the underlying drivers always transmit as soon as sendtoWait() is called. RHReliableDatagram waits for an acknowledgement, and if one is not received after a timeout period the message is transmitted again. If no acknowledgement is received after several retries, the transmissions is deemed to have failed. No contention for media is detected. This will be recognised as "pure ALOHA". The addition of Clear Channel Assessment (CCA) is desirable and planned.
There is no message queuing or threading in RHReliableDatagram. sendtoWait() waits until an acknowledgement is received, retransmitting up to (by default) 3 retries time with a default 200ms timeout. During this transmit-acknowledge phase, any received message (other than the expected acknowledgement) will be ignored. Your sketch will be unresponsive to new messages until an acknowledgement is received or the retries are exhausted. Central server-type sketches should be very cautious about their retransmit strategy and configuration lest they hang for a long time trying to reply to clients that are unreachable.
Caution: if you have a radio network with a mixture of slow and fast processors and ReliableDatagrams, you may be affected by race conditions where the fast processor acknowledges a message before the sender is ready to process the acknowledgement. Best practice is to use the same processors (and radios) throughout your network.
RHReliableDatagram::RHReliableDatagram | ( | RHGenericDriver & | driver, |
uint8_t | thisAddress = 0 |
||
) |
Constructor.
[in] | driver | The RadioHead driver to use to transport messages. |
[in] | thisAddress | The address to assign to this node. Defaults to 0 |
|
protected |
Send an ACK for the message id to the given from address Blocks until the ACK has been sent
References RHDatagram::sendto(), RHDatagram::setHeaderFlags(), RHDatagram::setHeaderId(), and RHDatagram::waitPacketSent().
Referenced by recvfromAck(), and sendtoWait().
|
protected |
Checks whether the message currently in the Rx buffer is a new message, not previously received based on the from address and the sequence. If it is new, it is acknowledged and returns true
bool RHReliableDatagram::recvfromAck | ( | uint8_t * | buf, |
uint8_t * | len, | ||
uint8_t * | from = NULL , |
||
uint8_t * | to = NULL , |
||
uint8_t * | id = NULL , |
||
uint8_t * | flags = NULL |
||
) |
If there is a valid message available for this node, send an acknowledgement to the SRC address (blocking until this is complete), then copy the message to buf and return true else return false. If a message is copied, *len is set to the length. If from is not NULL, the SRC address is placed in *from. If to is not NULL, the DEST address is placed in *to. This is the preferred function for getting messages addressed to this node. If the message is not a broadcast, acknowledge to the sender before returning. You should be sure to call this function frequently enough to not miss any messages. It is recommended that you call it in your main loop.
[in] | buf | Location to copy the received message |
[in,out] | len | Pointer to the number of octets available in buf. The number be reset to the actual number of octets copied. |
[in] | from | If present and not NULL, the referenced uint8_t will be set to the SRC address |
[in] | to | If present and not NULL, the referenced uint8_t will be set to the DEST address |
[in] | id | If present and not NULL, the referenced uint8_t will be set to the ID |
[in] | flags | If present and not NULL, the referenced uint8_t will be set to the FLAGS (not just those addressed to this node). |
References RHDatagram::_thisAddress, acknowledge(), RHDatagram::available(), and RHDatagram::recvfrom().
Referenced by RHRouter::recvfromAck(), and recvfromAckTimeout().
bool RHReliableDatagram::recvfromAckTimeout | ( | uint8_t * | buf, |
uint8_t * | len, | ||
uint16_t | timeout, | ||
uint8_t * | from = NULL , |
||
uint8_t * | to = NULL , |
||
uint8_t * | id = NULL , |
||
uint8_t * | flags = NULL |
||
) |
Similar to recvfromAck(), this will block until either a valid message available for this node or the timeout expires. Starts the receiver automatically. You should be sure to call this function frequently enough to not miss any messages. It is recommended that you call it in your main loop.
[in] | buf | Location to copy the received message |
[in,out] | len | Pointer to the number of octets available in buf. The number be reset to the actual number of octets copied. |
[in] | timeout | Maximum time to wait in milliseconds |
[in] | from | If present and not NULL, the referenced uint8_t will be set to the SRC address |
[in] | to | If present and not NULL, the referenced uint8_t will be set to the DEST address |
[in] | id | If present and not NULL, the referenced uint8_t will be set to the ID |
[in] | flags | If present and not NULL, the referenced uint8_t will be set to the FLAGS (not just those addressed to this node). |
References recvfromAck(), and RHDatagram::waitAvailableTimeout().
void RHReliableDatagram::resetRetransmissions | ( | ) |
Resets the count of the number of retransmissions to 0.
uint32_t RHReliableDatagram::retransmissions | ( | ) |
Returns the number of retransmissions we have had to send since starting or since the last call to resetRetransmissions().
uint8_t RHReliableDatagram::retries | ( | ) |
Returns the currently configured maximum retries count. Can be changed with setRetries().
Referenced by sendtoWait(), and setRetries().
bool RHReliableDatagram::sendtoWait | ( | uint8_t * | buf, |
uint8_t | len, | ||
uint8_t | address | ||
) |
Send the message (with retries) and waits for an ack. Returns true if an acknowledgement is received. Synchronous: any message other than the desired ACK received while waiting is discarded. Blocks until an ACK is received or all retries are exhausted (ie up to retries*timeout milliseconds). If the destination address is the broadcast address RH_BROADCAST_ADDRESS (255), the message will be sent as a broadcast, but receiving nodes do not acknowledge, and sendtoWait() returns true immediately without waiting for any acknowledgements.
[in] | address | The address to send the message to. |
[in] | buf | Pointer to the binary message to send |
[in] | len | Number of octets to send |
References RHDatagram::_thisAddress, acknowledge(), RHDatagram::recvfrom(), retries(), RHDatagram::sendto(), RHDatagram::setHeaderFlags(), RHDatagram::setHeaderId(), RHDatagram::waitAvailableTimeout(), and RHDatagram::waitPacketSent().
Referenced by RHRouter::route().
void RHReliableDatagram::setRetries | ( | uint8_t | retries | ) |
Sets the maximum number of retries. Defaults to 3 at construction time. If set to 0, each message will only ever be sent once. sendtoWait will give up and return false if there is no ack received after all transmissions time out and the retries count is exhausted. param[in] retries The maximum number a retries.
References retries().
void RHReliableDatagram::setTimeout | ( | uint16_t | timeout | ) |
Sets the minimum retransmit timeout. If sendtoWait is waiting for an ack longer than this time (in milliseconds), it will retransmit the message. Defaults to 200ms. The timeout is measured from the end of transmission of the message. It must be at least longer than the the transmit time of the acknowledgement (preamble+6 octets) plus the latency/poll time of the receiver. For fast modulation schemes you can considerably shorten this time. Caution: if you are using slow packet rates and long packets you may need to change the timeout for reliable operations. The actual timeout is randomly varied between timeout and timeout*2.
[in] | timeout | The new timeout period in milliseconds |