This driver is a stripped down version of the Radiohead 1.45 driver, and covers fewer radios. Threading and an event queue have been added to make the ISR's more stable across architectures. Specifically The STM32L4 parts

Dependents:   Threaded_LoRa_Modem

Committer:
rlanders73
Date:
Wed Jun 23 15:53:12 2021 +0000
Revision:
7:250d1c72df36
Parent:
0:ab4e012489ef
explicitly not disabling interrupts for mbed

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