diff --git a/.travis.yml b/.travis.yml index 7d1e59067..9e4112ad4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,3 +69,4 @@ env: - BUILD_TYPE='compile-8051-ports' BUILD_CATEGORY='compile' BUILD_ARCH='8051' - BUILD_TYPE='compile-arm-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm' - BUILD_TYPE='compile-6502-ports' BUILD_CATEGORY='compile' BUILD_ARCH='6502' + - BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja' diff --git a/core/net/mac/Makefile.mac b/core/net/mac/Makefile.mac index 1d80a7fa3..e3f04262f 100644 --- a/core/net/mac/Makefile.mac +++ b/core/net/mac/Makefile.mac @@ -1,2 +1,2 @@ -CONTIKI_SOURCEFILES += cxmac.c xmac.c nullmac.c lpp.c frame802154.c sicslowmac.c nullrdc.c nullrdc-noframer.c mac.c +CONTIKI_SOURCEFILES += cxmac.c nullmac.c frame802154.c sicslowmac.c nullrdc.c nullrdc-noframer.c mac.c CONTIKI_SOURCEFILES += framer-nullmac.c framer-802154.c csma.c contikimac.c phase.c mac-sequence.c diff --git a/core/net/mac/lpp.c b/core/net/mac/lpp.c deleted file mode 100644 index 2b1545685..000000000 --- a/core/net/mac/lpp.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * 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. - * - */ - -/** - * \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 - * - * - * 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/list.h" -#include "lib/memb.h" -#include "lib/random.h" -#include "net/rime.h" -#include "net/netstack.h" -#include "net/mac/mac.h" -#include "net/mac/lpp.h" -#include "net/packetbuf.h" -#include "net/rime/announcement.h" -#include "sys/compower.h" -#include "net/mac/framer.h" - -#include -#include -#include - -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif - -#define WITH_ACK_OPTIMIZATION 0 -#define WITH_PROBE_AFTER_RECEPTION 0 -#define WITH_PROBE_AFTER_TRANSMISSION 0 -#define WITH_ENCOUNTER_OPTIMIZATION 0 -#define WITH_ADAPTIVE_OFF_TIME 0 -#define WITH_PENDING_BROADCAST 0 -#define WITH_STREAMING 1 - -#define LISTEN_TIME (CLOCK_SECOND / 128) -#define OFF_TIME (CLOCK_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE - LISTEN_TIME) - -#define PACKET_LIFETIME (LISTEN_TIME + OFF_TIME) -#define UNICAST_TIMEOUT (1 * PACKET_LIFETIME + PACKET_LIFETIME / 2) -#define PROBE_AFTER_TRANSMISSION_TIME (LISTEN_TIME * 2) - -#define LOWEST_OFF_TIME (CLOCK_SECOND / 8) - -#define ENCOUNTER_LIFETIME (16 * OFF_TIME) - -#ifdef QUEUEBUF_CONF_NUM -#define MAX_QUEUED_PACKETS QUEUEBUF_CONF_NUM / 2 -#else /* QUEUEBUF_CONF_NUM */ -#define MAX_QUEUED_PACKETS 4 -#endif /* QUEUEBUF_CONF_NUM */ - - -/* If CLOCK_SECOND is less than 4, we may end up with an OFF_TIME that - is 0 which will make compilation fail due to a modulo operation in - the code. To ensure that OFF_TIME is greater than zero, we use the - construct below. */ -#if OFF_TIME < 2 -#undef OFF_TIME -#define OFF_TIME 2 -#endif - -struct announcement_data { - uint16_t id; - uint16_t value; -}; - -#define ANNOUNCEMENT_MSG_HEADERLEN 2 -struct announcement_msg { - uint16_t num; - struct announcement_data data[]; -}; - -#define LPP_PROBE_HEADERLEN 2 - -#define TYPE_PROBE 1 -#define TYPE_DATA 2 -struct lpp_hdr { - uint16_t type; - rimeaddr_t sender; - rimeaddr_t receiver; -}; - -static uint8_t lpp_is_on; - -static struct compower_activity current_packet; - -static struct pt dutycycle_pt; -static struct ctimer timer; - -static uint8_t is_listening = 0; -static clock_time_t off_time_adjustment = 0; -static clock_time_t off_time = OFF_TIME; - -struct queue_list_item { - struct queue_list_item *next; - struct queuebuf *packet; - struct ctimer removal_timer; - struct compower_activity compower; - mac_callback_t sent_callback; - void *sent_callback_ptr; - uint8_t num_transmissions; -#if WITH_PENDING_BROADCAST - uint8_t broadcast_flag; -#endif /* WITH_PENDING_BROADCAST */ -}; - -#define BROADCAST_FLAG_NONE 0 -#define BROADCAST_FLAG_WAITING 1 -#define BROADCAST_FLAG_PENDING 2 -#define BROADCAST_FLAG_SEND 3 - -LIST(pending_packets_list); -LIST(queued_packets_list); -MEMB(queued_packets_memb, struct queue_list_item, MAX_QUEUED_PACKETS); - -struct encounter { - struct encounter *next; - rimeaddr_t neighbor; - clock_time_t time; - struct ctimer remove_timer; - struct ctimer turn_on_radio_timer; -}; - -#define MAX_ENCOUNTERS 4 -LIST(encounter_list); -MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS); - -static uint8_t is_streaming = 0; -#if WITH_STREAMING -static struct ctimer stream_probe_timer, stream_off_timer; -#define STREAM_PROBE_TIME CLOCK_SECOND / 128 -#define STREAM_OFF_TIME CLOCK_SECOND / 2 -#endif /* WITH_STREAMING */ - -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - -/*---------------------------------------------------------------------------*/ -static void -turn_radio_on(void) -{ - NETSTACK_RADIO.on(); - /* leds_on(LEDS_YELLOW);*/ -} -/*---------------------------------------------------------------------------*/ -static void -turn_radio_off(void) -{ - if(lpp_is_on && is_streaming == 0) { - NETSTACK_RADIO.off(); - } - /* leds_off(LEDS_YELLOW);*/ -} -/*---------------------------------------------------------------------------*/ -static void -remove_encounter(void *encounter) -{ - struct encounter *e = encounter; - - ctimer_stop(&e->remove_timer); - ctimer_stop(&e->turn_on_radio_timer); - list_remove(encounter_list, e); - memb_free(&encounter_memb, e); -} -/*---------------------------------------------------------------------------*/ -static void -register_encounter(rimeaddr_t *neighbor, clock_time_t time) -{ - struct encounter *e; - - /* If we have an entry for this neighbor already, we renew it. */ - for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) { - if(rimeaddr_cmp(neighbor, &e->neighbor)) { - e->time = time; - ctimer_set(&e->remove_timer, ENCOUNTER_LIFETIME, remove_encounter, e); - break; - } - } - /* No matchin encounter was found, so we allocate a new one. */ - if(e == NULL) { - e = memb_alloc(&encounter_memb); - if(e == NULL) { - /* We could not allocate memory for this encounter, so we just drop it. */ - return; - } - rimeaddr_copy(&e->neighbor, neighbor); - e->time = time; - ctimer_set(&e->remove_timer, ENCOUNTER_LIFETIME, remove_encounter, e); - list_add(encounter_list, e); - } -} - -#if WITH_ENCOUNTER_OPTIMIZATION -/*---------------------------------------------------------------------------*/ -static void -turn_radio_on_callback(void *packet) -{ - struct queue_list_item *p = packet; - - list_remove(pending_packets_list, p); - list_add(queued_packets_list, p); - turn_radio_on(); - - /* printf("enc\n");*/ -} -#endif /* WITH_ENCOUNTER_OPTIMIZATION */ - -/*---------------------------------------------------------------------------*/ -static void -stream_off(void *dummy) -{ - is_streaming = 0; -} -/*---------------------------------------------------------------------------*/ -/* 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; -} -/*---------------------------------------------------------------------------*/ -static void -remove_queued_packet(struct queue_list_item *i, uint8_t tx_ok) -{ - mac_callback_t sent; - void *ptr; - int num_transmissions = 0; - int status; - - PRINTF("%d.%d: removing queued packet\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); - - - queuebuf_to_packetbuf(i->packet); - - ctimer_stop(&i->removal_timer); - queuebuf_free(i->packet); - list_remove(pending_packets_list, i); - list_remove(queued_packets_list, i); - - /* XXX potential optimization */ - if(list_length(queued_packets_list) == 0 && is_listening == 0) { - turn_radio_off(); - compower_accumulate(&i->compower); - } - - sent = i->sent_callback; - ptr = i->sent_callback_ptr; - num_transmissions = i->num_transmissions; - memb_free(&queued_packets_memb, i); - if(num_transmissions == 0 || tx_ok == 0) { - status = MAC_TX_NOACK; - } else { - status = MAC_TX_OK; - } - mac_call_sent_callback(sent, ptr, status, num_transmissions); -} -/*---------------------------------------------------------------------------*/ -static void -remove_queued_old_packet_callback(void *item) -{ - remove_queued_packet(item, 0); -} - -#if WITH_PENDING_BROADCAST -/*---------------------------------------------------------------------------*/ -static void -remove_queued_broadcast_packet_callback(void *item) -{ - remove_queued_packet(item, 1); -} -/*---------------------------------------------------------------------------*/ -static void -set_broadcast_flag(struct queue_list_item *i, uint8_t flag) -{ - i->broadcast_flag = flag; - ctimer_set(&i->removal_timer, PACKET_LIFETIME, - remove_queued_broadcast_packet_callback, i); -} -#endif /* WITH_PENDING_BROADCAST */ -/*---------------------------------------------------------------------------*/ -static void -listen_callback(int periods) -{ - is_listening = periods; - turn_radio_on(); -} -/*---------------------------------------------------------------------------*/ -/** - * Send a probe packet. - */ -static void -send_probe(void) -{ - struct lpp_hdr *hdr; - struct announcement_msg *adata; - struct announcement *a; - - /* Set up the probe header. */ - packetbuf_clear(); - packetbuf_set_datalen(sizeof(struct lpp_hdr)); - hdr = packetbuf_dataptr(); - hdr->type = TYPE_PROBE; - rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr); - /* rimeaddr_copy(&hdr->receiver, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));*/ - rimeaddr_copy(&hdr->receiver, &rimeaddr_null); - - packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null); - { - int hdrlen = NETSTACK_FRAMER.create(); - if(hdrlen < 0) { - /* Failed to send */ - return; - } - } - - /* Construct the announcements */ - adata = (struct announcement_msg *)((char *)hdr + sizeof(struct lpp_hdr)); - - adata->num = 0; - for(a = announcement_list(); a != NULL; a = list_item_next(a)) { - adata->data[adata->num].id = a->id; - adata->data[adata->num].value = a->value; - adata->num++; - } - - packetbuf_set_datalen(sizeof(struct lpp_hdr) + - ANNOUNCEMENT_MSG_HEADERLEN + - sizeof(struct announcement_data) * adata->num); - - /* PRINTF("Sending probe\n");*/ - - /* printf("probe\n");*/ - - if(NETSTACK_RADIO.channel_clear()) { - NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); - } else { - off_time_adjustment = random_rand() % (OFF_TIME / 2); - } - - compower_accumulate(&compower_idle_activity); -} -/*---------------------------------------------------------------------------*/ -static void -send_stream_probe(void *dummy) -{ - /* Turn on the radio for sending a probe packet and - anticipating a data packet from a neighbor. */ - turn_radio_on(); - - /* Send a probe packet. */ - send_probe(); - -#if WITH_STREAMING - is_streaming = 1; -#endif /* WITH_STREAMING */ -} -/*---------------------------------------------------------------------------*/ -static int -num_packets_to_send(void) -{ -#if WITH_PENDING_BROADCAST - struct queue_list_item *i; - int num = 0; - - for(i = list_head(queued_packets_list); i != NULL; i = list_item_next(i)) { - if(i->broadcast_flag == BROADCAST_FLAG_SEND || - i->broadcast_flag == BROADCAST_FLAG_NONE) { - ++num; - } - } - return num; -#else /* WITH_PENDING_BROADCAST */ - return list_length(queued_packets_list); -#endif /* WITH_PENDING_BROADCAST */ -} -/*---------------------------------------------------------------------------*/ -/** - * Duty cycle the radio and send probes. This function is called - * repeatedly by a ctimer. The function restart_dutycycle() is used to - * (re)start the duty cycling. - */ -static int -dutycycle(void *ptr) -{ - struct ctimer *t = ptr; - - PT_BEGIN(&dutycycle_pt); - - while(1) { - -#if WITH_PENDING_BROADCAST - { - /* Before sending the probe, we mark all broadcast packets in - our output queue to be pending. This means that they are - ready to be sent, once we know that no neighbor is - currently broadcasting. */ - for(p = list_head(queued_packets_list); p != NULL; p = list_item_next(p)) { - if(p->broadcast_flag == BROADCAST_FLAG_WAITING) { - PRINTF("wait -> pending\n"); - set_broadcast_flag(p, BROADCAST_FLAG_PENDING); - } - } - } -#endif /* WITH_PENDING_BROADCAST */ - - /* Turn on the radio for sending a probe packet and - anticipating a data packet from a neighbor. */ - turn_radio_on(); - - /* Send a probe packet. */ - send_probe(); - - /* Set a timer so that we keep the radio on for LISTEN_TIME. */ - ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t); - PT_YIELD(&dutycycle_pt); - -#if WITH_PENDING_BROADCAST - { - struct queue_list_item *p; - /* Go through the list of packets we are waiting to send, and - check if there are any pending broadcasts in the list. If - there are pending broadcasts, and we did not receive any - broadcast packets from a neighbor in response to our probe, - we mark the broadcasts as being ready to send. */ - for(p = list_head(queued_packets_list); p != NULL; p = list_item_next(p)) { - if(p->broadcast_flag == BROADCAST_FLAG_PENDING) { - PRINTF("pending -> send\n"); - set_broadcast_flag(p, BROADCAST_FLAG_SEND); - turn_radio_on(); - } - } - } -#endif /* WITH_PENDING_BROADCAST */ - - /* If we have no packets to send (indicated by the list length of - queued_packets_list being zero), we should turn the radio - off. Othersize, we keep the radio on. */ - if(num_packets_to_send() == 0) { - - /* If we are not listening for announcements, we turn the radio - off and wait until we send the next probe. */ - if(is_listening == 0) { - int current_off_time; - if(!NETSTACK_RADIO.receiving_packet()) { - turn_radio_off(); - compower_accumulate(&compower_idle_activity); - } - current_off_time = off_time - off_time_adjustment; - if(current_off_time < LISTEN_TIME * 2) { - current_off_time = LISTEN_TIME * 2; - } - off_time_adjustment = 0; - ctimer_set(t, current_off_time, (void (*)(void *))dutycycle, t); - PT_YIELD(&dutycycle_pt); - -#if WITH_ADAPTIVE_OFF_TIME - off_time += LOWEST_OFF_TIME; - if(off_time > OFF_TIME) { - off_time = OFF_TIME; - } -#endif /* WITH_ADAPTIVE_OFF_TIME */ - - } else { - /* We are listening for annonucements, so we count down the - listen time, and keep the radio on. */ - is_listening--; - ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t); - PT_YIELD(&dutycycle_pt); - } - } else { - /* We had pending packets to send, so we do not turn the radio off. */ - - ctimer_set(t, off_time, (void (*)(void *))dutycycle, t); - PT_YIELD(&dutycycle_pt); - } - } - - PT_END(&dutycycle_pt); -} -/*---------------------------------------------------------------------------*/ -static void -restart_dutycycle(clock_time_t initial_wait) -{ - PT_INIT(&dutycycle_pt); - ctimer_set(&timer, initial_wait, (void (*)(void *))dutycycle, &timer); -} -/*---------------------------------------------------------------------------*/ -/** - * - * 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); - } - } -} -/*---------------------------------------------------------------------------*/ -static void -send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list) -{ - if(buf_list != NULL) { - queuebuf_to_packetbuf(buf_list->buf); - send_packet(sent, ptr); - } -} -/*---------------------------------------------------------------------------*/ -static int -detect_ack(void) -{ -#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000 -#define ACK_LEN 3 -#define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1000 - rtimer_clock_t wt; - uint8_t ack_received = 0; - - wt = RTIMER_NOW(); - leds_on(LEDS_GREEN); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { } - leds_off(LEDS_GREEN); - /* Check for incoming ACK. */ - if((NETSTACK_RADIO.receiving_packet() || - NETSTACK_RADIO.pending_packet() || - NETSTACK_RADIO.channel_clear() == 0)) { - int len; - uint8_t ackbuf[ACK_LEN + 2]; - - 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) { - ack_received = 1; - } - } - if(ack_received) { - leds_toggle(LEDS_RED); - } - return ack_received; -} -/*---------------------------------------------------------------------------*/ -/** - * 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; - int ret; - - reception_time = clock_time(); - - if(NETSTACK_FRAMER.parse() < 0) { - 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; - ret = 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; - ret = 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 RDC_CONF_HARDWARE_ACK - - if(ret == RADIO_TX_OK) { - remove_queued_packet(i, 1); - } else { - remove_queued_packet(i, 0); - } -#else - if(detect_ack()) { - remove_queued_packet(i, 1); - } else { - remove_queued_packet(i, 0); - } - -#endif /* RDC_CONF_HARDWARE_ACK */ - - -#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 int -on(void) -{ - lpp_is_on = 1; - turn_radio_on(); - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -off(int keep_radio_on) -{ - lpp_is_on = 0; - if(keep_radio_on) { - turn_radio_on(); - } else { - turn_radio_off(); - } - return 1; -} -/*---------------------------------------------------------------------------*/ -static unsigned short -channel_check_interval(void) -{ - return OFF_TIME + LISTEN_TIME; -} -/*---------------------------------------------------------------------------*/ -static void -init(void) -{ - restart_dutycycle(random_rand() % OFF_TIME); - - lpp_is_on = 1; - - announcement_register_listen_callback(listen_callback); - - memb_init(&queued_packets_memb); - list_init(queued_packets_list); - list_init(pending_packets_list); -} -/*---------------------------------------------------------------------------*/ -const struct rdc_driver lpp_driver = { - "LPP", - init, - send_packet, - send_list, - input_packet, - on, - off, - channel_check_interval, -}; -/*---------------------------------------------------------------------------*/ diff --git a/core/net/mac/xmac.c b/core/net/mac/xmac.c deleted file mode 100644 index 94dab9734..000000000 --- a/core/net/mac/xmac.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Copyright (c) 2007, 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. - * - */ - -/** - * \file - * A simple power saving MAC protocol based on X-MAC [SenSys 2006] - * \author - * Adam Dunkels - * Niclas Finne - * Joakim Eriksson - */ - -#include "dev/leds.h" -#include "dev/radio.h" -#include "dev/watchdog.h" -#include "lib/random.h" -#include "net/netstack.h" -#include "net/mac/mac-sequence.h" -#include "net/mac/xmac.h" -#include "net/rime.h" -#include "net/rime/timesynch.h" -#include "sys/compower.h" -#include "sys/pt.h" -#include "sys/rtimer.h" - -#include "contiki-conf.h" - -#ifdef EXPERIMENT_SETUP -#include "experiment-setup.h" -#endif - -#include - -#ifndef WITH_ACK_OPTIMIZATION -#define WITH_ACK_OPTIMIZATION 0 -#endif -#ifndef WITH_ENCOUNTER_OPTIMIZATION -#define WITH_ENCOUNTER_OPTIMIZATION 1 -#endif -#ifndef WITH_STREAMING -#define WITH_STREAMING 1 -#endif -#ifndef WITH_STROBE_BROADCAST -#define WITH_STROBE_BROADCAST 0 -#endif - -struct announcement_data { - uint16_t id; - uint16_t value; -}; - -/* The maximum number of announcements in a single announcement - message - may need to be increased in the future. */ -#define ANNOUNCEMENT_MAX 10 - -/* The structure of the announcement messages. */ -struct announcement_msg { - uint16_t num; - struct announcement_data data[ANNOUNCEMENT_MAX]; -}; - -/* The length of the header of the announcement message, i.e., the - "num" field in the struct. */ -#define ANNOUNCEMENT_MSG_HEADERLEN (sizeof (uint16_t)) - -#define DISPATCH 0 -#define TYPE_STROBE 0x10 -/* #define TYPE_DATA 0x11 */ -#define TYPE_ANNOUNCEMENT 0x12 -#define TYPE_STROBE_ACK 0x13 - -struct xmac_hdr { - uint8_t dispatch; - uint8_t type; -}; - -#define MAX_STROBE_SIZE 50 - -#ifdef XMAC_CONF_ON_TIME -#define DEFAULT_ON_TIME (XMAC_CONF_ON_TIME) -#else -#define DEFAULT_ON_TIME (RTIMER_ARCH_SECOND / 160) -#endif - -#ifdef XMAC_CONF_OFF_TIME -#define DEFAULT_OFF_TIME (XMAC_CONF_OFF_TIME) -#else -#define DEFAULT_OFF_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE - DEFAULT_ON_TIME) -#endif - -#define DEFAULT_PERIOD (DEFAULT_OFF_TIME + DEFAULT_ON_TIME) - -#define WAIT_TIME_BEFORE_STROBE_ACK RTIMER_ARCH_SECOND / 1000 - -/* On some platforms, we may end up with a DEFAULT_PERIOD that is 0 - which will make compilation fail due to a modulo operation in the - code. To ensure that DEFAULT_PERIOD is greater than zero, we use - the construct below. */ -#if DEFAULT_PERIOD == 0 -#undef DEFAULT_PERIOD -#define DEFAULT_PERIOD 1 -#endif - -/* The cycle time for announcements. */ -#define ANNOUNCEMENT_PERIOD 4 * CLOCK_SECOND - -/* The time before sending an announcement within one announcement - cycle. */ -#define ANNOUNCEMENT_TIME (random_rand() % (ANNOUNCEMENT_PERIOD)) - -#define DEFAULT_STROBE_WAIT_TIME (5 * DEFAULT_ON_TIME / 8) - -struct xmac_config xmac_config = { - DEFAULT_ON_TIME, - DEFAULT_OFF_TIME, - 4 * DEFAULT_ON_TIME + DEFAULT_OFF_TIME, - DEFAULT_STROBE_WAIT_TIME -}; - -#include -static struct rtimer rt; -static struct pt pt; - -static volatile uint8_t xmac_is_on = 0; - -static volatile unsigned char waiting_for_packet = 0; -static volatile unsigned char someone_is_sending = 0; -static volatile unsigned char we_are_sending = 0; -static volatile unsigned char radio_is_on = 0; - -#undef LEDS_ON -#undef LEDS_OFF -#undef LEDS_TOGGLE - -#define LEDS_ON(x) leds_on(x) -#define LEDS_OFF(x) leds_off(x) -#define LEDS_TOGGLE(x) leds_toggle(x) -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINTDEBUG(...) printf(__VA_ARGS__) -#else -#undef LEDS_ON -#undef LEDS_OFF -#undef LEDS_TOGGLE -#define LEDS_ON(x) -#define LEDS_OFF(x) -#define LEDS_TOGGLE(x) -#define PRINTF(...) -#define PRINTDEBUG(...) -#endif - -#if XMAC_CONF_ANNOUNCEMENTS -/* Timers for keeping track of when to send announcements. */ -static struct ctimer announcement_cycle_ctimer, announcement_ctimer; - -static int announcement_radio_txpower; -#endif /* XMAC_CONF_ANNOUNCEMENTS */ - -/* Flag that is used to keep track of whether or not we are listening - for announcements from neighbors. */ -static uint8_t is_listening; - -#if XMAC_CONF_COMPOWER -static struct compower_activity current_packet; -#endif /* XMAC_CONF_COMPOWER */ - -#if WITH_ENCOUNTER_OPTIMIZATION - -#include "lib/list.h" -#include "lib/memb.h" - -struct encounter { - struct encounter *next; - rimeaddr_t neighbor; - rtimer_clock_t time; -}; - -#define MAX_ENCOUNTERS 4 -LIST(encounter_list); -MEMB(encounter_memb, struct encounter, MAX_ENCOUNTERS); -#endif /* WITH_ENCOUNTER_OPTIMIZATION */ - -static uint8_t is_streaming; -static rimeaddr_t is_streaming_to, is_streaming_to_too; -static rtimer_clock_t stream_until; -#define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND) - -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - - -/*---------------------------------------------------------------------------*/ -static void -on(void) -{ - if(xmac_is_on && radio_is_on == 0) { - radio_is_on = 1; - NETSTACK_RADIO.on(); - LEDS_ON(LEDS_RED); - } -} -/*---------------------------------------------------------------------------*/ -static void -off(void) -{ - if(xmac_is_on && radio_is_on != 0 && is_listening == 0 && - is_streaming == 0) { - radio_is_on = 0; - NETSTACK_RADIO.off(); - LEDS_OFF(LEDS_RED); - } -} -/*---------------------------------------------------------------------------*/ -static char powercycle(struct rtimer *t, void *ptr); -static void -schedule_powercycle(struct rtimer *t, rtimer_clock_t time) -{ - int r; - if(xmac_is_on) { - r = rtimer_set(t, RTIMER_TIME(t) + time, 1, - (void (*)(struct rtimer *, void *))powercycle, NULL); - if(r) { - PRINTF("schedule_powercycle: could not set rtimer\n"); - } - } -} -static void -powercycle_turn_radio_off(void) -{ - if(we_are_sending == 0 && - waiting_for_packet == 0) { - off(); - } -#if XMAC_CONF_COMPOWER - compower_accumulate(&compower_idle_activity); -#endif /* XMAC_CONF_COMPOWER */ -} -static void -powercycle_turn_radio_on(void) -{ - if(we_are_sending == 0 && - waiting_for_packet == 0) { - on(); - } -} -static char -powercycle(struct rtimer *t, void *ptr) -{ - if(is_streaming) { - if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until)) { - is_streaming = 0; - rimeaddr_copy(&is_streaming_to, &rimeaddr_null); - rimeaddr_copy(&is_streaming_to_too, &rimeaddr_null); - } - } - - 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 there were a strobe in the air, turn radio on */ - powercycle_turn_radio_on(); - schedule_powercycle(t, xmac_config.on_time); - PT_YIELD(&pt); - - if(xmac_config.off_time > 0 && !NETSTACK_RADIO.receiving_packet()) { - powercycle_turn_radio_off(); - if(waiting_for_packet != 0) { - 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; - powercycle_turn_radio_off(); - } - } - schedule_powercycle(t, xmac_config.off_time); - PT_YIELD(&pt); - } - } - - PT_END(&pt); -} -/*---------------------------------------------------------------------------*/ -#if XMAC_CONF_ANNOUNCEMENTS -static int -parse_announcements(const rimeaddr_t *from) -{ - /* Parse incoming announcements */ - struct announcement_msg adata; - int i; - - memcpy(&adata, packetbuf_dataptr(), MIN(packetbuf_datalen(), sizeof(adata))); - - /* printf("%d.%d: probe from %d.%d with %d announcements\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], - from->u8[0], from->u8[1], adata->num);*/ - /* for(i = 0; i < packetbuf_datalen(); ++i) { - printf("%02x ", ((uint8_t *)packetbuf_dataptr())[i]); - } - printf("\n");*/ - - 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(from, - adata.data[i].id, - adata.data[i].value); - } - return i; -} -/*---------------------------------------------------------------------------*/ -static int -format_announcement(char *hdr) -{ - struct announcement_msg adata; - struct announcement *a; - - /* Construct the announcements */ - /* adata = (struct announcement_msg *)hdr;*/ - - adata.num = 0; - for(a = announcement_list(); - a != NULL && adata.num < ANNOUNCEMENT_MAX; - a = list_item_next(a)) { - adata.data[adata.num].id = a->id; - adata.data[adata.num].value = a->value; - adata.num++; - } - - memcpy(hdr, &adata, sizeof(struct announcement_msg)); - - if(adata.num > 0) { - return ANNOUNCEMENT_MSG_HEADERLEN + - sizeof(struct announcement_data) * adata.num; - } else { - return 0; - } -} -#endif /* XMAC_CONF_ANNOUNCEMENTS */ -/*---------------------------------------------------------------------------*/ -#if WITH_ENCOUNTER_OPTIMIZATION -static void -register_encounter(const rimeaddr_t *neighbor, rtimer_clock_t time) -{ - struct encounter *e; - - /* If we have an entry for this neighbor already, we renew it. */ - for(e = list_head(encounter_list); e != NULL; e = list_item_next(e)) { - if(rimeaddr_cmp(neighbor, &e->neighbor)) { - e->time = time; - break; - } - } - /* No matching encounter was found, so we allocate a new one. */ - if(e == NULL) { - e = memb_alloc(&encounter_memb); - if(e == NULL) { - /* We could not allocate memory for this encounter, so we just drop it. */ - return; - } - rimeaddr_copy(&e->neighbor, neighbor); - e->time = time; - list_add(encounter_list, e); - } -} -#endif /* WITH_ENCOUNTER_OPTIMIZATION */ -/*---------------------------------------------------------------------------*/ -static int -detect_ack(void) -{ -#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000 -#define ACK_LEN 3 -#define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1000 - rtimer_clock_t wt; - uint8_t ack_received = 0; - - wt = RTIMER_NOW(); - leds_on(LEDS_GREEN); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + INTER_PACKET_INTERVAL)) { } - leds_off(LEDS_GREEN); - /* Check for incoming ACK. */ - if((NETSTACK_RADIO.receiving_packet() || - NETSTACK_RADIO.pending_packet() || - NETSTACK_RADIO.channel_clear() == 0)) { - int len; - uint8_t ackbuf[ACK_LEN + 2]; - - 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) { - ack_received = 1; - } - } - if(ack_received) { - leds_toggle(LEDS_RED); - } - return ack_received; -} -/*---------------------------------------------------------------------------*/ -static int -send_packet(void) -{ - rtimer_clock_t t0; - rtimer_clock_t t; - rtimer_clock_t encounter_time = 0; - int strobes; - int ret; -#if 0 - struct xmac_hdr *hdr; -#endif - uint8_t got_strobe_ack = 0; - uint8_t got_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("xmac: send broadcast\n"); - } else { -#if UIP_CONF_IPV6 - PRINTDEBUG("xmac: 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("xmac: 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); */ - - packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); - len = NETSTACK_FRAMER.create(); - strobe_len = len + sizeof(struct xmac_hdr); - if(len < 0 || strobe_len > (int)sizeof(strobe)) { - /* Failed to send */ - PRINTF("xmac: 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("xmac: 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); - if(wait < 2 * DEFAULT_ON_TIME) { - wait = 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 + xmac_config.strobe_time); - strobes++) { - - while(got_strobe_ack == 0 && - RTIMER_CLOCK_LT(RTIMER_NOW(), t + xmac_config.strobe_wait_time)) { -#if 0 - 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("xmac: strobe ack for someone else\n"); - } - } else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/ { - PRINTDEBUG("xmac: strobe from someone else\n"); - collisions++; - } - } else { - PRINTF("xmac: send failed to parse %u\n", len); - } - } -#endif /* 0 */ - } - - t = RTIMER_NOW(); - /* Send the strobe packet. */ - if(got_strobe_ack == 0 && collisions == 0) { - - if(is_broadcast) { -#if WITH_STROBE_BROADCAST - ret = NETSTACK_RADIO.send(strobe, strobe_len); -#else - /* restore the packet to send */ - queuebuf_to_packetbuf(packet); - ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); -#endif - off(); - } else { -#if 0 - rtimer_clock_t wt; -#endif - on(); - ret = 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(); - wt = RTIMER_NOW(); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK)); -#endif /* 0 */ -#if RDC_CONF_HARDWARE_ACK - if(ret == RADIO_TX_OK) { - got_strobe_ack = 1; - } else { - off(); - } -#else - if(detect_ack()) { - got_strobe_ack = 1; - } else { - off(); - } -#endif /* RDC_CONF_HARDWARE_ACK */ - - } - } - } - } - -#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(); - } -#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) { - ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); - - if(!is_broadcast) { -#if RDC_CONF_HARDWARE_ACK - if(ret == RADIO_TX_OK) { - got_ack = 1; - } -#else - if(detect_ack()) { - got_ack = 1; - } -#endif /* RDC_CONF_HARDWARE_ACK */ - } - } - off(); - -#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("xmac: send (strobes=%u,len=%u,%s), done\n", strobes, - packetbuf_totlen(), got_strobe_ack ? "ack" : "no ack"); - -#if XMAC_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 /* XMAC_CONF_COMPOWER */ - - we_are_sending = 0; - - LEDS_OFF(LEDS_BLUE); - if(collisions == 0) { - if(is_broadcast == 0 && got_ack == 0) { - return MAC_TX_NOACK; - } else { - return MAC_TX_OK; - } - } else { - someone_is_sending++; - return MAC_TX_COLLISION; - } - -} -/*---------------------------------------------------------------------------*/ -static void -qsend_packet(mac_callback_t sent, void *ptr) -{ - int ret; - - 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); - RIMESTATS_ADD(sendingdrop); - ret = MAC_TX_COLLISION; - } else { - PRINTF("xmac: send immediately.\n"); - ret = send_packet(); - } - - mac_call_sent_callback(sent, ptr, ret, 1); -} -/*---------------------------------------------------------------------------*/ -static void -qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list) -{ - if(buf_list != NULL) { - queuebuf_to_packetbuf(buf_list->buf); - qsend_packet(sent, ptr); - } -} -/*---------------------------------------------------------------------------*/ -static void -input_packet(void) -{ - struct xmac_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(); - - /* Check for duplicate packet. */ - if(mac_sequence_is_duplicate()) { - /* Drop the packet. */ - return; - } - mac_sequence_register_seqno(); - -#if XMAC_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 /* XMAC_CONF_COMPOWER */ - - waiting_for_packet = 0; - - PRINTDEBUG("xmac: data(%u)\n", packetbuf_datalen()); - NETSTACK_MAC.input(); - return; - } else { - PRINTDEBUG("xmac: 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. */ - waiting_for_packet = 1; -#if 0 - 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("xmac: send strobe ack %u\n", packetbuf_totlen()); - } else { - PRINTF("xmac: failed to send strobe ack\n"); - } -#endif /* 0 */ - } 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("xmac: strobe not for us\n"); - } - - /* We are done processing the strobe and we therefore return - to the caller. */ - return; -#if XMAC_CONF_ANNOUNCEMENTS - } else if(hdr->type == TYPE_ANNOUNCEMENT) { - packetbuf_hdrreduce(sizeof(struct xmac_hdr)); - parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER)); -#endif /* XMAC_CONF_ANNOUNCEMENTS */ - } else if(hdr->type == TYPE_STROBE_ACK) { - PRINTDEBUG("xmac: stray strobe ack\n"); - } else { - PRINTF("xmac: unknown type %u (%u/%u)\n", hdr->type, - packetbuf_datalen(), len); - } - } else { - PRINTF("xmac: failed to parse (%u)\n", packetbuf_totlen()); - } -} -/*---------------------------------------------------------------------------*/ -#if XMAC_CONF_ANNOUNCEMENTS -static void -send_announcement(void *ptr) -{ - struct xmac_hdr *hdr; - int announcement_len; - - /* Set up the probe header. */ - packetbuf_clear(); - hdr = packetbuf_dataptr(); - - announcement_len = format_announcement((char *)hdr + - sizeof(struct xmac_hdr)); - - if(announcement_len > 0) { - packetbuf_set_datalen(sizeof(struct xmac_hdr) + announcement_len); - hdr->dispatch = DISPATCH; - hdr->type = TYPE_ANNOUNCEMENT; - - packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr); - packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &rimeaddr_null); - packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER, announcement_radio_txpower); - if(NETSTACK_FRAMER.create() >= 0) { - NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); - } - } -} -/*---------------------------------------------------------------------------*/ -static void -cycle_announcement(void *ptr) -{ - ctimer_set(&announcement_ctimer, ANNOUNCEMENT_TIME, - send_announcement, NULL); - ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_PERIOD, - cycle_announcement, NULL); - if(is_listening > 0) { - is_listening--; - /* printf("is_listening %d\n", is_listening);*/ - } -} -/*---------------------------------------------------------------------------*/ -static void -listen_callback(int periods) -{ - is_listening = periods + 1; -} -#endif /* XMAC_CONF_ANNOUNCEMENTS */ -/*---------------------------------------------------------------------------*/ -void -xmac_set_announcement_radio_txpower(int txpower) -{ -#if XMAC_CONF_ANNOUNCEMENTS - announcement_radio_txpower = txpower; -#endif /* XMAC_CONF_ANNOUNCEMENTS */ -} -/*---------------------------------------------------------------------------*/ -static void -init(void) -{ - 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; - -#if WITH_ENCOUNTER_OPTIMIZATION - list_init(encounter_list); - memb_init(&encounter_memb); -#endif /* WITH_ENCOUNTER_OPTIMIZATION */ - -#if XMAC_CONF_ANNOUNCEMENTS - announcement_register_listen_callback(listen_callback); - ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_TIME, - cycle_announcement, NULL); -#endif /* XMAC_CONF_ANNOUNCEMENTS */ -} -/*---------------------------------------------------------------------------*/ -static int -turn_on(void) -{ - xmac_is_on = 1; - rtimer_set(&rt, RTIMER_NOW() + xmac_config.off_time, 1, - (void (*)(struct rtimer *, void *))powercycle, NULL); - return 1; -} -/*---------------------------------------------------------------------------*/ -static int -turn_off(int keep_radio_on) -{ - xmac_is_on = 0; - if(keep_radio_on) { - return NETSTACK_RADIO.on(); - } else { - return NETSTACK_RADIO.off(); - } -} -/*---------------------------------------------------------------------------*/ -static unsigned short -channel_check_interval(void) -{ - return (1ul * CLOCK_SECOND * DEFAULT_PERIOD) / RTIMER_ARCH_SECOND; -} -/*---------------------------------------------------------------------------*/ -const struct rdc_driver xmac_driver = - { - "X-MAC", - init, - qsend_packet, - qsend_list, - input_packet, - turn_on, - turn_off, - channel_check_interval, - }; diff --git a/core/net/mac/xmac.h b/core/net/mac/xmac.h deleted file mode 100644 index 93991c391..000000000 --- a/core/net/mac/xmac.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2007, 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. - * - */ - -/** - * \file - * A simple power saving MAC protocol based on X-MAC [SenSys 2006] - * \author - * Adam Dunkels - */ - -#ifndef XMAC_H_ -#define XMAC_H_ - -#include "sys/rtimer.h" -#include "net/mac/rdc.h" -#include "dev/radio.h" - -#define XMAC_RECEIVER "xmac.recv" -#define XMAC_STROBES "xmac.strobes" -#define XMAC_SEND_WITH_ACK "xmac.send.ack" -#define XMAC_SEND_WITH_NOACK "xmac.send.noack" - - -struct xmac_config { - rtimer_clock_t on_time; - rtimer_clock_t off_time; - rtimer_clock_t strobe_time; - rtimer_clock_t strobe_wait_time; -}; - -extern const struct rdc_driver xmac_driver; - -void xmac_set_announcement_radio_txpower(int txpower); - -#endif /* XMAC_H_ */ diff --git a/core/net/uip6.c b/core/net/uip6.c index aa1ac4a2e..f3f29ebf1 100644 --- a/core/net/uip6.c +++ b/core/net/uip6.c @@ -1832,8 +1832,12 @@ uip_process(uint8_t flag) UIP_TCP_BUF->seqno[2] != uip_connr->rcv_nxt[2] || UIP_TCP_BUF->seqno[3] != uip_connr->rcv_nxt[3])) { - if(UIP_TCP_BUF->flags & TCP_SYN) { - goto tcp_send_synack; + if((UIP_TCP_BUF->flags & TCP_SYN)) { + if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_RCVD) { + goto tcp_send_synack; + } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) { + goto tcp_send_syn; + } } goto tcp_send_ack; } @@ -2315,12 +2319,23 @@ uip_send(const void *data, int len) { int copylen; #define MIN(a,b) ((a) < (b)? (a): (b)) - copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - - (int)((char *)uip_sappdata - (char *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN])); + + if(uip_sappdata != NULL) { + copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - + (int)((char *)uip_sappdata - + (char *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN])); + } else { + copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN); + } if(copylen > 0) { uip_slen = copylen; if(data != uip_sappdata) { - memcpy(uip_sappdata, (data), uip_slen); + if(uip_sappdata == NULL) { + memcpy((char *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN], + (data), uip_slen); + } else { + memcpy(uip_sappdata, (data), uip_slen); + } } } } diff --git a/core/net/uipopt.h b/core/net/uipopt.h index 39a49a55f..d496f4a42 100644 --- a/core/net/uipopt.h +++ b/core/net/uipopt.h @@ -144,7 +144,11 @@ * * This should normally not be changed. */ +#ifdef UIP_CONF_TTL +#define UIP_TTL UIP_CONF_TTL +#else /* UIP_CONF_TTL */ #define UIP_TTL 64 +#endif /* UIP_CONF_TTL */ /** * The maximum time an IP fragment should wait in the reassembly @@ -378,7 +382,10 @@ * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. */ #ifdef UIP_CONF_TCP_MSS -#define UIP_TCP_MSS (UIP_CONF_TCP_MSS) +#if UIP_CONF_TCP_MSS < (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) +#error UIP_CONF_TCP_MSS is too large for the current UIP_BUFSIZE +#endif /* UIP_CONF_TCP_MSS < (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) */ +#define UIP_TCP_MSS (UIP_CONF_TCP_MSS) #else #define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) #endif diff --git a/cpu/cc2538/cc2538.lds b/cpu/cc2538/cc2538.lds index f63eb2d17..635ec454b 100644 --- a/cpu/cc2538/cc2538.lds +++ b/cpu/cc2538/cc2538.lds @@ -34,17 +34,22 @@ * ld script, which is called cc2538.ld and will be in the project directory */ #if (LPM_CONF_MAX_PM==2) && (LPM_CONF_ENABLE != 0) -#define SRAM_START 0x20004000 -#define SRAM_LEN 0x00004000 +#define NRSRAM_START 0x20000000 +#define NRSRAM_LEN 0x00004000 +#define SRAM_START 0x20004000 +#define SRAM_LEN 0x00004000 #else -#define SRAM_START 0x20000000 -#define SRAM_LEN 0x00008000 +#define SRAM_START 0x20000000 +#define SRAM_LEN 0x00008000 #endif MEMORY { FLASH (rx) : ORIGIN = 0x200000, LENGTH = 0x0007FFD4 - FLASH_CCA (RX) : ORIGIN = 0x0027FFD4, LENGTH = 12 + FLASH_CCA (RX) : ORIGIN = 0x0027FFD4, LENGTH = 44 +#if (LPM_CONF_MAX_PM==2) && (LPM_CONF_ENABLE != 0) + NRSRAM (RWX) : ORIGIN = NRSRAM_START, LENGTH = NRSRAM_LEN +#endif SRAM (RWX) : ORIGIN = SRAM_START, LENGTH = SRAM_LEN } @@ -80,6 +85,15 @@ SECTIONS _ebss = .; } > SRAM +#if (LPM_CONF_MAX_PM==2) && (LPM_CONF_ENABLE != 0) + .nrdata : + { + _nrdata = .; + *(.nrdata*) + _enrdata = .; + } > NRSRAM +#endif + .flashcca : { KEEP(*(.flashcca)) diff --git a/cpu/cc2538/dev/flash-cca.h b/cpu/cc2538/dev/flash-cca.h new file mode 100644 index 000000000..2dff2978b --- /dev/null +++ b/cpu/cc2538/dev/flash-cca.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Copyright (c) 2013, ADVANSEE - http://www.advansee.com/ + * Benoît Thébaudeau + * 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 copyright holder 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ +/** + * \addtogroup cc2538 + * @{ + * + * \defgroup cc2538-flash-cca cc2538 flash CCA + * + * Definitions for the cc2538 flash lock bit page and customer configuration + * area + * @{ + * + * \file + * Header file for the flash lock bit page and CCA definitions + */ +#ifndef FLASH_CCA_H_ +#define FLASH_CCA_H_ + +#include +/*---------------------------------------------------------------------------*/ +/** \name Bootloader backdoor configuration bit fields + * @{ + */ +#define FLASH_CCA_BOOTLDR_CFG_DISABLE 0xEFFFFFFF /**< Disable backdoor function */ +#define FLASH_CCA_BOOTLDR_CFG_ENABLE 0xF0FFFFFF /**< Enable backdoor function */ +#define FLASH_CCA_BOOTLDR_CFG_ACTIVE_HIGH 0x08000000 /**< Selected pin on pad A active high */ +#define FLASH_CCA_BOOTLDR_CFG_PORT_A_PIN_M 0x07000000 /**< Selected pin on pad A mask */ +#define FLASH_CCA_BOOTLDR_CFG_PORT_A_PIN_S 24 /**< Selected pin on pad A shift */ +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name Image valid definitions + * @{ + */ +#define FLASH_CCA_IMAGE_VALID 0x00000000 /**< Indicates valid image in flash */ +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name Lock page / debug definitions + * @{ + */ +#define FLASH_CCA_LOCKED 0 /**< Page or debug locked if bit == 0 */ +#define FLASH_CCA_LOCK_DEBUG_BYTE 31 /**< Lock byte containing the debug lock bit */ +#define FLASH_CCA_LOCK_DEBUG_BIT 7 /**< Debug lock bit position in the corresponding lock byte */ +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name Flash lock bit page and CCA layout + * @{ + */ +typedef struct { + uint32_t bootldr_cfg; /**< Bootloader backdoor configuration (page bytes 2004 - 2007) */ + uint32_t image_valid; /**< Image valid (page bytes 2008 - 2011) */ + const void *app_entry_point; /**< Flash vector table address (page bytes 2012 - 2015) */ + uint8_t lock[32]; /**< Page and debug lock bits (page bytes 2016 - 2047) */ +} flash_cca_lock_page_t; +/** @} */ + +#endif /* FLASH_CCA_H_ */ + +/** + * @} + * @} + */ diff --git a/cpu/cc2538/dev/gpio.c b/cpu/cc2538/dev/gpio.c index 80a1b7d8d..2961a2eb0 100644 --- a/cpu/cc2538/dev/gpio.c +++ b/cpu/cc2538/dev/gpio.c @@ -83,13 +83,14 @@ notify(uint8_t mask, uint8_t port) void gpio_port_a_isr() { - ENERGEST_ON(ENERGEST_TYPE_IRQ); - lpm_exit(); + ENERGEST_ON(ENERGEST_TYPE_IRQ); + notify(REG(GPIO_A_BASE | GPIO_MIS), GPIO_A_NUM); GPIO_CLEAR_INTERRUPT(GPIO_A_BASE, 0xFF); + GPIO_CLEAR_POWER_UP_INTERRUPT(GPIO_A_NUM, 0xFF); ENERGEST_OFF(ENERGEST_TYPE_IRQ); } @@ -98,13 +99,14 @@ gpio_port_a_isr() void gpio_port_b_isr() { - ENERGEST_ON(ENERGEST_TYPE_IRQ); - lpm_exit(); + ENERGEST_ON(ENERGEST_TYPE_IRQ); + notify(REG(GPIO_B_BASE | GPIO_MIS), GPIO_B_NUM); GPIO_CLEAR_INTERRUPT(GPIO_B_BASE, 0xFF); + GPIO_CLEAR_POWER_UP_INTERRUPT(GPIO_B_NUM, 0xFF); ENERGEST_OFF(ENERGEST_TYPE_IRQ); } @@ -113,13 +115,14 @@ gpio_port_b_isr() void gpio_port_c_isr() { - ENERGEST_ON(ENERGEST_TYPE_IRQ); - lpm_exit(); + ENERGEST_ON(ENERGEST_TYPE_IRQ); + notify(REG(GPIO_C_BASE | GPIO_MIS), GPIO_C_NUM); GPIO_CLEAR_INTERRUPT(GPIO_C_BASE, 0xFF); + GPIO_CLEAR_POWER_UP_INTERRUPT(GPIO_C_NUM, 0xFF); ENERGEST_OFF(ENERGEST_TYPE_IRQ); } @@ -128,13 +131,14 @@ gpio_port_c_isr() void gpio_port_d_isr() { - ENERGEST_ON(ENERGEST_TYPE_IRQ); - lpm_exit(); + ENERGEST_ON(ENERGEST_TYPE_IRQ); + notify(REG(GPIO_D_BASE | GPIO_MIS), GPIO_D_NUM); GPIO_CLEAR_INTERRUPT(GPIO_D_BASE, 0xFF); + GPIO_CLEAR_POWER_UP_INTERRUPT(GPIO_D_NUM, 0xFF); ENERGEST_OFF(ENERGEST_TYPE_IRQ); } diff --git a/cpu/cc2538/dev/gpio.h b/cpu/cc2538/dev/gpio.h index c81482c9e..8a61f668b 100644 --- a/cpu/cc2538/dev/gpio.h +++ b/cpu/cc2538/dev/gpio.h @@ -214,6 +214,51 @@ typedef void (* gpio_callback_t)(uint8_t port, uint8_t pin); #define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK) \ do { REG((PORT_BASE) | GPIO_AFSEL) &= ~(PIN_MASK); } while(0) +/** \brief Set pins with PIN_MASK of port PORT to trigger a power-up interrupt + * on rising edge. + * \param PORT GPIO Port (not port base address) + * \param PIN_MASK Pin number mask. Pin 0: 0x01, Pin 1: 0x02 ... Pin 7: 0x80 + */ +#define GPIO_POWER_UP_ON_RISING(PORT, PIN_MASK) \ + do { REG(GPIO_PORT_TO_BASE(PORT) | GPIO_P_EDGE_CTRL) &= \ + ~((PIN_MASK) << ((PORT) << 3)); } while(0) + +/** \brief Set pins with PIN_MASK of port PORT to trigger a power-up interrupt + * on falling edge. + * \param PORT GPIO Port (not port base address) + * \param PIN_MASK Pin number mask. Pin 0: 0x01, Pin 1: 0x02 ... Pin 7: 0x80 + */ +#define GPIO_POWER_UP_ON_FALLING(PORT, PIN_MASK) \ + do { REG(GPIO_PORT_TO_BASE(PORT) | GPIO_P_EDGE_CTRL) |= \ + (PIN_MASK) << ((PORT) << 3); } while(0) + +/** \brief Enable power-up interrupt triggering for pins with PIN_MASK of port + * PORT. + * \param PORT GPIO Port (not port base address) + * \param PIN_MASK Pin number mask. Pin 0: 0x01, Pin 1: 0x02 ... Pin 7: 0x80 + */ +#define GPIO_ENABLE_POWER_UP_INTERRUPT(PORT, PIN_MASK) \ + do { REG(GPIO_PORT_TO_BASE(PORT) | GPIO_PI_IEN) |= \ + (PIN_MASK) << ((PORT) << 3); } while(0) + +/** \brief Disable power-up interrupt triggering for pins with PIN_MASK of port + * PORT. + * \param PORT GPIO Port (not port base address) + * \param PIN_MASK Pin number mask. Pin 0: 0x01, Pin 1: 0x02 ... Pin 7: 0x80 + */ +#define GPIO_DISABLE_POWER_UP_INTERRUPT(PORT, PIN_MASK) \ + do { REG(GPIO_PORT_TO_BASE(PORT) | GPIO_PI_IEN) &= \ + ~((PIN_MASK) << ((PORT) << 3)); } while(0) + +/** \brief Clear power-up interrupt triggering for pins with PIN_MASK of port + * PORT. + * \param PORT GPIO Port (not port base address) + * \param PIN_MASK Pin number mask. Pin 0: 0x01, Pin 1: 0x02 ... Pin 7: 0x80 + */ +#define GPIO_CLEAR_POWER_UP_INTERRUPT(PORT, PIN_MASK) \ + do { REG(GPIO_PORT_TO_BASE(PORT) | GPIO_IRQ_DETECT_ACK) = \ + (PIN_MASK) << ((PORT) << 3); } while(0) + /** * \brief Converts a pin number to a pin mask * \param The pin number in the range [0..7] diff --git a/cpu/cc2538/dev/spi.c b/cpu/cc2538/dev/spi.c index 191c77a62..8d7dca49b 100644 --- a/cpu/cc2538/dev/spi.c +++ b/cpu/cc2538/dev/spi.c @@ -42,6 +42,15 @@ #include "dev/ssi.h" #include "dev/gpio.h" +#define SPI_CLK_PORT_BASE GPIO_PORT_TO_BASE(SPI_CLK_PORT) +#define SPI_CLK_PIN_MASK GPIO_PIN_MASK(SPI_CLK_PIN) +#define SPI_MOSI_PORT_BASE GPIO_PORT_TO_BASE(SPI_MOSI_PORT) +#define SPI_MOSI_PIN_MASK GPIO_PIN_MASK(SPI_MOSI_PIN) +#define SPI_MISO_PORT_BASE GPIO_PORT_TO_BASE(SPI_MISO_PORT) +#define SPI_MISO_PIN_MASK GPIO_PIN_MASK(SPI_MISO_PIN) +#define SPI_SEL_PORT_BASE GPIO_PORT_TO_BASE(SPI_SEL_PORT) +#define SPI_SEL_PIN_MASK GPIO_PIN_MASK(SPI_SEL_PIN) + /* Default: Motorola mode 3 with 8-bit data words */ #ifndef SPI_CONF_PHASE #define SPI_CONF_PHASE SSI_CR0_SPH @@ -61,10 +70,10 @@ * \brief Initialize the SPI bus. * * This SPI init() function uses the following #defines to set the pins: - * CC2538_SPI_CLK_PORT_NUM CC2538_SPI_CLK_PIN_NUM - * CC2538_SPI_MOSI_PORT_NUM CC2538_SPI_MOSI_PIN_NUM - * CC2538_SPI_MISO_PORT_NUM CC2538_SPI_MISO_PIN_NUM - * CC2538_SPI_SEL_PORT_NUM CC2538_SPI_SEL_PIN_NUM + * SPI_CLK_PORT SPI_CLK_PIN + * SPI_MOSI_PORT SPI_MOSI_PIN + * SPI_MISO_PORT SPI_MISO_PIN + * SPI_SEL_PORT SPI_SEL_PIN * * This sets the mode to Motorola SPI with the following format options: * SPI_CONF_PHASE: 0 or SSI_CR0_SPH @@ -83,22 +92,22 @@ spi_init(void) REG(SSI0_BASE + SSI_CC) = 1; /* Set the mux correctly to connect the SSI pins to the correct GPIO pins */ - ioc_set_sel(CC2538_SPI_CLK_PORT_NUM, CC2538_SPI_CLK_PIN_NUM, IOC_PXX_SEL_SSI0_CLKOUT); - ioc_set_sel(CC2538_SPI_MOSI_PORT_NUM, CC2538_SPI_MOSI_PIN_NUM, IOC_PXX_SEL_SSI0_TXD); - REG(IOC_SSIRXD_SSI0) = (CC2538_SPI_MISO_PORT_NUM * 8) + CC2538_SPI_MISO_PIN_NUM; - ioc_set_sel(CC2538_SPI_SEL_PORT_NUM, CC2538_SPI_SEL_PIN_NUM, IOC_PXX_SEL_SSI0_FSSOUT); + ioc_set_sel(SPI_CLK_PORT, SPI_CLK_PIN, IOC_PXX_SEL_SSI0_CLKOUT); + ioc_set_sel(SPI_MOSI_PORT, SPI_MOSI_PIN, IOC_PXX_SEL_SSI0_TXD); + REG(IOC_SSIRXD_SSI0) = (SPI_MISO_PORT * 8) + SPI_MISO_PIN; + ioc_set_sel(SPI_SEL_PORT, SPI_SEL_PIN, IOC_PXX_SEL_SSI0_FSSOUT); /* Put all the SSI gpios into peripheral mode */ - GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(CC2538_SPI_CLK_PORT_NUM), GPIO_PIN_MASK(CC2538_SPI_CLK_PIN_NUM)); - GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(CC2538_SPI_MOSI_PORT_NUM), GPIO_PIN_MASK(CC2538_SPI_MOSI_PIN_NUM)); - GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(CC2538_SPI_MISO_PORT_NUM), GPIO_PIN_MASK(CC2538_SPI_MISO_PIN_NUM)); - GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(CC2538_SPI_SEL_PORT_NUM), GPIO_PIN_MASK(CC2538_SPI_SEL_PIN_NUM)); + GPIO_PERIPHERAL_CONTROL(SPI_CLK_PORT_BASE, SPI_CLK_PIN_MASK); + GPIO_PERIPHERAL_CONTROL(SPI_MOSI_PORT_BASE, SPI_MOSI_PIN_MASK); + GPIO_PERIPHERAL_CONTROL(SPI_MISO_PORT_BASE, SPI_MISO_PIN_MASK); + GPIO_PERIPHERAL_CONTROL(SPI_SEL_PORT_BASE, SPI_SEL_PIN_MASK); /* Disable any pull ups or the like */ - ioc_set_over(CC2538_SPI_CLK_PORT_NUM, CC2538_SPI_CLK_PIN_NUM, IOC_OVERRIDE_DIS); - ioc_set_over(CC2538_SPI_MOSI_PORT_NUM, CC2538_SPI_MOSI_PIN_NUM, IOC_OVERRIDE_DIS); - ioc_set_over(CC2538_SPI_MISO_PORT_NUM, CC2538_SPI_MISO_PIN_NUM, IOC_OVERRIDE_DIS); - ioc_set_over(CC2538_SPI_SEL_PORT_NUM, CC2538_SPI_SEL_PIN_NUM, IOC_OVERRIDE_DIS); + ioc_set_over(SPI_CLK_PORT, SPI_CLK_PIN, IOC_OVERRIDE_DIS); + ioc_set_over(SPI_MOSI_PORT, SPI_MOSI_PIN, IOC_OVERRIDE_DIS); + ioc_set_over(SPI_MISO_PORT, SPI_MISO_PIN, IOC_OVERRIDE_DIS); + ioc_set_over(SPI_SEL_PORT, SPI_SEL_PIN, IOC_OVERRIDE_DIS); /* Configure the clock */ REG(SSI0_BASE + SSI_CPSR) = 2; diff --git a/cpu/cc2538/dev/uart.c b/cpu/cc2538/dev/uart.c index 304f717db..2354e565c 100644 --- a/cpu/cc2538/dev/uart.c +++ b/cpu/cc2538/dev/uart.c @@ -50,6 +50,18 @@ static int (* input_handler)(unsigned char c); /*---------------------------------------------------------------------------*/ +#define UART_RX_PORT_BASE GPIO_PORT_TO_BASE(UART_RX_PORT) +#define UART_RX_PIN_MASK GPIO_PIN_MASK(UART_RX_PIN) + +#define UART_TX_PORT_BASE GPIO_PORT_TO_BASE(UART_TX_PORT) +#define UART_TX_PIN_MASK GPIO_PIN_MASK(UART_TX_PIN) + +#define UART_CTS_PORT_BASE GPIO_PORT_TO_BASE(UART_CTS_PORT) +#define UART_CTS_PIN_MASK GPIO_PIN_MASK(UART_CTS_PIN) + +#define UART_RTS_PORT_BASE GPIO_PORT_TO_BASE(UART_RTS_PORT) +#define UART_RTS_PIN_MASK GPIO_PIN_MASK(UART_RTS_PIN) +/*---------------------------------------------------------------------------*/ /* * Once we know what UART we're on, configure correct values to be written to * the correct registers @@ -138,8 +150,8 @@ uart_init(void) ioc_set_over(UART_TX_PORT, UART_TX_PIN, IOC_OVERRIDE_OE); /* Set RX and TX pins to peripheral mode */ - GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(UART_TX_PORT), GPIO_PIN_MASK(UART_TX_PIN)); - GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(UART_RX_PORT), GPIO_PIN_MASK(UART_RX_PIN)); + GPIO_PERIPHERAL_CONTROL(UART_TX_PORT_BASE, UART_TX_PIN_MASK); + GPIO_PERIPHERAL_CONTROL(UART_RX_PORT_BASE, UART_RX_PIN_MASK); /* * UART Interrupt Masks: diff --git a/cpu/cc2538/lpm.c b/cpu/cc2538/lpm.c index bbc035219..80b536998 100644 --- a/cpu/cc2538/lpm.c +++ b/cpu/cc2538/lpm.c @@ -158,16 +158,28 @@ enter_pm0(void) static void select_32_mhz_xosc(void) { + /*First, make sure there is no ongoing clock source change */ + while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0); + /* Turn on the 32 MHz XOSC and source the system clock on it. */ REG(SYS_CTRL_CLOCK_CTRL) &= ~SYS_CTRL_CLOCK_CTRL_OSC; /* Wait for the switch to take place */ while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_OSC) != 0); + + /* Power down the unused oscillator. */ + REG(SYS_CTRL_CLOCK_CTRL) |= SYS_CTRL_CLOCK_CTRL_OSC_PD; } /*---------------------------------------------------------------------------*/ static void select_16_mhz_rcosc(void) { + /* + * Power up both oscillators in order to speed up the transition to the 32-MHz + * XOSC after wake up. + */ + REG(SYS_CTRL_CLOCK_CTRL) &= ~SYS_CTRL_CLOCK_CTRL_OSC_PD; + /*First, make sure there is no ongoing clock source change */ while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0); @@ -187,6 +199,16 @@ lpm_exit() return; } + /* + * When returning from PM1/2, the sleep timer value (used by RTIMER_NOW()) is + * not up-to-date until a positive edge on the 32-kHz clock has been detected + * after the system clock restarted. To ensure an updated value is read, wait + * for a positive transition on the 32-kHz clock by polling the + * SYS_CTRL_CLOCK_STA.SYNC_32K bit, before reading the sleep timer value. + */ + while(REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYNC_32K); + while(!(REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYNC_32K)); + LPM_STATS_ADD(REG(SYS_CTRL_PMCTL) & SYS_CTRL_PMCTL_PM3, RTIMER_NOW() - sleep_enter_time); @@ -301,6 +323,11 @@ lpm_enter() select_32_mhz_xosc(); REG(SYS_CTRL_PMCTL) = SYS_CTRL_PMCTL_PM0; + + /* Remember IRQ energest for next pass */ + ENERGEST_IRQ_SAVE(irq_energest); + ENERGEST_ON(ENERGEST_TYPE_CPU); + ENERGEST_OFF(ENERGEST_TYPE_LPM); } else { /* All clear. Assert WFI and drop to PM1/2. This is now un-interruptible */ assert_wfi(); diff --git a/cpu/cc2538/lpm.h b/cpu/cc2538/lpm.h index 22b4d4958..0c497b5be 100644 --- a/cpu/cc2538/lpm.h +++ b/cpu/cc2538/lpm.h @@ -126,6 +126,12 @@ void lpm_init(void); * lpm_exit(), which will always be called from within the Sleep Timer ISR * context. * + * \note Dropping to PM2 means that data in the SRAM non-retention area will + * be lost. It is recommended to disable PM2 if the total RAM footprint is + * larger than what will fit in the retention area. + * .nrdata* sections can be used to place uninitialized data in the SRAM + * non-retention area. + * * \sa main(), rtimer_arch_next_trigger(), lpm_exit(), lpm_set_max_pm() */ void lpm_enter(void); @@ -144,6 +150,12 @@ void lpm_enter(void); * interrupt. This may lead to other parts of the code trying to use the RF, * so we need to switch the clock source \e before said code gets executed. * + * This function also makes sure that the sleep timer value is up-to-date + * following wake-up from PM1/2 so that RTIMER_NOW() works. + * + * \note This function should be called at the very beginning of ISRs waking up + * the SoC in order to restore all clocks and timers. + * * \sa lpm_enter(), rtimer_isr() */ void lpm_exit(void); diff --git a/cpu/cc2538/rtimer-arch.c b/cpu/cc2538/rtimer-arch.c index 2407b64b6..ffb221024 100644 --- a/cpu/cc2538/rtimer-arch.c +++ b/cpu/cc2538/rtimer-arch.c @@ -136,13 +136,6 @@ rtimer_arch_now() void rtimer_isr() { - ENERGEST_ON(ENERGEST_TYPE_IRQ); - - next_trigger = 0; - - nvic_interrupt_unpend(NVIC_INT_SM_TIMER); - nvic_interrupt_disable(NVIC_INT_SM_TIMER); - /* * If we were in PM1+, call the wake-up sequence first. This will make sure * that the 32MHz OSC is selected as the clock source. We need to do this @@ -150,6 +143,13 @@ rtimer_isr() */ lpm_exit(); + ENERGEST_ON(ENERGEST_TYPE_IRQ); + + next_trigger = 0; + + nvic_interrupt_unpend(NVIC_INT_SM_TIMER); + nvic_interrupt_disable(NVIC_INT_SM_TIMER); + rtimer_run_next(); ENERGEST_OFF(ENERGEST_TYPE_IRQ); diff --git a/cpu/cc2538/usb/usb-arch.c b/cpu/cc2538/usb/usb-arch.c index 46b7bbd61..c209d7778 100644 --- a/cpu/cc2538/usb/usb-arch.c +++ b/cpu/cc2538/usb/usb-arch.c @@ -54,6 +54,13 @@ #include #include /*---------------------------------------------------------------------------*/ +#ifdef USB_PULLUP_PORT +#define USB_PULLUP_PORT_BASE GPIO_PORT_TO_BASE(USB_PULLUP_PORT) +#endif +#ifdef USB_PULLUP_PIN +#define USB_PULLUP_PIN_MASK GPIO_PIN_MASK(USB_PULLUP_PIN) +#endif +/*---------------------------------------------------------------------------*/ /* EP max FIFO sizes without double buffering */ #if CTRL_EP_SIZE > 32 #error Control endpoint size too big @@ -329,9 +336,11 @@ usb_arch_setup(void) /* Wait until USB PLL is stable */ while(!(REG(USB_CTRL) & USB_CTRL_PLL_LOCKED)); - /* Enable pull-up on usb port */ - GPIO_SET_OUTPUT(USB_PULLUP_PORT, USB_PULLUP_PIN_MASK); - GPIO_SET_PIN(USB_PULLUP_PORT, USB_PULLUP_PIN_MASK); + /* Enable pull-up on usb port if driven by GPIO */ +#if defined(USB_PULLUP_PORT_BASE) && defined(USB_PULLUP_PIN_MASK) + GPIO_SET_OUTPUT(USB_PULLUP_PORT_BASE, USB_PULLUP_PIN_MASK); + GPIO_SET_PIN(USB_PULLUP_PORT_BASE, USB_PULLUP_PIN_MASK); +#endif for(i = 0; i < USB_MAX_ENDPOINTS; i++) { usb_endpoints[i].flags = 0; diff --git a/platform/cc2538dk/README.md b/platform/cc2538dk/README.md index ada90abd1..18273d2b6 100644 --- a/platform/cc2538dk/README.md +++ b/platform/cc2538dk/README.md @@ -410,7 +410,6 @@ LPM is highly related to the operations of the Radio Duty Cycling (RDC) driver o * With ContikiMAC, PMs 0/1/2 are supported subject to user configuration. * When NullRDC is in use, the radio will be always on. As a result, the algorithm discussed above will always choose PM0 and will never attempt to drop to PM1/2. -* The LPP driver is also supported but in order to use it, one needs to set `LPM_CONF_MAX_PM` to 0. Setting a higher value will result in "Sleep Forever" situations. This is inefficient and as a result LPP is not recommended for situations requiring low energy consumption. The main reason for this behaviour is a [bug in LPP][lpp-rf-off-bug]. Once this has been resolved, simple modifications to the LPM module will be implemented to support all three PMs under LPP. Build headless nodes -------------------- @@ -458,4 +457,3 @@ More Reading [cc2538]: http://www.ti.com/product/cc2538 "CC2538" [uniflash]: http://processors.wiki.ti.com/index.php/Category:CCS_UniFlash "UniFlash" [pandoc]: http://johnmacfarlane.net/pandoc/ "Pandoc - a universal document converter" -[lpp-rf-off-bug]: https://github.com/contiki-os/contiki/issues/104 "LPP RF off() bug" diff --git a/platform/cc2538dk/contiki-conf.h b/platform/cc2538dk/contiki-conf.h index 86e8bd3fc..af15801b0 100644 --- a/platform/cc2538dk/contiki-conf.h +++ b/platform/cc2538dk/contiki-conf.h @@ -112,6 +112,7 @@ typedef uint32_t rtimer_clock_t; #define SLIP_BRIDGE_CONF_NO_PUTCHAR 1 #define SLIP_RADIO_CONF_NO_PUTCHAR 1 +#ifndef SLIP_ARCH_CONF_ENABLED /* * Determine whether we need SLIP * This will keep working while UIP_FALLBACK_INTERFACE and CMD_CONF_OUTPUT @@ -120,6 +121,7 @@ typedef uint32_t rtimer_clock_t; #if defined (UIP_FALLBACK_INTERFACE) || defined (CMD_CONF_OUTPUT) #define SLIP_ARCH_CONF_ENABLED 1 #endif +#endif /* * When set, the radio turns off address filtering and sends all captured diff --git a/platform/cc2538dk/dev/board.h b/platform/cc2538dk/dev/board.h index 1a4703392..b36ce9bbb 100644 --- a/platform/cc2538dk/dev/board.h +++ b/platform/cc2538dk/dev/board.h @@ -97,9 +97,8 @@ * * The USB pullup is driven by PC0 and is shared with LED1 */ -#define USB_PULLUP_PORT GPIO_C_BASE +#define USB_PULLUP_PORT GPIO_C_NUM #define USB_PULLUP_PIN 0 -#define USB_PULLUP_PIN_MASK GPIO_PIN_MASK(USB_PULLUP_PIN) /** @} */ /*---------------------------------------------------------------------------*/ /** \name UART configuration @@ -140,38 +139,28 @@ * @{ */ /** BUTTON_SELECT -> PA3 */ -#define BUTTON_SELECT_PORT_NO GPIO_A_NUM +#define BUTTON_SELECT_PORT GPIO_A_NUM #define BUTTON_SELECT_PIN 3 -#define BUTTON_SELECT_PORT GPIO_A_BASE -#define BUTTON_SELECT_PIN_MASK GPIO_PIN_MASK(BUTTON_SELECT_PIN) #define BUTTON_SELECT_VECTOR NVIC_INT_GPIO_PORT_A /** BUTTON_LEFT -> PC4 */ -#define BUTTON_LEFT_PORT_NO GPIO_C_NUM +#define BUTTON_LEFT_PORT GPIO_C_NUM #define BUTTON_LEFT_PIN 4 -#define BUTTON_LEFT_PORT GPIO_C_BASE -#define BUTTON_LEFT_PIN_MASK GPIO_PIN_MASK(BUTTON_LEFT_PIN) #define BUTTON_LEFT_VECTOR NVIC_INT_GPIO_PORT_C /** BUTTON_RIGHT -> PC5 */ -#define BUTTON_RIGHT_PORT_NO GPIO_C_NUM +#define BUTTON_RIGHT_PORT GPIO_C_NUM #define BUTTON_RIGHT_PIN 5 -#define BUTTON_RIGHT_PORT GPIO_C_BASE -#define BUTTON_RIGHT_PIN_MASK GPIO_PIN_MASK(BUTTON_RIGHT_PIN) #define BUTTON_RIGHT_VECTOR NVIC_INT_GPIO_PORT_C /** BUTTON_UP -> PC6 */ -#define BUTTON_UP_PORT_NO GPIO_C_NUM +#define BUTTON_UP_PORT GPIO_C_NUM #define BUTTON_UP_PIN 6 -#define BUTTON_UP_PORT GPIO_C_BASE -#define BUTTON_UP_PIN_MASK GPIO_PIN_MASK(BUTTON_UP_PIN) #define BUTTON_UP_VECTOR NVIC_INT_GPIO_PORT_C /** BUTTON_DOWN -> PC7 */ -#define BUTTON_DOWN_PORT_NO GPIO_C_NUM +#define BUTTON_DOWN_PORT GPIO_C_NUM #define BUTTON_DOWN_PIN 7 -#define BUTTON_DOWN_PORT GPIO_C_BASE -#define BUTTON_DOWN_PIN_MASK GPIO_PIN_MASK(BUTTON_DOWN_PIN) #define BUTTON_DOWN_VECTOR NVIC_INT_GPIO_PORT_C /* Notify various examples that we have Buttons */ @@ -184,14 +173,14 @@ * These values configure which CC2538 pins to use for the SPI lines. * @{ */ -#define CC2538_SPI_CLK_PORT_NUM GPIO_A_NUM -#define CC2538_SPI_CLK_PIN_NUM 2 -#define CC2538_SPI_MOSI_PORT_NUM GPIO_A_NUM -#define CC2538_SPI_MOSI_PIN_NUM 4 -#define CC2538_SPI_MISO_PORT_NUM GPIO_A_NUM -#define CC2538_SPI_MISO_PIN_NUM 5 -#define CC2538_SPI_SEL_PORT_NUM GPIO_B_NUM -#define CC2538_SPI_SEL_PIN_NUM 5 +#define SPI_CLK_PORT GPIO_A_NUM +#define SPI_CLK_PIN 2 +#define SPI_MOSI_PORT GPIO_A_NUM +#define SPI_MOSI_PIN 4 +#define SPI_MISO_PORT GPIO_A_NUM +#define SPI_MISO_PIN 5 +#define SPI_SEL_PORT GPIO_B_NUM +#define SPI_SEL_PIN 5 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/platform/cc2538dk/dev/button-sensor.c b/platform/cc2538dk/dev/button-sensor.c index 2a2a6a530..ba45e20c3 100644 --- a/platform/cc2538dk/dev/button-sensor.c +++ b/platform/cc2538dk/dev/button-sensor.c @@ -45,6 +45,21 @@ #include #include +#define BUTTON_SELECT_PORT_BASE GPIO_PORT_TO_BASE(BUTTON_SELECT_PORT) +#define BUTTON_SELECT_PIN_MASK GPIO_PIN_MASK(BUTTON_SELECT_PIN) + +#define BUTTON_LEFT_PORT_BASE GPIO_PORT_TO_BASE(BUTTON_LEFT_PORT) +#define BUTTON_LEFT_PIN_MASK GPIO_PIN_MASK(BUTTON_LEFT_PIN) + +#define BUTTON_RIGHT_PORT_BASE GPIO_PORT_TO_BASE(BUTTON_RIGHT_PORT) +#define BUTTON_RIGHT_PIN_MASK GPIO_PIN_MASK(BUTTON_RIGHT_PIN) + +#define BUTTON_UP_PORT_BASE GPIO_PORT_TO_BASE(BUTTON_UP_PORT) +#define BUTTON_UP_PIN_MASK GPIO_PIN_MASK(BUTTON_UP_PIN) + +#define BUTTON_DOWN_PORT_BASE GPIO_PORT_TO_BASE(BUTTON_DOWN_PORT) +#define BUTTON_DOWN_PIN_MASK GPIO_PIN_MASK(BUTTON_DOWN_PIN) +/*---------------------------------------------------------------------------*/ static struct timer debouncetimer; /*---------------------------------------------------------------------------*/ /** @@ -124,14 +139,13 @@ btn_callback(uint8_t port, uint8_t pin) static int config_select(int type, int value) { - config(BUTTON_SELECT_PORT, BUTTON_SELECT_PIN_MASK); + config(BUTTON_SELECT_PORT_BASE, BUTTON_SELECT_PIN_MASK); - ioc_set_over(BUTTON_SELECT_PORT_NO, BUTTON_SELECT_PIN, IOC_OVERRIDE_PUE); + ioc_set_over(BUTTON_SELECT_PORT, BUTTON_SELECT_PIN, IOC_OVERRIDE_PUE); nvic_interrupt_enable(BUTTON_SELECT_VECTOR); - gpio_register_callback(btn_callback, BUTTON_SELECT_PORT_NO, - BUTTON_SELECT_PIN); + gpio_register_callback(btn_callback, BUTTON_SELECT_PORT, BUTTON_SELECT_PIN); return 1; } /*---------------------------------------------------------------------------*/ @@ -149,14 +163,13 @@ config_select(int type, int value) static int config_left(int type, int value) { - config(BUTTON_LEFT_PORT, BUTTON_LEFT_PIN_MASK); + config(BUTTON_LEFT_PORT_BASE, BUTTON_LEFT_PIN_MASK); - ioc_set_over(BUTTON_LEFT_PORT_NO, BUTTON_LEFT_PIN, IOC_OVERRIDE_PUE); + ioc_set_over(BUTTON_LEFT_PORT, BUTTON_LEFT_PIN, IOC_OVERRIDE_PUE); nvic_interrupt_enable(BUTTON_LEFT_VECTOR); - gpio_register_callback(btn_callback, BUTTON_LEFT_PORT_NO, - BUTTON_LEFT_PIN); + gpio_register_callback(btn_callback, BUTTON_LEFT_PORT, BUTTON_LEFT_PIN); return 1; } /*---------------------------------------------------------------------------*/ @@ -174,14 +187,13 @@ config_left(int type, int value) static int config_right(int type, int value) { - config(BUTTON_RIGHT_PORT, BUTTON_RIGHT_PIN_MASK); + config(BUTTON_RIGHT_PORT_BASE, BUTTON_RIGHT_PIN_MASK); - ioc_set_over(BUTTON_RIGHT_PORT_NO, BUTTON_RIGHT_PIN, IOC_OVERRIDE_PUE); + ioc_set_over(BUTTON_RIGHT_PORT, BUTTON_RIGHT_PIN, IOC_OVERRIDE_PUE); nvic_interrupt_enable(BUTTON_RIGHT_VECTOR); - gpio_register_callback(btn_callback, BUTTON_RIGHT_PORT_NO, - BUTTON_RIGHT_PIN); + gpio_register_callback(btn_callback, BUTTON_RIGHT_PORT, BUTTON_RIGHT_PIN); return 1; } /*---------------------------------------------------------------------------*/ @@ -199,14 +211,13 @@ config_right(int type, int value) static int config_up(int type, int value) { - config(BUTTON_UP_PORT, BUTTON_UP_PIN_MASK); + config(BUTTON_UP_PORT_BASE, BUTTON_UP_PIN_MASK); - ioc_set_over(BUTTON_UP_PORT_NO, BUTTON_UP_PIN, IOC_OVERRIDE_PUE); + ioc_set_over(BUTTON_UP_PORT, BUTTON_UP_PIN, IOC_OVERRIDE_PUE); nvic_interrupt_enable(BUTTON_UP_VECTOR); - gpio_register_callback(btn_callback, BUTTON_UP_PORT_NO, - BUTTON_UP_PIN); + gpio_register_callback(btn_callback, BUTTON_UP_PORT, BUTTON_UP_PIN); return 1; } /*---------------------------------------------------------------------------*/ @@ -224,14 +235,13 @@ config_up(int type, int value) static int config_down(int type, int value) { - config(BUTTON_DOWN_PORT, BUTTON_DOWN_PIN_MASK); + config(BUTTON_DOWN_PORT_BASE, BUTTON_DOWN_PIN_MASK); - ioc_set_over(BUTTON_DOWN_PORT_NO, BUTTON_DOWN_PIN, IOC_OVERRIDE_PUE); + ioc_set_over(BUTTON_DOWN_PORT, BUTTON_DOWN_PIN, IOC_OVERRIDE_PUE); nvic_interrupt_enable(BUTTON_DOWN_VECTOR); - gpio_register_callback(btn_callback, BUTTON_DOWN_PORT_NO, - BUTTON_DOWN_PIN); + gpio_register_callback(btn_callback, BUTTON_DOWN_PORT, BUTTON_DOWN_PIN); return 1; } /*---------------------------------------------------------------------------*/ diff --git a/platform/cc2538dk/startup-gcc.c b/platform/cc2538dk/startup-gcc.c index 239f5a3d4..0c7587e45 100644 --- a/platform/cc2538dk/startup-gcc.c +++ b/platform/cc2538dk/startup-gcc.c @@ -38,13 +38,11 @@ */ #include "contiki.h" #include "reg.h" +#include "flash-cca.h" +#include "sys-ctrl.h" #include "uart.h" #include - -#define FLASH_START_ADDR 0x00200000 -#define BOOTLOADER_BACKDOOR_DISABLE 0xEFFFFFFF -#define SYS_CTRL_EMUOVR 0x400D20B4 /*---------------------------------------------------------------------------*/ extern int main(void); /*---------------------------------------------------------------------------*/ @@ -92,22 +90,19 @@ void uart_isr(void); /* Allocate stack space */ static unsigned long stack[512]; /*---------------------------------------------------------------------------*/ -/* - * Customer Configuration Area in the Lock Page - * Holds Image Vector table address (bytes 2012 - 2015) and - * Image Valid bytes (bytes 2008 -2011) - */ -typedef struct { - unsigned long bootldr_cfg; - unsigned long image_valid; - unsigned long image_vector_addr; -} lock_page_cca_t; +/* Linker construct indicating .text section location */ +extern uint8_t _text[0]; /*---------------------------------------------------------------------------*/ __attribute__ ((section(".flashcca"), used)) -const lock_page_cca_t __cca = { - BOOTLOADER_BACKDOOR_DISABLE, /* Bootloader backdoor disabled */ - 0, /* Image valid bytes */ - FLASH_START_ADDR /* Vector table located at the start of flash */ +const flash_cca_lock_page_t __cca = { + FLASH_CCA_BOOTLDR_CFG_DISABLE, /* Bootloader backdoor disabled */ + FLASH_CCA_IMAGE_VALID, /* Image valid */ + &_text, /* Vector table located at the start of .text */ + /* Unlock all pages and debug */ + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; /*---------------------------------------------------------------------------*/ __attribute__ ((section(".vectors"), used)) diff --git a/regression-tests/01-compile-base/Makefile b/regression-tests/01-compile-base/Makefile index a0e572144..ec01715ab 100644 --- a/regression-tests/01-compile-base/Makefile +++ b/regression-tests/01-compile-base/Makefile @@ -28,7 +28,7 @@ sky-shell-exec/sky \ sky-shell-webserver/sky \ telnet-server/minimal-net \ webserver/minimal-net \ -webserver-ipv6/sky \ +webserver-ipv6/exp5438 \ wget/minimal-net \ z1/z1 \ settings-example/avr-raven \ diff --git a/regression-tests/14-compile-8051-ports/Makefile b/regression-tests/14-compile-8051-ports/Makefile index 21d33740e..004c37d52 100644 --- a/regression-tests/14-compile-8051-ports/Makefile +++ b/regression-tests/14-compile-8051-ports/Makefile @@ -2,12 +2,7 @@ EXAMPLESDIR=../../examples TOOLSDIR=../../tools EXAMPLES = \ -hello-world/sensinode \ hello-world/cc2530dk \ -sensinode/sensinode \ -sensinode/border-router/sensinode \ -sensinode/udp-ipv6/sensinode \ -sensinode/sniffer/sensinode \ cc2530dk/cc2530dk \ cc2530dk/border-router/cc2530dk \ cc2530dk/udp-ipv6/cc2530dk \ diff --git a/regression-tests/17-slip-radio/01-sky-slip-radio-dio.csc b/regression-tests/17-slip-radio/01-sky-slip-radio-dio.csc new file mode 100644 index 000000000..02a7a3aae --- /dev/null +++ b/regression-tests/17-slip-radio/01-sky-slip-radio-dio.csc @@ -0,0 +1,190 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + slip radio 1 + 123456 + 1000000 + + se.sics.cooja.radiomediums.UDGM + 15.0 + 15.0 + 1.0 + 1.0 + + + 40000 + + + se.sics.cooja.mspmote.SkyMoteType + sky1 + slip radio + [CONTIKI_DIR]/examples/ipv6/slip-radio/slip-radio.c + make slip-radio.sky TARGET=sky + [CONTIKI_DIR]/examples/ipv6/slip-radio/slip-radio.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.Msp802154Radio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + se.sics.cooja.mspmote.SkyMoteType + sky2 + wait-dag + [CONTIKI_DIR]/regression-tests/17-slip-radio/code/wait-dag.c + make wait-dag.sky TARGET=sky + [CONTIKI_DIR]/regression-tests/17-slip-radio/code/wait-dag.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.Msp802154Radio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + + + se.sics.cooja.interfaces.Position + 43.565500781711165 + 14.697933087406794 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 1 + + sky1 + + + + + se.sics.cooja.interfaces.Position + 53.849666651434326 + 14.629826028666905 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 2 + + sky2 + + + + se.sics.cooja.plugins.SimControl + 315 + 1 + 175 + 433 + 0 + + + se.sics.cooja.plugins.Visualizer + + se.sics.cooja.plugins.skins.IDVisualizerSkin + se.sics.cooja.plugins.skins.GridVisualizerSkin + se.sics.cooja.plugins.skins.TrafficVisualizerSkin + se.sics.cooja.plugins.skins.UDGMVisualizerSkin + 14.682765905648006 0.0 0.0 14.682765905648006 -512.6620495401903 -96.80631081927221 + + 432 + 4 + 291 + 1 + 1 + + + se.sics.cooja.plugins.LogListener + + + + 758 + 3 + 289 + 748 + 159 + + + se.sics.cooja.plugins.Notes + + Slip-radio Tests, 01-sky-slip-radio-dio + +Test that we can send a packet over a slip-radio. +In this basic test, we send a DIO from mote 1, and wait for "DAG Found" in mote 2. + true + + 928 + 5 + 159 + 749 + -1 + + + se.sics.cooja.plugins.ScriptRunner + + + true + + 758 + 2 + 502 + 749 + 449 + + + se.sics.cooja.plugins.RadioLogger + + 150 + + 746 + 0 + 657 + 3 + 294 + + + diff --git a/regression-tests/17-slip-radio/Makefile b/regression-tests/17-slip-radio/Makefile new file mode 100644 index 000000000..272bc7da1 --- /dev/null +++ b/regression-tests/17-slip-radio/Makefile @@ -0,0 +1 @@ +include ../Makefile.simulation-test diff --git a/regression-tests/17-slip-radio/code/Makefile b/regression-tests/17-slip-radio/code/Makefile new file mode 100644 index 000000000..d1db363eb --- /dev/null +++ b/regression-tests/17-slip-radio/code/Makefile @@ -0,0 +1,9 @@ +all: wait-dag +APPS=servreg-hack +CONTIKI=../../.. + +WITH_UIP6=1 +UIP_CONF_IPV6=1 +CFLAGS+= -DUIP_CONF_IPV6_RPL + +include $(CONTIKI)/Makefile.include diff --git a/regression-tests/17-slip-radio/code/project-conf.h b/regression-tests/17-slip-radio/code/project-conf.h new file mode 100644 index 000000000..ce722a040 --- /dev/null +++ b/regression-tests/17-slip-radio/code/project-conf.h @@ -0,0 +1,12 @@ +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +#define NETSTACK_CONF_MAC csma_driver + +#undef NETSTACK_CONF_RDC +#define NETSTACK_CONF_RDC nullrdc_driver +#define NULLRDC_CONF_802154_AUTOACK 1 + +#define RPL_CONF_DAO_ACK 1 + +#endif /* __PROJECT_CONF_H__ */ diff --git a/core/net/mac/lpp.h b/regression-tests/17-slip-radio/code/wait-dag.c similarity index 58% rename from core/net/mac/lpp.h rename to regression-tests/17-slip-radio/code/wait-dag.c index f80541476..f1664b389 100644 --- a/core/net/mac/lpp.h +++ b/regression-tests/17-slip-radio/code/wait-dag.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Swedish Institute of Computer Science. + * Copyright (c) 2013, CETIC, www.cetic.be. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,22 +30,45 @@ * */ -/** - * \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 - */ +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/rpl/rpl.h" +#include "net/uip.h" +#include -#ifndef LPP_H_ -#define LPP_H_ +#define DEBUG DEBUG_FULL +#include "net/uip-debug.h" -#include "net/mac/rdc.h" -#include "dev/radio.h" +#define INTERVAL 5 * CLOCK_SECOND -extern const struct rdc_driver lpp_driver; +/*---------------------------------------------------------------------------*/ +PROCESS(wait_for_dag, "Wait for DAG process"); +AUTOSTART_PROCESSES(&wait_for_dag); +/*---------------------------------------------------------------------------*/ +static void +timeout_handler(void) +{ + rpl_dag_t *dag = rpl_get_any_dag(); + if (dag != NULL) { + PRINTF("DAG Found\n"); + } +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(wait_for_dag, ev, data) +{ + static struct etimer et; -#endif /* LPP_H_ */ + PROCESS_BEGIN(); + PRINTF("Wait for DAG process started\n"); + etimer_set(&et, INTERVAL); + while(1) { + PROCESS_YIELD(); + if(etimer_expired(&et)) { + timeout_handler(); + etimer_restart(&et); + } + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/