Dependents:   New

Committer:
SangSTBK
Date:
Mon Jul 02 01:29:58 2012 +0000
Revision:
0:e16ffa7cb900
RF

Who changed what in which revision?

UserRevisionLine numberNew contents of line
SangSTBK 0:e16ffa7cb900 1 // RF22ReliableDatagram.cpp
SangSTBK 0:e16ffa7cb900 2 //
SangSTBK 0:e16ffa7cb900 3 // Define addressed datagram
SangSTBK 0:e16ffa7cb900 4 //
SangSTBK 0:e16ffa7cb900 5 // Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers
SangSTBK 0:e16ffa7cb900 6 // (see http://www.hoperf.com)
SangSTBK 0:e16ffa7cb900 7 // RF22Datagram will be received only by the addressed node or all nodes within range if the
SangSTBK 0:e16ffa7cb900 8 // to address is RF22_BROADCAST_ADDRESS
SangSTBK 0:e16ffa7cb900 9 //
SangSTBK 0:e16ffa7cb900 10 // Author: Mike McCauley (mikem@open.com.au)
SangSTBK 0:e16ffa7cb900 11 // Copyright (C) 2011 Mike McCauley
SangSTBK 0:e16ffa7cb900 12 // $Id: RF22ReliableDatagram.cpp,v 1.8 2011/02/15 01:18:03 mikem Exp $
SangSTBK 0:e16ffa7cb900 13 // ported to mbed by Karl Zweimueller
SangSTBK 0:e16ffa7cb900 14
SangSTBK 0:e16ffa7cb900 15 #include <RF22ReliableDatagram.h>
SangSTBK 0:e16ffa7cb900 16 //#include <SPI.h>
SangSTBK 0:e16ffa7cb900 17
SangSTBK 0:e16ffa7cb900 18
SangSTBK 0:e16ffa7cb900 19 ////////////////////////////////////////////////////////////////////
SangSTBK 0:e16ffa7cb900 20 // Constructors
SangSTBK 0:e16ffa7cb900 21 RF22ReliableDatagram::RF22ReliableDatagram(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt )
SangSTBK 0:e16ffa7cb900 22 : RF22Datagram(thisAddress ,slaveSelectPin , mosi, miso, sclk, interrupt ) {
SangSTBK 0:e16ffa7cb900 23 _retransmissions = 0;
SangSTBK 0:e16ffa7cb900 24 _lastSequenceNumber = 0;
SangSTBK 0:e16ffa7cb900 25 _timeout = 200;
SangSTBK 0:e16ffa7cb900 26 _retries = 3;
SangSTBK 0:e16ffa7cb900 27 }
SangSTBK 0:e16ffa7cb900 28
SangSTBK 0:e16ffa7cb900 29 ////////////////////////////////////////////////////////////////////
SangSTBK 0:e16ffa7cb900 30 // Public methods
SangSTBK 0:e16ffa7cb900 31 void RF22ReliableDatagram::setTimeout(uint16_t timeout) {
SangSTBK 0:e16ffa7cb900 32 _timeout = timeout;
SangSTBK 0:e16ffa7cb900 33 }
SangSTBK 0:e16ffa7cb900 34
SangSTBK 0:e16ffa7cb900 35 ////////////////////////////////////////////////////////////////////
SangSTBK 0:e16ffa7cb900 36 void RF22ReliableDatagram::setRetries(uint8_t retries) {
SangSTBK 0:e16ffa7cb900 37 _retries = retries;
SangSTBK 0:e16ffa7cb900 38 }
SangSTBK 0:e16ffa7cb900 39
SangSTBK 0:e16ffa7cb900 40 ////////////////////////////////////////////////////////////////////
SangSTBK 0:e16ffa7cb900 41 boolean RF22ReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address) {
SangSTBK 0:e16ffa7cb900 42 // Assemble the message
SangSTBK 0:e16ffa7cb900 43 uint8_t thisSequenceNumber = ++_lastSequenceNumber;
SangSTBK 0:e16ffa7cb900 44
SangSTBK 0:e16ffa7cb900 45 Timer t;
SangSTBK 0:e16ffa7cb900 46
SangSTBK 0:e16ffa7cb900 47 uint8_t retries = 0;
SangSTBK 0:e16ffa7cb900 48 while (retries++ <= _retries) {
SangSTBK 0:e16ffa7cb900 49 setHeaderId(thisSequenceNumber);
SangSTBK 0:e16ffa7cb900 50 setHeaderFlags(0);
SangSTBK 0:e16ffa7cb900 51 sendto(buf, len, address);
SangSTBK 0:e16ffa7cb900 52 waitPacketSent();
SangSTBK 0:e16ffa7cb900 53
SangSTBK 0:e16ffa7cb900 54 // Never wait for ACKS to broadcasts:
SangSTBK 0:e16ffa7cb900 55 if (address == RF22_BROADCAST_ADDRESS)
SangSTBK 0:e16ffa7cb900 56 return true;
SangSTBK 0:e16ffa7cb900 57
SangSTBK 0:e16ffa7cb900 58 if (retries > 1)
SangSTBK 0:e16ffa7cb900 59 _retransmissions++;
SangSTBK 0:e16ffa7cb900 60 t.start();
SangSTBK 0:e16ffa7cb900 61 unsigned long thisSendTime = t.read_ms(); // Timeout does not include original transmit time
SangSTBK 0:e16ffa7cb900 62
SangSTBK 0:e16ffa7cb900 63
SangSTBK 0:e16ffa7cb900 64 // Compute a new timeout, random between _timeout and _timeout*2
SangSTBK 0:e16ffa7cb900 65 // This is to prevent collissions on every retransmit
SangSTBK 0:e16ffa7cb900 66 // if 2 nodes try to transmit at the same time
SangSTBK 0:e16ffa7cb900 67 uint16_t timeout = _timeout + (_timeout * (rand() % 100) / 100);
SangSTBK 0:e16ffa7cb900 68 while (t.read_ms() < (thisSendTime + timeout)) {
SangSTBK 0:e16ffa7cb900 69 if (available()) {
SangSTBK 0:e16ffa7cb900 70 clearRxBuf(); // Not using recv, so clear it ourselves
SangSTBK 0:e16ffa7cb900 71 uint8_t from = headerFrom();
SangSTBK 0:e16ffa7cb900 72 uint8_t to = headerTo();
SangSTBK 0:e16ffa7cb900 73 uint8_t id = headerId();
SangSTBK 0:e16ffa7cb900 74 uint8_t flags = headerFlags();
SangSTBK 0:e16ffa7cb900 75 // Now have a message: is it our ACK?
SangSTBK 0:e16ffa7cb900 76 if ( from == address
SangSTBK 0:e16ffa7cb900 77 && to == _thisAddress
SangSTBK 0:e16ffa7cb900 78 && (flags & RF22_FLAGS_ACK)
SangSTBK 0:e16ffa7cb900 79 && (id == thisSequenceNumber)) {
SangSTBK 0:e16ffa7cb900 80 // Its the ACK we are waiting for
SangSTBK 0:e16ffa7cb900 81 return true;
SangSTBK 0:e16ffa7cb900 82 } else if ( !(flags & RF22_FLAGS_ACK)
SangSTBK 0:e16ffa7cb900 83 && (id == _seenIds[from])) {
SangSTBK 0:e16ffa7cb900 84 // This is a request we have already received. ACK it again
SangSTBK 0:e16ffa7cb900 85 acknowledge(id, from);
SangSTBK 0:e16ffa7cb900 86 }
SangSTBK 0:e16ffa7cb900 87 // Else discard it
SangSTBK 0:e16ffa7cb900 88 }
SangSTBK 0:e16ffa7cb900 89 // Not the one we are waiting for, maybe keep waiting until timeout exhausted
SangSTBK 0:e16ffa7cb900 90 }
SangSTBK 0:e16ffa7cb900 91 // Timeout exhausted, maybe retry
SangSTBK 0:e16ffa7cb900 92 }
SangSTBK 0:e16ffa7cb900 93 return false;
SangSTBK 0:e16ffa7cb900 94 }
SangSTBK 0:e16ffa7cb900 95
SangSTBK 0:e16ffa7cb900 96 ////////////////////////////////////////////////////////////////////
SangSTBK 0:e16ffa7cb900 97 boolean RF22ReliableDatagram::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) {
SangSTBK 0:e16ffa7cb900 98 uint8_t _from;
SangSTBK 0:e16ffa7cb900 99 uint8_t _to;
SangSTBK 0:e16ffa7cb900 100 uint8_t _id;
SangSTBK 0:e16ffa7cb900 101 uint8_t _flags;
SangSTBK 0:e16ffa7cb900 102 // Get the message before its clobbered by the ACK (shared rx anfd tx buffer in RF22
SangSTBK 0:e16ffa7cb900 103 if (available() && recvfrom(buf, len, &_from, &_to, &_id, &_flags)) {
SangSTBK 0:e16ffa7cb900 104 // Never ACK an ACK
SangSTBK 0:e16ffa7cb900 105 if (!(_flags & RF22_FLAGS_ACK)) {
SangSTBK 0:e16ffa7cb900 106 // Its a normal message for this node, not an ACK
SangSTBK 0:e16ffa7cb900 107 if (_to != RF22_BROADCAST_ADDRESS) {
SangSTBK 0:e16ffa7cb900 108 // Its not a broadcast, so ACK it
SangSTBK 0:e16ffa7cb900 109 // Acknowledge message with ACK set in flags and ID set to received ID
SangSTBK 0:e16ffa7cb900 110 acknowledge(_id, _from);
SangSTBK 0:e16ffa7cb900 111 }
SangSTBK 0:e16ffa7cb900 112 // If we have not seen this message before, then we are interested in it
SangSTBK 0:e16ffa7cb900 113 if (_id != _seenIds[_from]) {
SangSTBK 0:e16ffa7cb900 114 if (from) *from = _from;
SangSTBK 0:e16ffa7cb900 115 if (to) *to = _to;
SangSTBK 0:e16ffa7cb900 116 if (id) *id = _id;
SangSTBK 0:e16ffa7cb900 117 if (flags) *flags = _flags;
SangSTBK 0:e16ffa7cb900 118 _seenIds[_from] = _id;
SangSTBK 0:e16ffa7cb900 119 return true;
SangSTBK 0:e16ffa7cb900 120 }
SangSTBK 0:e16ffa7cb900 121 // Else just re-ack it and wait for a new one
SangSTBK 0:e16ffa7cb900 122 }
SangSTBK 0:e16ffa7cb900 123 }
SangSTBK 0:e16ffa7cb900 124 // No message for us available
SangSTBK 0:e16ffa7cb900 125 return false;
SangSTBK 0:e16ffa7cb900 126 }
SangSTBK 0:e16ffa7cb900 127
SangSTBK 0:e16ffa7cb900 128 boolean RF22ReliableDatagram::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) {
SangSTBK 0:e16ffa7cb900 129 Timer t;
SangSTBK 0:e16ffa7cb900 130 unsigned long endtime = t.read_ms() + timeout;
SangSTBK 0:e16ffa7cb900 131 while (t.read_ms() < endtime)
SangSTBK 0:e16ffa7cb900 132 if (recvfromAck(buf, len, from, to, id, flags))
SangSTBK 0:e16ffa7cb900 133 return true;
SangSTBK 0:e16ffa7cb900 134 return false;
SangSTBK 0:e16ffa7cb900 135 }
SangSTBK 0:e16ffa7cb900 136
SangSTBK 0:e16ffa7cb900 137 uint16_t RF22ReliableDatagram::retransmissions() {
SangSTBK 0:e16ffa7cb900 138 return _retransmissions;
SangSTBK 0:e16ffa7cb900 139 }
SangSTBK 0:e16ffa7cb900 140
SangSTBK 0:e16ffa7cb900 141 void RF22ReliableDatagram::acknowledge(uint8_t id, uint8_t from) {
SangSTBK 0:e16ffa7cb900 142 setHeaderId(id);
SangSTBK 0:e16ffa7cb900 143 setHeaderFlags(RF22_FLAGS_ACK);
SangSTBK 0:e16ffa7cb900 144 // We would prefer to send a zero length ACK,
SangSTBK 0:e16ffa7cb900 145 // but if an RF22 receives a 0 length message with a CRC error, it will never receive
SangSTBK 0:e16ffa7cb900 146 // a 0 length message again, until its reset, which makes everything hang :-(
SangSTBK 0:e16ffa7cb900 147 // So we send an ACK of 1 octet
SangSTBK 0:e16ffa7cb900 148 // REVISIT: should we send the RSSI for the information of the sender?
SangSTBK 0:e16ffa7cb900 149 uint8_t ack = '!';
SangSTBK 0:e16ffa7cb900 150 sendto(&ack, sizeof(ack), from);
SangSTBK 0:e16ffa7cb900 151 waitPacketSent();
SangSTBK 0:e16ffa7cb900 152 }
SangSTBK 0:e16ffa7cb900 153