52 #define DEFAULT_SEND_INTERVAL CLOCK_SECOND * 2
53 #define TRICKLE_INTERVAL CLOCK_SECOND / 2
54 #define NACK_TIMEOUT CLOCK_SECOND / 4
55 #define REPAIR_TIMEOUT CLOCK_SECOND / 4
63 #define RUDOLPH1_DATASIZE 64
65 struct rudolph1_datapacket {
66 struct rudolph1_hdr h;
68 uint8_t data[RUDOLPH1_DATASIZE];
79 #define PRINTF(...) printf(__VA_ARGS__)
84 #define LT(a, b) ((signed char)((a) - (b)) < 0)
88 read_data(
struct rudolph1_conn *c, uint8_t *dataptr,
int chunk)
92 if(c->cb->read_chunk) {
93 len = c->cb->read_chunk(c, chunk * RUDOLPH1_DATASIZE,
94 dataptr, RUDOLPH1_DATASIZE);
100 format_data(
struct rudolph1_conn *c,
int chunk)
102 struct rudolph1_datapacket *p;
106 p->h.type = TYPE_DATA;
107 p->h.version = c->version;
109 p->datalen = read_data(c, p->data, chunk);
111 (RUDOLPH1_DATASIZE - p->datalen));
117 write_data(
struct rudolph1_conn *c,
int chunk, uint8_t *data,
int datalen)
120 c->cb->write_chunk(c, 0, RUDOLPH1_FLAG_NEWFILE, data, 0);
123 if(datalen < RUDOLPH1_DATASIZE) {
124 PRINTF(
"%d.%d: get %d bytes, file complete\n",
127 c->cb->write_chunk(c, chunk * RUDOLPH1_DATASIZE,
128 RUDOLPH1_FLAG_LASTCHUNK, data, datalen);
130 c->cb->write_chunk(c, chunk * RUDOLPH1_DATASIZE,
131 RUDOLPH1_FLAG_NONE, data, datalen);
136 send_nack(
struct rudolph1_conn *c)
138 struct rudolph1_hdr *hdr;
143 hdr->type = TYPE_NACK;
144 hdr->version = c->version;
145 hdr->chunk = c->chunk;
147 PRINTF(
"%d.%d: Sending nack for %d:%d\n",
149 hdr->version, hdr->chunk);
150 ipolite_send(&c->ipolite, NACK_TIMEOUT,
sizeof(
struct rudolph1_hdr));
154 handle_data(
struct rudolph1_conn *c,
struct rudolph1_datapacket *p)
156 if(LT(c->version, p->h.version)) {
157 PRINTF(
"%d.%d: rudolph1 new version %d, chunk %d\n",
159 p->h.version, p->h.chunk);
160 c->version = p->h.version;
161 c->highest_chunk_heard = c->chunk = 0;
162 if(p->h.chunk != 0) {
165 write_data(c, 0, p->data, p->datalen);
169 }
else if(p->h.version == c->version) {
170 PRINTF(
"%d.%d: got chunk %d (%d) highest heard %d\n",
172 p->h.chunk, c->chunk, c->highest_chunk_heard);
174 if(p->h.chunk == c->chunk) {
175 PRINTF(
"%d.%d: received chunk %d\n",
178 write_data(c, p->h.chunk, p->data, p->datalen);
179 if(c->highest_chunk_heard < c->chunk) {
180 c->highest_chunk_heard = c->chunk;
183 }
else if(p->h.chunk > c->chunk) {
184 PRINTF(
"%d.%d: received chunk %d > %d, sending NACK\n",
186 p->h.chunk, c->chunk);
188 c->highest_chunk_heard = p->h.chunk;
189 }
else if(p->h.chunk < c->chunk) {
196 if(c->highest_chunk_heard > p->h.chunk) {
206 recv_trickle(
struct trickle_conn *trickle)
208 struct rudolph1_conn *c = (
struct rudolph1_conn *)trickle;
211 if(p->h.type == TYPE_DATA) {
212 PRINTF(
"%d.%d: received trickle with chunk %d\n",
222 PRINTF(
"%d.%d: Sent ipolite\n",
229 PRINTF(
"%d.%d: dropped ipolite\n",
234 recv_ipolite(
struct ipolite_conn *ipolite,
const linkaddr_t *from)
236 struct rudolph1_conn *c = (
struct rudolph1_conn *)
237 ((
char *)ipolite - offsetof(
struct rudolph1_conn, ipolite));
240 PRINTF(
"%d.%d: Got ipolite type %d\n",
246 if(p->h.type == TYPE_NACK) {
247 PRINTF(
"%d.%d: Got NACK for %d:%d (%d:%d)\n",
249 p->h.version, p->h.chunk,
250 c->version, c->chunk);
251 if(p->h.version == c->version) {
252 if(p->h.chunk < c->chunk) {
254 PRINTF(
"%d.%d: sending repair for chunk %d\n",
257 format_data(c, p->h.chunk);
258 ipolite_send(&c->ipolite, REPAIR_TIMEOUT,
sizeof(
struct rudolph1_hdr));
260 }
else if(LT(p->h.version, c->version)) {
262 ipolite_send(&c->ipolite, c->send_interval / 2,
sizeof(
struct rudolph1_hdr));
264 }
else if(p->h.type == TYPE_DATA) {
266 PRINTF(
"%d.%d: got repair for chunk %d\n",
274 send_next_packet(
void *ptr)
276 struct rudolph1_conn *c = ptr;
279 len = format_data(c, c->chunk);
280 trickle_send(&c->trickle);
281 if(len == RUDOLPH1_DATASIZE) {
282 ctimer_set(&c->t, c->send_interval, send_next_packet, c);
284 PRINTF(
"%d.%d: send_next_packet chunk %d, next %d\n",
286 c->chunk, c->chunk + 1);
288 c->highest_chunk_heard = c->chunk;
292 ctimer_set(&c->t, c->send_interval, send_next_packet, c);
299 static const struct trickle_callbacks trickle = { recv_trickle };
302 rudolph1_open(
struct rudolph1_conn *c, uint16_t channel,
303 const struct rudolph1_callbacks *cb)
305 trickle_open(&c->trickle, TRICKLE_INTERVAL, channel, &trickle);
309 c->send_interval = DEFAULT_SEND_INTERVAL;
313 rudolph1_close(
struct rudolph1_conn *c)
315 trickle_close(&c->trickle);
320 rudolph1_send(
struct rudolph1_conn *c, clock_time_t send_interval)
323 c->chunk = c->highest_chunk_heard = 0;
326 trickle_send(&c->trickle);
328 c->send_interval = send_interval;
329 ctimer_set(&c->t, send_interval, send_next_packet, c);
333 rudolph1_stop(
struct rudolph1_conn *c)
A structure with callback functions for an ipolite connection.
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.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Header file for the Rime stack
void ipolite_close(struct ipolite_conn *c)
Close an ipolite connection.
void ipolite_open(struct ipolite_conn *c, uint16_t channel, uint8_t dups, const struct ipolite_callbacks *cb)
Open an ipolite 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.
An opaque structure with no user-visible elements that holds the state of an ipolite connection...
void packetbuf_clear(void)
Clear and reset the packetbuf.
Header file for the multi-hop reliable bulk data transfer mechanism
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
int ipolite_send(struct ipolite_conn *c, clock_time_t interval, uint8_t hdrsize)
Send a packet on an ipolite connection.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.