Library for HopeRF RFM22 transceiver module ported to mbed. Original Software from Mike McCauley (mikem@open.com.au) . See http://www.open.com.au/mikem/arduino/RF22/
Fork of RF22 by
Diff: RF22ReliableDatagram.cpp
- Revision:
- 1:813d4f57d630
- Parent:
- 0:79c6d0071c4c
- Child:
- 5:0386600f3408
--- a/RF22ReliableDatagram.cpp Tue Feb 14 19:39:36 2012 +0000 +++ b/RF22ReliableDatagram.cpp Fri Feb 17 21:40:57 2012 +0000 @@ -1,10 +1,10 @@ // RF22ReliableDatagram.cpp // // Define addressed datagram -// -// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers +// +// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers // (see http://www.hoperf.com) -// RF22Datagram will be received only by the addressed node or all nodes within range if the +// RF22Datagram will be received only by the addressed node or all nodes within range if the // to address is RF22_BROADCAST_ADDRESS // // Author: Mike McCauley (mikem@open.com.au) @@ -18,9 +18,8 @@ //////////////////////////////////////////////////////////////////// // Constructors -RF22ReliableDatagram::RF22ReliableDatagram(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt ) - : RF22Datagram(thisAddress ,slaveSelectPin , mosi, miso, sclk, interrupt ) -{ +RF22ReliableDatagram::RF22ReliableDatagram(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt ) + : RF22Datagram(thisAddress ,slaveSelectPin , mosi, miso, sclk, interrupt ) { _retransmissions = 0; _lastSequenceNumber = 0; _timeout = 200; @@ -29,134 +28,117 @@ //////////////////////////////////////////////////////////////////// // Public methods -void RF22ReliableDatagram::setTimeout(uint16_t timeout) -{ +void RF22ReliableDatagram::setTimeout(uint16_t timeout) { _timeout = timeout; } //////////////////////////////////////////////////////////////////// -void RF22ReliableDatagram::setRetries(uint8_t retries) -{ +void RF22ReliableDatagram::setRetries(uint8_t retries) { _retries = retries; } //////////////////////////////////////////////////////////////////// -boolean RF22ReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address) -{ +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(); + while (retries++ <= _retries) { + setHeaderId(thisSequenceNumber); + setHeaderFlags(0); + sendto(buf, len, address); + waitPacketSent(); - // Never wait for ACKS to broadcasts: - if (address == RF22_BROADCAST_ADDRESS) - return true; + // 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 + 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 collissions on every retransmit - // if 2 nodes try to transmit at the same time - uint16_t timeout = _timeout + (_timeout * rand()); - 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; + // Compute a new timeout, random between _timeout and _timeout*2 + // This is to prevent collissions 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 } - 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 + // Timeout exhausted, maybe retry } return false; } //////////////////////////////////////////////////////////////////// -boolean RF22ReliableDatagram::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) -{ +boolean RF22ReliableDatagram::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) { uint8_t _from; uint8_t _to; uint8_t _id; uint8_t _flags; // Get the message before its clobbered by the ACK (shared rx anfd tx buffer in RF22 - if (available() && recvfrom(buf, len, &_from, &_to, &_id, &_flags)) - { - // Never ACK an ACK - if (!(_flags & RF22_FLAGS_ACK)) - { - // Its a normal message for this node, not an ACK - if (_to != RF22_BROADCAST_ADDRESS) - { - // Its not a broadcast, so ACK it - // Acknowledge message with ACK set in flags and ID set to received ID - acknowledge(_id, _from); + if (available() && recvfrom(buf, len, &_from, &_to, &_id, &_flags)) { + // Never ACK an ACK + if (!(_flags & RF22_FLAGS_ACK)) { + // Its a normal message for this node, not an ACK + if (_to != RF22_BROADCAST_ADDRESS) { + // Its not a broadcast, so ACK it + // Acknowledge message with ACK set in flags and ID set to received ID + acknowledge(_id, _from); + } + // If we have not seen this message before, then we are interested in it + if (_id != _seenIds[_from]) { + if (from) *from = _from; + if (to) *to = _to; + if (id) *id = _id; + if (flags) *flags = _flags; + _seenIds[_from] = _id; + return true; + } + // Else just re-ack it and wait for a new one } - // If we have not seen this message before, then we are interested in it - if (_id != _seenIds[_from]) - { - if (from) *from = _from; - if (to) *to = _to; - if (id) *id = _id; - if (flags) *flags = _flags; - _seenIds[_from] = _id; - return true; - } - // Else just re-ack it and wait for a new one - } } // No message for us available return false; } -boolean RF22ReliableDatagram::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) -{ +boolean RF22ReliableDatagram::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) { Timer t; unsigned long endtime = t.read_ms() + timeout; while (t.read_ms() < endtime) - if (recvfromAck(buf, len, from, to, id, flags)) - return true; + if (recvfromAck(buf, len, from, to, id, flags)) + return true; return false; } -uint16_t RF22ReliableDatagram::retransmissions() -{ +uint16_t RF22ReliableDatagram::retransmissions() { return _retransmissions; } -void RF22ReliableDatagram::acknowledge(uint8_t id, uint8_t from) -{ +void RF22ReliableDatagram::acknowledge(uint8_t id, uint8_t from) { setHeaderId(id); setHeaderFlags(RF22_FLAGS_ACK); // We would prefer to send a zero length ACK, @@ -165,7 +147,7 @@ // 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); + sendto(&ack, sizeof(ack), from); waitPacketSent(); }