bool sendtoWait(uint8_t* buf, uint8_t len, uint8_t address) { // Assemble the message uint8_t thisSequenceNumber = ++_lastSequenceNumber; uint8_t retries = 0; while (retries++ <= _retries) { setHeaderId(thisSequenceNumber); // setHeaderFlags(RH_FLAGS_NONE, RH_FLAGS_ACK); // Clear the ACK flag setHeaderFlags(RH_FLAGS_NONE); // Clear the ACK flag sendto(buf, len, address); waitPacketSent(); // Never wait for ACKS to broadcasts: if (address == RH_BROADCAST_ADDRESS) return true; if (retries > 1) _retransmissions++; unsigned long thisSendTime = millis(); // Timeout does not include original transmit time // Compute a new timeout, random between _timeout and _timeout*2 // This is to prevent collisions on every retransmit // if 2 nodes try to transmit at the same time uint16_t timeout = _timeout + (_timeout * random(0, 256) / 256); int32_t timeLeft; while ((timeLeft = timeout - (millis() - thisSendTime)) > 0) { if (waitAvailableTimeout(timeLeft)) { uint8_t from, to, id, flags; if (recvfrom(0, 0, &from, &to, &id, &flags)) // Discards the message { // Now have a message: is it our ACK? if (from == address && to == _thisAddress && (flags & RH_FLAGS_ACK) && (id == thisSequenceNumber)) { // Its the ACK we are waiting for return true; } else if (!(flags & RH_FLAGS_ACK) && (id == _seenIds[from])) { // This is a request we have already received. ACK it again acknowledge(id, from); } // Else discard it } } // Not the one we are waiting for, maybe keep waiting until timeout exhausted YIELD; } // Timeout exhausted, maybe retry YIELD; } // Retries exhausted return false; }
bool recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) { unsigned long starttime = millis(); int32_t timeLeft; while ((timeLeft = timeout - (millis() - starttime)) > 0) { if (waitAvailableTimeout(timeLeft)) { if (recvfromAck(buf, len, from, to, id, flags)) return true; } YIELD; } return false; }
// Block until something is available void HardwareSerial::waitAvailable() { waitAvailableTimeout(0); // 0 = Wait forever }
bool RHReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address) { // Assemble the message uint8_t thisSequenceNumber = ++_lastSequenceNumber; uint8_t retries = 0; while (retries++ <= _retries) { setHeaderId(thisSequenceNumber); // Set and clear header flags depending on if this is an // initial send or a retry. uint8_t headerFlagsToSet = RH_FLAGS_NONE; // Always clear the ACK flag uint8_t headerFlagsToClear = RH_FLAGS_ACK; if (retries == 1) { // On an initial send, clear the RETRY flag in case // it was previously set headerFlagsToClear |= RH_FLAGS_RETRY; } else { // Not an initial send, set the RETRY flag headerFlagsToSet = RH_FLAGS_RETRY; } setHeaderFlags(headerFlagsToSet, headerFlagsToClear); sendto(buf, len, address); waitPacketSent(); // Never wait for ACKS to broadcasts: if (address == RH_BROADCAST_ADDRESS) return true; if (retries > 1) _retransmissions++; unsigned long thisSendTime = millis(); // Timeout does not include original transmit time // Compute a new timeout, random between _timeout and _timeout*2 // This is to prevent collisions on every retransmit // if 2 nodes try to transmit at the same time #if (RH_PLATFORM == RH_PLATFORM_RASPI) // use standard library random(), bugs in random(min, max) uint16_t timeout = _timeout + (_timeout * (random() & 0xFF) / 256); #else uint16_t timeout = _timeout + (_timeout * random(0, 256) / 256); #endif int32_t timeLeft; while ((timeLeft = timeout - (millis() - thisSendTime)) > 0) { if (waitAvailableTimeout(timeLeft)) { uint8_t from, to, id, flags; if (recvfrom(0, 0, &from, &to, &id, &flags)) // Discards the message { // Now have a message: is it our ACK? if ( from == address && to == _thisAddress && (flags & RH_FLAGS_ACK) && (id == thisSequenceNumber)) { // Its the ACK we are waiting for return true; } else if ( !(flags & RH_FLAGS_ACK) && (id == _seenIds[from])) { // This is a request we have already received. ACK it again acknowledge(id, from); } // Else discard it } } // Not the one we are waiting for, maybe keep waiting until timeout exhausted YIELD; } // Timeout exhausted, maybe retry YIELD; } // Retries exhausted return false; }
// Block until something is available void RH_TCP::waitAvailable() { waitAvailableTimeout(0); // 0 = Wait forever }