V148

Fork of RadioHead-148 by David Rimer

Committer:
davidr99
Date:
Thu Oct 15 01:27:00 2015 +0000
Revision:
0:ab4e012489ef
Messy start, but a port for RadioHead.; Currently the SPI modulus are the only ones that work.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
davidr99 0:ab4e012489ef 1 // RHReliableDatagram.h
davidr99 0:ab4e012489ef 2 //
davidr99 0:ab4e012489ef 3 // Author: Mike McCauley (mikem@airspayce.com)
davidr99 0:ab4e012489ef 4 // Copyright (C) 2011 Mike McCauley
davidr99 0:ab4e012489ef 5 // $Id: RHReliableDatagram.h,v 1.16 2015/08/12 23:18:51 mikem Exp $
davidr99 0:ab4e012489ef 6
davidr99 0:ab4e012489ef 7 #ifndef RHReliableDatagram_h
davidr99 0:ab4e012489ef 8 #define RHReliableDatagram_h
davidr99 0:ab4e012489ef 9
davidr99 0:ab4e012489ef 10 #include <RHDatagram.h>
davidr99 0:ab4e012489ef 11
davidr99 0:ab4e012489ef 12 // The acknowledgement bit in the FLAGS
davidr99 0:ab4e012489ef 13 // The top 4 bits of the flags are reserved for RadioHead. The lower 4 bits are reserved
davidr99 0:ab4e012489ef 14 // for application layer use.
davidr99 0:ab4e012489ef 15 #define RH_FLAGS_ACK 0x80
davidr99 0:ab4e012489ef 16
davidr99 0:ab4e012489ef 17 /// the default retry timeout in milliseconds
davidr99 0:ab4e012489ef 18 #define RH_DEFAULT_TIMEOUT 200
davidr99 0:ab4e012489ef 19
davidr99 0:ab4e012489ef 20 /// The default number of retries
davidr99 0:ab4e012489ef 21 #define RH_DEFAULT_RETRIES 3
davidr99 0:ab4e012489ef 22
davidr99 0:ab4e012489ef 23 /////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 24 /// \class RHReliableDatagram RHReliableDatagram.h <RHReliableDatagram.h>
davidr99 0:ab4e012489ef 25 /// \brief RHDatagram subclass for sending addressed, acknowledged, retransmitted datagrams.
davidr99 0:ab4e012489ef 26 ///
davidr99 0:ab4e012489ef 27 /// Manager class that extends RHDatagram to define addressed, reliable datagrams with acknowledgement and retransmission.
davidr99 0:ab4e012489ef 28 /// Based on RHDatagram, adds flags and sequence numbers. RHReliableDatagram is reliable in the sense
davidr99 0:ab4e012489ef 29 /// that messages are acknowledged by the recipient, and unacknowledged messages are retransmitted until acknowledged or the
davidr99 0:ab4e012489ef 30 /// retries are exhausted.
davidr99 0:ab4e012489ef 31 /// When addressed messages are sent (by sendtoWait()), it will wait for an ack, and retransmit
davidr99 0:ab4e012489ef 32 /// after timeout until an ack is received or retries are exhausted.
davidr99 0:ab4e012489ef 33 /// When addressed messages are collected by the application (by recvfromAck()),
davidr99 0:ab4e012489ef 34 /// an acknowledgement is automatically sent to the sender.
davidr99 0:ab4e012489ef 35 ///
davidr99 0:ab4e012489ef 36 /// You can use RHReliableDatagram to send broadcast messages, with a TO address of RH_BROADCAST_ADDRESS,
davidr99 0:ab4e012489ef 37 /// however broadcasts are not acknowledged or retransmitted and are therefore NOT actually reliable.
davidr99 0:ab4e012489ef 38 ///
davidr99 0:ab4e012489ef 39 /// The retransmit timeout is randomly varied between timeout and timeout*2 to prevent collisions on all
davidr99 0:ab4e012489ef 40 /// retries when 2 nodes happen to start sending at the same time .
davidr99 0:ab4e012489ef 41 ///
davidr99 0:ab4e012489ef 42 /// Each new message sent by sendtoWait() has its ID incremented.
davidr99 0:ab4e012489ef 43 ///
davidr99 0:ab4e012489ef 44 /// An ack consists of a message with:
davidr99 0:ab4e012489ef 45 /// - TO set to the from address of the original message
davidr99 0:ab4e012489ef 46 /// - FROM set to this node address
davidr99 0:ab4e012489ef 47 /// - ID set to the ID of the original message
davidr99 0:ab4e012489ef 48 /// - FLAGS with the RH_FLAGS_ACK bit set
davidr99 0:ab4e012489ef 49 /// - 1 octet of payload containing ASCII '!' (since some drivers cannot handle 0 length payloads)
davidr99 0:ab4e012489ef 50 ///
davidr99 0:ab4e012489ef 51 /// \par Media Access Strategy
davidr99 0:ab4e012489ef 52 ///
davidr99 0:ab4e012489ef 53 /// RHReliableDatagram and the underlying drivers always transmit as soon as
davidr99 0:ab4e012489ef 54 /// sendtoWait() is called. RHReliableDatagram waits for an acknowledgement,
davidr99 0:ab4e012489ef 55 /// and if one is not received after a timeout period the message is
davidr99 0:ab4e012489ef 56 /// transmitted again. If no acknowledgement is received after several
davidr99 0:ab4e012489ef 57 /// retries, the transmissions is deemed to have failed.
davidr99 0:ab4e012489ef 58 /// No contention for media is detected.
davidr99 0:ab4e012489ef 59 /// This will be recognised as "pure ALOHA".
davidr99 0:ab4e012489ef 60 /// The addition of Clear Channel Assessment (CCA) is desirable and planned.
davidr99 0:ab4e012489ef 61 ///
davidr99 0:ab4e012489ef 62 /// There is no message queuing or threading in RHReliableDatagram.
davidr99 0:ab4e012489ef 63 /// sendtoWait() waits until an acknowledgement is received, retransmitting
davidr99 0:ab4e012489ef 64 /// up to (by default) 3 retries time with a default 200ms timeout.
davidr99 0:ab4e012489ef 65 /// During this transmit-acknowledge phase, any received message (other than the expected
davidr99 0:ab4e012489ef 66 /// acknowledgement) will be ignored. Your sketch will be unresponsive to new messages
davidr99 0:ab4e012489ef 67 /// until an acknowledgement is received or the retries are exhausted.
davidr99 0:ab4e012489ef 68 /// Central server-type sketches should be very cautious about their
davidr99 0:ab4e012489ef 69 /// retransmit strategy and configuration lest they hang for a long time
davidr99 0:ab4e012489ef 70 /// trying to reply to clients that are unreachable.
davidr99 0:ab4e012489ef 71 ///
davidr99 0:ab4e012489ef 72 /// Caution: if you have a radio network with a mixture of slow and fast
davidr99 0:ab4e012489ef 73 /// processors and ReliableDatagrams, you may be affected by race conditions
davidr99 0:ab4e012489ef 74 /// where the fast processor acknowledges a message before the sender is ready
davidr99 0:ab4e012489ef 75 /// to process the acknowledgement. Best practice is to use the same processors (and
davidr99 0:ab4e012489ef 76 /// radios) throughout your network.
davidr99 0:ab4e012489ef 77 ///
davidr99 0:ab4e012489ef 78 class RHReliableDatagram : public RHDatagram
davidr99 0:ab4e012489ef 79 {
davidr99 0:ab4e012489ef 80 public:
davidr99 0:ab4e012489ef 81 /// Constructor.
davidr99 0:ab4e012489ef 82 /// \param[in] driver The RadioHead driver to use to transport messages.
davidr99 0:ab4e012489ef 83 /// \param[in] thisAddress The address to assign to this node. Defaults to 0
davidr99 0:ab4e012489ef 84 RHReliableDatagram(RHGenericDriver& driver, uint8_t thisAddress = 0);
davidr99 0:ab4e012489ef 85
davidr99 0:ab4e012489ef 86 /// Sets the minimum retransmit timeout. If sendtoWait is waiting for an ack
davidr99 0:ab4e012489ef 87 /// longer than this time (in milliseconds),
davidr99 0:ab4e012489ef 88 /// it will retransmit the message. Defaults to 200ms. The timeout is measured from the end of
davidr99 0:ab4e012489ef 89 /// transmission of the message. It must be at least longer than the the transmit
davidr99 0:ab4e012489ef 90 /// time of the acknowledgement (preamble+6 octets) plus the latency/poll time of the receiver.
davidr99 0:ab4e012489ef 91 /// For fast modulation schemes you can considerably shorten this time.
davidr99 0:ab4e012489ef 92 /// The actual timeout is randomly varied between timeout and timeout*2.
davidr99 0:ab4e012489ef 93 /// \param[in] timeout The new timeout period in milliseconds
davidr99 0:ab4e012489ef 94 void setTimeout(uint16_t timeout);
davidr99 0:ab4e012489ef 95
davidr99 0:ab4e012489ef 96 /// Sets the maximum number of retries. Defaults to 3 at construction time.
davidr99 0:ab4e012489ef 97 /// If set to 0, each message will only ever be sent once.
davidr99 0:ab4e012489ef 98 /// sendtoWait will give up and return false if there is no ack received after all transmissions time out
davidr99 0:ab4e012489ef 99 /// and the retries count is exhausted.
davidr99 0:ab4e012489ef 100 /// param[in] retries The maximum number a retries.
davidr99 0:ab4e012489ef 101 void setRetries(uint8_t retries);
davidr99 0:ab4e012489ef 102
davidr99 0:ab4e012489ef 103 /// Returns the currently configured maximum retries count.
davidr99 0:ab4e012489ef 104 /// Can be changed with setRetries().
davidr99 0:ab4e012489ef 105 /// \return The currently configured maximum number of retries.
davidr99 0:ab4e012489ef 106 uint8_t retries();
davidr99 0:ab4e012489ef 107
davidr99 0:ab4e012489ef 108 /// Send the message (with retries) and waits for an ack. Returns true if an acknowledgement is received.
davidr99 0:ab4e012489ef 109 /// Synchronous: any message other than the desired ACK received while waiting is discarded.
davidr99 0:ab4e012489ef 110 /// Blocks until an ACK is received or all retries are exhausted (ie up to retries*timeout milliseconds).
davidr99 0:ab4e012489ef 111 /// If the destination address is the broadcast address RH_BROADCAST_ADDRESS (255), the message will
davidr99 0:ab4e012489ef 112 /// be sent as a broadcast, but receiving nodes do not acknowledge, and sendtoWait() returns true immediately
davidr99 0:ab4e012489ef 113 /// without waiting for any acknowledgements.
davidr99 0:ab4e012489ef 114 /// \param[in] address The address to send the message to.
davidr99 0:ab4e012489ef 115 /// \param[in] buf Pointer to the binary message to send
davidr99 0:ab4e012489ef 116 /// \param[in] len Number of octets to send
davidr99 0:ab4e012489ef 117 /// \return true if the message was transmitted and an acknowledgement was received.
davidr99 0:ab4e012489ef 118 bool sendtoWait(uint8_t* buf, uint8_t len, uint8_t address);
davidr99 0:ab4e012489ef 119
davidr99 0:ab4e012489ef 120 /// If there is a valid message available for this node, send an acknowledgement to the SRC
davidr99 0:ab4e012489ef 121 /// address (blocking until this is complete), then copy the message to buf and return true
davidr99 0:ab4e012489ef 122 /// else return false.
davidr99 0:ab4e012489ef 123 /// If a message is copied, *len is set to the length..
davidr99 0:ab4e012489ef 124 /// If from is not NULL, the SRC address is placed in *from.
davidr99 0:ab4e012489ef 125 /// If to is not NULL, the DEST address is placed in *to.
davidr99 0:ab4e012489ef 126 /// This is the preferred function for getting messages addressed to this node.
davidr99 0:ab4e012489ef 127 /// If the message is not a broadcast, acknowledge to the sender before returning.
davidr99 0:ab4e012489ef 128 /// You should be sure to call this function frequently enough to not miss any messages
davidr99 0:ab4e012489ef 129 /// It is recommended that you call it in your main loop.
davidr99 0:ab4e012489ef 130 /// \param[in] buf Location to copy the received message
davidr99 0:ab4e012489ef 131 /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
davidr99 0:ab4e012489ef 132 /// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address
davidr99 0:ab4e012489ef 133 /// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address
davidr99 0:ab4e012489ef 134 /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
davidr99 0:ab4e012489ef 135 /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
davidr99 0:ab4e012489ef 136 /// (not just those addressed to this node).
davidr99 0:ab4e012489ef 137 /// \return true if a valid message was copied to buf
davidr99 0:ab4e012489ef 138 bool recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
davidr99 0:ab4e012489ef 139
davidr99 0:ab4e012489ef 140 /// Similar to recvfromAck(), this will block until either a valid message available for this node
davidr99 0:ab4e012489ef 141 /// or the timeout expires. Starts the receiver automatically.
davidr99 0:ab4e012489ef 142 /// You should be sure to call this function frequently enough to not miss any messages
davidr99 0:ab4e012489ef 143 /// It is recommended that you call it in your main loop.
davidr99 0:ab4e012489ef 144 /// \param[in] buf Location to copy the received message
davidr99 0:ab4e012489ef 145 /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
davidr99 0:ab4e012489ef 146 /// \param[in] timeout Maximum time to wait in milliseconds
davidr99 0:ab4e012489ef 147 /// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address
davidr99 0:ab4e012489ef 148 /// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address
davidr99 0:ab4e012489ef 149 /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
davidr99 0:ab4e012489ef 150 /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
davidr99 0:ab4e012489ef 151 /// (not just those addressed to this node).
davidr99 0:ab4e012489ef 152 /// \return true if a valid message was copied to buf
davidr99 0:ab4e012489ef 153 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);
davidr99 0:ab4e012489ef 154
davidr99 0:ab4e012489ef 155 /// Returns the number of retransmissions
davidr99 0:ab4e012489ef 156 /// we have had to send since starting or since the last call to resetRetransmissions().
davidr99 0:ab4e012489ef 157 /// \return The number of retransmissions since initialisation.
davidr99 0:ab4e012489ef 158 uint32_t retransmissions();
davidr99 0:ab4e012489ef 159
davidr99 0:ab4e012489ef 160 /// Resets the count of the number of retransmissions
davidr99 0:ab4e012489ef 161 /// to 0.
davidr99 0:ab4e012489ef 162 void resetRetransmissions();
davidr99 0:ab4e012489ef 163
davidr99 0:ab4e012489ef 164 protected:
davidr99 0:ab4e012489ef 165 /// Send an ACK for the message id to the given from address
davidr99 0:ab4e012489ef 166 /// Blocks until the ACK has been sent
davidr99 0:ab4e012489ef 167 void acknowledge(uint8_t id, uint8_t from);
davidr99 0:ab4e012489ef 168
davidr99 0:ab4e012489ef 169 /// Checks whether the message currently in the Rx buffer is a new message, not previously received
davidr99 0:ab4e012489ef 170 /// based on the from address and the sequence. If it is new, it is acknowledged and returns true
davidr99 0:ab4e012489ef 171 /// \return true if there is a message received and it is a new message
davidr99 0:ab4e012489ef 172 bool haveNewMessage();
davidr99 0:ab4e012489ef 173
davidr99 0:ab4e012489ef 174 private:
davidr99 0:ab4e012489ef 175 /// Count of retransmissions we have had to send
davidr99 0:ab4e012489ef 176 uint32_t _retransmissions;
davidr99 0:ab4e012489ef 177
davidr99 0:ab4e012489ef 178 /// The last sequence number to be used
davidr99 0:ab4e012489ef 179 /// Defaults to 0
davidr99 0:ab4e012489ef 180 uint8_t _lastSequenceNumber;
davidr99 0:ab4e012489ef 181
davidr99 0:ab4e012489ef 182 // Retransmit timeout (milliseconds)
davidr99 0:ab4e012489ef 183 /// Defaults to 200
davidr99 0:ab4e012489ef 184 uint16_t _timeout;
davidr99 0:ab4e012489ef 185
davidr99 0:ab4e012489ef 186 // Retries (0 means one try only)
davidr99 0:ab4e012489ef 187 /// Defaults to 3
davidr99 0:ab4e012489ef 188 uint8_t _retries;
davidr99 0:ab4e012489ef 189
davidr99 0:ab4e012489ef 190 /// Array of the last seen sequence number indexed by node address that sent it
davidr99 0:ab4e012489ef 191 /// It is used for duplicate detection. Duplicated messages are re-acknowledged when received
davidr99 0:ab4e012489ef 192 /// (this is generally due to lost ACKs, causing the sender to retransmit, even though we have already
davidr99 0:ab4e012489ef 193 /// received that message)
davidr99 0:ab4e012489ef 194 uint8_t _seenIds[256];
davidr99 0:ab4e012489ef 195 };
davidr99 0:ab4e012489ef 196
davidr99 0:ab4e012489ef 197 /// @example rf22_reliable_datagram_client.pde
davidr99 0:ab4e012489ef 198 /// @example rf22_reliable_datagram_server.pde
davidr99 0:ab4e012489ef 199
davidr99 0:ab4e012489ef 200 #endif
davidr99 0:ab4e012489ef 201