-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRHReliableDatagram.cpp
More file actions
255 lines (225 loc) · 7.64 KB
/
Copy pathRHReliableDatagram.cpp
File metadata and controls
255 lines (225 loc) · 7.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// RHReliableDatagram.cpp
//
// Define addressed datagram
//
// Part of the Arduino RH library for operating with HopeRF RH compatible transceivers
// (see http://www.hoperf.com)
// RHDatagram will be received only by the addressed node or all nodes within range if the
// to address is RH_BROADCAST_ADDRESS
//
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2011 Mike McCauley
// $Id: RHReliableDatagram.cpp,v 1.18 2018/11/08 02:31:43 mikem Exp $
#include <RHReliableDatagram.h>
////////////////////////////////////////////////////////////////////
// Constructors
RHReliableDatagram::RHReliableDatagram(RHGenericDriver &driver, uint8_t thisAddress)
: RHDatagram(driver, thisAddress)
{
_retransmissions = 0;
_lastSequenceNumber = 0;
_timeout = RH_DEFAULT_TIMEOUT;
_retries = RH_DEFAULT_RETRIES;
memset(_seenIds, 0, sizeof(_seenIds));
}
////////////////////////////////////////////////////////////////////
// Public methods
void RHReliableDatagram::setTimeout(uint16_t timeout)
{
_timeout = timeout;
}
////////////////////////////////////////////////////////////////////
void RHReliableDatagram::setRetries(uint8_t retries)
{
_retries = retries;
}
////////////////////////////////////////////////////////////////////
uint8_t RHReliableDatagram::retries()
{
return _retries;
}
////////////////////////////////////////////////////////////////////
bool RHReliableDatagram::sendtoWait(uint8_t *buf, uint8_t len, uint8_t address, uint8_t flagsToSend)
{
// 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 || flagsToSend;
// 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();
//TOMAS
//Nunca esperar un ACK de broadcasts enviados por Access Points. Solo esperar ACKs de broadcasts si se trata de moviles
if (address == RH_BROADCAST_ADDRESS && !(flagsToSend & RH_FLAG_MOVIL))
{
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
{
//TOMAS
//Agrego " flags || RH_FLAG_MOVIL" en la primera clasusula
//Esto significa que o estamos recibiendo un ACK comun o bien estamos recibiendo un ACK de un Access Point de un broadcast que mandamos desde un movil
if ((from == address || flagsToSend & RH_FLAG_MOVIL) && to == _thisAddress && (flags & RH_FLAGS_ACK) && (id == thisSequenceNumber))
// 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;
}
////////////////////////////////////////////////////////////////////
bool RHReliableDatagram::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 (overwritten) by the ACK (shared rx and tx buffer in some drivers
if (available() && recvfrom(buf, len, &_from, &_to, &_id, &_flags))
{
// Never ACK an ACK
if (!(_flags & RH_FLAGS_ACK))
{
// Its a normal message not an ACK
if (_to == _thisAddress)
{
Serial.println(F("En RHReliableDatagram el paquete recibido es: "));
Serial.println((char[60])buf);
// Its for this node and
// Its not a broadcast, so ACK it
// Acknowledge message with ACK set in flags and ID set to received ID
acknowledge(_id, _from);
}
//TOMAS
//Si el mensaje fue enviado por un movil (tiene el flag movil), devolver un ACK
//La segunda clausula es para testing
if ((_flags & RH_FLAG_MOVIL) && _thisAddress != GATEWAY_ADDRESS)
{
Serial.println(F("En RHReliableDatagram el paquete es: "));
Serial.println((char[60])buf);
Serial.print(F("Recibi un mensaje de broadcast del movil "));
Serial.print(_from);
Serial.println(F(". Ahora le envío un ACK"));
// RHGenericDriver RHgd;
// RH_RF95 holanda = new RHGenericDriver();
// RHGenericDriver::lastRssi;
// int16_t rssi = holanda->lastRssi();
Serial.print(F("El ultimo RSSI es: "));
Serial.println(_driver.lastRssi());
int espera = _driver.lastRssi() * -10;
Serial.print(F("La espera sera: "));
Serial.println(espera);
//funcion de delay de espera
acknowledge(_id, _from);
}
// Filter out retried messages that we have seen before. This explicitly
// only filters out messages that are marked as retries to protect against
// the scenario where a transmitting device sends just one message and
// shuts down between transmissions. Devices that do this will report the
// the same ID each time since their internal sequence number will reset
// to zero each time the device starts up.
if ((RH_ENABLE_EXPLICIT_RETRY_DEDUP && !(_flags & RH_FLAGS_RETRY)) || _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;
}
bool RHReliableDatagram::recvfromAckTimeout(uint8_t *buf, uint8_t *len, uint16_t timeout, uint8_t *from, uint8_t *to, uint8_t *id, uint8_t *flags)
{
unsigned long starttime = millis();
int32_t timeLeft;
while ((timeLeft = timeout - (millis() - starttime)) > 0)
{
if (waitAvailableTimeout(timeLeft))
{
if (recvfromAck(buf, len, from, to, id, flags))
return true;
}
YIELD;
}
return false;
}
uint32_t RHReliableDatagram::retransmissions()
{
return _retransmissions;
}
void RHReliableDatagram::resetRetransmissions()
{
_retransmissions = 0;
}
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();
}