📄 xmac.c
字号:
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 struct queuebuf *queued_packet;static intqsend_packet(void){ if(someone_is_sending) { PRINTF("xmac: should queue packet, now just dropping %d %d %d %d.\n", waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on); if(queued_packet != NULL) { RIMESTATS_ADD(sendingdrop); return 0; } else {#if WITH_QUEUE queued_packet = queuebuf_new_from_rimebuf(); return 1;#else RIMESTATS_ADD(sendingdrop); return 0;#endif } } else { PRINTF("xmac: send immediately.\n"); return send_packet(); }}/*---------------------------------------------------------------------------*/static voidinput_packet(const struct radio_driver *d){ if(receiver_callback) { receiver_callback(&xmac_driver); }}/*---------------------------------------------------------------------------*/static intread_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;}/*---------------------------------------------------------------------------*/const struct mac_driver *xmac_init(const struct radio_driver *d){#if WITH_TIMETABLE timetable_clear(&xmac_timetable);#endif radio_is_on = 0; waiting_for_packet = 0; PT_INIT(&pt); rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1, (void (*)(struct rtimer *, void *))powercycle, NULL); xmac_is_on = 1; radio = d; radio->set_receive_function(input_packet); BB_SET("xmac.state_addr", (int) &waiting_for_packet); BB_SET(XMAC_RECEIVER, 0); BB_SET(XMAC_STROBES, 0); BB_SET(XMAC_SEND_WITH_ACK, 0); BB_SET(XMAC_SEND_WITH_NOACK, 0); return &xmac_driver;}/*---------------------------------------------------------------------------*/static intturn_on(void){ xmac_is_on = 1; return 1;}/*---------------------------------------------------------------------------*/static intturn_off(int keep_radio_on){ xmac_is_on = 0; if(keep_radio_on) { return radio->on(); } else { return radio->off(); }}/*---------------------------------------------------------------------------*/const struct mac_driver xmac_driver = { "X-MAC", qsend_packet, read_packet, set_receive_function, turn_on, turn_off };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -