/*---------------------------------------------------------------------------*/ PROCESS_THREAD(cc2420_process, ev, data) { int len; PROCESS_BEGIN(); PRINTF("cc2420_process: started\n"); while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); #if CC2420_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(cc2420_timetable, "poll"); #endif /* CC2420_TIMETABLE_PROFILING */ PRINTF("cc2420_process: calling receiver callback\n"); packetbuf_clear(); packetbuf_set_attr(PACKETBUF_ATTR_TIMESTAMP, last_packet_timestamp); len = cc2420_read(packetbuf_dataptr(), PACKETBUF_SIZE); packetbuf_set_datalen(len); NETSTACK_RDC.input(); #if CC2420_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(cc2420_timetable, "end"); timetable_aggregate_compute_detailed(&aggregate_time, &cc2420_timetable); timetable_clear(&cc2420_timetable); #endif /* CC2420_TIMETABLE_PROFILING */ } PROCESS_END(); }
/* Process to handle input packets * Receive interrupts cause this process to be polled * It calls the core MAC layer which calls rf230_read to get the packet */ PROCESS_THREAD(nrf24l01_process, ev, data) { PROCESS_BEGIN(); while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); #if RF230_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(rf230_timetable, "poll"); #endif /* RF230_TIMETABLE_PROFILING */ if(receiver_callback != NULL) { receiver_callback(&nrf24l01_driver); #if RF230_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(rf230_timetable, "end"); timetable_aggregate_compute_detailed(&aggregate_time, &rf230_timetable); timetable_clear(&rf230_timetable); #endif /* RF230_TIMETABLE_PROFILING */ } else { PRINTF("nrf24l01_process not receiving function\n"); //flushrx(); } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(cc2420_process, ev, data) { PROCESS_BEGIN(); PRINTF("cc2420_process: started\n"); while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); #if CC2420_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(cc2420_timetable, "poll"); #endif /* CC2420_TIMETABLE_PROFILING */ if(receiver_callback != NULL) { PRINTF("cc2420_process: calling receiver callback\n"); receiver_callback(&cc2420_driver); #if CC2420_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(cc2420_timetable, "end"); timetable_aggregate_compute_detailed(&aggregate_time, &cc2420_timetable); timetable_clear(&cc2420_timetable); #endif /* CC2420_TIMETABLE_PROFILING */ } else { PRINTF("cc2420_process not receiving function\n"); flushrx(); } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ void timetable_init(void) { char dummy1, dummy2; #define temp_size 4 TIMETABLE_STATIC(temp); timetable_clear(&temp); /* Measure the time for taking a timestamp. */ TIMETABLE_TIMESTAMP(temp, &dummy1); TIMETABLE_TIMESTAMP(temp, &dummy2); timetable_timestamp_time = timetable_timediff(&temp, &dummy1, &dummy2); }
/*---------------------------------------------------------------------------*/ static void off(void) { if(xmac_is_on && radio_is_on != 0) { radio_is_on = 0; radio->off(); #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "off"); #endif LEDS_OFF(LEDS_RED); CPRINTF("\\"); } }
/*---------------------------------------------------------------------------*/ static void on(void) { if(xmac_is_on && radio_is_on == 0) { radio_is_on = 1; radio->on(); LEDS_ON(LEDS_RED); CPRINTF("/"); #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "on"); #endif } }
/* * Interrupt leaves frame intact in FIFO. */ static volatile rtimer_clock_t interrupt_time; static volatile int interrupt_time_set; #if CC2420_TIMETABLE_PROFILING #define cc2420_timetable_size 16 TIMETABLE(cc2420_timetable); TIMETABLE_AGGREGATE(aggregate_time, 10); #endif /* CC2420_TIMETABLE_PROFILING */ int cc2420_interrupt(void) { interrupt_time = timesynch_time(); interrupt_time_set = 1; CLEAR_FIFOP_INT(); process_poll(&cc2420_process); #if CC2420_TIMETABLE_PROFILING timetable_clear(&cc2420_timetable); TIMETABLE_TIMESTAMP(cc2420_timetable, "interrupt"); #endif /* CC2420_TIMETABLE_PROFILING */ return 1; }
/* * Interrupt leaves frame intact in FIFO. */ #if CC2420_TIMETABLE_PROFILING #define cc2420_timetable_size 16 TIMETABLE(cc2420_timetable); TIMETABLE_AGGREGATE(aggregate_time, 10); #endif /* CC2420_TIMETABLE_PROFILING */ int cc2420_interrupt(void) { CC2420_CLEAR_FIFOP_INT(); process_poll(&cc2420_process); #if CC2420_TIMETABLE_PROFILING timetable_clear(&cc2420_timetable); TIMETABLE_TIMESTAMP(cc2420_timetable, "interrupt"); #endif /* CC2420_TIMETABLE_PROFILING */ pending++; cc2420_packets_seen++; return 1; }
/* * Interrupt leaves frame intact in FIFO. */ #if CC2420_TIMETABLE_PROFILING #define cc2420_timetable_size 16 TIMETABLE(cc2420_timetable); TIMETABLE_AGGREGATE(aggregate_time, 10); #endif /* CC2420_TIMETABLE_PROFILING */ int cc2420_interrupt(void) { //printf("Enter cc2420 interrupt.\n"); CC2420_CLEAR_FIFOP_INT(); process_poll(&cc2420_process); #if CC2420_TIMETABLE_PROFILING timetable_clear(&cc2420_timetable); TIMETABLE_TIMESTAMP(cc2420_timetable, "interrupt"); #endif /* CC2420_TIMETABLE_PROFILING */ last_packet_timestamp = cc2420_sfd_start_time; //printf("Radio rec time = %u\n",cc2420_sfd_start_time); pending++; cc2420_packets_seen++; return 1; }
void nrf24l01_interrupt(void) { #if RF230_CONF_TIMESTAMPS interrupt_time = timesynch_time(); interrupt_time_set = 1; #endif /* RF230_CONF_TIMESTAMPS */ isr_event_write.isr_type= ISR_RX_DR; process_poll(&nrf24l01_process); #if RF230_TIMETABLE_PROFILING timetable_clear(&rf230_timetable); TIMETABLE_TIMESTAMP(rf230_timetable, "interrupt"); #endif /* RF230_TIMETABLE_PROFILING */ return; }
nRF24L01_ISR() { #if RF230_CONF_TIMESTAMPS interrupt_time = timesynch_time(); interrupt_time_set = 1; #endif /* RF230_CONF_TIMESTAMPS */ volatile uint8_t status; status = spi_register_read(NOP); //PRINTF("ISR: status=0x%x\r\n", status); //Rx FIFO data ready if(status & (1 << MASK_RX_DR)) { uint8_t rx_pipe_no = (status & 0x07); if(rx_pipe_no < 6) { status_rx_dr_handler(rx_pipe_no); } sbi(status, MASK_RX_DR); } //Tx FIFO data has been sent successfully else if(status & (1 << MASK_TX_DS)) { status_tx_ds_handler(); sbi(status, MASK_TX_DS); //clear intertupt } //Re transmit is up to the max counter, //Note: // 1. If you don't clear this interrupt, no data can be transmitted any more // 2. The package lost counter(PLOS_CNT) is incremented at each MAX_RT interrupt else if(status & (1 << MASK_MAX_RT)) { status_max_rt_handler(); sbi(status, MASK_MAX_RT); //clear the interrupt } else {} //clean interrupts SPI_WRITE_REG(WRITE_REG+STATUS, status); #if RF230_TIMETABLE_PROFILING timetable_clear(&rf230_timetable); TIMETABLE_TIMESTAMP(rf230_timetable, "interrupt"); #endif /* RF230_TIMETABLE_PROFILING */ }
/*---------------------------------------------------------------------------*/ static int read_packet(void) { struct xmac_hdr *hdr; uint8_t len; rimebuf_clear(); len = radio->read(rimebuf_dataptr(), RIMEBUF_SIZE); if(len > 0) { rimebuf_set_datalen(len); hdr = rimebuf_dataptr(); rimebuf_hdrreduce(sizeof(struct xmac_hdr)); if(rimebuf_totlen() == 0) { CPRINTF("."); /* There is no data in the packet so it has to be a strobe. */ someone_is_sending = 2; if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_node_addr)) { /* This is a strobe packet for us. */ if(rimeaddr_cmp(&hdr->sender, &rimeaddr_node_addr)) { /* If the sender address is our node address, the strobe is a stray strobe ACK to us, which we ignore unless we are currently sending a packet. */ CPRINTF("&"); someone_is_sending = 0; } else { struct xmac_hdr msg; /* 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. */ #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "read send ack"); #endif rimeaddr_copy(&msg.receiver, &hdr->sender); rimeaddr_copy(&msg.sender, &hdr->sender); CPRINTF("!"); /* We turn on the radio in anticipation of the incoming packet. */ someone_is_sending = 1; waiting_for_packet = 1; on(); radio->send((const uint8_t *)&msg, sizeof(struct xmac_hdr)); } } else if(rimeaddr_cmp(&hdr->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(); } /* We are done processing the strobe and we therefore return to the caller. */ return RIME_OK; } else { CPRINTF("-"); someone_is_sending = 0; if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_node_addr) || rimeaddr_cmp(&hdr->receiver, &rimeaddr_null)) { #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "read got packet"); #endif /* 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(); waiting_for_packet = 0; /* XXX should set timer to send queued packet later. */ if(queued_packet != NULL) { queuebuf_free(queued_packet); queued_packet = NULL; } return rimebuf_totlen(); } } } return 0; }
/*---------------------------------------------------------------------------*/ static int send_packet(void) { rtimer_clock_t t0; rtimer_clock_t t; int strobes; struct xmac_hdr *hdr; int got_ack = 0; struct xmac_hdr msg; int len; int is_broadcast = 0; #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "send"); #endif #if WITH_CHANNEL_CHECK /* Check if there are other strobes in the air. */ waiting_for_packet = 1; on(); t0 = RTIMER_NOW(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_wait_time * 2)) { len = radio->read(&msg, sizeof(msg)); if(len > 0) { someone_is_sending = 1; } } waiting_for_packet = 0; while(someone_is_sending); /* {printf("z");}*/ #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "send 2"); #endif /* WITH_TIMETABLE */ #endif /* WITH_CHANNEL_CHECK */ /* 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; off(); rimebuf_hdralloc(sizeof(struct xmac_hdr)); hdr = rimebuf_hdrptr(); rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr); rimeaddr_copy(&hdr->receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER)); if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_null)) { is_broadcast = 1; } rimebuf_compact(); t0 = RTIMER_NOW(); strobes = 0; BB_SET(XMAC_RECEIVER, hdr->receiver.u16[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. */ if(!is_broadcast) { on(); } watchdog_stop(); got_ack = 0; for(strobes = 0; got_ack == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + xmac_config.strobe_time); strobes++) { t = RTIMER_NOW(); rimeaddr_copy(&msg.sender, &rimeaddr_node_addr); rimeaddr_copy(&msg.receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER)); #if WITH_TIMETABLE if(rimeaddr_cmp(&msg.receiver, &rimeaddr_null)) { TIMETABLE_TIMESTAMP(xmac_timetable, "send broadcast strobe"); } else { TIMETABLE_TIMESTAMP(xmac_timetable, "send strobe"); } #endif if(is_broadcast) { /* If we are sending a broadcast, we don't send strobes, we simply send the data packet repetedly */ radio->send(rimebuf_hdrptr(), rimebuf_totlen()); } else { /* Send the strobe packet. */ radio->send((const uint8_t *)&msg, sizeof(struct xmac_hdr)); } CPRINTF("+"); while(got_ack == 0 && RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time)) { /* See if we got an ACK */ len = radio->read((uint8_t *)&msg, sizeof(struct xmac_hdr)); if(len > 0) { CPRINTF("_"); if(rimeaddr_cmp(&msg.sender, &rimeaddr_node_addr) && rimeaddr_cmp(&msg.receiver, &rimeaddr_node_addr)) { #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "send ack received"); #endif CPRINTF("@"); /* We got an ACK from the receiver, so we can immediately send the packet. */ got_ack = 1; } } } /* XXX: turn off radio if we haven't heard an ACK within a specified time interval. */ /* if(got_ack == 0) { off(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time)); on(); }*/ } if(got_ack /* XXX && needs_ack */) { #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "send got ack"); #endif on(); /* Wait for possible ACK packet */ } else if(!is_broadcast) { #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "send no ack received"); #endif on(); /* shell ping don't seem to work with off() here, so we'll keep it on() for a while. */ } /* Send the data packet. */ if(is_broadcast || got_ack) { #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "send packet"); #endif radio->send(rimebuf_hdrptr(), rimebuf_totlen()); CPRINTF("#"); } watchdog_start(); PRINTF("xmac: send (strobes=%u,len=%u,%s), done\n", strobes, rimebuf_totlen(), got_ack ? "ack" : "no ack"); BB_SET(XMAC_STROBES, strobes); if(got_ack) { BB_INC(XMAC_SEND_WITH_ACK, 1); } else { BB_INC(XMAC_SEND_WITH_NOACK, 1); } /* printf("Strobe %d got_ack %d\n", strobes, got_ack);*/ we_are_sending = 0; #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "send we_are_sending = 0"); #endif LEDS_OFF(LEDS_BLUE); return 1; }
/*---------------------------------------------------------------------------*/ static char powercycle(struct rtimer *t, void *ptr) { int r; #if WITH_TIMESYNCH rtimer_clock_t should_be, adjust; #endif /* WITH_TIMESYNCH */ CPRINTF("*"); PT_BEGIN(&pt); while(1) { /* Only wait for some cycles to pass for someone to start sending */ if(someone_is_sending > 0) { someone_is_sending--; } if(xmac_config.off_time > 0) { if(waiting_for_packet == 0) { if(we_are_sending == 0) { off(); } } else { waiting_for_packet++; if(waiting_for_packet > 2) { /* We should not be awake for more than two consecutive power cycles without having heard a packet, so we turn off the radio. */ waiting_for_packet = 0; #if WITH_TIMETABLE TIMETABLE_TIMESTAMP(xmac_timetable, "off waiting"); #endif off(); } } #if WITH_TIMESYNCH #define NUM_SLOTS 8 should_be = ((timesynch_rtimer_to_time(RTIMER_TIME(t)) + xmac_config.off_time) & ~(xmac_config.off_time + xmac_config.on_time - 1)) + (rimeaddr_node_addr.u8[0] % NUM_SLOTS * ((xmac_config.off_time + xmac_config.on_time) / NUM_SLOTS)); should_be = timesynch_time_to_rtimer(should_be); if(should_be - RTIMER_TIME(t) > xmac_config.off_time) { adjust = xmac_config.off_time / 2; } else { adjust = should_be - RTIMER_TIME(t); } r = rtimer_set(t, RTIMER_TIME(t) + adjust, 1, (void (*)(struct rtimer *, void *))powercycle, ptr); #else /* WITH_TIMESYNCH */ r = rtimer_set(t, RTIMER_TIME(t) + xmac_config.off_time, 1, TC(powercycle), ptr); #endif /* WITH_TIMESYNCH */ if(r) { PRINTF("xmac: 1 could not set rtimer %d\n", r); } PT_YIELD(&pt); } if(we_are_sending == 0 && waiting_for_packet == 0) { on(); } r = rtimer_set(t, RTIMER_TIME(t) + xmac_config.on_time, 1, TC(powercycle), ptr); if(r) { PRINTF("xmac: 3 could not set rtimer %d\n", r); } PT_YIELD(&pt); } PT_END(&pt); }