/** * * Send a packet. This function builds a complete packet with an LPP * header and queues the packet. When a probe is heard (in the * read_packet() function), and the sender of the probe matches the * receiver of the queued packet, the queued packet is sent. * * ACK packets are treated differently from other packets: if a node * sends a packet that it expects to be ACKed, the sending node keeps * its radio on for some time after sending its packet. So we do not * need to wait for a probe packet: we just transmit the ACK packet * immediately. * */ static void send_packet(mac_callback_t sent, void *ptr) { struct lpp_hdr hdr; clock_time_t timeout; uint8_t is_broadcast = 0; rimeaddr_copy(&hdr.sender, &rimeaddr_node_addr); rimeaddr_copy(&hdr.receiver, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) { is_broadcast = 1; } hdr.type = TYPE_DATA; packetbuf_hdralloc(sizeof(struct lpp_hdr)); memcpy(packetbuf_hdrptr(), &hdr, sizeof(struct lpp_hdr)); packetbuf_compact(); packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); { int hdrlen = NETSTACK_FRAMER.create(); if(hdrlen == 0) { /* Failed to send */ mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 0); return; } } PRINTF("%d.%d: queueing packet to %d.%d, channel %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], hdr.receiver.u8[0], hdr.receiver.u8[1], packetbuf_attr(PACKETBUF_ATTR_CHANNEL)); #if WITH_ACK_OPTIMIZATION if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_ACK) { /* Send ACKs immediately. */ NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); mac_call_sent_callback(sent, ptr, MAC_TX_OK, 1); return; } #endif /* WITH_ACK_OPTIMIZATION */ #if WITH_ADAPTIVE_OFF_TIME off_time = LOWEST_OFF_TIME; restart_dutycycle(off_time); #endif /* WITH_ADAPTIVE_OFF_TIME */ { struct queue_list_item *i; i = memb_alloc(&queued_packets_memb); if(i != NULL) { i->sent_callback = sent; i->sent_callback_ptr = ptr; i->num_transmissions = 0; i->packet = queuebuf_new_from_packetbuf(); if(i->packet == NULL) { memb_free(&queued_packets_memb, i); printf("null packet\n"); mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 0); return; } else { if(is_broadcast) { timeout = PACKET_LIFETIME; #if WITH_PENDING_BROADCAST /* We set the broadcast state of the packet to be waiting. This means that the packet is waiting for our next probe to be sent. Our next probe is used to check if there are any neighbors currently broadcasting a packet. If so, we will get a broadcast packet in response to our probe. If no broadcast packet is received in response to our probe, we mark the packet as ready to be sent. */ set_broadcast_flag(i, BROADCAST_FLAG_WAITING); PRINTF("-> waiting\n"); #endif /* WITH_PENDING_BROADCAST */ } else { timeout = UNICAST_TIMEOUT; #if WITH_PENDING_BROADCAST i->broadcast_flag = BROADCAST_FLAG_NONE; #endif /* WITH_PENDING_BROADCAST */ } ctimer_set(&i->removal_timer, timeout, remove_queued_old_packet_callback, i); /* Wait for a probe packet from a neighbor. The actual packet transmission is handled by the read_packet() function, which receives the probe from the neighbor. */ turn_radio_on_for_neighbor(&hdr.receiver, i); } } else { printf("i == NULL\n"); mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 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(); } }
/*---------------------------------------------------------------------------*/ static void input_packet(void) { struct cxmac_hdr *hdr; if(NETSTACK_FRAMER.parse() >= 0) { hdr = packetbuf_dataptr(); if(hdr->dispatch != DISPATCH) { someone_is_sending = 0; if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_node_addr) || rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { /* This is a regular packet that is destined to us or to the broadcast address. */ /* We have received the final packet, so we can go back to being asleep. */ off(); #if CXMAC_CONF_COMPOWER /* 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); #endif /* CXMAC_CONF_COMPOWER */ waiting_for_packet = 0; PRINTDEBUG("cxmac: data(%u)\n", packetbuf_datalen()); NETSTACK_MAC.input(); return; } else { PRINTDEBUG("cxmac: data not for us\n"); } } else if(hdr->type == TYPE_STROBE) { someone_is_sending = 2; if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_node_addr)) { /* This is a strobe packet for us. */ /* If the sender address is someone else, we should acknowledge the strobe and wait for the packet. By using the same address as both sender and receiver, we flag the message is a strobe ack. */ hdr->type = TYPE_STROBE_ACK; packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, packetbuf_addr(PACKETBUF_ADDR_SENDER)); packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr); packetbuf_compact(); if(NETSTACK_FRAMER.create() >= 0) { /* We turn on the radio in anticipation of the incoming packet. */ someone_is_sending = 1; waiting_for_packet = 1; on(); NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); PRINTDEBUG("cxmac: send strobe ack %u\n", packetbuf_totlen()); } else { PRINTF("cxmac: failed to send strobe ack\n"); } } else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { /* If the receiver address is null, the strobe is sent to prepare for an incoming broadcast packet. If this is the case, we turn on the radio and wait for the incoming broadcast packet. */ waiting_for_packet = 1; on(); } else { PRINTDEBUG("cxmac: strobe not for us\n"); } /* We are done processing the strobe and we therefore return to the caller. */ return; #if CXMAC_CONF_ANNOUNCEMENTS } else if(hdr->type == TYPE_ANNOUNCEMENT) { packetbuf_hdrreduce(sizeof(struct cxmac_hdr)); parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER)); #endif /* CXMAC_CONF_ANNOUNCEMENTS */ } else if(hdr->type == TYPE_STROBE_ACK) { PRINTDEBUG("cxmac: stray strobe ack\n"); } else { PRINTF("cxmac: unknown type %u (%u)\n", hdr->type, packetbuf_datalen()); } } else { PRINTF("cxmac: failed to parse (%u)\n", packetbuf_totlen()); } }
/* This function goes through all encounters to see if it finds a matching neighbor. If so, we set a ctimer that will turn on the radio just before we expect the neighbor to send a probe packet. If we cannot find a matching encounter, we just turn on the radio. The outbound packet is put on either the pending_packets_list or the queued_packets_list, depending on if the packet should be sent immediately. */ static void turn_radio_on_for_neighbor(rimeaddr_t *neighbor, struct queue_list_item *i) { #if WITH_STREAMING if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_STREAM) { is_streaming = 1; turn_radio_on(); list_add(queued_packets_list, i); ctimer_set(&stream_off_timer, STREAM_OFF_TIME, stream_off, NULL); return; } #endif /* WITH_STREAMING */ if(rimeaddr_cmp(neighbor, &rimeaddr_null)) { #if ! WITH_PENDING_BROADCAST /* We have been asked to turn on the radio for a broadcast, so we just turn on the radio. */ turn_radio_on(); #endif /* ! WITH_PENDING_BROADCAST */ list_add(queued_packets_list, i); return; } #if WITH_ENCOUNTER_OPTIMIZATION struct encounter *e; /* We go through the list of encounters to find if we have recorded an encounter with this particular neighbor. If so, we can compute the time for the next expected encounter and setup a ctimer to switch on the radio just before the encounter. */ for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) { if(rimeaddr_cmp(neighbor, &e->neighbor)) { clock_time_t wait, now; /* We expect encounters to happen roughly every OFF_TIME time units. The next expected encounter is at time e->time + OFF_TIME. To compute a relative offset, we subtract with clock_time(). Because we are only interested in turning on the radio within the OFF_TIME period, we compute the waiting time with modulo OFF_TIME. */ now = clock_time(); wait = (((clock_time_t)(e->time - now)) % (OFF_TIME + LISTEN_TIME)) - 2 * LISTEN_TIME; /* printf("now %d e %d e-n %d w %d %d\n", now, e->time, e->time - now, (e->time - now) % (OFF_TIME), wait); printf("Time now %lu last encounter %lu next expected encouter %lu wait %lu/%d (%lu)\n", (1000ul * (unsigned long)now) / CLOCK_SECOND, (1000ul * (unsigned long)e->time) / CLOCK_SECOND, (1000ul * (unsigned long)(e->time + OFF_TIME)) / CLOCK_SECOND, (1000ul * (unsigned long)wait) / CLOCK_SECOND, wait, (1000ul * (unsigned long)(wait + now)) / CLOCK_SECOND);*/ /* printf("Neighbor %d.%d found encounter, waiting %d ticks\n", neighbor->u8[0], neighbor->u8[1], wait);*/ ctimer_set(&e->turn_on_radio_timer, wait, turn_radio_on_callback, i); list_add(pending_packets_list, i); return; } } #endif /* WITH_ENCOUNTER_OPTIMIZATION */ /* We did not find the neighbor in the list of recent encounters, so we just turn on the radio. */ /* printf("Neighbor %d.%d not found in recent encounters\n", neighbor->u8[0], neighbor->u8[1]);*/ turn_radio_on(); list_add(queued_packets_list, i); return; }
// receives packet -- called in radio.c,radio.h static void input(void) { if(NETSTACK_FRAMER.parse() < 0) printf("Incorrect decode frame\n"); #ifdef SF_MOTE_TYPE_SENSOR /*-------------SN CODE----------------------*/ ctimer_stop(&SN_sleep_timer); ctimer_stop(&SN_listen_timer); //check if the packet is from BS if (!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),&rimeaddr_null)) { printf("Packet is not from base station, rejected!\n"); incorrect_rx_counter++; if (incorrect_rx_counter < TOTAL_TS*2) { TDMA_SN_listen(); } else { TDMA_SN_sleep(); } return; } uint8_t *rx_pkt = (uint8_t *)packetbuf_dataptr(); uint16_t rx_pkt_len = packetbuf_datalen(); //turn off radio -- save power if(NETSTACK_RADIO.off() != 1) { printf("TDMA RDC: SN fails to turn off radio"); } SN_RX_start_time = packetbuf_attr(PACKETBUF_ATTR_TIMESTAMP); /*--------from BS------------*/ if (packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_CMD) { //skip this period for TX rtimer_clock_t next_bkn_time = SN_RX_start_time + SEGMENT_PERIOD - GRD_PERIOD; rtimer_set(&SNTimer,next_bkn_time,0,NETSTACK_RADIO.on,NULL); #ifdef SF_FEATURE_SHELL_OPT char command_string[128]; strncpy(command_string,rx_pkt,rx_pkt_len); command_string[rx_pkt_len] = (uint8_t)'\0'; PRINTF("RX Command: %s %d\n",command_string,strlen(command_string)); //process_post(&remote_shell_process,remote_command_event_message,command_string); remote_shell_input(); return; #endif /* SF_FEATURE_SHELL_OPT */ } else if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_DATA) { //schedule for TX if (sf_tdma_slot_num != -1) { //PRINTF("Schedule for TX at Slot %d\n",my_slot); rtimer_clock_t SN_TX_time = SN_RX_start_time + (BS_period+TS_period * (sf_tdma_slot_num-1))-GRD_PERIOD+33;//20 might need to be changed later, do better calibration, increase to 33 if timing problems rtimer_set(&SNTimer,SN_TX_time,0,TDMA_SN_send,NULL); } } app_conn_input(); //For debugging timing #endif /* SF_MOTE_TYPE_SENSOR */ #ifdef SF_MOTE_TYPE_AP /*-----------------BS CODE---------------*/ rimeaddr_t *sent_sn_addr = packetbuf_addr(PACKETBUF_ADDR_SENDER); uint8_t sent_sn_id = sent_sn_addr->u8[0]; rtimer_clock_t relFrameTime =(rtimer_clock_t)((packetbuf_attr(PACKETBUF_ATTR_TIMESTAMP)-radio_TX_time)%segment_period); uint16_t current_TS = (uint16_t)((relFrameTime-BS_period)/TS_period )+1; uint8_t packet_id = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID); //lab 6 if (cc2420_get_channel() == 20 && (packet_id % 10) != 0) { bkn_pkt[sent_sn_id] = packet_id; } //set flag in pkt for TS occupancy /* if(node_list[current_TS-1] == FREE_SLOT_CONST) //collision -- ask the node to find a new available slot { //node_list[current_TS] = rx_pkt[NODE_INDEX]; node_list[current_TS-1] = sent_sn_id; } */ PRINTF("[Sensor: %u] [Slot: %u] [Seq: %u]\n", sent_sn_id,current_TS,packetbuf_attr(PACKETBUF_ATTR_PACKET_ID)); PRINTF("Channel: %d;", cc2420_get_channel()); PRINTF("RSSI: %d\n", cc2420_last_rssi-45); if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_DATA) { // callback to application layer app_conn_input(); } #endif /*SF_MOTE_TYPE_AP */ }
/*---------------------------------------------------------------------------*/ static int send_packet(void) { rtimer_clock_t t0; rtimer_clock_t t; rtimer_clock_t encounter_time = 0; int strobes; struct cxmac_hdr *hdr; int got_strobe_ack = 0; uint8_t strobe[MAX_STROBE_SIZE]; int strobe_len, len; int is_broadcast = 0; int is_reliable; struct encounter *e; struct queuebuf *packet; int is_already_streaming = 0; uint8_t collisions; /* Create the X-MAC header for the data packet. */ packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr); if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { is_broadcast = 1; PRINTDEBUG("cxmac: send broadcast\n"); } else { #if UIP_CONF_IPV6 PRINTDEBUG("cxmac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]); #else PRINTDEBUG("cxmac: send unicast to %u.%u\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]); #endif /* UIP_CONF_IPV6 */ } is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) || packetbuf_attr(PACKETBUF_ATTR_ERELIABLE); len = NETSTACK_FRAMER.create(); strobe_len = len + sizeof(struct cxmac_hdr); if(len < 0 || strobe_len > (int)sizeof(strobe)) { /* Failed to send */ PRINTF("cxmac: send failed, too large header\n"); return MAC_TX_ERR_FATAL; } memcpy(strobe, packetbuf_hdrptr(), len); strobe[len] = DISPATCH; /* dispatch */ strobe[len + 1] = TYPE_STROBE; /* type */ packetbuf_compact(); packet = queuebuf_new_from_packetbuf(); if(packet == NULL) { /* No buffer available */ PRINTF("cxmac: send failed, no queue buffer available (of %u)\n", QUEUEBUF_CONF_NUM); return MAC_TX_ERR; } #if WITH_STREAMING if(is_streaming == 1 && (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &is_streaming_to) || rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &is_streaming_to_too))) { is_already_streaming = 1; } if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_STREAM) { is_streaming = 1; if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) { rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } else if(!rimeaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) { rimeaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME; } #endif /* WITH_STREAMING */ off(); #if WITH_ENCOUNTER_OPTIMIZATION /* We go through the list of encounters to find if we have recorded an encounter with this particular neighbor. If so, we can compute the time for the next expected encounter and setup a ctimer to switch on the radio just before the encounter. */ for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) { const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(rimeaddr_cmp(neighbor, &e->neighbor)) { rtimer_clock_t wait, now, expected; /* We expect encounters to happen every DEFAULT_PERIOD time units. The next expected encounter is at time e->time + DEFAULT_PERIOD. To compute a relative offset, we subtract with clock_time(). Because we are only interested in turning on the radio within the DEFAULT_PERIOD period, we compute the waiting time with modulo DEFAULT_PERIOD. */ now = RTIMER_NOW(); wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD); expected = now + wait - 2 * DEFAULT_ON_TIME; #if WITH_ACK_OPTIMIZATION /* Wait until the receiver is expected to be awake */ if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) != PACKETBUF_ATTR_PACKET_TYPE_ACK && is_streaming == 0) { /* Do not wait if we are sending an ACK, because then the receiver will already be awake. */ while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)); } #else /* WITH_ACK_OPTIMIZATION */ /* Wait until the receiver is expected to be awake */ while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)); #endif /* WITH_ACK_OPTIMIZATION */ } } #endif /* WITH_ENCOUNTER_OPTIMIZATION */ /* By setting we_are_sending to one, we ensure that the rtimer powercycle interrupt do not interfere with us sending the packet. */ we_are_sending = 1; t0 = RTIMER_NOW(); strobes = 0; LEDS_ON(LEDS_BLUE); /* Send a train of strobes until the receiver answers with an ACK. */ /* Turn on the radio to listen for the strobe ACK. */ on(); collisions = 0; if(!is_already_streaming) { watchdog_stop(); got_strobe_ack = 0; t = RTIMER_NOW(); for(strobes = 0, collisions = 0; got_strobe_ack == 0 && collisions == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + cxmac_config.strobe_time); strobes++) { while(got_strobe_ack == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t + cxmac_config.strobe_wait_time)) { rtimer_clock_t now = RTIMER_NOW(); /* See if we got an ACK */ packetbuf_clear(); len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE); if(len > 0) { packetbuf_set_datalen(len); if(NETSTACK_FRAMER.parse() >= 0) { hdr = packetbuf_dataptr(); if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE_ACK) { if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_node_addr)) { /* We got an ACK from the receiver, so we can immediately send the packet. */ got_strobe_ack = 1; encounter_time = now; } else { PRINTDEBUG("cxmac: strobe ack for someone else\n"); } } else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/ { PRINTDEBUG("cxmac: strobe from someone else\n"); collisions++; } } else { PRINTF("cxmac: send failed to parse %u\n", len); } } } t = RTIMER_NOW(); /* Send the strobe packet. */ if(got_strobe_ack == 0 && collisions == 0) { if(is_broadcast) { #if WITH_STROBE_BROADCAST NETSTACK_RADIO.send(strobe, strobe_len); #else /* restore the packet to send */ queuebuf_to_packetbuf(packet); NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); #endif off(); } else { NETSTACK_RADIO.send(strobe, strobe_len); #if 0 /* Turn off the radio for a while to let the other side respond. We don't need to keep our radio on when we know that the other side needs some time to produce a reply. */ off(); rtimer_clock_t wt = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK)); #endif /* 0 */ on(); } } } } #if WITH_ACK_OPTIMIZATION /* If we have received the strobe ACK, and we are sending a packet that will need an upper layer ACK (as signified by the PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */ if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) || packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) || packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_STREAM)) { on(); /* Wait for ACK packet */ waiting_for_packet = 1; } else { off(); } #else /* WITH_ACK_OPTIMIZATION */ off(); #endif /* WITH_ACK_OPTIMIZATION */ /* restore the packet to send */ queuebuf_to_packetbuf(packet); queuebuf_free(packet); /* Send the data packet. */ if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) { NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); } #if WITH_ENCOUNTER_OPTIMIZATION if(got_strobe_ack && !is_streaming) { register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time); } #endif /* WITH_ENCOUNTER_OPTIMIZATION */ watchdog_start(); PRINTF("cxmac: send (strobes=%u,len=%u,%s), done\n", strobes, packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack"); #if CXMAC_CONF_COMPOWER /* Accumulate the power consumption for the packet transmission. */ compower_accumulate(¤t_packet); /* Convert the accumulated power consumption for the transmitted packet to packet attributes so that the higher levels can keep track of the amount of energy spent on transmitting the packet. */ compower_attrconv(¤t_packet); /* Clear the accumulated power consumption so that it is ready for the next packet. */ compower_clear(¤t_packet); #endif /* CXMAC_CONF_COMPOWER */ we_are_sending = 0; LEDS_OFF(LEDS_BLUE); if(collisions == 0) { if(!is_broadcast && !got_strobe_ack) { return MAC_TX_NOACK; } else { return MAC_TX_OK; } } else { someone_is_sending++; return MAC_TX_COLLISION; } }
MACTransmissionStatus XBeeMACLayer::send(const uip_lladdr_t* lladdr_dest, uint8_t* data, uint16_t length, int *number_transmissions){ unsigned long send_start_time; unsigned int sending_time; uint8_t status; // Broadcast is expressed as an all-zeroes address (rimeaddr_null), we check to see if lladdr_dest is a broadcast address comparing it to rimeaddr_null. bool isNotBroadcast = !rimeaddr_cmp((rimeaddr_t*)lladdr_dest, &rimeaddr_null, UIP_LLADDR_LEN); // lladdr_dest != NULL if (isNotBroadcast){ // lladdr_dest is NOT a broadcast address if (UIP_LLADDR_LEN == UIP_802154_LONGADDR_LEN){ ((char*)(&dest))[3] = lladdr_dest->addr[0]; ((char*)(&dest))[2] = lladdr_dest->addr[1]; ((char*)(&dest))[1] = lladdr_dest->addr[2]; ((char*)(&dest))[0] = lladdr_dest->addr[3]; destAddr64.setMsb(dest); ((char*)(&dest))[3] = lladdr_dest->addr[4]; ((char*)(&dest))[2] = lladdr_dest->addr[5]; ((char*)(&dest))[1] = lladdr_dest->addr[6]; ((char*)(&dest))[0] = lladdr_dest->addr[7]; destAddr64.setLsb(dest); Tx64Request longReq(destAddr64, data, length); xbeeRequest = &longReq; }else{ ((char*)(&dest))[1] = lladdr_dest->addr[0]; ((char*)(&dest))[0] = lladdr_dest->addr[1]; Tx16Request shortReq(dest16, data, length); xbeeRequest = &shortReq; } }else{// lladdr_dest is a broadcast address, we send to broadcast Tx16Request shortReq(0xFFFF, data, length); xbeeRequest = &shortReq; } send_start_time = millis(); xbee.send(*xbeeRequest); // after sending a tx request, we expect a status response // wait up to 5 seconds for the status response for(int i=0; i<AT_RESPONSE_MAX_ATTEMPTS; ++i){ if (xbee.readPacket(5000)) { // got a response! // should be a znet tx status if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) { xbee.getResponse().getTxStatusResponse(txStatus); // get the delivery status, the fifth byte switch (txStatus.getStatus()) { case XBEE_SEND_OK: *number_transmissions = getNumberOfTransmissions(); ++number_transmissions;//we have always one (the first one), plus the number of times that we had cca failure (collision) return MAC_TX_STATUS_OK; case XBEE_SEND_NO_ACK: return MAC_TX_STATUS_NO_ACK; case XBEE_SEND_COLLISION: *number_transmissions = getNumberOfTransmissions(); ++number_transmissions;//we have always one (the first one), plus the number of times that we had cca failure (collision) return MAC_TX_STATUS_COLLISION; case XBEE_SEND_PURGED: default: return MAC_TX_STATUS_ERR; } } } } return MAC_TX_STATUS_ERR; }
/*---------------------------------------------------------------------------*/ static int send_packet(void) { frame802154_t params; uint8_t len; /* init to zeros */ memset(¶ms, 0, sizeof(params)); /* Build the FCF. */ params.fcf.frame_type = FRAME802154_DATAFRAME; params.fcf.security_enabled = 0; params.fcf.frame_pending = 0; params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_RELIABLE); params.fcf.panid_compression = 0; /* Insert IEEE 802.15.4 (2003) version bit. */ params.fcf.frame_version = FRAME802154_IEEE802154_2003; /* Increment and set the data sequence number. */ params.seq = mac_dsn++; /* Complete the addressing fields. */ /** \todo For phase 1 the addresses are all long. We'll need a mechanism in the rime attributes to tell the mac to use long or short for phase 2. */ params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE; params.dest_pid = mac_dst_pan_id; /* * If the output address is NULL in the Rime buf, then it is broadcast * on the 802.15.4 network. */ if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { /* Broadcast requires short address mode. */ params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE; params.dest_addr.u8[0] = 0xFF; params.dest_addr.u8[1] = 0xFF; } else { rimeaddr_copy(¶ms.dest_addr, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); params.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE; } /* Set the source PAN ID to the global variable. */ params.src_pid = mac_src_pan_id; /* * Set up the source address using only the long address mode for * phase 1. */ rimeaddr_copy(¶ms.src_addr, &rimeaddr_node_addr); params.payload = packetbuf_dataptr(); params.payload_len = packetbuf_datalen(); len = frame802154_hdrlen(¶ms); if(packetbuf_hdralloc(len)) { frame802154_create(¶ms, packetbuf_hdrptr(), len); PRINTF("6MAC-UT: %2X", params.fcf.frame_type); PRINTADDR(params.dest_addr.u8); PRINTF("%u %u (%u)\n", len, packetbuf_datalen(), packetbuf_totlen()); return radio->send(packetbuf_hdrptr(), packetbuf_totlen()); } else { PRINTF("6MAC-UT: too large header: %u\n", len); } return 0; }
/*---------------------------------------------------------------------------*/ static int send_packet(mac_callback_t mac_callback, void *mac_callback_ptr) { rtimer_clock_t t0; rtimer_clock_t encounter_time = 0, previous_txtime = 0; int strobes; uint8_t got_strobe_ack = 0; int hdrlen, len; uint8_t is_broadcast = 0; uint8_t is_reliable = 0; uint8_t is_known_receiver = 0; uint8_t collisions; int transmit_len; int i; int ret; uint8_t contikimac_was_on; #if WITH_CONTIKIMAC_HEADER struct hdr *chdr; #endif /* WITH_CONTIKIMAC_HEADER */ if(packetbuf_totlen() == 0) { PRINTF("contikimac: send_packet data len 0\n"); return MAC_TX_ERR_FATAL; } packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr); if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { is_broadcast = 1; PRINTDEBUG("contikimac: send broadcast\n"); if(broadcast_rate_drop()) { return MAC_TX_COLLISION; } } else { #if UIP_CONF_IPV6 PRINTDEBUG("contikimac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]); #else /* UIP_CONF_IPV6 */ PRINTDEBUG("contikimac: send unicast to %u.%u\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]); #endif /* UIP_CONF_IPV6 */ } is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) || packetbuf_attr(PACKETBUF_ATTR_ERELIABLE); if(WITH_STREAMING) { if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_STREAM) { if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) { rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } else if(!rimeaddr_cmp (&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) { rimeaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); } stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME; is_streaming = 1; } } if(is_streaming) { packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1); } packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); #if WITH_CONTIKIMAC_HEADER hdrlen = packetbuf_totlen(); if(packetbuf_hdralloc(sizeof(struct hdr)) == 0) { /* Failed to allocate space for contikimac header */ PRINTF("contikimac: send failed, too large header\n"); return MAC_TX_ERR_FATAL; } chdr = packetbuf_hdrptr(); chdr->id = CONTIKIMAC_ID; chdr->len = hdrlen; /* Create the MAC header for the data packet. */ hdrlen = NETSTACK_FRAMER.create(); if(hdrlen == 0) { /* Failed to send */ PRINTF("contikimac: send failed, too large header\n"); packetbuf_hdr_remove(sizeof(struct hdr)); return MAC_TX_ERR_FATAL; } hdrlen += sizeof(struct hdr); #else /* Create the MAC header for the data packet. */ hdrlen = NETSTACK_FRAMER.create(); if(hdrlen == 0) { /* Failed to send */ PRINTF("contikimac: send failed, too large header\n"); return MAC_TX_ERR_FATAL; } #endif /* Make sure that the packet is longer or equal to the shortest packet length. */ transmit_len = packetbuf_totlen(); if(transmit_len < SHORTEST_PACKET_SIZE) { #if 0 /* Pad with zeroes */ uint8_t *ptr; ptr = packetbuf_dataptr(); memset(ptr + packetbuf_datalen(), 0, SHORTEST_PACKET_SIZE - packetbuf_totlen()); #endif PRINTF("contikimac: shorter than shortest (%d)\n", packetbuf_totlen()); transmit_len = SHORTEST_PACKET_SIZE; } packetbuf_compact(); NETSTACK_RADIO.prepare(packetbuf_hdrptr(), transmit_len); /* Remove the MAC-layer header since it will be recreated next time around. */ packetbuf_hdr_remove(hdrlen); if(!is_broadcast && !is_streaming) { #if WITH_PHASE_OPTIMIZATION ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), CYCLE_TIME, GUARD_TIME, mac_callback, mac_callback_ptr); if(ret == PHASE_DEFERRED) { return MAC_TX_DEFERRED; } if(ret != PHASE_UNKNOWN) { is_known_receiver = 1; } #endif /* WITH_PHASE_OPTIMIZATION */ } /* By setting we_are_sending to one, we ensure that the rtimer powercycle interrupt do not interfere with us sending the packet. */ we_are_sending = 1; /* If we have a pending packet in the radio, we should not send now, because we will trash the received packet. Instead, we signal that we have a collision, which lets the packet be received. This packet will be retransmitted later by the MAC protocol instread. */ if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet()) { we_are_sending = 0; PRINTF("contikimac: collision receiving %d, pending %d\n", NETSTACK_RADIO.receiving_packet(), NETSTACK_RADIO.pending_packet()); return MAC_TX_COLLISION; } /* Switch off the radio to ensure that we didn't start sending while the radio was doing a channel check. */ off(); strobes = 0; /* Send a train of strobes until the receiver answers with an ACK. */ collisions = 0; got_strobe_ack = 0; /* Set contikimac_is_on to one to allow the on() and off() functions to control the radio. We restore the old value of contikimac_is_on when we are done. */ contikimac_was_on = contikimac_is_on; contikimac_is_on = 1; if(is_streaming == 0) { /* Check if there are any transmissions by others. */ for(i = 0; i < CCA_COUNT_MAX; ++i) { t0 = RTIMER_NOW(); on(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_CHECK_TIME)) { } if(NETSTACK_RADIO.channel_clear() == 0) { collisions++; off(); break; } off(); t0 = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_SLEEP_TIME)) { } } } if(collisions > 0) { we_are_sending = 0; off(); PRINTF("contikimac: collisions before sending\n"); contikimac_is_on = contikimac_was_on; return MAC_TX_COLLISION; } if(!is_broadcast) { on(); } watchdog_periodic(); t0 = RTIMER_NOW(); for(strobes = 0, collisions = 0; got_strobe_ack == 0 && collisions == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) { watchdog_periodic(); if(is_known_receiver && !RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) { PRINTF("miss to %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]); break; } len = 0; previous_txtime = RTIMER_NOW(); { rtimer_clock_t wt; rtimer_clock_t txtime; int ret; txtime = RTIMER_NOW(); ret = NETSTACK_RADIO.transmit(transmit_len); wt = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { } if(!is_broadcast && (NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0)) { uint8_t ackbuf[ACK_LEN]; wt = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { } len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN) { got_strobe_ack = 1; encounter_time = previous_txtime; break; } else { PRINTF("contikimac: collisions while sending\n"); collisions++; } } previous_txtime = txtime; } } off(); PRINTF("contikimac: send (strobes=%u, len=%u, %s, %s), done\n", strobes, packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack", collisions ? "collision" : "no collision"); #if CONTIKIMAC_CONF_COMPOWER /* Accumulate the power consumption for the packet transmission. */ compower_accumulate(¤t_packet); /* Convert the accumulated power consumption for the transmitted packet to packet attributes so that the higher levels can keep track of the amount of energy spent on transmitting the packet. */ compower_attrconv(¤t_packet); /* Clear the accumulated power consumption so that it is ready for the next packet. */ compower_clear(¤t_packet); #endif /* CONTIKIMAC_CONF_COMPOWER */ contikimac_is_on = contikimac_was_on; we_are_sending = 0; /* Determine the return value that we will return from the function. We must pass this value to the phase module before we return from the function. */ if(collisions > 0) { ret = MAC_TX_COLLISION; } else if(!is_broadcast && !got_strobe_ack) { ret = MAC_TX_NOACK; } else { ret = MAC_TX_OK; } #if WITH_PHASE_OPTIMIZATION if(is_known_receiver && got_strobe_ack) { PRINTF("no miss %d wake-ups %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], strobes); } if(!is_broadcast) { if(collisions == 0 && is_streaming == 0) { phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time, ret); } } #endif /* WITH_PHASE_OPTIMIZATION */ if(WITH_STREAMING) { if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_STREAM_END) { is_streaming = 0; } } return ret; }
/*---------------------------------------------------------------------------*/ static void input_packet(void) { /* We have received the packet, so we can go back to being asleep. */ off(); /* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/ if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse()) { #if WITH_CONTIKIMAC_HEADER struct hdr *chdr; chdr = packetbuf_dataptr(); if(chdr->id != CONTIKIMAC_ID) { PRINTF("contikimac: failed to parse hdr (%u)\n", packetbuf_totlen()); return; } packetbuf_hdrreduce(sizeof(struct hdr)); packetbuf_set_datalen(chdr->len); #endif /* WITH_CONTIKIMAC_HEADER */ if(packetbuf_datalen() > 0 && packetbuf_totlen() > 0 && (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_node_addr) || rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null))) { /* This is a regular packet that is destined to us or to the broadcast address. */ #if CONTIKIMAC_CONF_ANNOUNCEMENTS { struct announcement_msg *hdr = packetbuf_dataptr(); uint8_t magic[2]; memcpy(magic, hdr->announcement_magic, 2); if(magic[0] == ANNOUNCEMENT_MAGIC1 && magic[1] == ANNOUNCEMENT_MAGIC2) { parse_announcements(); } } #endif /* CONTIKIMAC_CONF_ANNOUNCEMENTS */ #if WITH_PHASE_OPTIMIZATION /* If the sender has set its pending flag, it has its radio turned on and we should drop the phase estimation that we have from before. */ if(packetbuf_attr(PACKETBUF_ATTR_PENDING)) { phase_remove(&phase_list, packetbuf_addr(PACKETBUF_ADDR_SENDER)); } #endif /* WITH_PHASE_OPTIMIZATION */ /* Check for duplicate packet by comparing the sequence number of the incoming packet with the last few ones we saw. */ { int i; for(i = 0; i < MAX_SEQNOS; ++i) { if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno && rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER), &received_seqnos[i].sender)) { /* Drop the packet. */ /* printf("Drop duplicate ContikiMAC layer packet\n");*/ return; } } for(i = MAX_SEQNOS - 1; i > 0; --i) { memcpy(&received_seqnos[i], &received_seqnos[i - 1], sizeof(struct seqno)); } received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID); rimeaddr_copy(&received_seqnos[0].sender, packetbuf_addr(PACKETBUF_ADDR_SENDER)); } #if CONTIKIMAC_CONF_COMPOWER /* 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); #endif /* CONTIKIMAC_CONF_COMPOWER */ PRINTDEBUG("contikimac: data (%u)\n", packetbuf_datalen()); NETSTACK_MAC.input(); return; } else { PRINTDEBUG("contikimac: data not for us\n"); } } else { PRINTF("contikimac: failed to parse (%u)\n", packetbuf_totlen()); } }
/*---------------------------------------------------------------------------*/ static void node_packet_received(struct runicast_conn *c, const rimeaddr_t *from, uint8_t seqno) { struct collect_conn *tc = (struct collect_conn *) ((char *)c - offsetof(struct collect_conn, runicast_conn)); int i; /* To protect against forwarding duplicate packets, we keep a list of recently forwarded packet seqnos. If the seqno of the current packet exists in the list, we drop the packet. */ for(i = 0; i < NUM_RECENT_PACKETS; i++) { if(recent_packets[i].seqno == packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID) && rimeaddr_cmp(&recent_packets[i].originator, packetbuf_addr(PACKETBUF_ADDR_ESENDER))) { PRINTF("%d.%d: dropping duplicate packet from %d.%d with seqno %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], recent_packets[i].originator.u8[0], recent_packets[i].originator.u8[1], packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID)); /* Drop the packet. */ return; } } recent_packets[recent_packet_ptr].seqno = packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID); rimeaddr_copy(&recent_packets[recent_packet_ptr].originator, packetbuf_addr(PACKETBUF_ADDR_ESENDER)); recent_packet_ptr = (recent_packet_ptr + 1) % NUM_RECENT_PACKETS; if(tc->rtmetric == SINK) { /* If we are the sink, we call the receive function. */ PRINTF("%d.%d: sink received packet from %d.%d via %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], packetbuf_addr(PACKETBUF_ADDR_ESENDER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_ESENDER)->u8[1], from->u8[0], from->u8[1]); if(tc->cb->recv != NULL) { tc->cb->recv(packetbuf_addr(PACKETBUF_ADDR_ESENDER), packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID), packetbuf_attr(PACKETBUF_ATTR_HOPS)); } return; } else if(packetbuf_attr(PACKETBUF_ATTR_TTL) > 1 && tc->rtmetric != RTMETRIC_MAX) { /* If we are not the sink, we forward the packet to the best neighbor. */ packetbuf_set_attr(PACKETBUF_ATTR_HOPS, packetbuf_attr(PACKETBUF_ATTR_HOPS) + 1); packetbuf_set_attr(PACKETBUF_ATTR_TTL, packetbuf_attr(PACKETBUF_ATTR_TTL) - 1); PRINTF("%d.%d: packet received from %d.%d via %d.%d, forwarding %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], packetbuf_addr(PACKETBUF_ADDR_ESENDER)->u8[0], packetbuf_addr(PACKETBUF_ADDR_ESENDER)->u8[1], from->u8[0], from->u8[1], tc->forwarding); if(packetqueue_enqueue_packetbuf(&forwarding_queue, FORWARD_PACKET_LIFETIME, tc)) { send_queued_packet(); } else { PRINTF("%d.%d: packet dropped: no queue buffer available\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); } } return; }
/*---------------------------------------------------------------------------*/ static void recv_mesh(struct mesh_conn *mesh, const rimeaddr_t *from, uint8_t hops) { struct rudolph1mh_conn *c = (struct rudolph1mh_conn *) ((char *) mesh - offsetof(struct rudolph1mh_conn, mesh)); struct rudolph1mh_datapacket *p = packetbuf_dataptr(); PRINTF("%d.%d: Got mesh type %d from %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], p->h.type, from->u8[0], from->u8[1]); if(!rimeaddr_cmp(&c->partner, from)){ if(!rimeaddr_cmp(&c->partner, &rimeaddr_null)){ rimeaddr_t lfrom; PRINTF("%d.%d: Unexpected packet from %d.%d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], from->u8[0], from->u8[1]); rimeaddr_copy(&lfrom, from); send_busy(c, &lfrom); return; } else { rimeaddr_copy(&c->partner, from); } } if(p->h.type == TYPE_ACK){ if(p->h.s_id == c->s_id && p->h.chunk == c->highest_chunk){ ctimer_stop(&c->t); rimeaddr_copy(&c->partner, &rimeaddr_null); if(c->cb->read_done){ c->cb->read_done(c); } PRINTF("GOT ACK\n"); } else { PRINTF("Unexpected ACK sid %i,%i C %i,%i\n", p->h.s_id, c->s_id, p->h.chunk, c->highest_chunk); } } else if(p->h.type == TYPE_NACK) { c->nacks++; PRINTF("%d.%d: Got NACK for %d:%d (%d:%d)\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], p->h.s_id, p->h.chunk, c->s_id, c->chunk); if(p->h.s_id == c->s_id) { if(p->h.chunk < c->chunk) { /* Format and send a repair packet */ PRINTF("%d.%d: sending repair for chunk %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], p->h.chunk); format_data(c, p->h.chunk); mesh_send(&c->mesh, &c->partner); } } else if(LT(p->h.s_id, c->s_id)) { format_data(c, 0); mesh_send(&c->mesh, &c->partner); } } else if(p->h.type == TYPE_DATA ) { /* This is a repair packet from someone else. */ PRINTF("%d.%d: got chunk %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], p->h.chunk); handle_data(c, p); } else if(p->h.type == TYPE_FIN ) { /* This is a repair packet from someone else. */ PRINTF("%d.%d: got last chunk %d\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], p->h.chunk); if(!rimeaddr_cmp(&c->partner, &rimeaddr_null)){ handle_data(c, p); }{ rimeaddr_copy(&c->partner, from); } send_ack(c); rimeaddr_copy(&c->partner, &rimeaddr_null); } else if(p->h.type == TYPE_BUSY){ PRINTF("%d.%d: %d.%d is busy\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], from->u8[0], from->u8[1]); //Wait } }
int message_is_published_to_me(void) { return (packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == MWARE_MSG_PUB && rimeaddr_cmp(&(packetbuf_msg_pub())->next_hop, &rimeaddr_node_addr)); }
int identifier_is_mine(struct identifier *i) { return rimeaddr_cmp(&i->subscriber, &rimeaddr_node_addr); }
int subscription_is_unsubscribed(struct subscription_item *si) { return (rimeaddr_cmp(&si->next_hop, &rimeaddr_null)); }