59 #define SEND_INTERVAL CLOCK_SECOND / 2
60 #define STEADY_INTERVAL CLOCK_SECOND * 16
61 #define RESEND_INTERVAL SEND_INTERVAL * 4
62 #define NACK_TIMEOUT CLOCK_SECOND / 4
66 uint8_t hops_from_base;
71 #define POLITE_HEADER 1
80 #define FLAG_LAST_SENT 0x01
81 #define FLAG_LAST_RECEIVED 0x02
82 #define FLAG_IS_STOPPED 0x04
87 #define PRINTF(...) printf(__VA_ARGS__)
92 #define LT(a, b) ((signed short)((a) - (b)) < 0)
96 read_data(
struct rudolph2_conn *c, uint8_t *dataptr,
int chunk)
100 if(c->cb->read_chunk) {
101 len = c->cb->read_chunk(c, chunk * RUDOLPH2_DATASIZE,
102 dataptr, RUDOLPH2_DATASIZE);
108 format_data(
struct rudolph2_conn *c,
int chunk)
110 struct rudolph2_hdr *hdr;
115 hdr->type = TYPE_DATA;
116 hdr->hops_from_base = c->hops_from_base;
117 hdr->version = c->version;
119 len = read_data(c, (uint8_t *)hdr +
sizeof(
struct rudolph2_hdr), chunk);
126 write_data(
struct rudolph2_conn *c,
int chunk, uint8_t *data,
int datalen)
129 if(c->flags & FLAG_IS_STOPPED) {
134 c->cb->write_chunk(c, 0, RUDOLPH2_FLAG_NEWFILE, data, 0);
137 PRINTF(
"%d.%d: get %d bytes\n",
142 if(datalen < RUDOLPH2_DATASIZE) {
143 PRINTF(
"%d.%d: get %d bytes, file complete\n",
146 c->cb->write_chunk(c, chunk * RUDOLPH2_DATASIZE,
147 RUDOLPH2_FLAG_LASTCHUNK, data, datalen);
149 c->cb->write_chunk(c, chunk * RUDOLPH2_DATASIZE,
150 RUDOLPH2_FLAG_NONE, data, datalen);
155 send_data(
struct rudolph2_conn *c, clock_time_t interval)
159 len = format_data(c, c->snd_nxt);
161 PRINTF(
"%d.%d: send_data chunk %d, rcv_nxt %d\n",
163 c->snd_nxt, c->rcv_nxt);
169 send_nack(
struct rudolph2_conn *c)
171 struct rudolph2_hdr *hdr;
176 hdr->hops_from_base = c->hops_from_base;
177 hdr->type = TYPE_NACK;
178 hdr->version = c->version;
179 hdr->chunk = c->rcv_nxt;
181 PRINTF(
"%d.%d: Sending nack for %d\n",
189 send_next(
struct rudolph2_conn *c)
192 clock_time_t interval;
194 if(c->flags & FLAG_LAST_SENT) {
195 interval = STEADY_INTERVAL;
197 interval = SEND_INTERVAL;
200 len = send_data(c, interval);
202 if(len < RUDOLPH2_DATASIZE) {
203 c->flags |= FLAG_LAST_SENT;
205 c->flags &= ~FLAG_LAST_SENT;
209 len == RUDOLPH2_DATASIZE &&
210 c->snd_nxt + 1 < c->rcv_nxt) {
248 timed_send(
void *ptr)
250 struct rudolph2_conn *c = (
struct rudolph2_conn *)ptr;
251 clock_time_t interval;
254 if((c->flags & FLAG_IS_STOPPED) == 0 &&
255 (c->flags & FLAG_LAST_RECEIVED)) {
263 if(c->flags & FLAG_LAST_SENT) {
264 interval = STEADY_INTERVAL;
266 interval = SEND_INTERVAL;
270 len = send_data(c, interval);
272 if(len < RUDOLPH2_DATASIZE) {
273 c->flags |= FLAG_LAST_SENT;
275 c->flags &= ~FLAG_LAST_SENT;
279 len == RUDOLPH2_DATASIZE &&
280 c->snd_nxt + 1 < c->rcv_nxt) {
291 struct rudolph2_conn *c = (
struct rudolph2_conn *)polite;
297 if(hdr->type == TYPE_NACK && hdr->hops_from_base > c->hops_from_base) {
299 PRINTF(
"%d.%d: Got NACK for %d:%d (%d:%d)\n",
301 hdr->version, hdr->chunk,
302 c->version, c->rcv_nxt);
303 if(hdr->version == c->version) {
304 if(hdr->chunk < c->rcv_nxt) {
305 c->snd_nxt = hdr->chunk;
306 send_data(c, SEND_INTERVAL);
308 }
else if(LT(hdr->version, c->version)) {
310 send_data(c, SEND_INTERVAL);
312 }
else if(hdr->type == TYPE_DATA) {
313 if(hdr->hops_from_base < c->hops_from_base) {
316 c->hops_from_base = hdr->hops_from_base + 1;
317 if(LT(c->version, hdr->version)) {
318 PRINTF(
"%d.%d: rudolph2 new version %d, chunk %d\n",
320 hdr->version, hdr->chunk);
321 c->version = hdr->version;
322 c->snd_nxt = c->rcv_nxt = 0;
323 c->flags &= ~FLAG_LAST_RECEIVED;
324 c->flags &= ~FLAG_LAST_SENT;
325 if(hdr->chunk != 0) {
331 }
else if(hdr->version == c->version) {
332 PRINTF(
"%d.%d: got chunk %d snd_nxt %d rcv_nxt %d\n",
334 hdr->chunk, c->snd_nxt, c->rcv_nxt);
336 if(hdr->chunk == c->rcv_nxt) {
339 PRINTF(
"%d.%d: received chunk %d len %d\n",
345 if(len < RUDOLPH2_DATASIZE) {
346 c->flags |= FLAG_LAST_RECEIVED;
347 send_data(c, RESEND_INTERVAL);
348 ctimer_set(&c->t, RESEND_INTERVAL, timed_send, c);
350 }
else if(hdr->chunk > c->rcv_nxt) {
351 PRINTF(
"%d.%d: received chunk %d > %d, sending NACK\n",
353 hdr->chunk, c->rcv_nxt);
355 }
else if(hdr->chunk < c->rcv_nxt) {
366 rudolph2_open(
struct rudolph2_conn *c, uint16_t channel,
367 const struct rudolph2_callbacks *cb)
372 c->hops_from_base = HOPS_MAX;
376 rudolph2_close(
struct rudolph2_conn *c)
382 rudolph2_send(
struct rudolph2_conn *c, clock_time_t send_interval)
386 c->hops_from_base = 0;
389 len = RUDOLPH2_DATASIZE;
391 for(c->rcv_nxt = 0; len == RUDOLPH2_DATASIZE; c->rcv_nxt++) {
394 c->flags = FLAG_LAST_RECEIVED;
396 send_data(c, SEND_INTERVAL);
397 ctimer_set(&c->t, SEND_INTERVAL, timed_send, c);
401 rudolph2_stop(
struct rudolph2_conn *c)
404 c->flags |= FLAG_IS_STOPPED;
int packetbuf_hdralloc(int size)
Extend the header of the packetbuf, for outbound packets.
linkaddr_t linkaddr_node_addr
The Rime address of the node.
int polite_send(struct polite_conn *c, clock_time_t interval, uint8_t hdrsize)
Send a packet on a polite connection.
Header file for the single-hop reliable bulk data transfer module
void(* dropped)(struct polite_conn *c)
Called when a packet is dropped because a packet was heard from a neighbor.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Header file for the Rime stack
Header file for Polite Anonymous best effort local Broadcast (polite)
void polite_open(struct polite_conn *c, uint16_t channel, const struct polite_callbacks *cb)
Open a polite connection.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
void(* sent)(struct polite_conn *c)
Called when a packet is sent on the connection.
An opaque structure with no user-visible elements that holds the state of a polite connection...
void polite_cancel(struct polite_conn *c)
Cancel a pending packet.
void packetbuf_clear(void)
Clear and reset the packetbuf.
void polite_close(struct polite_conn *c)
Close a polite connection.
void(* recv)(struct polite_conn *c)
Called when a packet is received on the connection.
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
A structure with callback functions for a polite connection.
int packetbuf_hdrreduce(int size)
Reduce the header in the packetbuf, for incoming packets.