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 Karl Zweimüller

Committer:
charly
Date:
Fri Feb 17 21:40:57 2012 +0000
Revision:
1:813d4f57d630
Parent:
0:79c6d0071c4c
Child:
5:0386600f3408
fixed use of rand() in ReliableDatagram

Who changed what in which revision?

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