/*---------------------------------------------------------------------------*/ static void recv(struct broadcast_conn *broadcast, const linkaddr_t *from) { struct ipolite_conn *c = (struct ipolite_conn *)broadcast; if(c->q != NULL && packetbuf_datalen() == queuebuf_datalen(c->q) && memcmp(packetbuf_dataptr(), queuebuf_dataptr(c->q), MIN(c->hdrsize, packetbuf_datalen())) == 0) { /* We received a copy of our own packet, so we increase the duplicate counter. If it reaches its maximum, do not send out our packet. */ c->dups++; if(c->dups == c->maxdups) { queuebuf_free(c->q); c->q = NULL; ctimer_stop(&c->t); if(c->cb->dropped) { c->cb->dropped(c); } } } if(c->cb->recv) { c->cb->recv(c, from); } }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(shell_packetize_process, ev, data) { static struct queuebuf *q = NULL; static char *ptr; static int size; int len; PROCESS_BEGIN(); while(1) { struct shell_input *input; PROCESS_WAIT_EVENT_UNTIL(ev == shell_event_input); if(q == NULL) { packetbuf_clear(); q = queuebuf_new_from_packetbuf(); if(q == NULL) { shell_output_str(&packetize_command, "packetize: could not allocate packet buffer", ""); PROCESS_EXIT(); } ptr = queuebuf_dataptr(q); size = 0; } input = data; len = input->len1 + input->len2; if(len + size >= PACKETBUF_SIZE || len == 0) { shell_output(&packetize_command, ptr, size, "", 0); queuebuf_free(q); q = NULL; PROCESS_EXIT(); } memcpy(ptr + size, input->data1, input->len1); size += input->len1; memcpy(ptr + size, input->data2, input->len2); size += input->len2; } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ static void recv(struct abc_conn *abc) { struct polite_conn *c = (struct polite_conn *)abc; if(c->q != NULL && packetbuf_datalen() == queuebuf_datalen(c->q) && memcmp(packetbuf_dataptr(), queuebuf_dataptr(c->q), MIN(c->hdrsize, packetbuf_datalen())) == 0) { /* We received a copy of our own packet, so we do not send out packet. */ queuebuf_free(c->q); c->q = NULL; ctimer_stop(&c->t); if(c->cb->dropped) { c->cb->dropped(c); } } if(c->cb->recv) { c->cb->recv(c); } }
/*---------------------------------------------------------------------------*/ static char transmitter(struct rtimer *t, void *ptr) { int r; rtimer_clock_t now, rest, period_start, slot_start; /* Calculate slot start time */ now = RTIMER_NOW(); rest = now % PERIOD_LENGTH; period_start = now - rest; slot_start = period_start + MY_SLOT*SLOT_LENGTH; /* Check if we are inside our slot */ if(now < slot_start || now > slot_start + SLOT_LENGTH - GUARD_PERIOD) { PRINTF("TIMER We are outside our slot: %u != [%u,%u]\n", now, slot_start, slot_start + SLOT_LENGTH); while(now > slot_start + SLOT_LENGTH - GUARD_PERIOD) { slot_start += PERIOD_LENGTH; } PRINTF("TIMER Rescheduling until %u\n", slot_start); r = rtimer_set(&rtimer, slot_start, 1, (void (*)(struct rtimer *, void *))transmitter, NULL); if(r) { PRINTF("TIMER Error #1: %d\n", r); } return 1; } /* Transmit queued packets */ while(nextsend != freeslot) { PRINTF("RADIO Transmitting packet #%i\n", id[nextsend]); if(!radio->send(queuebuf_dataptr(data[nextsend]), queuebuf_datalen(data[nextsend]))) { sent_counter++; PRINTF("RADIO Transmit OK for #%i, total=%i\n", id[nextsend], sent_counter); DLEDS_TOGGLE(LEDS_GREEN); } else { PRINTF("RADIO Transmit failed for #%i, total=%i\n", id[nextsend], sent_counter); DLEDS_TOGGLE(LEDS_RED); } nextsend = (nextsend + 1) % NUM_PACKETS; /* Recalculate new slot */ if(RTIMER_NOW() > slot_start + SLOT_LENGTH - GUARD_PERIOD) { PRINTF("TIMER No more time to transmit\n"); break; } } /* Calculate time of our next slot */ slot_start += PERIOD_LENGTH; PRINTF("TIMER Rescheduling until %u\n", slot_start); r = rtimer_set(&rtimer, slot_start, 1, (void (*)(struct rtimer *, void *))transmitter, NULL); if(r) { PRINTF("TIMER Error #2: %d\n", r); } return 0; }
/** * Read a packet from the underlying radio driver. If the incoming * packet is a probe packet and the sender of the probe matches the * destination address of the queued packet (if any), the queued packet * is sent. */ static void input_packet(void) { struct lpp_hdr hdr; clock_time_t reception_time; reception_time = clock_time(); if(!NETSTACK_FRAMER.parse()) { printf("lpp input_packet framer error\n"); } memcpy(&hdr, packetbuf_dataptr(), sizeof(struct lpp_hdr));; packetbuf_hdrreduce(sizeof(struct lpp_hdr)); /* PRINTF("got packet type %d\n", hdr->type);*/ if(hdr.type == TYPE_PROBE) { struct announcement_msg adata; /* Register the encounter with the sending node. We now know the neighbor's phase. */ register_encounter(&hdr.sender, reception_time); /* Parse incoming announcements */ memcpy(&adata, packetbuf_dataptr(), MIN(packetbuf_datalen(), sizeof(adata))); #if 0 PRINTF("%d.%d: probe from %d.%d with %d announcements\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], hdr.sender.u8[0], hdr.sender.u8[1], adata->num); if(adata.num / sizeof(struct announcement_data) > sizeof(struct announcement_msg)) { /* Sanity check. The number of announcements is too large - corrupt packet has been received. */ return 0; } for(i = 0; i < adata.num; ++i) { /* PRINTF("%d.%d: announcement %d: %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], adata->data[i].id, adata->data[i].value);*/ announcement_heard(&hdr.sender, adata.data[i].id, adata.data[i].value); } #endif /* 0 */ /* Go through the list of packets to be sent to see if any of them match the sender of the probe, or if they are a broadcast packet that should be sent. */ if(list_length(queued_packets_list) > 0) { struct queue_list_item *i; for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) { const rimeaddr_t *receiver; uint8_t sent; sent = 0; receiver = queuebuf_addr(i->packet, PACKETBUF_ADDR_RECEIVER); if(rimeaddr_cmp(receiver, &hdr.sender) || rimeaddr_cmp(receiver, &rimeaddr_null)) { queuebuf_to_packetbuf(i->packet); #if WITH_PENDING_BROADCAST if(i->broadcast_flag == BROADCAST_FLAG_NONE || i->broadcast_flag == BROADCAST_FLAG_SEND) { i->num_transmissions = 1; NETSTACK_RADIO.send(queuebuf_dataptr(i->packet), queuebuf_datalen(i->packet)); sent = 1; PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], hdr.sender.u8[0], hdr.sender.u8[1], receiver->u8[0], receiver->u8[1]); } else { PRINTF("%d.%d: got a probe from %d.%d, did not send packet\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], hdr.sender.u8[0], hdr.sender.u8[1]); } #else /* WITH_PENDING_BROADCAST */ i->num_transmissions = 1; NETSTACK_RADIO.send(queuebuf_dataptr(i->packet), queuebuf_datalen(i->packet)); PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], hdr.sender.u8[0], hdr.sender.u8[1], receiver->u8[0], receiver->u8[1]); #endif /* WITH_PENDING_BROADCAST */ /* off();*/ /* Attribute the energy spent on listening for the probe to this packet transmission. */ compower_accumulate(&i->compower); /* If the packet was not a broadcast packet, we dequeue it now. Broadcast packets should be transmitted to all neighbors, and are dequeued by the dutycycling function instead, after the appropriate time. */ if(!rimeaddr_cmp(receiver, &rimeaddr_null)) { if(detect_ack()) { remove_queued_packet(i, 1); } else { remove_queued_packet(i, 0); } #if WITH_PROBE_AFTER_TRANSMISSION /* Send a probe packet to catch any reply from the other node. */ restart_dutycycle(PROBE_AFTER_TRANSMISSION_TIME); #endif /* WITH_PROBE_AFTER_TRANSMISSION */ #if WITH_STREAMING if(is_streaming) { ctimer_set(&stream_probe_timer, STREAM_PROBE_TIME, send_stream_probe, NULL); } #endif /* WITH_STREAMING */ } if(sent) { turn_radio_off(); } #if WITH_ACK_OPTIMIZATION if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE) || packetbuf_attr(PACKETBUF_ATTR_ERELIABLE)) { /* We're sending a packet that needs an ACK, so we keep the radio on in anticipation of the ACK. */ turn_radio_on(); } #endif /* WITH_ACK_OPTIMIZATION */ } } } } else if(hdr.type == TYPE_DATA) { turn_radio_off(); if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) { if(!rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) { /* Not broadcast or for us */ PRINTF("%d.%d: data not for us from %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], hdr.sender.u8[0], hdr.sender.u8[1]); return; } packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &hdr.receiver); } packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &hdr.sender); PRINTF("%d.%d: got data from %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], hdr.sender.u8[0], hdr.sender.u8[1]); /* Accumulate the power consumption for the packet reception. */ compower_accumulate(¤t_packet); /* Convert the accumulated power consumption for the received packet to packet attributes so that the higher levels can keep track of the amount of energy spent on receiving the packet. */ compower_attrconv(¤t_packet); /* Clear the accumulated power consumption so that it is ready for the next packet. */ compower_clear(¤t_packet); #if WITH_PENDING_BROADCAST if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) { /* This is a broadcast packet. Check the list of pending packets to see if we are currently sending a broadcast. If so, we refrain from sending our broadcast until one sleep cycle period, so that the other broadcaster will have finished sending. */ struct queue_list_item *i; for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) { /* If the packet is a broadcast packet that is not yet ready to be sent, we do not send it. */ if(i->broadcast_flag == BROADCAST_FLAG_PENDING) { PRINTF("Someone else is sending, pending -> waiting\n"); set_broadcast_flag(i, BROADCAST_FLAG_WAITING); } } } #endif /* WITH_PENDING_BROADCAST */ #if WITH_PROBE_AFTER_RECEPTION /* XXX send probe after receiving a packet to facilitate data streaming. We must first copy the contents of the packetbuf into a queuebuf to avoid overwriting the data with the probe packet. */ if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_node_addr)) { struct queuebuf *q; q = queuebuf_new_from_packetbuf(); if(q != NULL) { send_probe(); queuebuf_to_packetbuf(q); queuebuf_free(q); } } #endif /* WITH_PROBE_AFTER_RECEPTION */ #if WITH_ADAPTIVE_OFF_TIME off_time = LOWEST_OFF_TIME; restart_dutycycle(off_time); #endif /* WITH_ADAPTIVE_OFF_TIME */ NETSTACK_MAC.input(); } }