V148

Fork of RadioHead-148 by David Rimer

Committer:
ilkaykozak
Date:
Wed Oct 25 05:14:09 2017 +0000
Revision:
1:b7641da2b203
Parent:
0:ab4e012489ef
V148

Who changed what in which revision?

UserRevisionLine numberNew 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