From f31d6f271fe7b1989fb335a251cfa07a22f83f57 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Fri, 22 Nov 2013 15:37:21 +0100 Subject: [PATCH 01/22] Bugfix: if a SYN is received in the SYN_RCVD state we should not send a blank SYN, but a SYNACK in response. --- core/net/uip6.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/net/uip6.c b/core/net/uip6.c index e79486ff1..7f51ce4e9 100644 --- a/core/net/uip6.c +++ b/core/net/uip6.c @@ -1833,8 +1833,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; } From d577d03e212daa32a7b332a5e4297daf264f9c94 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Fri, 22 Nov 2013 15:38:20 +0100 Subject: [PATCH 02/22] Bugfix: correctly handle the case if uip_sappdata is NULL. --- core/net/uip6.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/core/net/uip6.c b/core/net/uip6.c index 7f51ce4e9..f0d93688c 100644 --- a/core/net/uip6.c +++ b/core/net/uip6.c @@ -2320,12 +2320,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); + } } } } From 61a8fa9977a0078af84ca5e41890c84a1ff5d686 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Fri, 22 Nov 2013 15:44:48 +0100 Subject: [PATCH 03/22] Allow the default TTL to be configured with UIP_CONF_TTL --- core/net/uipopt.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/net/uipopt.h b/core/net/uipopt.h index 7c9939003..ce871985f 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 From ea4bc3816f649175f2d2d3592dd2abd84735ac49 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Fri, 22 Nov 2013 15:46:48 +0100 Subject: [PATCH 04/22] Produce an error if the UIP_TCP_MSS is too large for UIP_BUFSIZE --- core/net/uipopt.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/net/uipopt.h b/core/net/uipopt.h index ce871985f..d0d3219ad 100644 --- a/core/net/uipopt.h +++ b/core/net/uipopt.h @@ -382,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 From d2f3795a3025c95c1eea10cb362f4d40011d1ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Mon, 25 Nov 2013 15:00:41 +0100 Subject: [PATCH 05/22] cc2538: Clean up port and pin definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Homogenize port and pin definitions naming: - PERIPHERAL_FUNCTION_PORT for the port ID, - PERIPHERAL_FUNCTION_PIN for the pin ID, - PERIPHERAL_FUNCTION_PORT_BASE for the port base, - PERIPHERAL_FUNCTION_PIN_MASK for the pin mask. Define only PERIPHERAL_FUNCTION_PORT and PERIPHERAL_FUNCTION_PIN in board.h, and deduce PERIPHERAL_FUNCTION_PORT_BASE and PERIPHERAL_FUNCTION_PIN_MASK in the driver from the former definitions. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/dev/spi.c | 41 +++++++++++++--------- cpu/cc2538/dev/uart.c | 16 +++++++-- cpu/cc2538/usb/usb-arch.c | 7 ++-- platform/cc2538dk/dev/board.h | 39 ++++++++------------- platform/cc2538dk/dev/button-sensor.c | 50 ++++++++++++++++----------- 5 files changed, 88 insertions(+), 65 deletions(-) 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/usb/usb-arch.c b/cpu/cc2538/usb/usb-arch.c index 46b7bbd61..d9c58558b 100644 --- a/cpu/cc2538/usb/usb-arch.c +++ b/cpu/cc2538/usb/usb-arch.c @@ -54,6 +54,9 @@ #include #include /*---------------------------------------------------------------------------*/ +#define USB_PULLUP_PORT_BASE GPIO_PORT_TO_BASE(USB_PULLUP_PORT) +#define USB_PULLUP_PIN_MASK GPIO_PIN_MASK(USB_PULLUP_PIN) +/*---------------------------------------------------------------------------*/ /* EP max FIFO sizes without double buffering */ #if CTRL_EP_SIZE > 32 #error Control endpoint size too big @@ -330,8 +333,8 @@ usb_arch_setup(void) 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); + GPIO_SET_OUTPUT(USB_PULLUP_PORT_BASE, USB_PULLUP_PIN_MASK); + GPIO_SET_PIN(USB_PULLUP_PORT_BASE, USB_PULLUP_PIN_MASK); for(i = 0; i < USB_MAX_ENDPOINTS; i++) { usb_endpoints[i].flags = 0; 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; } /*---------------------------------------------------------------------------*/ From 270ed237fd8956c347608e3c60d79e941f3ccdae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Mon, 25 Nov 2013 15:15:35 +0100 Subject: [PATCH 06/22] cc2538: usb: Make the GPIO driving the pull-up optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The data sheet recommends that the USB pull-up resistor be driven by a GPIO so that it can be controlled by software, but this is not mandatory. Hence, leave the choice so that CC253-based boards not using this option can build and work fine. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/usb/usb-arch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cpu/cc2538/usb/usb-arch.c b/cpu/cc2538/usb/usb-arch.c index d9c58558b..c209d7778 100644 --- a/cpu/cc2538/usb/usb-arch.c +++ b/cpu/cc2538/usb/usb-arch.c @@ -54,8 +54,12 @@ #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 @@ -332,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 */ + /* 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; From 621f4f7339eac31b424fcbcd6838e2822e9c1f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Mon, 25 Nov 2013 15:43:37 +0100 Subject: [PATCH 07/22] cc2538: lpm: Give access to the SRAM non-retention area for PM2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If PM2 is enabled with LPM_CONF_MAX_PM, but not active, the non-retention area of the SRAM can be useful to place temporary data that does not fit in the low-leakage SRAM, typically after having called lpm_set_max_pm(LPM_PM1). Hence, give access to this non-retention area thanks to .nrdata* sections. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/cc2538.lds | 22 ++++++++++++++++++---- cpu/cc2538/lpm.h | 6 ++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cpu/cc2538/cc2538.lds b/cpu/cc2538/cc2538.lds index f63eb2d17..6ed024a30 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 +#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/lpm.h b/cpu/cc2538/lpm.h index 22b4d4958..f4ca3366f 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); From 436b585d7e44250cdb73523f9e2f54b4556a1a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Mon, 25 Nov 2013 20:48:52 +0100 Subject: [PATCH 08/22] cc2538dk: Make it possible to override SLIP_ARCH_CONF_ENABLED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the comment in contiki-conf.h says, the automatic definition of SLIP_ARCH_CONF_ENABLED works only if UIP_FALLBACK_INTERFACE is tied to SLIP. If UIP_FALLBACK_INTERFACE is set to another interface, SLIP_ARCH_CONF_ENABLED is still automatically set to 1, leading to unwanted SLIP_END characters from dbg.c:putchar() being printed on the UART. This change makes it possible to force the definition of SLIP_ARCH_CONF_ENABLED (e.g. from project-conf.h), so that it can be disabled if UIP_FALLBACK_INTERFACE is used with something else than SLIP. Signed-off-by: Benoît Thébaudeau --- platform/cc2538dk/contiki-conf.h | 2 ++ 1 file changed, 2 insertions(+) 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 From 44a5c76884d0190675373b16ee42c9a254650262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Tue, 26 Nov 2013 22:10:47 +0100 Subject: [PATCH 09/22] cc2538: gpio: Add macros to use GPIO power-up interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GPIO power-up interrupts have to be configured and enabled in order to be able to wake-up the SoC from PM1+ upon a signal edge occurring on a GPIO input pin. This set of macros allows to: - configure the signal edge triggering a power-up interrupt, - enable and disable a power-up interrupt, - clear a power-up interrupt flag. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/dev/gpio.h | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) 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] From 1a696eb123613835a6c8ae663ed79f87395c4874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Tue, 26 Nov 2013 22:20:05 +0100 Subject: [PATCH 10/22] cc2538: gpio: Clear the power-up interrupts in the port ISRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pending GPIO power-up interrupts have to be cleared in the ISRs in order not to re-trigger the interrupts and the wake-up events. The power-up interrupts of all pins are cleared for each port in the corresponding port ISR. This is done after calling the registered callbacks so that the callbacks can know which pin woke up the SoC. This is done after clearing the regular interrupt in order to avoid getting a new wake-up interrupt without the regular interrupt in the case of a new wake-up edge occurring between the two clears. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/dev/gpio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpu/cc2538/dev/gpio.c b/cpu/cc2538/dev/gpio.c index 80a1b7d8d..111946001 100644 --- a/cpu/cc2538/dev/gpio.c +++ b/cpu/cc2538/dev/gpio.c @@ -90,6 +90,7 @@ gpio_port_a_isr() 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); } @@ -105,6 +106,7 @@ gpio_port_b_isr() 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); } @@ -120,6 +122,7 @@ gpio_port_c_isr() 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); } @@ -135,6 +138,7 @@ gpio_port_d_isr() 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); } From f86aaf7c146214d43630af1999fc68d5764f2f06 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Thu, 28 Nov 2013 15:24:22 +0100 Subject: [PATCH 11/22] Removed the xmac.c code --- core/net/mac/Makefile.mac | 2 +- core/net/mac/xmac.c | 1009 ------------------------------------- core/net/mac/xmac.h | 64 --- 3 files changed, 1 insertion(+), 1074 deletions(-) delete mode 100644 core/net/mac/xmac.c delete mode 100644 core/net/mac/xmac.h diff --git a/core/net/mac/Makefile.mac b/core/net/mac/Makefile.mac index 1d80a7fa3..7bdb7d957 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 lpp.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/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_ */ From 0908924f91f2a0ea9359dcab0605f68ffd4b41e3 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Thu, 28 Nov 2013 15:24:40 +0100 Subject: [PATCH 12/22] Removed the lpp.c code --- core/net/mac/Makefile.mac | 2 +- core/net/mac/lpp.c | 1054 ------------------------------------- core/net/mac/lpp.h | 51 -- 3 files changed, 1 insertion(+), 1106 deletions(-) delete mode 100644 core/net/mac/lpp.c delete mode 100644 core/net/mac/lpp.h diff --git a/core/net/mac/Makefile.mac b/core/net/mac/Makefile.mac index 7bdb7d957..e3f04262f 100644 --- a/core/net/mac/Makefile.mac +++ b/core/net/mac/Makefile.mac @@ -1,2 +1,2 @@ -CONTIKI_SOURCEFILES += cxmac.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/lpp.h b/core/net/mac/lpp.h deleted file mode 100644 index f80541476..000000000 --- a/core/net/mac/lpp.h +++ /dev/null @@ -1,51 +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 - */ - -#ifndef LPP_H_ -#define LPP_H_ - -#include "net/mac/rdc.h" -#include "dev/radio.h" - -extern const struct rdc_driver lpp_driver; - -#endif /* LPP_H_ */ From b01469907bc8e483c4776e30441e8f526a5e1d2c Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Sun, 24 Nov 2013 17:45:34 +0100 Subject: [PATCH 13/22] Don't compile webserver-ipv6 for the sky platform, as it is a little too small. Use the larger exp5438 instead --- regression-tests/01-compile-base/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 \ From d8d15fec67e84d55ce13a380823220e509b5b59d Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Tue, 3 Dec 2013 13:21:39 +0000 Subject: [PATCH 14/22] Remove Sensinode tests from travis --- regression-tests/14-compile-8051-ports/Makefile | 5 ----- 1 file changed, 5 deletions(-) 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 \ From 65806f53ebffae14278f6c051ff4a7634b9aea22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Wed, 27 Nov 2013 21:49:24 +0100 Subject: [PATCH 15/22] cc2538dk: startup-gcc: Do not redefine SYS_CTRL_EMUOVR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SYS_CTRL_EMUOVR is already defined in sys-ctrl.h, so #include this header file instead of redefining SYS_CTRL_EMUOVR in startup-gcc.c. Signed-off-by: Benoît Thébaudeau --- platform/cc2538dk/startup-gcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/cc2538dk/startup-gcc.c b/platform/cc2538dk/startup-gcc.c index 239f5a3d4..ce4768fb2 100644 --- a/platform/cc2538dk/startup-gcc.c +++ b/platform/cc2538dk/startup-gcc.c @@ -38,13 +38,13 @@ */ #include "contiki.h" #include "reg.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); /*---------------------------------------------------------------------------*/ From a2686e581eb1d27356aa0a008b88afd6ec1d2433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Wed, 27 Nov 2013 21:55:18 +0100 Subject: [PATCH 16/22] cc2538: Add header file for flash CCA page and use it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a dedicated header file with all the definitions for the flash lock bit page and customer configuration area. This avoids duplicating those definitions in the startup-gcc.c files of all CC2538-based platforms, and this also allows to easily manipulate the CCA from outside startup-gcc.c (e.g. for on-the-air firmware update). The definitions are now complete contrary to what was in startup-gcc.c: - Definitions have been added to select the bootloader backdoor pin and active level if enabled. - Definitions have been added to access the page and debug lock bits. The debug lock bit can be used to prevent someone from reading back a programmed firmware through JTAG if the firmware binary image has to be confidential, which should be combined with a disabled bootloader backdoor. - The application entry point is now tied to the beginning of the .text section instead of to the beginning of the flash. This allows projects using custom linker scripts to place the application entry point anywhere in the flash, which can be useful e.g. for on-the-air firmware update. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/cc2538.lds | 2 +- cpu/cc2538/dev/flash-cca.h | 93 +++++++++++++++++++++++++++++++++ platform/cc2538dk/startup-gcc.c | 29 +++++----- 3 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 cpu/cc2538/dev/flash-cca.h diff --git a/cpu/cc2538/cc2538.lds b/cpu/cc2538/cc2538.lds index 6ed024a30..635ec454b 100644 --- a/cpu/cc2538/cc2538.lds +++ b/cpu/cc2538/cc2538.lds @@ -46,7 +46,7 @@ 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 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/platform/cc2538dk/startup-gcc.c b/platform/cc2538dk/startup-gcc.c index ce4768fb2..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 /*---------------------------------------------------------------------------*/ 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)) From 6f22fd66428c8c3b47fba2a5977d3f0d74adf107 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Thu, 5 Dec 2013 18:16:04 +0000 Subject: [PATCH 17/22] Remove LPP discussion from the cc2538 README --- platform/cc2538dk/README.md | 2 -- 1 file changed, 2 deletions(-) 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" From 8514a91ea98dd5015aba083af2d3f16a54b93e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Tue, 3 Dec 2013 18:44:01 +0100 Subject: [PATCH 18/22] cc2538: lpm: Fix energest context when aborting lpm_enter() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In one of the abort cases in lpm_enter(), the energest context has previously been set to LPM, so the abort code needs to set it back to CPU. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/lpm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpu/cc2538/lpm.c b/cpu/cc2538/lpm.c index bbc035219..74d00df91 100644 --- a/cpu/cc2538/lpm.c +++ b/cpu/cc2538/lpm.c @@ -301,6 +301,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(); From 13006e1c737bf557f83ef9da6ccd9037eacb5a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Tue, 3 Dec 2013 18:51:39 +0100 Subject: [PATCH 19/22] cc2538: lpm: Let system clock transitions complete before further changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a matter of precaution, always make sure that pending system clock transitions are complete before requesting a new change of the system clock source. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/lpm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpu/cc2538/lpm.c b/cpu/cc2538/lpm.c index 74d00df91..da0349495 100644 --- a/cpu/cc2538/lpm.c +++ b/cpu/cc2538/lpm.c @@ -158,6 +158,9 @@ 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; From f149197aa8b755754edfd7717b73ba666498a0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Tue, 3 Dec 2013 19:03:00 +0100 Subject: [PATCH 20/22] cc2538: lpm: Speed up the transition to the 32-MHz XOSC after wake-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As recommended by the CC2538 User's Guide, set SYS_CTRL_CLOCK_CTRL.OSC_PD to 0 before asserting WFI, and set it to 1 after the system clock is sourced from the 32-MHz XOSC following wake-up. This allows to automatically start both oscillators upon wake-up in order to partially hide the 32-MHz XOSC startup time by the 16-MHz RCOSC startup time. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/lpm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cpu/cc2538/lpm.c b/cpu/cc2538/lpm.c index da0349495..f1605771b 100644 --- a/cpu/cc2538/lpm.c +++ b/cpu/cc2538/lpm.c @@ -166,11 +166,20 @@ select_32_mhz_xosc(void) /* 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); From 5261bb861d21b0001a664e2e2028ea7af966caab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Tue, 3 Dec 2013 19:16:24 +0100 Subject: [PATCH 21/22] cc2538: lpm: Fix RTIMER_NOW() upon wake-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Because of this RTIMER_NOW() fixup, lpm_exit() has to be called at the very beginning of ISRs waking up the SoC. This also ensures that all clocks and timers are enabled at the correct frequency and updated before using them following wake-up. Without this fix, etimers could sometimes (randomly, depending on timings) become ultra slow (observed from 10x to 40x slower than normal) if the system exited PM1/2 very often. This issue occurred more often with PM1. Signed-off-by: Benoît Thébaudeau --- cpu/cc2538/dev/gpio.c | 16 ++++++++-------- cpu/cc2538/lpm.c | 10 ++++++++++ cpu/cc2538/lpm.h | 6 ++++++ cpu/cc2538/rtimer-arch.c | 14 +++++++------- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/cpu/cc2538/dev/gpio.c b/cpu/cc2538/dev/gpio.c index 111946001..2961a2eb0 100644 --- a/cpu/cc2538/dev/gpio.c +++ b/cpu/cc2538/dev/gpio.c @@ -83,10 +83,10 @@ 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); @@ -99,10 +99,10 @@ 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); @@ -115,10 +115,10 @@ 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); @@ -131,10 +131,10 @@ 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); diff --git a/cpu/cc2538/lpm.c b/cpu/cc2538/lpm.c index f1605771b..80b536998 100644 --- a/cpu/cc2538/lpm.c +++ b/cpu/cc2538/lpm.c @@ -199,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); diff --git a/cpu/cc2538/lpm.h b/cpu/cc2538/lpm.h index f4ca3366f..0c497b5be 100644 --- a/cpu/cc2538/lpm.h +++ b/cpu/cc2538/lpm.h @@ -150,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); From d772baa37d7b8d02b7eb654e78a6f43152beba3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dawans?= Date: Tue, 12 Mar 2013 02:06:58 +0100 Subject: [PATCH 22/22] Travis test for slip-radio --- .travis.yml | 1 + .../17-slip-radio/01-sky-slip-radio-dio.csc | 190 ++++++++++++++++++ regression-tests/17-slip-radio/Makefile | 1 + regression-tests/17-slip-radio/code/Makefile | 9 + .../17-slip-radio/code/project-conf.h | 12 ++ .../17-slip-radio/code/wait-dag.c | 74 +++++++ 6 files changed, 287 insertions(+) create mode 100644 regression-tests/17-slip-radio/01-sky-slip-radio-dio.csc create mode 100644 regression-tests/17-slip-radio/Makefile create mode 100644 regression-tests/17-slip-radio/code/Makefile create mode 100644 regression-tests/17-slip-radio/code/project-conf.h create mode 100644 regression-tests/17-slip-radio/code/wait-dag.c 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/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/regression-tests/17-slip-radio/code/wait-dag.c b/regression-tests/17-slip-radio/code/wait-dag.c new file mode 100644 index 000000000..f1664b389 --- /dev/null +++ b/regression-tests/17-slip-radio/code/wait-dag.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013, CETIC, www.cetic.be. + * 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. + * + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/rpl/rpl.h" +#include "net/uip.h" +#include + +#define DEBUG DEBUG_FULL +#include "net/uip-debug.h" + +#define INTERVAL 5 * CLOCK_SECOND + +/*---------------------------------------------------------------------------*/ +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; + + 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(); +} +/*---------------------------------------------------------------------------*/