⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpp.c

📁 Contiki是一个开源
💻 C
字号:
/* * Copyright (c) 2008, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the Contiki operating system. * * $Id: lpp.c,v 1.5 2008/06/30 08:08:59 adamdunkels Exp $ *//** * \file *         Low power probing (R. Musaloiu-Elefteri, C. Liang, *         A. Terzis. Koala: Ultra-Low Power Data Retrieval in *         Wireless Sensor Networks, IPSN 2008) * * \author *         Adam Dunkels <adam@sics.se> * * * This is an implementation of the LPP (Low-Power Probing) MAC * protocol. LPP is a power-saving MAC protocol that works by sending * a probe packet each time the radio is turned on. If another node * wants to transmit a packet, it can do so after hearing the * probe. To send a packet, the sending node turns on its radio to * listen for probe packets. * */#include "dev/leds.h"#include "lib/random.h"#include "net/rime.h"#include "net/mac/mac.h"#include "net/mac/lpp.h"#include "net/rime/rimebuf.h"#define DEBUG 0#if DEBUG#include <stdio.h>#define PRINTF(...) printf(__VA_ARGS__)#else#define PRINTF(...)#endif#define TYPE_PROBE        1#define TYPE_DATA         2struct lpp_hdr {  uint16_t type;  rimeaddr_t sender;  rimeaddr_t receiver;};static const struct radio_driver *radio;static void (* receiver_callback)(const struct mac_driver *);static struct pt pt;static struct ctimer timer;static struct queuebuf *queued_packet;#define LISTEN_TIME CLOCK_SECOND / 128#define OFF_TIME CLOCK_SECOND / 4#define DUMP_QUEUED_PACKET 1/*---------------------------------------------------------------------------*/static voidturn_radio_on(void){  radio->on();  leds_on(LEDS_YELLOW);}/*---------------------------------------------------------------------------*/static voidturn_radio_off(void){  radio->off();  leds_off(LEDS_YELLOW);}/*---------------------------------------------------------------------------*//** * Send a probe packet. */static voidsend_probe(void){  struct lpp_hdr *hdr;  rimebuf_clear();  hdr = rimebuf_dataptr();  rimebuf_set_datalen(sizeof(struct lpp_hdr));  rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr);  rimeaddr_copy(&hdr->receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER));  hdr->type = TYPE_PROBE;  PRINTF("Sending probe\n");  radio->send(rimebuf_hdrptr(), rimebuf_totlen());}/*---------------------------------------------------------------------------*//** * Duty cycle the radio. The protothread is driven by a ctimer that is * initiated in the lpp_init() function. */static intdutycycle(void *ptr){  struct ctimer *t = ptr;    PT_BEGIN(&pt);  while(1) {    if(queued_packet != NULL) {            /* We are currently sending a packet so we should keep the radio	 turned on and not send any probes at this point. */      ctimer_set(t, OFF_TIME * 2, (void (*)(void *))dutycycle, t);      PT_YIELD(&pt);      queuebuf_free(queued_packet);      queued_packet = NULL;      PRINTF("Removing old packet\n");    }    turn_radio_on();    send_probe();    ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);    PT_YIELD(&pt);    turn_radio_off();    /* There is a bit of randomness here right now to avoid collisions       due to synchronization effects. Not sure how needed it is       though. XXX */    ctimer_set(t, OFF_TIME / 2 + (random_rand() % OFF_TIME / 2),	       (void (*)(void *))dutycycle, t);    PT_YIELD(&pt);  }  PT_END(&pt);}/*---------------------------------------------------------------------------*//** * * 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 intsend_packet(void){  struct lpp_hdr *hdr;  rimebuf_hdralloc(sizeof(struct lpp_hdr));  hdr = rimebuf_hdrptr();  rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr);  rimeaddr_copy(&hdr->receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER));  hdr->type = TYPE_DATA;  rimebuf_compact();  PRINTF("queueing packet type %d\n", hdr->type);  if(rimebuf_attr(RIMEBUF_ATTR_PACKET_TYPE) == RIMEBUF_ATTR_PACKET_TYPE_ACK) {    /* Immediately send ACKs - we're assuming that the other node is       listening. */    /*    printf("Immediately sending ACK\n");*/    return radio->send(rimebuf_hdrptr(), rimebuf_totlen());  } else {    /* If a packet is already queued, the DUMP_QUEUED_PACKET option       determines if the queued packet should be replaced with the new       packet, or if the new packet should be dropped. XXX haven't       measured the effect of this option */#if DUMP_QUEUED_PACKET    if(queued_packet != NULL) {      queuebuf_free(queued_packet);    }    queued_packet = queuebuf_new_from_rimebuf();#else /* DUMP_QUEUED_PACKET */    if(queued_packet == NULL) {      queued_packet = queuebuf_new_from_rimebuf();    }#endif /* DUMP_QUEUED_PACKET */    /* Wait for a probe packet from a neighbor */    turn_radio_on();  }  return 1;}/*---------------------------------------------------------------------------*//** * 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 intread_packet(void){  int len;  struct lpp_hdr *hdr, *qhdr;    rimebuf_clear();  len = radio->read(rimebuf_dataptr(), RIMEBUF_SIZE);  if(len > 0) {    rimebuf_set_datalen(len);    hdr = rimebuf_dataptr();    rimebuf_hdrreduce(sizeof(struct lpp_hdr));    PRINTF("got packet type %d\n", hdr->type);    if(hdr->type == TYPE_PROBE) {      if(queued_packet != NULL) {	qhdr = queuebuf_dataptr(queued_packet);	if(rimeaddr_cmp(&qhdr->receiver, &hdr->sender) ||	   rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {	  PRINTF("%d.%d: got a probe from %d.%d\n",		 rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],		 hdr->sender.u8[0], hdr->sender.u8[1]);	  radio->send(queuebuf_dataptr(queued_packet),		      queuebuf_datalen(queued_packet));	  queuebuf_free(queued_packet);	  queued_packet = NULL;	  turn_radio_on(); /* XXX Awaiting an ACK: we should check the			      packet type of the queued packet to see			      if it is a data packet. If not, we			      should not turn the radio on. */	}      }    } else if(hdr->type == TYPE_DATA) {      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]);    }    len = rimebuf_datalen();  }  return len;}/*---------------------------------------------------------------------------*/static voidset_receive_function(void (* recv)(const struct mac_driver *)){  receiver_callback = recv;}/*---------------------------------------------------------------------------*/static inton(void){  turn_radio_on();  return 1;}/*---------------------------------------------------------------------------*/static intoff(int keep_radio_on){  if(keep_radio_on) {    turn_radio_on();  } else {    turn_radio_off();  }  return 1;}/*---------------------------------------------------------------------------*/static const struct mac_driver lpp_driver = {  "LPP",  send_packet,  read_packet,  set_receive_function,  on,  off,};/*---------------------------------------------------------------------------*/static voidinput_packet(const struct radio_driver *d){  if(receiver_callback) {    receiver_callback(&lpp_driver);  }}/*---------------------------------------------------------------------------*/const struct mac_driver *lpp_init(const struct radio_driver *d){  radio = d;  radio->set_receive_function(input_packet);  ctimer_set(&timer, LISTEN_TIME, (void (*)(void *))dutycycle, &timer);  return &lpp_driver;}/*---------------------------------------------------------------------------*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -