Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of RadioHead-148 by
RHReliableDatagram.cpp@1:b7641da2b203, 2017-10-25 (annotated)
- Committer:
- ilkaykozak
- Date:
- Wed Oct 25 05:14:09 2017 +0000
- Revision:
- 1:b7641da2b203
- Parent:
- 0:ab4e012489ef
V148
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| davidr99 | 0:ab4e012489ef | 1 | // RHReliableDatagram.cpp |
| davidr99 | 0:ab4e012489ef | 2 | // |
| davidr99 | 0:ab4e012489ef | 3 | // Define addressed datagram |
| davidr99 | 0:ab4e012489ef | 4 | // |
| davidr99 | 0:ab4e012489ef | 5 | // Part of the Arduino RH library for operating with HopeRF RH compatible transceivers |
| davidr99 | 0:ab4e012489ef | 6 | // (see http://www.hoperf.com) |
| davidr99 | 0:ab4e012489ef | 7 | // RHDatagram will be received only by the addressed node or all nodes within range if the |
| davidr99 | 0:ab4e012489ef | 8 | // to address is RH_BROADCAST_ADDRESS |
| davidr99 | 0:ab4e012489ef | 9 | // |
| davidr99 | 0:ab4e012489ef | 10 | // Author: Mike McCauley (mikem@airspayce.com) |
| davidr99 | 0:ab4e012489ef | 11 | // Copyright (C) 2011 Mike McCauley |
| davidr99 | 0:ab4e012489ef | 12 | // $Id: RHReliableDatagram.cpp,v 1.14 2015/08/13 02:45:47 mikem Exp $ |
| davidr99 | 0:ab4e012489ef | 13 | |
| davidr99 | 0:ab4e012489ef | 14 | #include <RHReliableDatagram.h> |
| davidr99 | 0:ab4e012489ef | 15 | |
| davidr99 | 0:ab4e012489ef | 16 | //////////////////////////////////////////////////////////////////// |
| davidr99 | 0:ab4e012489ef | 17 | // Constructors |
| davidr99 | 0:ab4e012489ef | 18 | RHReliableDatagram::RHReliableDatagram(RHGenericDriver& driver, uint8_t thisAddress) |
| davidr99 | 0:ab4e012489ef | 19 | : RHDatagram(driver, thisAddress) |
| davidr99 | 0:ab4e012489ef | 20 | { |
| davidr99 | 0:ab4e012489ef | 21 | _retransmissions = 0; |
| davidr99 | 0:ab4e012489ef | 22 | _lastSequenceNumber = 0; |
| davidr99 | 0:ab4e012489ef | 23 | _timeout = RH_DEFAULT_TIMEOUT; |
| davidr99 | 0:ab4e012489ef | 24 | _retries = RH_DEFAULT_RETRIES; |
| davidr99 | 0:ab4e012489ef | 25 | } |
| davidr99 | 0:ab4e012489ef | 26 | |
| davidr99 | 0:ab4e012489ef | 27 | //////////////////////////////////////////////////////////////////// |
| davidr99 | 0:ab4e012489ef | 28 | // Public methods |
| davidr99 | 0:ab4e012489ef | 29 | void RHReliableDatagram::setTimeout(uint16_t timeout) |
| davidr99 | 0:ab4e012489ef | 30 | { |
| davidr99 | 0:ab4e012489ef | 31 | _timeout = timeout; |
| davidr99 | 0:ab4e012489ef | 32 | } |
| davidr99 | 0:ab4e012489ef | 33 | |
| davidr99 | 0:ab4e012489ef | 34 | //////////////////////////////////////////////////////////////////// |
| davidr99 | 0:ab4e012489ef | 35 | void RHReliableDatagram::setRetries(uint8_t retries) |
| davidr99 | 0:ab4e012489ef | 36 | { |
| davidr99 | 0:ab4e012489ef | 37 | _retries = retries; |
| davidr99 | 0:ab4e012489ef | 38 | } |
| davidr99 | 0:ab4e012489ef | 39 | |
| davidr99 | 0:ab4e012489ef | 40 | //////////////////////////////////////////////////////////////////// |
| davidr99 | 0:ab4e012489ef | 41 | uint8_t RHReliableDatagram::retries() |
| davidr99 | 0:ab4e012489ef | 42 | { |
| davidr99 | 0:ab4e012489ef | 43 | return _retries; |
| davidr99 | 0:ab4e012489ef | 44 | } |
| davidr99 | 0:ab4e012489ef | 45 | |
| davidr99 | 0:ab4e012489ef | 46 | //////////////////////////////////////////////////////////////////// |
| davidr99 | 0:ab4e012489ef | 47 | bool RHReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address) |
| davidr99 | 0:ab4e012489ef | 48 | { |
| davidr99 | 0:ab4e012489ef | 49 | // Assemble the message |
| davidr99 | 0:ab4e012489ef | 50 | uint8_t thisSequenceNumber = ++_lastSequenceNumber; |
| davidr99 | 0:ab4e012489ef | 51 | uint8_t retries = 0; |
| davidr99 | 0:ab4e012489ef | 52 | while (retries++ <= _retries) |
| davidr99 | 0:ab4e012489ef | 53 | { |
| davidr99 | 0:ab4e012489ef | 54 | setHeaderId(thisSequenceNumber); |
| davidr99 | 0:ab4e012489ef | 55 | setHeaderFlags(RH_FLAGS_NONE, RH_FLAGS_ACK); // Clear the ACK flag |
| davidr99 | 0:ab4e012489ef | 56 | sendto(buf, len, address); |
| davidr99 | 0:ab4e012489ef | 57 | waitPacketSent(); |
| davidr99 | 0:ab4e012489ef | 58 | |
| davidr99 | 0:ab4e012489ef | 59 | // Never wait for ACKS to broadcasts: |
| davidr99 | 0:ab4e012489ef | 60 | if (address == RH_BROADCAST_ADDRESS) |
| davidr99 | 0:ab4e012489ef | 61 | return true; |
| davidr99 | 0:ab4e012489ef | 62 | |
| davidr99 | 0:ab4e012489ef | 63 | if (retries > 1) |
| davidr99 | 0:ab4e012489ef | 64 | _retransmissions++; |
| davidr99 | 0:ab4e012489ef | 65 | unsigned long thisSendTime = millis(); // Timeout does not include original transmit time |
| davidr99 | 0:ab4e012489ef | 66 | |
| davidr99 | 0:ab4e012489ef | 67 | // Compute a new timeout, random between _timeout and _timeout*2 |
| davidr99 | 0:ab4e012489ef | 68 | // This is to prevent collisions on every retransmit |
| davidr99 | 0:ab4e012489ef | 69 | // if 2 nodes try to transmit at the same time |
| davidr99 | 0:ab4e012489ef | 70 | #if (RH_PLATFORM == RH_PLATFORM_RASPI) // use standard library random(), bugs in random(min, max) |
| davidr99 | 0:ab4e012489ef | 71 | uint16_t timeout = _timeout + (_timeout * (random() & 0xFF) / 256); |
| davidr99 | 0:ab4e012489ef | 72 | #elif (RH_PLATFORM == RH_PLATFORM_MBED) |
| davidr99 | 0:ab4e012489ef | 73 | uint16_t timeout = _timeout + (_timeout * (rand() & 0xFF) / 256); |
| davidr99 | 0:ab4e012489ef | 74 | #else |
| davidr99 | 0:ab4e012489ef | 75 | uint16_t timeout = _timeout + (_timeout * random(0, 256) / 256); |
| davidr99 | 0:ab4e012489ef | 76 | #endif |
| davidr99 | 0:ab4e012489ef | 77 | int32_t timeLeft; |
| davidr99 | 0:ab4e012489ef | 78 | while ((timeLeft = timeout - (millis() - thisSendTime)) > 0) |
| davidr99 | 0:ab4e012489ef | 79 | { |
| davidr99 | 0:ab4e012489ef | 80 | if (waitAvailableTimeout(timeLeft)) |
| davidr99 | 0:ab4e012489ef | 81 | { |
| davidr99 | 0:ab4e012489ef | 82 | uint8_t from, to, id, flags; |
| davidr99 | 0:ab4e012489ef | 83 | if (recvfrom(0, 0, &from, &to, &id, &flags)) // Discards the message |
| davidr99 | 0:ab4e012489ef | 84 | { |
| davidr99 | 0:ab4e012489ef | 85 | // Now have a message: is it our ACK? |
| davidr99 | 0:ab4e012489ef | 86 | if ( from == address |
| davidr99 | 0:ab4e012489ef | 87 | && to == _thisAddress |
| davidr99 | 0:ab4e012489ef | 88 | && (flags & RH_FLAGS_ACK) |
| davidr99 | 0:ab4e012489ef | 89 | && (id == thisSequenceNumber)) |
| davidr99 | 0:ab4e012489ef | 90 | { |
| davidr99 | 0:ab4e012489ef | 91 | // Its the ACK we are waiting for |
| davidr99 | 0:ab4e012489ef | 92 | return true; |
| davidr99 | 0:ab4e012489ef | 93 | } |
| davidr99 | 0:ab4e012489ef | 94 | else if ( !(flags & RH_FLAGS_ACK) |
| davidr99 | 0:ab4e012489ef | 95 | && (id == _seenIds[from])) |
| davidr99 | 0:ab4e012489ef | 96 | { |
| davidr99 | 0:ab4e012489ef | 97 | // This is a request we have already received. ACK it again |
| davidr99 | 0:ab4e012489ef | 98 | acknowledge(id, from); |
| davidr99 | 0:ab4e012489ef | 99 | } |
| davidr99 | 0:ab4e012489ef | 100 | // Else discard it |
| davidr99 | 0:ab4e012489ef | 101 | } |
| davidr99 | 0:ab4e012489ef | 102 | } |
| davidr99 | 0:ab4e012489ef | 103 | // Not the one we are waiting for, maybe keep waiting until timeout exhausted |
| davidr99 | 0:ab4e012489ef | 104 | YIELD; |
| davidr99 | 0:ab4e012489ef | 105 | } |
| davidr99 | 0:ab4e012489ef | 106 | // Timeout exhausted, maybe retry |
| davidr99 | 0:ab4e012489ef | 107 | YIELD; |
| davidr99 | 0:ab4e012489ef | 108 | } |
| davidr99 | 0:ab4e012489ef | 109 | // Retries exhausted |
| davidr99 | 0:ab4e012489ef | 110 | return false; |
| davidr99 | 0:ab4e012489ef | 111 | } |
| davidr99 | 0:ab4e012489ef | 112 | |
| davidr99 | 0:ab4e012489ef | 113 | //////////////////////////////////////////////////////////////////// |
| davidr99 | 0:ab4e012489ef | 114 | bool RHReliableDatagram::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) |
| davidr99 | 0:ab4e012489ef | 115 | { |
| davidr99 | 0:ab4e012489ef | 116 | uint8_t _from; |
| davidr99 | 0:ab4e012489ef | 117 | uint8_t _to; |
| davidr99 | 0:ab4e012489ef | 118 | uint8_t _id; |
| davidr99 | 0:ab4e012489ef | 119 | uint8_t _flags; |
| davidr99 | 0:ab4e012489ef | 120 | // Get the message before its clobbered by the ACK (shared rx and tx buffer in some drivers |
| davidr99 | 0:ab4e012489ef | 121 | if (available() && recvfrom(buf, len, &_from, &_to, &_id, &_flags)) |
| davidr99 | 0:ab4e012489ef | 122 | { |
| davidr99 | 0:ab4e012489ef | 123 | // Never ACK an ACK |
| davidr99 | 0:ab4e012489ef | 124 | if (!(_flags & RH_FLAGS_ACK)) |
| davidr99 | 0:ab4e012489ef | 125 | { |
| davidr99 | 0:ab4e012489ef | 126 | // Its a normal message for this node, not an ACK |
| davidr99 | 0:ab4e012489ef | 127 | if (_to != RH_BROADCAST_ADDRESS) |
| davidr99 | 0:ab4e012489ef | 128 | { |
| davidr99 | 0:ab4e012489ef | 129 | // Its not a broadcast, so ACK it |
| davidr99 | 0:ab4e012489ef | 130 | // Acknowledge message with ACK set in flags and ID set to received ID |
| davidr99 | 0:ab4e012489ef | 131 | acknowledge(_id, _from); |
| davidr99 | 0:ab4e012489ef | 132 | } |
| davidr99 | 0:ab4e012489ef | 133 | // If we have not seen this message before, then we are interested in it |
| davidr99 | 0:ab4e012489ef | 134 | if (_id != _seenIds[_from]) |
| davidr99 | 0:ab4e012489ef | 135 | { |
| davidr99 | 0:ab4e012489ef | 136 | if (from) *from = _from; |
| davidr99 | 0:ab4e012489ef | 137 | if (to) *to = _to; |
| davidr99 | 0:ab4e012489ef | 138 | if (id) *id = _id; |
| davidr99 | 0:ab4e012489ef | 139 | if (flags) *flags = _flags; |
| davidr99 | 0:ab4e012489ef | 140 | _seenIds[_from] = _id; |
| davidr99 | 0:ab4e012489ef | 141 | return true; |
| davidr99 | 0:ab4e012489ef | 142 | } |
| davidr99 | 0:ab4e012489ef | 143 | // Else just re-ack it and wait for a new one |
| davidr99 | 0:ab4e012489ef | 144 | } |
| davidr99 | 0:ab4e012489ef | 145 | } |
| davidr99 | 0:ab4e012489ef | 146 | // No message for us available |
| davidr99 | 0:ab4e012489ef | 147 | return false; |
| davidr99 | 0:ab4e012489ef | 148 | } |
| davidr99 | 0:ab4e012489ef | 149 | |
| davidr99 | 0:ab4e012489ef | 150 | bool RHReliableDatagram::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) |
| davidr99 | 0:ab4e012489ef | 151 | { |
| davidr99 | 0:ab4e012489ef | 152 | unsigned long starttime = millis(); |
| davidr99 | 0:ab4e012489ef | 153 | int32_t timeLeft; |
| davidr99 | 0:ab4e012489ef | 154 | while ((timeLeft = timeout - (millis() - starttime)) > 0) |
| davidr99 | 0:ab4e012489ef | 155 | { |
| davidr99 | 0:ab4e012489ef | 156 | if (waitAvailableTimeout(timeLeft)) |
| davidr99 | 0:ab4e012489ef | 157 | { |
| davidr99 | 0:ab4e012489ef | 158 | if (recvfromAck(buf, len, from, to, id, flags)) |
| davidr99 | 0:ab4e012489ef | 159 | return true; |
| davidr99 | 0:ab4e012489ef | 160 | } |
| davidr99 | 0:ab4e012489ef | 161 | YIELD; |
| davidr99 | 0:ab4e012489ef | 162 | } |
| davidr99 | 0:ab4e012489ef | 163 | return false; |
| davidr99 | 0:ab4e012489ef | 164 | } |
| davidr99 | 0:ab4e012489ef | 165 | |
| davidr99 | 0:ab4e012489ef | 166 | uint32_t RHReliableDatagram::retransmissions() |
| davidr99 | 0:ab4e012489ef | 167 | { |
| davidr99 | 0:ab4e012489ef | 168 | return _retransmissions; |
| davidr99 | 0:ab4e012489ef | 169 | } |
| davidr99 | 0:ab4e012489ef | 170 | |
| davidr99 | 0:ab4e012489ef | 171 | void RHReliableDatagram::resetRetransmissions() |
| davidr99 | 0:ab4e012489ef | 172 | { |
| davidr99 | 0:ab4e012489ef | 173 | _retransmissions = 0; |
| davidr99 | 0:ab4e012489ef | 174 | } |
| davidr99 | 0:ab4e012489ef | 175 | |
| davidr99 | 0:ab4e012489ef | 176 | void RHReliableDatagram::acknowledge(uint8_t id, uint8_t from) |
| davidr99 | 0:ab4e012489ef | 177 | { |
| davidr99 | 0:ab4e012489ef | 178 | setHeaderId(id); |
| davidr99 | 0:ab4e012489ef | 179 | setHeaderFlags(RH_FLAGS_ACK); |
| davidr99 | 0:ab4e012489ef | 180 | // We would prefer to send a zero length ACK, |
| davidr99 | 0:ab4e012489ef | 181 | // but if an RH_RF22 receives a 0 length message with a CRC error, it will never receive |
| davidr99 | 0:ab4e012489ef | 182 | // a 0 length message again, until its reset, which makes everything hang :-( |
| davidr99 | 0:ab4e012489ef | 183 | // So we send an ACK of 1 octet |
| davidr99 | 0:ab4e012489ef | 184 | // REVISIT: should we send the RSSI for the information of the sender? |
| davidr99 | 0:ab4e012489ef | 185 | uint8_t ack = '!'; |
| davidr99 | 0:ab4e012489ef | 186 | sendto(&ack, sizeof(ack), from); |
| davidr99 | 0:ab4e012489ef | 187 | waitPacketSent(); |
| davidr99 | 0:ab4e012489ef | 188 | } |
| davidr99 | 0:ab4e012489ef | 189 |
