bool RH_RF24::send(const uint8_t* data, uint8_t len) { if (len > RH_RF24_MAX_MESSAGE_LEN) return false; waitPacketSent(); // Make sure we dont interrupt an outgoing message setModeIdle(); // Prevent RX while filling the fifo // Put the payload in the FIFO // First the length in fixed length field 1. This wont appear in the receiver fifo since // we have turned off IN_FIFO in PKT_LEN _buf[0] = len + RH_RF24_HEADER_LEN; // Now the rest of the payload in variable length field 2 // First the headers _buf[1] = _txHeaderTo; _buf[2] = _txHeaderFrom; _buf[3] = _txHeaderId; _buf[4] = _txHeaderFlags; // Then the message memcpy(_buf + 1 + RH_RF24_HEADER_LEN, data, len); _bufLen = len + 1 + RH_RF24_HEADER_LEN; _txBufSentIndex = 0; // Set the field 2 length to the variable payload length uint8_t l[] = { (uint8_t)(len + RH_RF24_HEADER_LEN)}; set_properties(RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_7_0, l, sizeof(l)); sendNextFragment(); setModeTx(); return true; }
bool RH_RF95::send(const uint8_t* data, uint8_t len) { if (len > RH_RF95_MAX_MESSAGE_LEN) return false; waitPacketSent(); // Make sure we dont interrupt an outgoing message setModeIdle(); if (!waitCAD()) return false; // Check channel activity // Position at the beginning of the FIFO spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, 0); // The headers spiWrite(RH_RF95_REG_00_FIFO, _txHeaderTo); spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFrom); spiWrite(RH_RF95_REG_00_FIFO, _txHeaderId); spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFlags); // The message data spiBurstWrite(RH_RF95_REG_00_FIFO, data, len); spiWrite(RH_RF95_REG_22_PAYLOAD_LENGTH, len + RH_RF95_HEADER_LEN); setModeTx(); // Start the transmitter // when Tx is done, interruptHandler will fire and radio mode will return to STANDBY return true; }
boolean RF22ReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address) { // Assemble the message uint8_t thisSequenceNumber = ++_lastSequenceNumber; Timer t; uint8_t retries = 0; while (retries++ <= _retries) { setHeaderId(thisSequenceNumber); setHeaderFlags(0); sendto(buf, len, address); waitPacketSent(3000); // Never wait for ACKS to broadcasts: if (address == RF22_BROADCAST_ADDRESS) return true; if (retries > 1) _retransmissions++; t.start(); unsigned long thisSendTime = t.read_ms(); // 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 * (rand() % 100) / 100); while (t.read_ms() < (thisSendTime + timeout)) { if (available()) { clearRxBuf(); // Not using recv, so clear it ourselves uint8_t from = headerFrom(); uint8_t to = headerTo(); uint8_t id = headerId(); uint8_t flags = headerFlags(); // Now have a message: is it our ACK? if ( from == address && to == _thisAddress && (flags & RF22_FLAGS_ACK) && (id == thisSequenceNumber)) { // Its the ACK we are waiting for return true; } else if ( !(flags & RF22_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 } // Timeout exhausted, maybe retry } return false; }
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); setHeaderFlags(0); 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); while ((millis() - thisSendTime) < timeout) { if (available()) { 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; } return false; }
uint8_t RF22::send(const uint8_t* data, uint8_t len) { waitPacketSent(); if (!fillTxBuf(data, len)) return false; startTransmit(); return true; }
bool RF22::send(const uint8_t* data, uint8_t len) { waitPacketSent(); //TODO check piLock(1); if (!fillTxBuf(data, len)) return false; startTransmit(); piUnlock(1); // printBuffer("send:", data, len); return true; }
void RHReliableDatagram::acknowledge(uint8_t id, uint8_t from) { setHeaderId(id); setHeaderFlags(RH_FLAGS_ACK); // We would prefer to send a zero length ACK, // but if an RH_RF22 receives a 0 length message with a CRC error, it will never receive // a 0 length message again, until its reset, which makes everything hang :-( // So we send an ACK of 1 octet // REVISIT: should we send the RSSI for the information of the sender? uint8_t ack = '!'; sendto(&ack, sizeof(ack), from); waitPacketSent(); }
bool RH_RF22::send(const uint8_t* data, uint8_t len) { bool ret = true; waitPacketSent(); ATOMIC_BLOCK_START; if (!fillTxBuf(data, len)) ret = false; else startTransmit(); ATOMIC_BLOCK_END; // printBuffer("send:", data, len); return ret; }
bool RH_RF22::send(const uint8_t* data, uint8_t len) { bool ret = true; waitPacketSent(); ATOMIC_BLOCK_START; spiWrite(RH_RF22_REG_3A_TRANSMIT_HEADER3, _txHeaderTo); spiWrite(RH_RF22_REG_3B_TRANSMIT_HEADER2, _txHeaderFrom); spiWrite(RH_RF22_REG_3C_TRANSMIT_HEADER1, _txHeaderId); spiWrite(RH_RF22_REG_3D_TRANSMIT_HEADER0, _txHeaderFlags); if (!fillTxBuf(data, len)) ret = false; else startTransmit(); ATOMIC_BLOCK_END; // printBuffer("send:", data, len); return ret; }
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; }