User | Revision | Line number | New 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
|
|